untrusted comment: verify with openbsd-79-base.pub RWTSdNN9A3yvWOwfHTvLuU2gTYMJZiMCmmcgauS0HuuI2BHbITKJn5A3mM0Xu9GZJbdNDKuTQipaf8IsDSLnwP8aXSxZ372GOgs= OpenBSD 7.9 errata 023, September 30, 2026: Update unbound(8) to version 1.26.1. CVE-2026-14586 CVE-2026-32665 CVE-2026-32792 CVE-2026-33278 CVE-2026-40622 CVE-2026-40691 CVE-2026-41292 CVE-2026-41637 CVE-2026-42534 CVE-2026-42923 CVE-2026-42944 CVE-2026-42955 CVE-2026-42959 CVE-2026-42960 CVE-2026-44390 CVE-2026-44608 CVE-2026-44621 CVE-2026-44687 CVE-2026-44690 CVE-2026-46582 CVE-2026-50045 CVE-2026-50046 CVE-2026-50243 CVE-2026-50248 CVE-2026-50251 CVE-2026-50252 CVE-2026-52863 CVE-2026-54478 CVE-2026-55708 CVE-2026-55717 CVE-2026-55973 CVE-2026-55990 CVE-2026-55991 CVE-2026-56416 CVE-2026-56444 Apply by doing: signify -Vep /etc/signify/openbsd-79-base.pub -x 023_unbound.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install unwind and unbound: cd /usr/src/sbin/unwind make obj make make install cd /usr/src/usr.sbin/unbound make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper clean make -f Makefile.bsd-wrapper make -f Makefile.bsd-wrapper install Index: sbin/unwind/libunbound/config.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/config.h,v diff -u -p -r1.28 config.h --- sbin/unwind/libunbound/config.h 28 Nov 2025 07:37:51 -0000 1.28 +++ sbin/unwind/libunbound/config.h 21 Sep 2026 16:27:57 -0000 @@ -36,6 +36,9 @@ /* Whether daemon is deprecated */ /* #undef DEPRECATED_DAEMON */ +/* Whether X509_NAME_get_text_by_NID is deprecated */ +/* #undef DEPRECATED_X509_NAME_GET_TEXT_BY_NID */ + /* Deprecate RSA 1024 bit length, makes that an unsupported key */ /* #undef DEPRECATE_RSA_1024 */ @@ -65,12 +68,18 @@ /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 +/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */ +#define HAVE_ASN1_STRING_GET0_DATA 1 + /* Whether the C compiler accepts the "fallthrough" attribute */ #define HAVE_ATTR_FALLTHROUGH 1 /* Whether the C compiler accepts the "format" attribute */ #define HAVE_ATTR_FORMAT 1 +/* Whether the C compiler accepts the "nonstring" attribute */ +#define HAVE_ATTR_NONSTRING 1 + /* Whether the C compiler accepts the "noreturn" attribute */ #define HAVE_ATTR_NORETURN 1 @@ -142,6 +151,10 @@ to 0 if you don't. */ /* #undef HAVE_DECL_NGTCP2_CRYPTO_ENCRYPT_CB */ +/* Define to 1 if you have the declaration of `ngtcp2_crypto_ossl_ctx_new', + and to 0 if you don't. */ +/* #undef HAVE_DECL_NGTCP2_CRYPTO_OSSL_CTX_NEW */ + /* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you don't. */ #define HAVE_DECL_NID_ED25519 1 @@ -291,6 +304,12 @@ /* Define to 1 if you have the `FIPS_mode' function. */ #define HAVE_FIPS_MODE 1 +/* Define to 1 if you have the `fnmatch' function. */ +#define HAVE_FNMATCH 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FNMATCH_H 1 + /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 @@ -515,6 +534,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_BN_H 1 +/* Define to 1 if you have the `OPENSSL_cleanup' function. */ +#define HAVE_OPENSSL_CLEANUP 1 + /* Define to 1 if you have the `OPENSSL_config' function. */ #define HAVE_OPENSSL_CONFIG 1 @@ -566,12 +588,27 @@ /* Define if you have POSIX threads libraries and header files. */ /* #undef HAVE_PTHREAD */ +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PTHREAD_NP_H */ + /* Have PTHREAD_PRIO_INHERIT. */ /* #undef HAVE_PTHREAD_PRIO_INHERIT */ /* Define to 1 if the system has the type `pthread_rwlock_t'. */ /* #undef HAVE_PTHREAD_RWLOCK_T */ +/* Define if pthread_setname_np has the common 2 arguments. */ +/* #undef HAVE_PTHREAD_SETNAME_NP */ + +/* Define if pthread_setname_np has only 1 argument. */ +/* #undef HAVE_PTHREAD_SETNAME_NP1 */ + +/* Define if pthread_setname_np has 3 arguments. */ +/* #undef HAVE_PTHREAD_SETNAME_NP3 */ + +/* Define if pthread_setname_np exists as pthread_set_name_np instead. */ +/* #undef HAVE_PTHREAD_SET_NAME_NP */ + /* Define to 1 if the system has the type `pthread_spinlock_t'. */ /* #undef HAVE_PTHREAD_SPINLOCK_T */ @@ -672,9 +709,16 @@ /* Define to 1 if you have the `SSL_is_quic' function. */ /* #undef HAVE_SSL_IS_QUIC */ +/* Define to 1 if you have the `SSL_set1_dnsname' function. */ +/* #undef HAVE_SSL_SET1_DNSNAME */ + /* Define to 1 if you have the `SSL_set1_host' function. */ #define HAVE_SSL_SET1_HOST 1 +/* Define to 1 if you have the `SSL_set_quic_tls_early_data_enabled' function. + */ +/* #undef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED */ + /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 @@ -737,6 +781,12 @@ /* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */ #define HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1 +/* Define to 1 if `st_mtimensec' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1 + +/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 + /* Define if you have Swig libraries and header files. */ /* #undef HAVE_SWIG */ @@ -833,6 +883,12 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_WS2TCPIP_H */ +/* Define to 1 if you have the `X509_get_key_usage' function. */ +#define HAVE_X509_GET_KEY_USAGE 1 + +/* Define to 1 if you have the `X509_NAME_get_text_by_NID' function. */ +#define HAVE_X509_NAME_GET_TEXT_BY_NID 1 + /* Define to 1 if you have the `X509_VERIFY_PARAM_set1_host' function. */ #define HAVE_X509_VERIFY_PARAM_SET1_HOST 1 @@ -895,7 +951,7 @@ #define PACKAGE_NAME "unbound" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "unbound 1.24.1" +#define PACKAGE_STRING "unbound 1.26.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "unbound" @@ -904,7 +960,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.24.1" +#define PACKAGE_VERSION "1.26.1" /* default pidfile location */ #define PIDFILE "" @@ -927,7 +983,7 @@ #define ROOT_CERT_FILE "/var/unbound/etc/icannbundle.pem" /* version number for resource files */ -#define RSRC_PACKAGE_VERSION 1,24,1,0 +#define RSRC_PACKAGE_VERSION 1,26,1,0 /* Directory to chdir to */ #define RUN_DIR "/var/unbound/etc" @@ -1384,6 +1440,17 @@ #else /* !HAVE_ATTR_UNUSED */ # define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ + + +#if defined(DOXYGEN) +# define ATTR_NONSTRING(x) x +#elif defined(__cplusplus) +# define ATTR_NONSTRING(x) __attribute__((nonstring)) x +#elif defined(HAVE_ATTR_NONSTRING) +# define ATTR_NONSTRING(x) __attribute__((nonstring)) x +#else /* !HAVE_ATTR_NONSTRING */ +# define ATTR_NONSTRING(x) x +#endif /* !HAVE_ATTR_NONSTRING */ #ifndef HAVE_FSEEKO Index: sbin/unwind/libunbound/daemon/remote.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/daemon/remote.h,v diff -u -p -r1.1 remote.h --- sbin/unwind/libunbound/daemon/remote.h 14 Sep 2025 15:16:53 -0000 1.1 +++ sbin/unwind/libunbound/daemon/remote.h 21 Sep 2026 16:27:57 -0000 @@ -49,6 +49,26 @@ #include #endif #include "util/locks.h" + +struct comm_reply; +struct comm_point; + +/** fast reload thread commands to remote service thread event callback */ +void fast_reload_service_cb(int fd, short bits, void* arg); + +/** fast reload callback for the remote control client connection */ +int fast_reload_client_callback(struct comm_point* c, void* arg, int err, + struct comm_reply* rep); + +/** handle remote control accept callbacks */ +int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*); + +/** handle remote control data callbacks */ +int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*); + +/** routine to printout option values over SSL */ +void remote_get_opt_ssl(char* line, void* arg); + struct config_file; struct listen_list; struct listen_port; @@ -206,6 +226,12 @@ struct fast_reload_thread { int commpair[2]; /** thread id, of the io thread */ ub_thread_type tid; +#ifdef HAVE_GETTID + /** thread tid, the LWP id */ + pid_t thread_tid; + /** if logging should include the LWP id */ + int thread_tid_log; +#endif /** if the io processing has started */ int started; /** if the thread has to quit */ @@ -249,6 +275,8 @@ struct fast_reload_thread { struct fast_reload_auth_change* auth_zone_change_list; /** the old tree of auth zones, to lookup. */ struct auth_zones* old_auth_zones; + /** If the ssl ctxs have changed. */ + int sslctxs_changed; }; /** Index: sbin/unwind/libunbound/daemon/worker.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/daemon/worker.h,v diff -u -p -r1.4 worker.h --- sbin/unwind/libunbound/daemon/worker.h 14 Sep 2025 15:16:53 -0000 1.4 +++ sbin/unwind/libunbound/daemon/worker.h 21 Sep 2026 16:27:57 -0000 @@ -104,10 +104,6 @@ struct worker { struct listen_dnsport* front; /** the backside outside network interface to the auth servers */ struct outside_network* back; - /** ports to be used by this worker. */ - int* ports; - /** number of ports for this worker */ - int numports; /** the signal handler */ struct comm_signal* comsig; /** commpoint to listen to commands. */ @@ -146,11 +142,9 @@ struct worker { * with backpointers only. Use worker_init on it later. * @param daemon: the daemon that this worker thread is part of. * @param id: the thread number from 0.. numthreads-1. - * @param ports: the ports it is allowed to use, array. - * @param n: the number of ports. * @return: the new worker or NULL on alloc failure. */ -struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n); +struct worker* worker_create(struct daemon* daemon, int id); /** * Initialize worker. Index: sbin/unwind/libunbound/dns64/dns64.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/dns64/dns64.c,v diff -u -p -r1.13 dns64.c --- sbin/unwind/libunbound/dns64/dns64.c 29 Sep 2025 14:53:38 -0000 1.13 +++ sbin/unwind/libunbound/dns64/dns64.c 21 Sep 2026 16:27:57 -0000 @@ -366,22 +366,23 @@ static int dns64_apply_cfg(struct dns64_env* dns64_env, struct config_file* cfg) { struct config_strlist* s; - verbose(VERB_ALGO, "dns64-prefix: %s", cfg->dns64_prefix); - if (!netblockstrtoaddr(cfg->dns64_prefix ? cfg->dns64_prefix : - DEFAULT_DNS64_PREFIX, 0, &dns64_env->prefix_addr, + const char* dns64_prefix = cfg->dns64_prefix ? + cfg->dns64_prefix : DEFAULT_DNS64_PREFIX; + verbose(VERB_ALGO, "dns64-prefix: %s", dns64_prefix); + if (!netblockstrtoaddr(dns64_prefix, 0, &dns64_env->prefix_addr, &dns64_env->prefix_addrlen, &dns64_env->prefix_net)) { - log_err("cannot parse dns64-prefix netblock: %s", cfg->dns64_prefix); + log_err("cannot parse dns64-prefix netblock: %s", dns64_prefix); return 0; } if (!addr_is_ip6(&dns64_env->prefix_addr, dns64_env->prefix_addrlen)) { - log_err("dns64_prefix is not IPv6: %s", cfg->dns64_prefix); + log_err("dns64_prefix is not IPv6: %s", dns64_prefix); return 0; } if (dns64_env->prefix_net != 32 && dns64_env->prefix_net != 40 && dns64_env->prefix_net != 48 && dns64_env->prefix_net != 56 && dns64_env->prefix_net != 64 && dns64_env->prefix_net != 96 ) { - log_err("dns64-prefix length it not 32, 40, 48, 56, 64 or 96: %s", - cfg->dns64_prefix); + log_err("dns64-prefix length is not 32, 40, 48, 56, 64 or 96: %s", + dns64_prefix); return 0; } for(s = cfg->dns64_ignore_aaaa; s; s = s->next) { @@ -496,8 +497,8 @@ handle_ipv6_ptr(struct module_qstate* qs /* Create the new sub-query. */ fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0, 0, - &subq)) + if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->client_info, + qstate->query_flags, 0, 0, &subq)) return module_error; if (subq) { subq->curmod = id; @@ -522,8 +523,8 @@ generate_type_A_query(struct module_qsta /* Start the sub-query. */ fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0, - 0, &subq)) + if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->client_info, + qstate->query_flags, 0, 0, &subq)) { verbose(VERB_ALGO, "dns64: sub-query creation failed"); return module_error; @@ -642,6 +643,12 @@ handle_event_moddone(struct module_qstat qstate->return_msg->rep && reply_find_answer_rrset(&qstate->qinfo, qstate->return_msg->rep); int synth_qname = 0; + if(could_synth && !has_data && qstate->env->need_to_validate && + qstate->return_msg && qstate->return_msg->rep && + qstate->return_msg->rep->security == sec_status_bogus) { + verbose(VERB_ALGO, "dns64: bogus AAAA reply not synthesized"); + could_synth = 0; + } if(could_synth && (!has_data || @@ -653,8 +660,11 @@ handle_event_moddone(struct module_qstat /* Store the response in cache. */ if( (!iq || !iq->started_no_cache_store) && + !qstate->rpz_applied && !qstate->rpz_passthru && + !qstate->is_subnet_answer && qstate->return_msg && qstate->return_msg->rep && + !qstate->fwd_stub_no_cache && !dns_cache_store( qstate->env, &qstate->qinfo, qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0, NULL, @@ -716,8 +726,15 @@ dns64_operate(struct module_qstate* qsta } if(qstate->ext_state[id] == module_finished) { iq = (struct dns64_qstate*)qstate->minfo[id]; - if(iq && iq->state != DNS64_INTERNAL_QUERY) - qstate->no_cache_store = iq->started_no_cache_store; + if(iq && iq->state != DNS64_INTERNAL_QUERY) { + if(qstate->fwd_stub_no_cache) { + /* If the forward/stub has no cache, then + * continue with the query with no cache. */ + qstate->no_cache_store = qstate->fwd_stub_no_cache; + } else { + qstate->no_cache_store = iq->started_no_cache_store; + } + } } } @@ -824,6 +841,7 @@ dns64_adjust_a(int id, struct module_qst size_t i, s; struct packed_rrset_data* fd, *dd; struct ub_packed_rrset_key* fk, *dk; + int allocated_return_msg = 0; verbose(VERB_ALGO, "converting A answers to AAAA answers"); @@ -839,6 +857,7 @@ dns64_adjust_a(int id, struct module_qst return; memset(super->return_msg, 0, sizeof(*super->return_msg)); super->return_msg->qinfo = super->qinfo; + allocated_return_msg = 1; } rep = qstate->return_msg->rep; @@ -851,11 +870,14 @@ dns64_adjust_a(int id, struct module_qst rep->serve_expired_norec_ttl, rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count, rep->security, LDNS_EDE_NONE); - if(!cp) + if(!cp) { + if(allocated_return_msg) super->return_msg = NULL; return; + } /* allocate ub_key structures special or not */ if(!reply_info_alloc_rrset_keys(cp, NULL, super->region)) { + if(allocated_return_msg) super->return_msg = NULL; return; } @@ -870,8 +892,10 @@ dns64_adjust_a(int id, struct module_qst if(ian_numrrsets && fk->rk.type == htons(LDNS_RR_TYPE_A)) { /* also sets dk->entry.hash */ dns64_synth_aaaa_data(fk, fd, dk, &dd, super->region, dns64_env); - if(!dd) + if(!dd) { + if(allocated_return_msg) super->return_msg = NULL; return; + } /* Delete negative AAAA record from cache stored by * the iterator module */ rrset_cache_remove(super->env->rrset_cache, dk->rk.dname, @@ -888,15 +912,19 @@ dns64_adjust_a(int id, struct module_qst dk->rk.dname = (uint8_t*)regional_alloc_init(super->region, fk->rk.dname, fk->rk.dname_len); - if(!dk->rk.dname) + if(!dk->rk.dname) { + if(allocated_return_msg) super->return_msg = NULL; return; + } s = packed_rrset_sizeof(fd); dd = (struct packed_rrset_data*)regional_alloc_init( super->region, fd, s); - if(!dd) + if(!dd) { + if(allocated_return_msg) super->return_msg = NULL; return; + } } packed_rrset_ptr_fixup(dd); @@ -927,8 +955,10 @@ dns64_adjust_ptr(struct module_qstate* q return; super->return_msg->qinfo = super->qinfo; if (!(super->return_msg->rep = reply_info_copy(qstate->return_msg->rep, - NULL, super->region))) + NULL, super->region))) { + super->return_msg = NULL; return; + } /* * Adjust the domain name of the answer RR set so that it matches the @@ -997,6 +1027,21 @@ dns64_inform_super(struct module_qstate* /* Use return code from A query in response to client. */ if (super->return_rcode != LDNS_RCODE_NOERROR) super->return_rcode = qstate->return_rcode; + /* RPZ applied to the subquery need to then change (not cache) + * the super query. With the super query not cached, it is + * going to run the state machine modules on incoming queries, + * that fetch the subquery (cache) response, and modify it + * according to the rpz policy. That makes the synthesized + * super query also adjusted by rpz policies. But loses cache + * hits. Even though the subquery likely is answered from cache, + * internally in its state machine process. */ + if(qstate->rpz_applied) + super->rpz_applied = 1; + if(qstate->rpz_passthru) + super->rpz_passthru = 1; + + /* Since the super qstate has a new response, its errinf is removed. */ + super->errinf = NULL; /* Generate a response suitable for the original query. */ if (qstate->qinfo.qtype == LDNS_RR_TYPE_A) { @@ -1005,9 +1050,16 @@ dns64_inform_super(struct module_qstate* log_assert(qstate->qinfo.qtype == LDNS_RR_TYPE_PTR); dns64_adjust_ptr(qstate, super); } + /* If the sub-query has no cache store, then also the super query. */ + if(qstate->fwd_stub_no_cache) + super->fwd_stub_no_cache = 1; /* Store the generated response in cache. */ - if ( (!super_dq || !super_dq->started_no_cache_store) && + if ( super->return_msg && super->return_msg->rep && + (!super_dq || !super_dq->started_no_cache_store) && + !qstate->fwd_stub_no_cache && + !super->rpz_applied && !super->rpz_passthru && + !super->is_subnet_answer && !dns_cache_store(super->env, &super->qinfo, super->return_msg->rep, 0, super->prefetch_leeway, 0, NULL, super->query_flags, qstate->qstarttime, qstate->is_valrec)) Index: sbin/unwind/libunbound/dnscrypt/dnscrypt.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/dnscrypt/dnscrypt.h,v diff -u -p -r1.2 dnscrypt.h --- sbin/unwind/libunbound/dnscrypt/dnscrypt.h 1 Mar 2022 18:34:21 -0000 1.2 +++ sbin/unwind/libunbound/dnscrypt/dnscrypt.h 21 Sep 2026 16:27:57 -0000 @@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dn * \return 0 in case of failure. */ -int dnsc_handle_uncurved_request(struct comm_reply *repinfo); +int dnsc_handle_uncurved_request(struct comm_reply *repinfo, + struct sldns_buffer* buffer); /** * Computes the size of the shared secret cache entry. Index: sbin/unwind/libunbound/dnstap/dnstap.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/dnstap/dnstap.h,v diff -u -p -r1.8 dnstap.h --- sbin/unwind/libunbound/dnstap/dnstap.h 14 Sep 2025 15:16:53 -0000 1.8 +++ sbin/unwind/libunbound/dnstap/dnstap.h 21 Sep 2026 16:27:57 -0000 @@ -102,9 +102,9 @@ dt_create(struct config_file* cfg); * Apply config settings. * @param env: dnstap environment object. * @param cfg: new config settings. + * @return false on failure. */ -void -dt_apply_cfg(struct dt_env *env, struct config_file *cfg); +int dt_apply_cfg(struct dt_env *env, struct config_file *cfg); /** * Apply config settings for log enable for message types. Index: sbin/unwind/libunbound/iterator/iter_delegpt.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_delegpt.c,v diff -u -p -r1.7 iter_delegpt.c --- sbin/unwind/libunbound/iterator/iter_delegpt.c 14 Sep 2025 15:16:53 -0000 1.7 +++ sbin/unwind/libunbound/iterator/iter_delegpt.c 21 Sep 2026 16:27:57 -0000 @@ -118,10 +118,10 @@ delegpt_add_ns(struct delegpt* dp, struc sizeof(struct delegpt_ns)); if(!ns) return 0; - ns->next = dp->nslist; ns->namelen = len; - dp->nslist = ns; ns->name = regional_alloc_init(region, name, ns->namelen); + if(!ns->name) + return 0; ns->cache_lookup_count = 0; ns->resolved = 0; ns->got4 = 0; @@ -137,7 +137,9 @@ delegpt_add_ns(struct delegpt* dp, struc } else { ns->tls_auth_name = NULL; } - return ns->name != 0; + ns->next = dp->nslist; + dp->nslist = ns; + return 1; } struct delegpt_ns* @@ -223,11 +225,7 @@ delegpt_add_addr(struct delegpt* dp, str sizeof(struct delegpt_addr)); if(!a) return 0; - a->next_target = dp->target_list; - dp->target_list = a; a->next_result = 0; - a->next_usable = dp->usable_list; - dp->usable_list = a; memcpy(&a->addr, addr, addrlen); a->addrlen = addrlen; a->attempts = 0; @@ -241,6 +239,10 @@ delegpt_add_addr(struct delegpt* dp, str } else { a->tls_auth_name = NULL; } + a->next_target = dp->target_list; + dp->target_list = a; + a->next_usable = dp->usable_list; + dp->usable_list = a; return 1; } @@ -398,30 +400,33 @@ delegpt_count_missing_targets(struct del /** find NS rrset in given list */ static struct ub_packed_rrset_key* -find_NS(struct reply_info* rep, size_t from, size_t to) +find_NS(struct reply_info* rep, size_t from, size_t to, uint16_t qclass) { size_t i; for(i=from; irrsets[i]->rk.type) == LDNS_RR_TYPE_NS) + if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS && + ntohs(rep->rrsets[i]->rk.rrset_class) == qclass) return rep->rrsets[i]; } return NULL; } struct delegpt* -delegpt_from_message(struct dns_msg* msg, struct regional* region) +delegpt_from_message(struct dns_msg* msg, struct regional* region, int port) { struct ub_packed_rrset_key* ns_rrset = NULL; struct delegpt* dp; size_t i; /* look for NS records in the authority section... */ ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets, - msg->rep->an_numrrsets+msg->rep->ns_numrrsets); + msg->rep->an_numrrsets+msg->rep->ns_numrrsets, + msg->qinfo.qclass); /* In some cases (even legitimate, perfectly legal cases), the * NS set for the "referral" might be in the answer section. */ if(!ns_rrset) - ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets); + ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets, + msg->qinfo.qclass); /* If there was no NS rrset in the authority section, then this * wasn't a referral message. (It might not actually be a @@ -436,7 +441,7 @@ delegpt_from_message(struct dns_msg* msg dp->has_parent_side_NS = 1; /* created from message */ if(!delegpt_set_name(dp, region, ns_rrset->rk.dname)) return NULL; - if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0)) + if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0, port)) return NULL; /* add glue, A and AAAA in answer and additional section */ @@ -447,10 +452,12 @@ delegpt_from_message(struct dns_msg* msg i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets)) continue; - if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { + if(ntohs(s->rk.type) == LDNS_RR_TYPE_A && + ntohs(s->rk.rrset_class) == msg->qinfo.qclass) { if(!delegpt_add_rrset_A(dp, region, s, 0, NULL)) return NULL; - } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { + } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA && + ntohs(s->rk.rrset_class) == msg->qinfo.qclass) { if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL)) return NULL; } @@ -460,7 +467,7 @@ delegpt_from_message(struct dns_msg* msg int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ns_rrset, uint8_t lame) + struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port) { struct packed_rrset_data* nsdata = (struct packed_rrset_data*) ns_rrset->entry.data; @@ -475,7 +482,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, continue; /* bad format */ /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame, - NULL, UNBOUND_DNS_PORT)) + NULL, (port==-1?UNBOUND_DNS_PORT:port))) return 0; } return 1; @@ -534,7 +541,7 @@ delegpt_add_rrset(struct delegpt* dp, st if(!rrset) return 1; if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) - return delegpt_rrset_add_ns(dp, region, rrset, lame); + return delegpt_rrset_add_ns(dp, region, rrset, lame, -1); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) return delegpt_add_rrset_A(dp, region, rrset, lame, additions); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) @@ -659,8 +666,6 @@ int delegpt_add_ns_mlc(struct delegpt* d free(ns); return 0; } - ns->next = dp->nslist; - dp->nslist = ns; ns->cache_lookup_count = 0; ns->resolved = 0; ns->got4 = 0; @@ -679,6 +684,8 @@ int delegpt_add_ns_mlc(struct delegpt* d } else { ns->tls_auth_name = NULL; } + ns->next = dp->nslist; + dp->nslist = ns; return 1; } @@ -704,11 +711,7 @@ int delegpt_add_addr_mlc(struct delegpt* a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr)); if(!a) return 0; - a->next_target = dp->target_list; - dp->target_list = a; a->next_result = 0; - a->next_usable = dp->usable_list; - dp->usable_list = a; memcpy(&a->addr, addr, addrlen); a->addrlen = addrlen; a->attempts = 0; @@ -724,6 +727,10 @@ int delegpt_add_addr_mlc(struct delegpt* } else { a->tls_auth_name = NULL; } + a->next_target = dp->target_list; + dp->target_list = a; + a->next_usable = dp->usable_list; + dp->usable_list = a; return 1; } Index: sbin/unwind/libunbound/iterator/iter_delegpt.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_delegpt.h,v diff -u -p -r1.8 iter_delegpt.h --- sbin/unwind/libunbound/iterator/iter_delegpt.h 29 Sep 2025 14:53:38 -0000 1.8 +++ sbin/unwind/libunbound/iterator/iter_delegpt.h 21 Sep 2026 16:27:57 -0000 @@ -221,10 +221,11 @@ int delegpt_add_ns(struct delegpt* dp, s * @param regional: where to allocate the info. * @param ns_rrset: NS rrset. * @param lame: rrset is lame, disprefer it. + * @param port: port or -1 if not set. * @return 0 on alloc error. */ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* ns_rrset, uint8_t lame); + struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port); /** * Add target address to the delegation point. @@ -365,11 +366,12 @@ size_t delegpt_count_targets(struct dele * * @param msg: the dns message, referral. * @param regional: where to allocate delegation point. + * @param port: if not -1 specifies a port number. * @return new delegation point or NULL on alloc error, or if the * message was not appropriate. */ struct delegpt* delegpt_from_message(struct dns_msg* msg, - struct regional* regional); + struct regional* regional, int port); /** * Mark negative return in delegation point for specific nameserver. Index: sbin/unwind/libunbound/iterator/iter_donotq.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_donotq.c,v diff -u -p -r1.1 iter_donotq.c --- sbin/unwind/libunbound/iterator/iter_donotq.c 23 Jan 2019 13:05:27 -0000 1.1 +++ sbin/unwind/libunbound/iterator/iter_donotq.c 21 Sep 2026 16:27:57 -0000 @@ -132,6 +132,18 @@ donotq_apply_cfg(struct iter_donotq* dq, if(cfg->do_ip6) { if(!donotq_str_cfg(dq, "::1")) return 0; + if(!donotq_str_cfg(dq, "::ffff:127.0.0.0/104")) + return 0; + } + /* RFC 1122 3.2.1.3 / RFC 6890 / RFC 4291 2.5.2: not valid as + * destination; on Linux these route to the local host. */ + if(!donotq_str_cfg(dq, "0.0.0.0/8")) + return 0; + if(cfg->do_ip6) { + if(!donotq_str_cfg(dq, "::")) + return 0; + if(!donotq_str_cfg(dq, "::ffff:0:0/96")) + return 0; } } addr_tree_init_parents(&dq->tree); Index: sbin/unwind/libunbound/iterator/iter_fwd.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_fwd.c,v diff -u -p -r1.7 iter_fwd.c --- sbin/unwind/libunbound/iterator/iter_fwd.c 29 Sep 2025 14:53:38 -0000 1.7 +++ sbin/unwind/libunbound/iterator/iter_fwd.c 21 Sep 2026 16:27:57 -0000 @@ -228,6 +228,11 @@ read_fwds_host(struct config_stub* s, st s->name, p->str); return 0; } + if(dname_subdomain_c(dname, dp->name)) { + log_warn("forward-host '%s' may have a circular " + "dependency on forward-zone '%s'", + p->str, s->name); + } #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) if(tls_auth_name) log_err("no name verification functionality in " Index: sbin/unwind/libunbound/iterator/iter_hints.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_hints.c,v diff -u -p -r1.7 iter_hints.c --- sbin/unwind/libunbound/iterator/iter_hints.c 14 Sep 2025 15:16:53 -0000 1.7 +++ sbin/unwind/libunbound/iterator/iter_hints.c 21 Sep 2026 16:27:57 -0000 @@ -231,6 +231,11 @@ read_stubs_host(struct config_stub* s, s s->name, p->str); return 0; } + if(dname_subdomain_c(dname, dp->name)) { + log_warn("stub-host '%s' may have a circular " + "dependency on stub-zone '%s'", + p->str, s->name); + } #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) if(tls_auth_name) log_err("no name verification functionality in " Index: sbin/unwind/libunbound/iterator/iter_priv.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_priv.c,v diff -u -p -r1.2 iter_priv.c --- sbin/unwind/libunbound/iterator/iter_priv.c 13 Apr 2024 13:58:34 -0000 1.2 +++ sbin/unwind/libunbound/iterator/iter_priv.c 21 Sep 2026 16:27:57 -0000 @@ -207,6 +207,168 @@ size_t priv_get_mem(struct iter_priv* pr return sizeof(*priv) + regional_get_mem(priv->region); } +/** + * Check if svcparam ipv4hint contains a private address. + * @param priv: private address lookup struct. + * @param d: the data bytes. + * @param data_len: number of data bytes in the svcparam. + * @param addr: address to return the private address to log in to. + * It has space for IPv4 and IPv6 addresses. + * @param addrlen: length of the addr. Returns the correct size for the addr. + * @return true if the rdata contains a private address. + */ +static int svcb_ipv4hint_contains_priv_addr(struct iter_priv* priv, + uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr, + socklen_t* addrlen) +{ + struct sockaddr_in sa; + *addrlen = (socklen_t)sizeof(struct sockaddr_in); + memset(&sa, 0, sizeof(struct sockaddr_in)); + sa.sin_family = AF_INET; + sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); + + while(data_len >= LDNS_IP4ADDRLEN) { + memmove(&sa.sin_addr, d, LDNS_IP4ADDRLEN); + memmove(addr, &sa, *addrlen); + if(priv_lookup_addr(priv, addr, *addrlen)) + return 1; + + d += LDNS_IP4ADDRLEN; + data_len -= LDNS_IP4ADDRLEN; + } + /* if data_len != 0 here, then the svcparam is malformed. */ + return 0; +} + +/** + * Check if svcparam ipv6hint contains a private address. + * @param priv: private address lookup struct. + * @param d: the data bytes. + * @param data_len: number of data bytes in the svcparam. + * @param addr: address to return the private address to log in to. + * It has space for IPv4 and IPv6 addresses. + * @param addrlen: length of the addr. Returns the correct size for the addr. + * @return true if the rdata contains a private address. + */ +static int svcb_ipv6hint_contains_priv_addr(struct iter_priv* priv, + uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr, + socklen_t* addrlen) +{ + struct sockaddr_in6 sa; + *addrlen = (socklen_t)sizeof(struct sockaddr_in6); + memset(&sa, 0, sizeof(struct sockaddr_in6)); + sa.sin6_family = AF_INET6; + sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); + + while(data_len >= LDNS_IP6ADDRLEN) { + memmove(&sa.sin6_addr, d, LDNS_IP6ADDRLEN); + memmove(addr, &sa, *addrlen); + if(priv_lookup_addr(priv, addr, *addrlen)) + return 1; + + d += LDNS_IP6ADDRLEN; + data_len -= LDNS_IP6ADDRLEN; + } + /* if data_len != 0 here, then the svcparam is malformed. */ + return 0; +} + +/** + * Check if type SVCB and HTTPS rdata contains a private address. + * @param priv: private address lookup struct. + * @param pkt: the packet. + * @param rr: the rr with rdata to check. + * @param addr: address to return the private address to log in to. + * @param addrlen: length of the addr. Initially the total size, on + * return the correct size for the addr. + * @return true if the rdata contains a private address. + */ +static int svcb_rr_contains_priv_addr(struct iter_priv* priv, + sldns_buffer* pkt, struct rr_parse* rr, struct sockaddr_storage* addr, + socklen_t* addrlen) +{ + uint8_t* d = rr->ttl_data; + uint16_t svcparamkey, data_len, rdatalen; + size_t oldpos, dname_len, dname_start, dname_compr_len; + d += 4; /* skip TTL */ + rdatalen = sldns_read_uint16(d); /* read rdata length */ + d += 2; + + if(rdatalen < 2 /* priority */ + 1 /* 1 length target */) + return 0; /* malformed, too short */ + d += 2; /* skip priority */ + rdatalen -= 2; + oldpos = sldns_buffer_position(pkt); + sldns_buffer_set_position(pkt, (size_t)(d - sldns_buffer_begin(pkt))); + dname_start = sldns_buffer_position(pkt); + dname_len = pkt_dname_len(pkt); + dname_compr_len = sldns_buffer_position(pkt) - dname_start; + sldns_buffer_set_position(pkt, oldpos); + if(dname_len == 0) + return 0; /* dname malformed */ + if(dname_compr_len > rdatalen) + return 0; /* malformed */ + d += dname_compr_len; /* skip target */ + rdatalen -= dname_compr_len; + + while(rdatalen >= 4) { + svcparamkey = sldns_read_uint16(d); + data_len = sldns_read_uint16(d+2); + d += 4; + rdatalen -= 4; + + /* verify that we have data_len data */ + if(data_len > rdatalen) { + /* It is malformed, but if there are addresses + * in there it can be rejected. */ + data_len = rdatalen; + } + + if(!data_len) + continue; /* no data for the svcparamkey */ + + if(svcparamkey == SVCB_KEY_IPV4HINT) { + if(svcb_ipv4hint_contains_priv_addr(priv, d, data_len, + addr, addrlen)) + return 1; + } else if(svcparamkey == SVCB_KEY_IPV6HINT) { + if(svcb_ipv6hint_contains_priv_addr(priv, d, data_len, + addr, addrlen)) + return 1; + } + d += data_len; + rdatalen -= data_len; + } + /* If rdatalen != 0 here, then the svcb rdata is malformed. */ + return 0; +} + +/** + * Check if the SVCB and HTTPS rrset is bad. + * @param priv: private address lookup struct. + * @param pkt: the packet. + * @param rrset: the rrset to check. + * @return 1 if the entire rrset has to be removed. 0 if not. + * It removes RRs if they have private addresses, and log that. + */ +static int priv_svcb_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt, + struct rrset_parse* rrset) +{ + struct rr_parse* rr, *prev = NULL; + struct sockaddr_storage addr; + socklen_t addrlen = (socklen_t)sizeof(addr); + for(rr = rrset->rr_first; rr; rr = rr->next) { + if(svcb_rr_contains_priv_addr(priv, pkt, rr, &addr, + &addrlen)) { + if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, addrlen)) + return 1; + continue; + } + prev = rr; + } + return 0; +} + int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt, struct rrset_parse* rrset) { @@ -268,7 +430,11 @@ int priv_rrset_bad(struct iter_priv* pri } prev = rr; } - } + } else if(rrset->type == LDNS_RR_TYPE_SVCB || + rrset->type == LDNS_RR_TYPE_HTTPS) { + if(priv_svcb_rrset_bad(priv, pkt, rrset)) + return 1; + } } return 0; } Index: sbin/unwind/libunbound/iterator/iter_resptype.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_resptype.c,v diff -u -p -r1.4 iter_resptype.c --- sbin/unwind/libunbound/iterator/iter_resptype.c 13 Apr 2024 13:58:34 -0000 1.4 +++ sbin/unwind/libunbound/iterator/iter_resptype.c 21 Sep 2026 16:27:57 -0000 @@ -107,7 +107,7 @@ response_type_from_cache(struct dns_msg* enum response_type response_type_from_server(int rdset, struct dns_msg* msg, struct query_info* request, struct delegpt* dp, - int* empty_nodata_found) + int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral) { uint8_t* origzone = (uint8_t*)"\000"; /* the default */ struct ub_packed_rrset_key* s; @@ -122,6 +122,10 @@ response_type_from_server(int rdset, /* If the message is NXDOMAIN, then it answers the question. */ if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) { + if(msg->rep->an_numrrsets == 0 && + msg->rep->ns_numrrsets == 0 && + msg_lame_empty) + return RESPONSE_TYPE_LAME; /* make sure its not recursive when we don't want it to */ if( (msg->rep->flags&BIT_RA) && !(msg->rep->flags&BIT_AA) && !rdset) @@ -143,6 +147,10 @@ response_type_from_server(int rdset, if(FLAGS_GET_RCODE(msg->rep->flags) != LDNS_RCODE_NOERROR) return RESPONSE_TYPE_THROWAWAY; + if(msg->rep->an_numrrsets == 0 && msg->rep->ns_numrrsets == 0 && + msg_lame_empty) + return RESPONSE_TYPE_LAME; + /* Note: TC bit has already been handled */ if(dp) { @@ -249,13 +257,16 @@ response_type_from_server(int rdset, * which gives ns==zone delegation from cache * without AA bit as well, with nodata nosoa*/ /* real answer must be +AA and SOA RFC(2308), - * so this is wrong, and we SERVFAIL it if - * this is the only possible reply, if it - * is misdeployed the THROWAWAY makes us pick - * the next server from the selection */ - if(msg->rep->an_numrrsets==0 && + * this is picked up as lame_referral by the + * sanitize step, so it can spot if there + * was data in the answer section before + * removal. If such data is then removed we + * do not want to turn that answer into lame. + * But if it was not there, it can be lame. */ + if(msg_lame_referral && + msg->rep->an_numrrsets==0 && !(msg->rep->flags&BIT_AA) && !rdset) - return RESPONSE_TYPE_THROWAWAY; + return RESPONSE_TYPE_LAME; return RESPONSE_TYPE_ANSWER; } /* If we are getting a referral upwards (or to Index: sbin/unwind/libunbound/iterator/iter_resptype.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_resptype.h,v diff -u -p -r1.2 iter_resptype.h --- sbin/unwind/libunbound/iterator/iter_resptype.h 13 Apr 2024 13:58:34 -0000 1.2 +++ sbin/unwind/libunbound/iterator/iter_resptype.h 21 Sep 2026 16:27:57 -0000 @@ -120,10 +120,14 @@ enum response_type response_type_from_ca * @param dp: The delegation point that was being queried * when the response was returned. * @param empty_nodata_found: flag to keep track of empty nodata detection. + * @param msg_lame_empty: The scrubber indicates that this empty message + * is lame, before it became empty. + * @param msg_lame_referral: returned true if the reply has a referral before + * scrub. * @return the response type (CNAME or ANSWER). */ enum response_type response_type_from_server(int rdset, struct dns_msg* msg, struct query_info* request, struct delegpt* dp, - int* empty_nodata_found); + int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral); #endif /* ITERATOR_ITER_RESPTYPE_H */ Index: sbin/unwind/libunbound/iterator/iter_scrub.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_scrub.c,v diff -u -p -r1.11 iter_scrub.c --- sbin/unwind/libunbound/iterator/iter_scrub.c 28 Nov 2025 07:38:36 -0000 1.11 +++ sbin/unwind/libunbound/iterator/iter_scrub.c 21 Sep 2026 16:27:57 -0000 @@ -285,6 +285,24 @@ synth_cname_rrset(uint8_t** sname, size_ return NULL; memmove(cn->rr_first->ttl_data, rrset->rr_first->ttl_data, sizeof(uint32_t)); /* RFC6672: synth CNAME TTL == DNAME TTL */ + /* Apply cache TTL policy so DNAME and synthesized CNAME stay equal + * and respect cache-min-ttl/cache-max-ttl (same as rdata_copy path). */ + if(!SERVE_ORIGINAL_TTL) { + uint32_t ttl = sldns_read_uint32(cn->rr_first->ttl_data); + time_t ttl_t = (time_t)ttl; + if(ttl_t < MIN_TTL) ttl_t = MIN_TTL; + if(ttl_t > MAX_TTL) ttl_t = MAX_TTL; + ttl = (uint32_t)ttl_t; + sldns_write_uint32(cn->rr_first->ttl_data, ttl); + /* Do NOT write the clamp back into the packet buffer: + * parse_packet already sized every name from the original + * bytes and rdata_copy re-walks them trusting those sizes; + * mutating packet bytes between the walks breaks that + * invariant (compression pointers can target these TTL + * bytes). The DNAME rrset receives the same clamp at store + * time in rdata_copy, so the DNAME and the synthesized + * CNAME still carry equal TTLs in the cache. */ + } sldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen); memmove(cn->rr_first->ttl_data+6, alias, aliaslen); cn->rr_first->size = sizeof(uint16_t)+aliaslen; @@ -305,6 +323,20 @@ synth_cname_rrset(uint8_t** sname, size_ return cn; } +/** Check if the packet has type NS in answer or authority section */ +static int +pkt_contains_ns(struct msg_parse* msg) +{ + struct rrset_parse* rrset; + for(rrset = msg->rrset_first; rrset; rrset = rrset->rrset_all_next) { + if(rrset->type == LDNS_RR_TYPE_NS && + (rrset->section == LDNS_SECTION_ANSWER || + rrset->section == LDNS_SECTION_AUTHORITY)) + return 1; + } + return 0; +} + /** check if DNAME applies to a name */ static int pkt_strict_sub(sldns_buffer* pkt, uint8_t* sname, uint8_t* dr) @@ -383,6 +415,8 @@ shorten_rrset(sldns_buffer* pkt, struct struct rr_parse* rr = rrset->rr_first, *prev = NULL; if(!rr) return; + if(count < 1) + return; /* cannot leave a still-linked rrset_parse with rr_count == 0 */ for(i=0; inext; @@ -408,6 +442,43 @@ shorten_rrset(sldns_buffer* pkt, struct else rrset->rr_first = NULL; } +/** Shorten RRSIGs list */ +static void +shorten_rrsig(sldns_buffer* pkt, struct rrset_parse* rrset, int count) +{ + /* The too large list of RRSIGs on the RRset is shortened. + * This is so that too large content does not overwhelm the cache. + * The validator does not validate more than a max number of + * RRSIGs as well. */ + int i; + struct rr_parse* rr = rrset->rrsig_first, *prev = NULL; + if(!rr) + return; + for(i=0; inext; + if(!rr) + return; /* The RRSIG list is already short. */ + } + if(verbosity >= VERB_QUERY + && rrset->dname_len <= LDNS_MAX_DOMAINLEN) { + uint8_t buf[LDNS_MAX_DOMAINLEN+1]; + dname_pkt_copy(pkt, buf, rrset->dname); + log_nametypeclass(VERB_QUERY, "normalize: shorten RRSIGs:", + buf, rrset->type, ntohs(rrset->rrset_class)); + } + /* remove further rrsigs */ + rrset->rrsig_last = prev; + rrset->rrsig_count = count; + while(rr) { + rrset->size -= rr->size; + rr = rr->next; + } + if(rrset->rrsig_last) + rrset->rrsig_last->next = NULL; + else rrset->rrsig_first = NULL; +} + /** * This routine normalizes a response. This includes removing "irrelevant" * records from the answer and additional sections and (re)synthesizing @@ -430,6 +501,7 @@ scrub_normalize(sldns_buffer* pkt, struc size_t snamelen = qinfo->qname_len; struct rrset_parse* rrset, *prev, *nsset=NULL; int cname_length = 0; /* number of CNAMEs, or DNAMEs */ + int has_answer = 0; /* if answer section contains nonCNAME,nonDNAME */ if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR && FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN && @@ -445,6 +517,8 @@ scrub_normalize(sldns_buffer* pkt, struc prev = NULL; rrset = msg->rrset_first; while(rrset && rrset->section == LDNS_SECTION_ANSWER) { + if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig) + shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig); if(cname_length > env->cfg->iter_scrub_cname) { /* Too many CNAMEs, or DNAMEs, from the authority * server, scrub down the length to something @@ -455,8 +529,9 @@ scrub_normalize(sldns_buffer* pkt, struc pkt, msg, prev, &rrset); continue; } - if(rrset->type == LDNS_RR_TYPE_DNAME && - pkt_strict_sub(pkt, sname, rrset->dname)) { + if(rrset->type == LDNS_RR_TYPE_DNAME && + pkt_strict_sub(pkt, sname, rrset->dname) && + pkt_sub(pkt, rrset->dname, zonename)) { /* check if next rrset is correct CNAME. else, * synthesize a CNAME */ struct rrset_parse* nx = rrset->rrset_all_next; @@ -468,6 +543,11 @@ scrub_normalize(sldns_buffer* pkt, struc (unsigned)rrset->rr_count); return 0; } + if(has_answer) { + remove_rrset("normalize: removing DNAME redirection after answer:", + pkt, msg, prev, &rrset); + continue; + } if(!synth_cname(sname, snamelen, rrset, alias, &aliaslen, pkt)) { verbose(VERB_ALGO, "synthesized CNAME " @@ -502,8 +582,6 @@ scrub_normalize(sldns_buffer* pkt, struc log_err("out of memory synthesizing CNAME"); return 0; } - /* FIXME: resolve the conflict between synthesized - * CNAME ttls and the cache. */ rrset = nx; continue; @@ -520,12 +598,18 @@ scrub_normalize(sldns_buffer* pkt, struc if(rrset->type == LDNS_RR_TYPE_CNAME) { struct rrset_parse* nx = rrset->rrset_all_next; uint8_t* oldsname = sname; + if(has_answer) { + remove_rrset("normalize: removing redirection after answer:", + pkt, msg, prev, &rrset); + continue; + } cname_length++; /* see if the next one is a DNAME, if so, swap them */ if(nx && nx->section == LDNS_SECTION_ANSWER && nx->type == LDNS_RR_TYPE_DNAME && nx->rr_count == 1 && - pkt_strict_sub(pkt, sname, nx->dname)) { + pkt_strict_sub(pkt, sname, nx->dname) && + pkt_sub(pkt, nx->dname, zonename)) { /* there is a DNAME after this CNAME, it * is in the ANSWER section, and the DNAME * applies to the name we cover */ @@ -571,6 +655,9 @@ scrub_normalize(sldns_buffer* pkt, struc if(rrset->type == LDNS_RR_TYPE_NS && rrset->rr_count > env->cfg->iter_scrub_ns) { shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); + } else if(rrset->type == LDNS_RR_TYPE_DS && + rrset->rr_count > env->cfg->iter_scrub_ns) { + shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); } prev = rrset; rrset = rrset->rrset_all_next; @@ -590,6 +677,9 @@ scrub_normalize(sldns_buffer* pkt, struc if(rrset->type == LDNS_RR_TYPE_NS && rrset->rr_count > env->cfg->iter_scrub_ns) { shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); + } else if(rrset->type == LDNS_RR_TYPE_DS && + rrset->rr_count > env->cfg->iter_scrub_ns) { + shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); } /* Mark the additional names from relevant rrset as OK. */ @@ -597,6 +687,7 @@ scrub_normalize(sldns_buffer* pkt, struc * will be removed by sanitize, so no additional for them */ if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) == 0) mark_additional_rrset(pkt, msg, rrset); + has_answer = 1; prev = rrset; rrset = rrset->rrset_all_next; @@ -620,6 +711,8 @@ scrub_normalize(sldns_buffer* pkt, struc "RRset:", pkt, msg, prev, &rrset); continue; } + if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig) + shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig); /* only one NS set allowed in authority section */ if(rrset->type==LDNS_RR_TYPE_NS) { /* NS set must be pertinent to the query */ @@ -680,6 +773,11 @@ scrub_normalize(sldns_buffer* pkt, struc "RRset:", pkt, msg, prev, &rrset); continue; } + if(ntohs(rrset->rrset_class) != qinfo->qclass) { + remove_rrset("normalize: removing other class " + "RRset:", pkt, msg, prev, &rrset); + continue; + } if(nsset == NULL) { nsset = rrset; } else { @@ -706,6 +804,11 @@ scrub_normalize(sldns_buffer* pkt, struc shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); } } + } else if(rrset->type==LDNS_RR_TYPE_DS) { + if(rrset->rr_count > env->cfg->iter_scrub_ns) { + shorten_rrset(pkt, rrset, + env->cfg->iter_scrub_ns); + } } /* if this is type DS and we query for type DS we just got * a referral answer for our type DS query, fix packet */ @@ -725,7 +828,13 @@ scrub_normalize(sldns_buffer* pkt, struc rrset->rrset_all_next = NULL; return 1; } - mark_additional_rrset(pkt, msg, rrset); + /* Only mark glue as allowed for type NS in the authority + * section. Other RR types do not get glue for them, it + * is allowed from the answer section, but not authority + * so that a message can not have address records cached + * as a side effect to the query. */ + if(rrset->type==LDNS_RR_TYPE_NS) + mark_additional_rrset(pkt, msg, rrset); prev = rrset; rrset = rrset->rrset_all_next; } @@ -762,6 +871,8 @@ scrub_normalize(sldns_buffer* pkt, struc "RRset:", pkt, msg, prev, &rrset); continue; } + if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig) + shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig); prev = rrset; rrset = rrset->rrset_all_next; } @@ -908,12 +1019,20 @@ scrub_sanitize_rr_length(sldns_buffer* p * @param env: module environment with config and cache. * @param ie: iterator environment with private address data. * @param qstate: for setting errinf for EDE error messages. + * @param pkt_before_NS: if the packet had type NS before scrub. If that + * is removed now, that indicates this may have been lame. + * @param msg_lame_empty: returned true if the empty packet is lame. + * @param msg_lame_referral: returned true if the reply has a referral before + * scrub. + * @param rdset: if RD bit was sent in query sent by unbound. * @return 0 on error. */ static int scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg, struct query_info* qinfo, uint8_t* zonename, struct module_env* env, - struct iter_env* ie, struct module_qstate* qstate) + struct iter_env* ie, struct module_qstate* qstate, + int pkt_before_NS, int* msg_lame_empty, int* msg_lame_referral, + int rdset) { int del_addi = 0; /* if additional-holding rrsets are deleted, we do not trust the normalized additional-A-AAAA any more */ @@ -972,8 +1091,10 @@ scrub_sanitize(sldns_buffer* pkt, struct } /* remove private addresses */ - if( (rrset->type == LDNS_RR_TYPE_A || - rrset->type == LDNS_RR_TYPE_AAAA)) { + if(rrset->type == LDNS_RR_TYPE_A || + rrset->type == LDNS_RR_TYPE_AAAA || + rrset->type == LDNS_RR_TYPE_SVCB || + rrset->type == LDNS_RR_TYPE_HTTPS) { /* do not set servfail since this leads to too * many drops of other people using rfc1918 space */ @@ -1068,6 +1189,21 @@ scrub_sanitize(sldns_buffer* pkt, struct prev = rrset; rrset = rrset->rrset_all_next; } + + /* If the packet is empty now, but it was not before. And there + * was type NS in authority, then that indicates the answer is lame. */ + if(msg->rrset_first == NULL && pkt_before_NS) { + *msg_lame_empty = 1; + verbose(VERB_ALGO, "sanitize: empty message had referral to NS before, marked as lame"); + } else if(pkt_before_NS && msg->an_rrsets==0 && + !(msg->flags&BIT_AA) && !rdset) { + /* If the packet is now a referral, not really a nodata, + * then if it was also with an empty answer section before, + * it is also lame. */ + *msg_lame_referral = 1; + verbose(VERB_ALGO, "sanitize: message has referral not answer, marked as lame"); + } + return 1; } @@ -1075,11 +1211,15 @@ int scrub_message(sldns_buffer* pkt, struct msg_parse* msg, struct query_info* qinfo, uint8_t* zonename, struct regional* region, struct module_env* env, struct module_qstate* qstate, - struct iter_env* ie) + struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral, + int rdset) { + int pkt_before_NS; /* basic sanity checks */ log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS, qinfo->qclass); + *msg_lame_empty = 0; + *msg_lame_referral = 0; if(msg->qdcount > 1) return 0; if( !(msg->flags&BIT_QR) ) @@ -1104,11 +1244,21 @@ scrub_message(sldns_buffer* pkt, struct return 0; } + /* If the packet contains type NS in authority before scrub, + * like a self referral. With the answer section empty, it + * was not AA, the query was not sent with RD, with NS in auth, + * and no SOA in auth. For a negative answer, type SOA is present. + * This detects certain lameness if after has removed that. */ + pkt_before_NS = msg->an_rrsets == 0 && + !(msg->flags&BIT_AA) && !rdset && + pkt_contains_ns(msg) && !soa_in_auth(msg); + /* normalize the response, this cleans up the additional. */ if(!scrub_normalize(pkt, msg, qinfo, region, env, zonename)) return 0; /* delete all out-of-zone information */ - if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate)) + if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate, + pkt_before_NS, msg_lame_empty, msg_lame_referral, rdset)) return 0; return 1; } Index: sbin/unwind/libunbound/iterator/iter_scrub.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_scrub.h,v diff -u -p -r1.2 iter_scrub.h --- sbin/unwind/libunbound/iterator/iter_scrub.h 13 Apr 2024 13:58:34 -0000 1.2 +++ sbin/unwind/libunbound/iterator/iter_scrub.h 21 Sep 2026 16:27:57 -0000 @@ -62,11 +62,16 @@ struct module_qstate; * @param env: module environment with config settings and cache. * @param qstate: for setting errinf for EDE error messages. * @param ie: iterator module environment data. + * @param msg_lame_empty: returned true if the empty packet is lame. + * @param msg_lame_referral: returned true if the reply has a referral before + * scrub. + * @param rdset: if RD bit was sent in query sent by unbound. * @return: false if the message is total waste. true if scrubbed with success. */ int scrub_message(struct sldns_buffer* pkt, struct msg_parse* msg, struct query_info* qinfo, uint8_t* zonename, struct regional* regional, struct module_env* env, struct module_qstate* qstate, - struct iter_env* ie); + struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral, + int rdset); #endif /* ITERATOR_ITER_SCRUB_H */ Index: sbin/unwind/libunbound/iterator/iter_utils.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_utils.c,v diff -u -p -r1.15 iter_utils.c --- sbin/unwind/libunbound/iterator/iter_utils.c 14 Sep 2025 15:16:53 -0000 1.15 +++ sbin/unwind/libunbound/iterator/iter_utils.c 21 Sep 2026 16:27:57 -0000 @@ -253,7 +253,9 @@ iter_apply_cfg(struct iter_env* iter_env return 1; } -/** filter out unsuitable targets +/** filter out unsuitable targets. + * Applies NAT64 if needed as well by replacing the IPv4 with the synthesized + * IPv6 address. * @param iter_env: iterator environment with ipv6-support flag. * @param env: module environment with infra cache. * @param name: zone name @@ -306,9 +308,30 @@ iter_filter_unsuitable(struct iter_env* if(a->bogus) return -1; /* address of server is bogus */ if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) { - log_addr(VERB_ALGO, "skip addr on the donotquery list", - &a->addr, a->addrlen); - return -1; /* server is on the donotquery list */ + if(iter_env->nat64.use_nat64 && + addr_is_ip6(&a->addr, a->addrlen) && + a->addrlen == iter_env->nat64.nat64_prefix_addrlen && + addr_in_common(&a->addr, 128, + &iter_env->nat64.nat64_prefix_addr, + iter_env->nat64.nat64_prefix_net, + iter_env->nat64.nat64_prefix_addrlen) == + iter_env->nat64.nat64_prefix_net) { + /* The NAT64 is enabled, and address is IPv6, it is + * in the NAT64 prefix. It is allowed. + * So that in an IPv6-only cluster without internet + * access, that makes the NAT64 translation continue + * to work. The NAT64 prefix is allowed. */ + /* Otherwise, after a timeout, the already NAT64 + * translated address would be treated differently, + * and that causes confusion. */ + log_addr(VERB_ALGO, "the addr is on the donotquery " + "list, but allowed because it is NAT64", + &a->addr, a->addrlen); + } else { + log_addr(VERB_ALGO, "skip addr on the donotquery list", + &a->addr, a->addrlen); + return -1; /* server is on the donotquery list */ + } } if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) { return -1; /* there is no ip6 available */ @@ -317,6 +340,20 @@ iter_filter_unsuitable(struct iter_env* !addr_is_ip6(&a->addr, a->addrlen)) { return -1; /* there is no ip4 available */ } + if(iter_env->nat64.use_nat64 && !addr_is_ip6(&a->addr, a->addrlen)) { + struct sockaddr_storage real_addr; + socklen_t real_addrlen; + addr_to_nat64(&a->addr, &iter_env->nat64.nat64_prefix_addr, + iter_env->nat64.nat64_prefix_addrlen, + iter_env->nat64.nat64_prefix_net, + &real_addr, &real_addrlen); + log_name_addr(VERB_QUERY, "NAT64 apply: from: ", + name, &a->addr, a->addrlen); + log_name_addr(VERB_QUERY, "NAT64 apply: to: ", + name, &real_addr, real_addrlen); + a->addr = real_addr; + a->addrlen = real_addrlen; + } /* check lameness - need zone , class info */ if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen, name, namelen, qtype, &lame, &dnsseclame, &reclame, @@ -1276,7 +1313,8 @@ iter_lookup_parent_NS_from_cache(struct log_rrset_key(VERB_ALGO, "found parent-side NS in cache", akey); dp->has_parent_side_NS = 1; /* and mark the new names as lame */ - if(!delegpt_rrset_add_ns(dp, region, akey, 1)) { + if(!delegpt_rrset_add_ns(dp, region, akey, 1, + deleg_port_number(env))) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -1511,6 +1549,11 @@ iter_stub_fwd_no_cache(struct module_qst struct delegpt *dp; int nolock = 1; + log_assert((retdpname && retdpnamelen + && dpname_storage && dpname_storage_len > 0) || + (retdpname == NULL && retdpnamelen == NULL + && dpname_storage == NULL && dpname_storage_len == 0)); + /* Check for stub. */ /* Lock both forwards and hints for atomic read. */ lock_rw_rdlock(&qstate->env->fwds->lock); @@ -1660,4 +1703,12 @@ iter_make_minimal(struct reply_info* rep rep->ns_numrrsets = 0; rep->ar_numrrsets = 0; rep->rrset_count -= rem; +} + +int +deleg_port_number(struct module_env* env) +{ + if(env->cfg->ssl_upstream) + return env->cfg->ssl_port; + return -1; } Index: sbin/unwind/libunbound/iterator/iter_utils.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iter_utils.h,v diff -u -p -r1.11 iter_utils.h --- sbin/unwind/libunbound/iterator/iter_utils.h 14 Sep 2025 15:16:53 -0000 1.11 +++ sbin/unwind/libunbound/iterator/iter_utils.h 21 Sep 2026 16:27:57 -0000 @@ -84,6 +84,7 @@ int iter_apply_cfg(struct iter_env* iter /** * Select a valid, nice target to send query to. * Sorting and removing unsuitable targets is combined. + * Adds records to the infra cache if not already there. * * @param iter_env: iterator module global state, with ip6 enabled and * do-not-query-addresses. @@ -481,5 +482,8 @@ void limit_nsec_ttl(struct dns_msg* msg) * @param rep: reply to modify. */ void iter_make_minimal(struct reply_info* rep); + +/** See if we need a different port number */ +int deleg_port_number(struct module_env* env); #endif /* ITERATOR_ITER_UTILS_H */ Index: sbin/unwind/libunbound/iterator/iterator.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iterator.c,v diff -u -p -r1.22 iterator.c --- sbin/unwind/libunbound/iterator/iterator.c 29 Sep 2025 14:53:38 -0000 1.22 +++ sbin/unwind/libunbound/iterator/iterator.c 21 Sep 2026 16:27:57 -0000 @@ -81,7 +81,8 @@ int BLACKLIST_PENALTY = (120000*4); /** Timeout when only a single probe query per IP is allowed. */ int PROBE_MAXRTO = PROBE_MAXRTO_DEFAULT; /* in msec */ -static void target_count_increase_nx(struct iter_qstate* iq, int num); +static void target_count_increase_nx(struct module_qstate* qstate, + struct iter_qstate* iq, int num); int iter_init(struct module_env* env, int id) @@ -250,7 +251,7 @@ error_supers(struct module_qstate* qstat if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) && (dpns->got6 == 2 || !ie->supports_ipv6)) { dpns->resolved = 1; /* mark as failed */ - target_count_increase_nx(super_iq, 1); + target_count_increase_nx(super, super_iq, 1); } } if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) { @@ -297,6 +298,7 @@ error_response_cache(struct module_qstat struct reply_info err; struct msgreply_entry* msg; if(qstate->no_cache_store) { + qstate->error_response_cache = 1; return error_response(qstate, id, rcode); } if(qstate->prefetch_leeway > NORR_TTL) { @@ -733,7 +735,7 @@ is_caps_whitelisted(struct iter_env* ie, * created for the parent query. */ static void -target_count_create(struct iter_qstate* iq) +target_count_create(struct module_qstate* qstate, struct iter_qstate* iq) { if(!iq->target_count) { iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int)); @@ -741,33 +743,57 @@ target_count_create(struct iter_qstate* if(iq->target_count) { iq->target_count[TARGET_COUNT_REF] = 1; iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*)); + /* continue global quota from where it was. */ + if(qstate->global_quota_reached > + iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]) + iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] = + qstate->global_quota_reached; } } } static void -target_count_increase(struct iter_qstate* iq, int num) +target_count_store(struct module_qstate* qstate, struct iter_qstate* iq) { - target_count_create(iq); + if(iq->target_count) { + /* By storing the global quota counter, it stays + * there to be picked up if the module is restarted, + * eg. due to a validator retry, and then the + * target_count_create routine picks it up. */ + if(iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] > + qstate->global_quota_reached) + qstate->global_quota_reached = + iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]; + } +} + +static void +target_count_increase(struct module_qstate* qstate, + struct iter_qstate* iq, int num) +{ + target_count_create(qstate, iq); if(iq->target_count) iq->target_count[TARGET_COUNT_QUERIES] += num; iq->dp_target_count++; } static void -target_count_increase_nx(struct iter_qstate* iq, int num) +target_count_increase_nx(struct module_qstate* qstate, + struct iter_qstate* iq, int num) { - target_count_create(iq); + target_count_create(qstate, iq); if(iq->target_count) iq->target_count[TARGET_COUNT_NX] += num; } static void -target_count_increase_global_quota(struct iter_qstate* iq, int num) +target_count_increase_global_quota(struct module_qstate* qstate, + struct iter_qstate* iq, int num) { - target_count_create(iq); + target_count_create(qstate, iq); if(iq->target_count) iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num; + target_count_store(qstate, iq); } /** @@ -829,7 +855,7 @@ generate_sub_request(uint8_t* qname, siz struct mesh_state* sub = NULL; fptr_ok(fptr_whitelist_modenv_add_sub( qstate->env->add_sub)); - if(!(*qstate->env->add_sub)(qstate, &qinf, + if(!(*qstate->env->add_sub)(qstate, &qinf, NULL, qflags, prime, valrec, &subq, &sub)){ return 0; } @@ -838,8 +864,8 @@ generate_sub_request(uint8_t* qname, siz /* attach subquery, lookup existing or make a new one */ fptr_ok(fptr_whitelist_modenv_attach_sub( qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, - valrec, &subq)) { + if(!(*qstate->env->attach_sub)(qstate, &qinf, NULL, qflags, + prime, valrec, &subq)) { return 0; } } @@ -860,7 +886,7 @@ generate_sub_request(uint8_t* qname, siz subiq = (struct iter_qstate*)subq->minfo[id]; memset(subiq, 0, sizeof(*subiq)); subiq->num_target_queries = 0; - target_count_create(iq); + target_count_create(qstate, iq); subiq->target_count = iq->target_count; if(iq->target_count) { iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */ @@ -1485,6 +1511,7 @@ processInitRequest(struct module_qstate* verbose(VERB_ALGO, "no-cache set, going to the network"); qstate->no_cache_lookup = 1; qstate->no_cache_store = 1; + qstate->fwd_stub_no_cache = 1; msg = NULL; } else if(qstate->blacklist) { /* if cache, or anything else, was blacklisted then @@ -1504,7 +1531,7 @@ processInitRequest(struct module_qstate* msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase, qstate->region, qstate->env->rrset_cache, qstate->env->scratch_buffer, - *qstate->env->now, 1/*add SOA*/, NULL, + *qstate->env->now, 1/*add SOA*/, dpname, qstate->env->cfg); } /* item taken from cache does not match our query name, thus @@ -2082,7 +2109,7 @@ query_for_targets(struct module_qstate* ns->resolved = 1; } break; - } + } } /* Send the A request. */ if((ie->supports_ipv4 || ie->nat64.use_nat64) && @@ -2104,7 +2131,7 @@ query_for_targets(struct module_qstate* * a missing target. */ ns->resolved = 1; break; - } + } } /* mark this target as in progress. */ @@ -2229,11 +2256,11 @@ processLastResort(struct module_qstate* errinf(qstate, "could not fetch nameserver"); errinf_dname(qstate, "at zone", iq->dp->name); if(ret == 1) - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += qs; - target_count_increase(iq, qs); + target_count_increase(qstate, iq, qs); if(qs != 0) { qstate->ext_state[id] = module_wait_subquery; return 0; /* and wait for them */ @@ -2289,7 +2316,7 @@ processLastResort(struct module_qstate* * lookups at a time. */ verbose(VERB_ALGO, "try parent-side glue lookup"); iq->num_target_queries += query_count; - target_count_increase(iq, query_count); + target_count_increase(qstate, iq, query_count); qstate->ext_state[id] = module_wait_subquery; return 0; } @@ -2309,7 +2336,7 @@ processLastResort(struct module_qstate* if(query_count != 0) { /* suspend to await results */ verbose(VERB_ALGO, "try parent-side glue lookup"); iq->num_target_queries += query_count; - target_count_increase(iq, query_count); + target_count_increase(qstate, iq, query_count); qstate->ext_state[id] = module_wait_subquery; return 0; } @@ -2365,6 +2392,12 @@ processDSNSFind(struct module_qstate* qs /* go up one (more) step, until we hit the dp, if so, end */ dname_remove_label(&iq->dsns_point, &iq->dsns_point_len); + if(++iq->dsns_count > MAX_DSNS_FIND_COUNT) { + verbose(VERB_QUERY, "DS NS search exceeded %d labels", + MAX_DSNS_FIND_COUNT); + errinf(qstate, "DS NS search exceeded label limit"); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); + } if(query_dname_compare(iq->dsns_point, iq->dp->name) == 0) { /* there was no inbetween nameserver, use the old delegation * point again. And this time, because dsns_point is nonNULL @@ -2436,8 +2469,6 @@ processQueryTargets(struct module_qstate int tf_policy; struct delegpt_addr* target; struct outbound_entry* outq; - struct sockaddr_storage real_addr; - socklen_t real_addrlen; int auth_fallback = 0; uint8_t* qout_orig = NULL; size_t qout_orig_len = 0; @@ -2785,11 +2816,11 @@ processQueryTargets(struct module_qstate if((ret=query_for_targets(qstate, iq, ie, id, -1, &extra))!=0) { errinf(qstate, "could not fetch nameservers for 0x20 fallback"); if(ret == 1) - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += extra; - target_count_increase(iq, extra); + target_count_increase(qstate, iq, extra); if(iq->num_target_queries > 0) { /* wait to get all targets, we want to try em */ verbose(VERB_ALGO, "wait for all targets for fallback"); @@ -2840,7 +2871,7 @@ processQueryTargets(struct module_qstate /* errors ignored, these targets are not strictly necessary for * this result, we do not have to reply with SERVFAIL */ iq->num_target_queries += extra; - target_count_increase(iq, extra); + target_count_increase(qstate, iq, extra); } /* Add the current set of unused targets to our queue. */ @@ -2937,8 +2968,8 @@ processQueryTargets(struct module_qstate errinf(qstate, "could not fetch nameserver"); errinf_dname(qstate, "at zone", iq->dp->name); if(ret == 1) - return error_response(qstate, id, - LDNS_RCODE_SERVFAIL); + return error_response(qstate, id, + LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -2963,7 +2994,7 @@ processQueryTargets(struct module_qstate LDNS_RCODE_SERVFAIL); } iq->num_target_queries += qs; - target_count_increase(iq, qs); + target_count_increase(qstate, iq, qs); } /* Since a target query might have been made, we * need to check again. */ @@ -3023,7 +3054,7 @@ processQueryTargets(struct module_qstate * this result, we do not have to reply with SERVFAIL */ if(extra > 0) { iq->num_target_queries += extra; - target_count_increase(iq, extra); + target_count_increase(qstate, iq, extra); check_waiting_queries(iq, qstate, id); /* undo qname minimise step because we'll get back here * to do it again */ @@ -3036,7 +3067,7 @@ processQueryTargets(struct module_qstate } } - target_count_increase_global_quota(iq, 1); + target_count_increase_global_quota(qstate, iq, 1); if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] > MAX_GLOBAL_QUOTA) { char s[LDNS_MAX_DOMAINLEN]; @@ -3049,7 +3080,9 @@ processQueryTargets(struct module_qstate /* Do not check ratelimit for forwarding queries or if we already got a * pass. */ - sq_check_ratelimit = (!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok); + sq_check_ratelimit = ((!(iq->chase_flags & BIT_RD) && + !iq->ratelimit_ok)); + iq->ratelimit_incremented = 0; /* We have a valid target. */ if(verbosity >= VERB_QUERY) { log_query_info(VERB_QUERY, "sending query:", &iq->qinfo_out); @@ -3060,17 +3093,6 @@ processQueryTargets(struct module_qstate iq->dnssec_lame_query?" but lame_query anyway": ""); } - real_addr = target->addr; - real_addrlen = target->addrlen; - - if(ie->nat64.use_nat64 && target->addr.ss_family == AF_INET) { - addr_to_nat64(&target->addr, &ie->nat64.nat64_prefix_addr, - ie->nat64.nat64_prefix_addrlen, ie->nat64.nat64_prefix_net, - &real_addr, &real_addrlen); - log_name_addr(VERB_QUERY, "applied NAT64:", - iq->dp->name, &real_addr, real_addrlen); - } - fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query)); outq = (*qstate->env->send_query)(&iq->qinfo_out, iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), @@ -3082,11 +3104,12 @@ processQueryTargets(struct module_qstate !qstate->blacklist&&(!iter_qname_indicates_dnssec(qstate->env, &iq->qinfo_out)||target->attempts==1)?0:BIT_CD), iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted( - ie, iq), sq_check_ratelimit, &real_addr, real_addrlen, + ie, iq), sq_check_ratelimit, &target->addr, target->addrlen, iq->dp->name, iq->dp->namelen, (iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream), (iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream), - target->tls_auth_name, qstate, &sq_was_ratelimited); + target->tls_auth_name, qstate, &sq_was_ratelimited, + &iq->ratelimit_incremented); if(!outq) { if(sq_was_ratelimited) { lock_basic_lock(&ie->queries_ratelimit_lock); @@ -3099,7 +3122,7 @@ processQueryTargets(struct module_qstate return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } log_addr(VERB_QUERY, "error sending query to auth server", - &real_addr, real_addrlen); + &target->addr, target->addrlen); if(qstate->env->cfg->qname_minimisation) iq->minimisation_state = SKIP_MINIMISE_STATE; return next_state(iq, QUERYTARGETS_STATE); @@ -3124,7 +3147,6 @@ find_NS(struct reply_info* rep, size_t f return NULL; } - /** * Process the query response. All queries end up at this state first. This * process generally consists of analyzing the response and routing the @@ -3166,7 +3188,8 @@ processQueryResponse(struct module_qstat orig_empty_nodata_found = iq->empty_nodata_found; type = response_type_from_server( (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd), - iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found); + iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found, + iq->msg_lame_empty, iq->msg_lame_referral); iq->chase_to_rd = 0; /* remove TC flag, if this is erroneously set by TCP upstream */ iq->response->rep->flags &= ~BIT_TC; @@ -3236,8 +3259,19 @@ processQueryResponse(struct module_qstat } else iter_scrub_ds(iq->response, NULL, NULL); if(type == RESPONSE_TYPE_THROWAWAY && FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) { - /* YXDOMAIN is a permanent error, no need to retry */ - type = RESPONSE_TYPE_ANSWER; + /* YXDOMAIN is a permanent error for DNAME expansion overflow + * (RFC 6672 Section 2.2). Only accept if the response + * contains a DNAME record in the answer section; otherwise + * treat as invalid, to make sure the authoritative answer + * make sense. */ + size_t i; + for(i=0; iresponse->rep->an_numrrsets; i++) { + if(ntohs(iq->response->rep->rrsets[i]->rk.type) + == LDNS_RR_TYPE_DNAME) { + type = RESPONSE_TYPE_ANSWER; + break; + } + } } if(type == RESPONSE_TYPE_CNAME) origtypecname = 1; @@ -3433,7 +3467,14 @@ processQueryResponse(struct module_qstat iq->deleg_msg = iq->response; /* Keep current delegation point for label comparison */ old_dp = iq->dp; - iq->dp = delegpt_from_message(iq->response, qstate->region); + /* A referral reply is "pleasant", refund the + * parent dp's rate charge before descending to the child. */ + if(iq->ratelimit_incremented) + infra_ratelimit_dec(qstate->env->infra_cache, + old_dp->name, old_dp->namelen, + *qstate->env->now); + iq->dp = delegpt_from_message(iq->response, qstate->region, + deleg_port_number(qstate->env)); if (qstate->env->cfg->qname_minimisation) iq->minimisation_state = INIT_MINIMISE_STATE; if(!iq->dp) { @@ -3616,7 +3657,7 @@ processQueryResponse(struct module_qstat return next_state(iq, INIT_REQUEST_STATE); } else if(type == RESPONSE_TYPE_LAME) { /* Cache the LAMEness. */ - verbose(VERB_DETAIL, "query response was %sLAME", + verbose(VERB_DETAIL, "query response was categorized as %sLAME", dnsseclame?"DNSSEC ":""); if(!dname_subdomain_c(iq->qchase.qname, iq->dp->name)) { log_err("mark lame: mismatch in qname and dpname"); @@ -3655,7 +3696,7 @@ processQueryResponse(struct module_qstat * In this case, the event is just sent directly back to * the QUERYTARGETS_STATE without resetting anything, * because, clearly, the next target must be tried. */ - verbose(VERB_DETAIL, "query response was THROWAWAY"); + verbose(VERB_DETAIL, "query response was categorized as THROWAWAY"); } else { log_warn("A query response came back with an unknown type: %d", (int)type); @@ -3710,7 +3751,8 @@ prime_supers(struct module_qstate* qstat log_assert(qstate->is_priming || foriq->wait_priming_stub); log_assert(qstate->return_rcode == LDNS_RCODE_NOERROR); /* Convert our response to a delegation point */ - dp = delegpt_from_message(qstate->return_msg, forq->region); + dp = delegpt_from_message(qstate->return_msg, forq->region, + deleg_port_number(forq->env)); if(!dp) { /* if there is no convertible delegation point, then * the ANSWER type was (presumably) a negative answer. */ @@ -3761,7 +3803,8 @@ processPrimeResponse(struct module_qstat iq->response->rep->flags &= ~(BIT_RD|BIT_RA); /* ignore rec-lame */ type = response_type_from_server( (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd), - iq->response, &iq->qchase, iq->dp, NULL); + iq->response, &iq->qchase, iq->dp, NULL, iq->msg_lame_empty, + iq->msg_lame_referral); if(type == RESPONSE_TYPE_ANSWER) { qstate->return_rcode = LDNS_RCODE_NOERROR; qstate->return_msg = iq->response; @@ -3880,7 +3923,7 @@ processTargetResponse(struct module_qsta /* no new addresses, increase the nxns counter, like * this could be a list of wildcards with no new * addresses */ - target_count_increase_nx(foriq, 1); + target_count_increase_nx(qstate, foriq, 1); } verbose(VERB_ALGO, "added target response"); delegpt_log(VERB_ALGO, foriq->dp); @@ -3892,7 +3935,7 @@ processTargetResponse(struct module_qsta dpns->resolved = 1; /* fail the target */ /* do not count cached answers */ if(qstate->reply_origin && qstate->reply_origin->len != 0) { - target_count_increase_nx(foriq, 1); + target_count_increase_nx(qstate, foriq, 1); } } } @@ -3925,7 +3968,8 @@ processDSNSResponse(struct module_qstate /* else, store as DP and continue at querytargets */ foriq->state = QUERYTARGETS_STATE; - foriq->dp = delegpt_from_message(qstate->return_msg, forq->region); + foriq->dp = delegpt_from_message(qstate->return_msg, forq->region, + deleg_port_number(forq->env)); if(!foriq->dp) { log_err("out of memory in dsns dp alloc"); errinf(qstate, "malloc failure, in DS search"); @@ -3974,7 +4018,7 @@ processClassResponse(struct module_qstat /* if there are records, copy RCODE */ /* lower sec_state if this message is lower */ if(from->rep->rrset_count != 0) { - size_t n = from->rep->rrset_count+to->rep->rrset_count; + size_t i, n = from->rep->rrset_count+to->rep->rrset_count; struct ub_packed_rrset_key** dest, **d; /* copy appropriate rcode */ to->rep->flags = from->rep->flags; @@ -3996,24 +4040,49 @@ processClassResponse(struct module_qstat memcpy(dest, to->rep->rrsets, to->rep->an_numrrsets * sizeof(dest[0])); dest += to->rep->an_numrrsets; - memcpy(dest, from->rep->rrsets, from->rep->an_numrrsets - * sizeof(dest[0])); + for(i=0; irep->an_numrrsets; i++) { + dest[i] = packed_rrset_copy_region( + from->rep->rrsets[i], forq->region, 0); + if(!dest[i]) { + log_err("malloc failed in collect ANY"); + foriq->state = FINISHED_STATE; + return; + } + } dest += from->rep->an_numrrsets; /* copy NS */ memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets, to->rep->ns_numrrsets * sizeof(dest[0])); dest += to->rep->ns_numrrsets; - memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets, - from->rep->ns_numrrsets * sizeof(dest[0])); + for(i=0; irep->ns_numrrsets; i++) { + dest[i] = packed_rrset_copy_region( + from->rep->rrsets[ + from->rep->an_numrrsets+i], + forq->region, 0); + if(!dest[i]) { + log_err("malloc failed in collect ANY"); + foriq->state = FINISHED_STATE; + return; + } + } dest += from->rep->ns_numrrsets; /* copy AR */ memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets+ to->rep->ns_numrrsets, to->rep->ar_numrrsets * sizeof(dest[0])); dest += to->rep->ar_numrrsets; - memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets+ - from->rep->ns_numrrsets, - from->rep->ar_numrrsets * sizeof(dest[0])); + for(i=0; irep->ar_numrrsets; i++) { + dest[i] = packed_rrset_copy_region( + from->rep->rrsets[ + from->rep->an_numrrsets+ + from->rep->ns_numrrsets+i], + forq->region, 0); + if(!dest[i]) { + log_err("malloc failed in collect ANY"); + foriq->state = FINISHED_STATE; + return; + } + } /* update counts */ to->rep->rrsets = d; to->rep->an_numrrsets += from->rep->an_numrrsets; @@ -4117,6 +4186,7 @@ processFinished(struct module_qstate* qs iter_store_parentside_neg(qstate->env, &qstate->qinfo, iq->deleg_msg?iq->deleg_msg->rep: (iq->response?iq->response->rep:NULL)); + target_count_store(qstate, iq); if(!iq->response) { verbose(VERB_ALGO, "No response is set, servfail"); errinf(qstate, "(no response found at query finish)"); @@ -4370,7 +4440,10 @@ process_response(struct module_qstate* q /* normalize and sanitize: easy to delete items from linked lists */ if(!scrub_message(pkt, prs, &iq->qinfo_out, iq->dp->name, - qstate->env->scratch, qstate->env, qstate, ie)) { + qstate->env->scratch, qstate->env, qstate, ie, + &iq->msg_lame_empty, &iq->msg_lame_referral, + (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd) + )) { /* if 0x20 enabled, start fallback, but we have no message */ if(event == module_event_capsfail && !iq->caps_fallback) { iq->caps_fallback = 1; @@ -4532,6 +4605,7 @@ iter_clear(struct module_qstate* qstate, iq = (struct iter_qstate*)qstate->minfo[id]; if(iq) { outbound_list_clear(&iq->outlist); + target_count_store(qstate, iq); if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) { free(iq->target_count); if(*iq->nxns_dp) free(*iq->nxns_dp); Index: sbin/unwind/libunbound/iterator/iterator.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/iterator/iterator.h,v diff -u -p -r1.12 iterator.h --- sbin/unwind/libunbound/iterator/iterator.h 14 Sep 2025 15:16:53 -0000 1.12 +++ sbin/unwind/libunbound/iterator/iterator.h 21 Sep 2026 16:27:57 -0000 @@ -104,6 +104,11 @@ extern int BLACKLIST_PENALTY; #define RTT_BAND 400 /** Number of retries for empty nodata packets before it is accepted. */ #define EMPTY_NODATA_RETRY_COUNT 2 +/** max label-strip iterations in DSNS_FIND_STATE (RFC 4035 4.2 parent-NS + * search) before giving up; bounds upstream NS sends per client DS. + * Means the max number of labels in grandchild to the grandparent zone that + * are co-hosted. */ +#define MAX_DSNS_FIND_COUNT 20 /** * Iterator global state for nat64. @@ -375,6 +380,10 @@ struct iter_qstate { /** if true, already tested for ratelimiting and passed the test */ int ratelimit_ok; + /** If the last query, that may be a referral, incremented the + * ratelimit counter. */ + int ratelimit_incremented; + /** * The query must store NS records from referrals as parentside RRs * Enabled once it hits resolution problems, to throttle retries. @@ -399,6 +408,8 @@ struct iter_qstate { uint8_t* dsns_point; /** length of the dname in dsns_point */ size_t dsns_point_len; + /** number of label-strip iterations performed in DSNS_FIND_STATE */ + int dsns_count; /** * expected dnssec information for this iteration step. @@ -433,6 +444,13 @@ struct iter_qstate { * This flag detects that a completely empty nodata was received, * already so that it is accepted later. */ int empty_nodata_found; + + /** Store if the answer was empty, but lame, before it became empty.*/ + int msg_lame_empty; + + /** Store if the answer was a referral, to self, before scrub. So the + * it is not some sort of answer. */ + int msg_lame_referral; /** list of pending queries to authoritative servers. */ struct outbound_list outlist; Index: sbin/unwind/libunbound/libunbound/context.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/libunbound/context.h,v diff -u -p -r1.5 context.h --- sbin/unwind/libunbound/libunbound/context.h 5 Sep 2023 15:44:01 -0000 1.5 +++ sbin/unwind/libunbound/libunbound/context.h 21 Sep 2026 16:27:57 -0000 @@ -167,6 +167,8 @@ struct ctx_query { ub_event_callback_type cb_event; /** for async query, the callback user arg */ void* cb_arg; + /** for async query the unique info */ + void* unique_info; /** answer message, result from resolver lookup. */ uint8_t* msg; Index: sbin/unwind/libunbound/libunbound/libunbound.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/libunbound/libunbound.c,v diff -u -p -r1.12 libunbound.c --- sbin/unwind/libunbound/libunbound/libunbound.c 5 Sep 2024 08:22:47 -0000 1.12 +++ sbin/unwind/libunbound/libunbound/libunbound.c 21 Sep 2026 16:27:57 -0000 @@ -571,6 +571,8 @@ ub_ctx_async(struct ub_ctx* ctx, int dot int ub_poll(struct ub_ctx* ctx) { + if(!ctx || ctx->event_base) + return UB_INITFAIL; /* no need to hold lock while testing for readability. */ return tube_poll(ctx->rr_pipe); } @@ -578,6 +580,8 @@ ub_poll(struct ub_ctx* ctx) int ub_fd(struct ub_ctx* ctx) { + if(!ctx || ctx->event_base) + return -1; return tube_read_fd(ctx->rr_pipe); } @@ -672,6 +676,8 @@ ub_process(struct ub_ctx* ctx) int r; uint8_t* msg; uint32_t len; + if(!ctx || ctx->event_base) + return UB_INITFAIL; while(1) { msg = NULL; lock_basic_lock(&ctx->rrpipe_lock); @@ -700,6 +706,8 @@ ub_wait(struct ub_ctx* ctx) int r; uint8_t* msg; uint32_t len; + if(!ctx || ctx->event_base) + return UB_INITFAIL; /* this is basically the same loop as _process(), but with changes. * holds the rrpipe lock and waits with tube_wait */ while(1) { @@ -837,6 +845,8 @@ ub_resolve_async(struct ub_ctx* ctx, con struct ctx_query* q; uint8_t* msg = NULL; uint32_t len = 0; + if(!ctx || ctx->event_base) + return UB_INITFAIL; if(async_id) *async_id = 0; @@ -1467,8 +1477,15 @@ ub_ctx_set_event(struct ub_ctx* ctx, str lock_basic_lock(&ctx->cfglock); /* destroy the current worker - safe to pass in NULL */ + + /* Unlock the cfglock during libworker_delete_event, since it + * calls context_release_alloc, that wants to lock cfglock again. + * Since the event base is used from one thread, the one that + * called this function, it is safe to do so. */ + lock_basic_unlock(&ctx->cfglock); libworker_delete_event(ctx->event_worker); ctx->event_worker = NULL; + lock_basic_lock(&ctx->cfglock); new_base = ub_libevent_event_base(base); if (new_base) ctx->event_base = new_base; Index: sbin/unwind/libunbound/libunbound/libworker.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/libunbound/libworker.c,v diff -u -p -r1.18 libworker.c --- sbin/unwind/libunbound/libunbound/libworker.c 29 Sep 2025 14:53:38 -0000 1.18 +++ sbin/unwind/libunbound/libunbound/libworker.c 21 Sep 2026 16:27:57 -0000 @@ -105,6 +105,7 @@ libworker_delete_env(struct libworker* w SSL_CTX_free(w->sslctx); #endif outside_network_delete(w->back); + shared_ports_delete(w->shared_ports); } /** delete libworker struct */ @@ -219,17 +220,25 @@ libworker_setup(struct ub_ctx* ctx, int libworker_delete(w); return NULL; } + if(!(w->shared_ports = shared_ports_create(cfg->out_ifs, + cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, ports, numports))) { + if(!w->is_bg || w->is_bg_thread) { + lock_basic_unlock(&ctx->cfglock); + } + libworker_delete(w); + return NULL; + } w->back = outside_network_create(w->base, cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, - ports, numports, cfg->unwanted_threshold, + cfg->unwanted_threshold, cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w, cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx, cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect, cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout, - cfg->tcp_auth_query_timeout); + cfg->tcp_auth_query_timeout, w->shared_ports); w->env->outnet = w->back; if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); @@ -642,7 +651,8 @@ int libworker_fg(struct ub_ctx* ctx, str } /* process new query */ if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, - w->back->udp_buff, qid, libworker_fg_done_cb, q, 0)) { + w->back->udp_buff, qid, libworker_fg_done_cb, q, 0, + &q->unique_info)) { free(qinfo.qname); return UB_NOMEM; } @@ -723,7 +733,8 @@ int libworker_attach_mesh(struct ub_ctx* if(async_id) *async_id = q->querynum; if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, - w->back->udp_buff, qid, libworker_event_done_cb, q, 0)) { + w->back->udp_buff, qid, libworker_event_done_cb, q, 0, + &q->unique_info)) { free(qinfo.qname); return UB_NOMEM; } @@ -861,7 +872,8 @@ handle_newq(struct libworker* w, uint8_t q->w = w; /* process new query */ if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, - w->back->udp_buff, qid, libworker_bg_done_cb, q, 0)) { + w->back->udp_buff, qid, libworker_bg_done_cb, q, 0, + &q->unique_info)) { add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0); } free(qinfo.qname); @@ -879,7 +891,8 @@ struct outbound_entry* libworker_send_qu int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, - struct module_qstate* q, int* was_ratelimited) + struct module_qstate* q, int* was_ratelimited, + int* ratelimit_incremented) { struct libworker* w = (struct libworker*)q->env->worker; struct outbound_entry* e = (struct outbound_entry*)regional_alloc( @@ -891,7 +904,7 @@ struct outbound_entry* libworker_send_qu want_dnssec, nocaps, check_ratelimit, tcp_upstream, ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q, libworker_handle_service_reply, e, w->back->udp_buff, q->env, - was_ratelimited); + was_ratelimited, ratelimit_incremented); if(!e->qsent) { return NULL; } @@ -976,7 +989,8 @@ struct outbound_entry* worker_send_query struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), - struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) + struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited), + int* ATTR_UNUSED(ratelimit_incremented)) { log_assert(0); return 0; Index: sbin/unwind/libunbound/libunbound/libworker.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/libunbound/libworker.h,v diff -u -p -r1.1 libworker.h --- sbin/unwind/libunbound/libunbound/libworker.h 23 Jan 2019 13:05:27 -0000 1.1 +++ sbin/unwind/libunbound/libunbound/libworker.h 21 Sep 2026 16:27:57 -0000 @@ -60,6 +60,7 @@ struct tube; struct sldns_buffer; struct ub_event_base; struct query_info; +struct shared_ports; /** * The library-worker status structure @@ -84,6 +85,8 @@ struct libworker { struct comm_base* base; /** the backside outside network interface to the auth servers */ struct outside_network* back; + /** shared ports structure */ + struct shared_ports* shared_ports; /** random() table for this worker. */ struct ub_randstate* rndstate; /** sslcontext for SSL wrapped DNS over TCP queries */ Index: sbin/unwind/libunbound/libunbound/unbound.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/libunbound/unbound.h,v diff -u -p -r1.12 unbound.h --- sbin/unwind/libunbound/libunbound/unbound.h 29 Sep 2025 14:53:38 -0000 1.12 +++ sbin/unwind/libunbound/libunbound/unbound.h 21 Sep 2026 16:27:57 -0000 @@ -853,6 +853,8 @@ struct ub_server_stats { long long qquic; /** number of queries removed due to discard-timeout */ long long num_queries_discard_timeout; + /** number of queries removed due to replyaddr limit */ + long long num_queries_replyaddr_limit; /** number of queries removed due to wait-limit */ long long num_queries_wait_limit; /** number of dns error reports generated */ @@ -872,6 +874,8 @@ struct ub_stats_info { long long mesh_num_states; /** mesh stats: current number of reply (user) states */ long long mesh_num_reply_states; + /** mesh stats: current number of reply entries */ + long long mesh_num_reply_addrs; /** mesh stats: number of reply states overwritten with a new one */ long long mesh_jostled; /** mesh stats: number of incoming queries dropped */ Index: sbin/unwind/libunbound/libunbound/worker.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/libunbound/worker.h,v diff -u -p -r1.3 worker.h --- sbin/unwind/libunbound/libunbound/worker.h 1 Mar 2022 18:34:22 -0000 1.3 +++ sbin/unwind/libunbound/libunbound/worker.h 21 Sep 2026 16:27:57 -0000 @@ -70,6 +70,8 @@ struct query_info; * @param q: which query state to reactivate upon return. * @param was_ratelimited: it will signal back if the query failed to pass the * ratelimit check. + * @param ratelimit_incremented: set to true if the ratelimit counter + * was increased. * @return: false on failure (memory or socket related). no query was * sent. */ @@ -78,7 +80,8 @@ struct outbound_entry* libworker_send_qu int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, - struct module_qstate* q, int* was_ratelimited); + struct module_qstate* q, int* was_ratelimited, + int* ratelimit_incremented); /** process incoming serviced query replies from the network */ int libworker_handle_service_reply(struct comm_point* c, void* arg, int error, @@ -126,6 +129,8 @@ void worker_sighandler(int sig, void* ar * @param q: which query state to reactivate upon return. * @param was_ratelimited: it will signal back if the query failed to pass the * ratelimit check. + * @param ratelimit_incremented: set to true if the ratelimit counter + * was increased. * @return: false on failure (memory or socket related). no query was * sent. */ @@ -134,7 +139,8 @@ struct outbound_entry* worker_send_query int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, - struct module_qstate* q, int* was_ratelimited); + struct module_qstate* q, int* was_ratelimited, + int* ratelimit_incremented); /** * process control messages from the main thread. Frees the control @@ -170,14 +176,5 @@ void worker_start_accept(void* arg); /** stop accept callback handler */ void worker_stop_accept(void* arg); - -/** handle remote control accept callbacks */ -int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*); - -/** handle remote control data callbacks */ -int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*); - -/** routine to printout option values over SSL */ -void remote_get_opt_ssl(char* line, void* arg); #endif /* LIBUNBOUND_WORKER_H */ Index: sbin/unwind/libunbound/respip/respip.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/respip/respip.c,v diff -u -p -r1.15 respip.c --- sbin/unwind/libunbound/respip/respip.c 14 Sep 2025 15:16:53 -0000 1.15 +++ sbin/unwind/libunbound/respip/respip.c 21 Sep 2026 16:27:58 -0000 @@ -899,27 +899,34 @@ respip_rewrite_reply(const struct query_ int rpz_cname_override = 0; char* log_name = NULL; - if(!cinfo) - goto done; - ctaglist = cinfo->taglist; - ctaglen = cinfo->taglen; - tag_actions = cinfo->tag_actions; - tag_actions_size = cinfo->tag_actions_size; - tag_datas = cinfo->tag_datas; - tag_datas_size = cinfo->tag_datas_size; - if(cinfo->view) { - view = cinfo->view; - lock_rw_rdlock(&view->lock); - } else if(cinfo->view_name) { - view = views_find_view(views, cinfo->view_name, 0); - if(!view) { - /* If the view no longer exists, the rewrite can not - * be processed further. */ - verbose(VERB_ALGO, "respip: failed because view %s no " - "longer exists", cinfo->view_name); - return 0; + if(!cinfo) { + /* Internal mesh sub-query (e.g. dns64 A lookup): no + * per-client view/tags, but global response-ip and RPZ + * rpz-ip must still apply. */ + ctaglist = NULL; ctaglen = 0; + tag_actions = NULL; tag_actions_size = 0; + tag_datas = NULL; tag_datas_size = 0; + } else { + ctaglist = cinfo->taglist; + ctaglen = cinfo->taglen; + tag_actions = cinfo->tag_actions; + tag_actions_size = cinfo->tag_actions_size; + tag_datas = cinfo->tag_datas; + tag_datas_size = cinfo->tag_datas_size; + if(cinfo->view) { + view = cinfo->view; + lock_rw_rdlock(&view->lock); + } else if(cinfo->view_name) { + view = views_find_view(views, cinfo->view_name, 0); + if(!view) { + /* If the view no longer exists, the rewrite can not + * be processed further. */ + verbose(VERB_ALGO, "respip: failed because view %s no " + "longer exists", cinfo->view_name); + return 0; + } + /* The view is rdlocked by views_find_view. */ } - /* The view is rdlocked by views_find_view. */ } log_assert(ipset); @@ -973,6 +980,9 @@ respip_rewrite_reply(const struct query_ lock_rw_unlock(&raddr->lock); lock_rw_unlock(&a->lock); lock_rw_unlock(&az->rpz_lock); + if(view) { + lock_rw_unlock(&view->lock); + } return 0; } if(rpz_used) { @@ -1074,7 +1084,8 @@ generate_cname_request(struct module_qst subqi.qtype = qstate->qinfo.qtype; subqi.qclass = qstate->qinfo.qclass; fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); - return (*qstate->env->attach_sub)(qstate, &subqi, BIT_RD, 0, 0, &subq); + return (*qstate->env->attach_sub)(qstate, &subqi, + qstate->client_info, BIT_RD, 0, 0, &subq); } void @@ -1110,7 +1121,13 @@ respip_operate(struct module_qstate* qst if((qstate->qinfo.qtype == LDNS_RR_TYPE_A || qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA || qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) && - qstate->return_msg && qstate->return_msg->rep) { + qstate->return_msg && qstate->return_msg->rep && + !(qstate->env->need_to_validate && + (!(qstate->query_flags & BIT_CD) + || qstate->env->cfg->ignore_cd) && + (qstate->return_msg->rep->security <= sec_status_bogus + || qstate->return_msg->rep->security == + sec_status_secure_sentinel_fail))) { struct reply_info* new_rep = qstate->return_msg->rep; struct ub_packed_rrset_key* alias_rrset = NULL; struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; @@ -1147,8 +1164,10 @@ respip_operate(struct module_qstate* qst * clients. */ qstate->is_drop = 1; } else if(alias_rrset) { - if(!generate_cname_request(qstate, alias_rrset)) + if(!generate_cname_request(qstate, alias_rrset)) { + errinf(qstate, "Could not generate CNAME request"); goto servfail; + } next_state = module_wait_subquery; } qstate->return_msg->rep = new_rep; @@ -1162,6 +1181,7 @@ respip_operate(struct module_qstate* qst servfail: qstate->return_rcode = LDNS_RCODE_SERVFAIL; qstate->return_msg = NULL; + qstate->ext_state[id] = module_finished; } int @@ -1233,7 +1253,8 @@ respip_inform_super(struct module_qstate struct respip_qstate* rq = (struct respip_qstate*)super->minfo[id]; struct reply_info* new_rep = NULL; - rq->state = RESPIP_SUBQUERY_FINISHED; + if(rq) + rq->state = RESPIP_SUBQUERY_FINISHED; /* respip subquery should have always been created with a valid reply * in super. */ @@ -1257,6 +1278,7 @@ respip_inform_super(struct module_qstate return; fail: + errinf(super, "CNAME lookup failed"); super->return_rcode = LDNS_RCODE_SERVFAIL; super->return_msg = NULL; return; Index: sbin/unwind/libunbound/services/authzone.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/authzone.c,v diff -u -p -r1.23 authzone.c --- sbin/unwind/libunbound/services/authzone.c 29 Sep 2025 14:53:38 -0000 1.23 +++ sbin/unwind/libunbound/services/authzone.c 21 Sep 2026 16:27:58 -0000 @@ -55,6 +55,7 @@ #include "util/log.h" #include "util/module.h" #include "util/random.h" +#include "util/timeval_func.h" #include "services/cache/dns.h" #include "services/outside_network.h" #include "services/listen_dnsport.h" @@ -95,6 +96,8 @@ /** number of timeouts before we fallback from IXFR to AXFR, * because some versions of servers (eg. dnsmasq) drop IXFR packets. */ #define NUM_TIMEOUTS_FALLBACK_IXFR 3 +/** number of IXFRs before an AXFR is performed, to consolidate RPZ memory. */ +#define NUM_IXFR_BEFORE_AXFR 5 /** pick up nextprobe task to start waiting to perform transfer actions */ static void xfr_set_timeout(struct auth_xfer* xfr, struct module_env* env, @@ -106,6 +109,9 @@ static void xfr_probe_send_or_end(struct * or transfer task if nothing to probe, or false if already in progress */ static int xfr_start_probe(struct auth_xfer* xfr, struct module_env* env, struct auth_master* spec); +/** copy the master addresses from the task_probe lookups to the allow_notify + * list of masters */ +static void probe_copy_masters_for_allow_notify(struct auth_xfer* xfr); /** delete xfer structure (not its tree entry) */ void auth_xfer_delete(struct auth_xfer* xfr); @@ -171,7 +177,7 @@ get_rrset_ttl(struct ub_packed_rrset_key /** Copy rrset into region from domain-datanode and packet rrset */ static struct ub_packed_rrset_key* auth_packed_rrset_copy_region(struct auth_zone* z, struct auth_data* node, - struct auth_rrset* rrset, struct regional* region, time_t adjust) + struct auth_rrset* rrset, struct regional* region) { struct ub_packed_rrset_key key; memset(&key, 0, sizeof(key)); @@ -182,7 +188,7 @@ auth_packed_rrset_copy_region(struct aut key.rk.type = htons(rrset->type); key.rk.rrset_class = htons(z->dclass); key.entry.hash = rrset_key_hash(&key.rk); - return packed_rrset_copy_region(&key, region, adjust); + return packed_rrset_copy_region(&key, region, 0); } /** fix up msg->rep TTL and prefetch ttl */ @@ -236,7 +242,7 @@ msg_add_rrset_an(struct auth_zone* z, st return 0; /* copy it */ if(!(msg->rep->rrsets[msg->rep->rrset_count] = - auth_packed_rrset_copy_region(z, node, rrset, region, 0))) + auth_packed_rrset_copy_region(z, node, rrset, region))) return 0; msg->rep->rrset_count++; msg->rep->an_numrrsets++; @@ -260,7 +266,7 @@ msg_add_rrset_ns(struct auth_zone* z, st return 0; /* copy it */ if(!(msg->rep->rrsets[msg->rep->rrset_count] = - auth_packed_rrset_copy_region(z, node, rrset, region, 0))) + auth_packed_rrset_copy_region(z, node, rrset, region))) return 0; msg->rep->rrset_count++; msg->rep->ns_numrrsets++; @@ -283,7 +289,7 @@ msg_add_rrset_ar(struct auth_zone* z, st return 0; /* copy it */ if(!(msg->rep->rrsets[msg->rep->rrset_count] = - auth_packed_rrset_copy_region(z, node, rrset, region, 0))) + auth_packed_rrset_copy_region(z, node, rrset, region))) return 0; msg->rep->rrset_count++; msg->rep->ar_numrrsets++; @@ -386,6 +392,20 @@ auth_data_del(rbnode_type* n, void* ATTR auth_data_delete(z); } +/** delete chunklist */ +static void +auth_chunk_list_delete(struct auth_chunk* first) +{ + struct auth_chunk* c, *cn; + c = first; + while(c) { + cn = c->next; + free(c->data); + free(c); + c = cn; + } +} + /** delete an auth zone structure (tree remove must be done elsewhere) */ static void auth_zone_delete(struct auth_zone* z, struct auth_zones* az) @@ -407,6 +427,7 @@ auth_zone_delete(struct auth_zone* z, st } if(z->rpz) rpz_delete(z->rpz); + auth_chunk_list_delete(z->perform_write_chunk_list); free(z->name); free(z->zonefile); free(z); @@ -432,7 +453,12 @@ auth_zone_create(struct auth_zones* az, rbtree_init(&z->data, &auth_data_cmp); lock_rw_init(&z->lock); lock_protect(&z->lock, &z->name, sizeof(*z)-sizeof(rbnode_type)- - sizeof(&z->rpz_az_next)-sizeof(&z->rpz_az_prev)); + sizeof(z->rpz_az_next)-sizeof(z->rpz_az_prev)- + sizeof(z->max_transfer_size)-sizeof(z->max_transfer_size)); + lock_protect(&z->lock, &z->max_transfer_size, + sizeof(z->max_transfer_size)); + lock_protect(&z->lock, &z->max_transfer_time, + sizeof(z->max_transfer_time)); lock_rw_wrlock(&z->lock); /* z lock protects all, except rbtree itself and the rpz linked list * pointers, which are protected using az->lock */ @@ -1175,6 +1201,22 @@ az_insert_rr(struct auth_zone* z, uint8_ log_err("wrong class for RR"); return 0; } + if(rr_type == LDNS_RR_TYPE_A && rdatalen != 6 /* 2 + 4 */) { + log_err("malformed A record"); + return 0; + } else if(rr_type == LDNS_RR_TYPE_AAAA && rdatalen != 18 /* 2 + 16 */) { + log_err("malformed AAAA record"); + return 0; + } + if(!dname_subdomain_c(dname, z->name)) { + char nm[LDNS_MAX_DOMAINLEN], zn[LDNS_MAX_DOMAINLEN]; + dname_str(dname, nm); + dname_str(z->name, zn); + verbose(VERB_ALGO, "auth-zone %s: dropping out-of-zone RR " + "%s", zn, nm); + if(duplicate) *duplicate=1; /* treat as bad insert */ + return 1; + } if(!(node=az_domain_find_or_create(z, dname, dname_len))) { log_err("cannot create domain"); return 0; @@ -1182,6 +1224,10 @@ az_insert_rr(struct auth_zone* z, uint8_ if(!az_domain_add_rr(node, rr_type, rr_ttl, rdata, rdatalen, duplicate)) { log_err("cannot add RR to domain"); + if(node->rrsets == NULL) { + (void)rbtree_delete(&z->data, node); + auth_data_delete(node); + } return 0; } if(z->rpz) { @@ -1369,6 +1415,10 @@ decompress_rr_into_buffer(struct sldns_b uncompressed_len = pkt_dname_len(&pktbuf); if(!uncompressed_len) return 0; /* parse error in dname */ + compressed_len = sldns_buffer_position( + &pktbuf) - oldpos; + if(compressed_len > rdlen) + return 0; /* dname exceeds rdata */ if(!sldns_buffer_available(buf, uncompressed_len)) /* dname too long for buffer */ @@ -1376,14 +1426,15 @@ decompress_rr_into_buffer(struct sldns_b dname_pkt_copy(&pktbuf, sldns_buffer_current(buf), rd); sldns_buffer_skip(buf, (ssize_t)uncompressed_len); - compressed_len = sldns_buffer_position( - &pktbuf) - oldpos; rd += compressed_len; rdlen -= compressed_len; count--; len = 0; break; case LDNS_RDF_TYPE_STR: + /* Check rdlen for resilience, because it is + * checked above, that rdlen > 0 */ + if(rdlen < 1) return 0; /* malformed */ len = rd[0] + 1; break; default: @@ -1391,6 +1442,8 @@ decompress_rr_into_buffer(struct sldns_b break; } if(len) { + if(len > rdlen) + return 0; /* malformed */ if(!sldns_buffer_available(buf, len)) return 0; /* too long for buffer */ sldns_buffer_write(buf, rd, len); @@ -1498,6 +1551,11 @@ az_parse_file(struct auth_zone* z, FILE* "exceeded", fname, state->lineno); return 0; } + /* A $INCLUDE is not expected for a secondary zone. */ + if(z->zone_is_slave) { + log_err("%s:%d $INCLUDE not allowed for secondary zone", fname, state->lineno); + return 0; + } /* skip spaces */ while(*incfile == ' ' || *incfile == '\t') incfile++; @@ -1563,6 +1621,16 @@ az_parse_file(struct auth_zone* z, FILE* return 1; } +void auth_zone_clear_data(struct auth_zone* z) +{ + /* clear the data tree */ + traverse_postorder(&z->data, auth_data_del, NULL); + rbtree_init(&z->data, &auth_data_cmp); + /* clear the RPZ policies */ + if(z->rpz) + rpz_clear(z->rpz); +} + int auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg) { @@ -1585,10 +1653,16 @@ auth_zone_read_zonefile(struct auth_zone in = fopen(zfilename, "r"); if(!in) { char* n = sldns_wire2str_dname(z->name, z->namelen); - if(z->zone_is_slave && errno == ENOENT) { - /* we fetch the zone contents later, no file yet */ - verbose(VERB_ALGO, "no zonefile %s for %s", - zfilename, n?n:"error"); + if(errno == ENOENT) { + /* For a secondary, fetch the zone contents later, no + * file yet. For a primary, no way to fetch the zone, + * so warn. */ + if(z->zone_is_slave) + verbose(VERB_ALGO, "no zonefile %s for %s", + zfilename, n?n:"error"); + else + log_warn("no zonefile %s for %s", + zfilename, n?n:"error"); free(n); return 1; } @@ -1791,9 +1865,11 @@ auth_zones_read_zones(struct auth_zones* RBTREE_FOR(z, struct auth_zone*, &az->ztree) { lock_rw_wrlock(&z->lock); if(!auth_zone_read_zonefile(z, cfg)) { + /* For both secondary and primary zones, not fatal. + * This keeps the server up. */ + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); - lock_rw_unlock(&az->lock); - return 0; + continue; } if(z->zonefile && z->zonefile[0]!=0 && env) zonemd_offline_verify(z, env, mods); @@ -1998,12 +2074,21 @@ auth_zone_get_serial(struct auth_zone* z struct auth_data* apex; struct auth_rrset* soa; struct packed_rrset_data* d; + size_t primlen, mboxlen; apex = az_find_name(z, z->name, z->namelen); if(!apex) return 0; soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA); if(!soa || soa->data->count==0) return 0; /* no RRset or no RRs in rrset */ if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */ + if((primlen = dname_valid(soa->data->rr_data[0]+2, + soa->data->rr_len[0]-2)) == 0) + return 0; /* primary dname malformed */ + if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen, + soa->data->rr_len[0]-2-primlen)) == 0) + return 0; /* mailbox dname malformed */ + if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0]) + return 0; /* rdata malformed */ d = soa->data; *serial = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-20)); return 1; @@ -2016,12 +2101,21 @@ xfr_find_soa(struct auth_zone* z, struct struct auth_data* apex; struct auth_rrset* soa; struct packed_rrset_data* d; + size_t primlen, mboxlen; apex = az_find_name(z, z->name, z->namelen); if(!apex) return 0; soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA); if(!soa || soa->data->count==0) return 0; /* no RRset or no RRs in rrset */ if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */ + if((primlen = dname_valid(soa->data->rr_data[0]+2, + soa->data->rr_len[0]-2)) == 0) + return 0; /* primary dname malformed */ + if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen, + soa->data->rr_len[0]-2-primlen)) == 0) + return 0; /* mailbox dname malformed */ + if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0]) + return 0; /* rdata malformed */ /* SOA record ends with serial, refresh, retry, expiry, minimum, * as 4 byte fields */ d = soa->data; @@ -2051,6 +2145,7 @@ auth_xfer_setup(struct auth_zone* z, str if(!xfr_find_soa(z, x)) { return 1; } + x->is_rpz = (z->rpz!=NULL); /* nothing for probe, nextprobe and transfer tasks */ return 1; } @@ -2110,6 +2205,9 @@ auth_zones_cfg(struct auth_zones* az, st } return 0; } + /* Populate the xfer related options early since we may create one now */ + z->max_transfer_size = c->max_transfer_size; + z->max_transfer_time = c->max_transfer_time; if(c->masters || c->urls) { if(!(x=auth_zones_find_or_add_xfer(az, z))) { lock_rw_unlock(&az->lock); @@ -2143,7 +2241,12 @@ auth_zones_cfg(struct auth_zones* az, st z->zonemd_reject_absence = c->zonemd_reject_absence; if(c->isrpz && !z->rpz){ if(!(z->rpz = rpz_create(c))){ - fatal_exit("Could not setup RPZ zones"); + log_err("Could not setup RPZ zones"); + if(x) { + lock_basic_unlock(&x->lock); + } + lock_rw_unlock(&z->lock); + lock_rw_unlock(&az->rpz_lock); return 0; } lock_protect(&z->lock, &z->rpz->local_zones, sizeof(*z->rpz)); @@ -2181,6 +2284,10 @@ auth_zones_cfg(struct auth_zones* az, st lock_rw_unlock(&z->lock); return 0; } + /* Pick up allow notify entries, early. This works for + * addresses and netblocks. */ + if(!x->allow_notify_list) + probe_copy_masters_for_allow_notify(x); lock_basic_unlock(&x->lock); } @@ -2277,17 +2384,11 @@ static void auth_chunks_delete(struct auth_transfer* at) { if(at->chunks_first) { - struct auth_chunk* c, *cn; - c = at->chunks_first; - while(c) { - cn = c->next; - free(c->data); - free(c); - c = cn; - } + auth_chunk_list_delete(at->chunks_first); } at->chunks_first = NULL; at->chunks_last = NULL; + at->chunks_total = 0; } /** free master addr list */ @@ -2619,7 +2720,7 @@ az_empty_nonterminal(struct auth_zone* z while(next && (rbnode_type*)next != RBTREE_NULL && next->rrsets == NULL) { /* the next name has empty rrsets, is an empty nonterminal * itself, see if there exists something below it */ - next = (struct auth_data*)rbtree_next(&node->node); + next = (struct auth_data*)rbtree_next(&next->node); } if((rbnode_type*)next == RBTREE_NULL || !next) { /* there is no next node, so something below it cannot @@ -3500,7 +3601,13 @@ int auth_zones_lookup(struct auth_zones* *fallback = 1; return 0; } - if(z->zone_expired) { + if(z->zone_expired || (z->zonemd_check && z->zonemd_callback_env)) { + /* Do not serve from a zonemd-check zone while its ZONEMD + * verification is still pending: the content is not yet known + * to pass the configured check. The pending marker + * (zonemd_callback_env) is set under z->lock when the async + * lookup is spawned and cleared by the callback under z->lock, + * so this test is race-free. */ *fallback = z->fallback_enabled; lock_rw_unlock(&z->lock); return 0; @@ -3602,7 +3709,10 @@ int auth_zones_downstream_answer(struct lock_rw_unlock(&z->lock); return 0; } - if(z->zone_expired) { + if(z->zone_expired || (z->zonemd_check && z->zonemd_callback_env)) { + /* see auth_zones_lookup: a pending ZONEMD verification is + * treated like expiry - the zone content is not yet known + * to pass the configured check. */ if(z->fallback_enabled) { lock_rw_unlock(&z->lock); return 0; @@ -3990,6 +4100,22 @@ auth_master_copy(struct auth_master* o) return m; } +/** append the master to the copied list. */ +static int +auth_master_copy_and_append(struct auth_master* p, struct auth_master** list, + struct auth_master** last) +{ + struct auth_master* m = auth_master_copy(p); + if(!m) { + return 0; + } + m->next = NULL; + if(*last) (*last)->next = m; + if(!*list) *list = m; + *last = m; + return 1; +} + /** copy the master addresses from the task_probe lookups to the allow_notify * list of masters */ static void @@ -3998,17 +4124,27 @@ probe_copy_masters_for_allow_notify(stru struct auth_master* list = NULL, *last = NULL; struct auth_master* p; /* build up new list with copies */ + /* The list in task probe has been looked up before the list in + * task transfer. */ + for(p = xfr->task_probe->masters; p; p=p->next) { + if(!auth_master_copy_and_append(p, &list, &last)) { + auth_free_masters(list); + /* failed because of malloc failure, use old list */ + return; + } + } + /* The list in task transfer also contains the http entries. */ for(p = xfr->task_transfer->masters; p; p=p->next) { - struct auth_master* m = auth_master_copy(p); - if(!m) { + /* Copy the http entries from this lookup. The allow_notify + * entries are not looked up from this list. The other + * ones are already in from the probe lookups. */ + if(!p->http) + continue; + if(!auth_master_copy_and_append(p, &list, &last)) { auth_free_masters(list); /* failed because of malloc failure, use old list */ return; } - m->next = NULL; - if(last) last->next = m; - if(!list) list = m; - last = m; } /* success, replace list */ auth_free_masters(xfr->allow_notify_list); @@ -4247,7 +4383,7 @@ xfr_create_ixfr_packet(struct auth_xfer* { struct query_info qinfo; uint32_t serial; - int have_zone; + int have_zone, get_full = 0; have_zone = xfr->have_zone; serial = xfr->serial; @@ -4260,7 +4396,18 @@ xfr_create_ixfr_packet(struct auth_xfer* xfr->task_transfer->on_ixfr_is_axfr = 0; xfr->task_transfer->on_ixfr = 1; qinfo.qtype = LDNS_RR_TYPE_IXFR; - if(!have_zone || xfr->task_transfer->ixfr_fail || !master->ixfr) { + if(xfr->num_ixfrs >= NUM_IXFR_BEFORE_AXFR && xfr->is_rpz) { + /* For the RPZ, an IXFR is going to grow regions, and a + * full transfer, zonefile read, AXFR and HTTP clear the + * region, but IXFR does not. That memory keeps growing, + * and getting a full transfer with AXFR here resets that. + * The rpz->client_set->region, rpz->ns_set->region and + * rpz->respip_set->region need to be reset, they are for + * rpz-client-ip, rpz-nsip and rpz-ip. */ + get_full = 1; + } + if(!have_zone || xfr->task_transfer->ixfr_fail || !master->ixfr + || get_full) { qinfo.qtype = LDNS_RR_TYPE_AXFR; xfr->task_transfer->ixfr_fail = 0; xfr->task_transfer->on_ixfr = 0; @@ -4411,29 +4558,31 @@ chunkline_get_line(struct auth_chunk** c } /** count number of open and closed parenthesis in a chunkline */ -static int +int chunkline_count_parens(sldns_buffer* buf, size_t start) { size_t end = sldns_buffer_position(buf); size_t i; int count = 0; - int squote = 0, dquote = 0; + int dquote = 0; + char prev_c = 0; for(i=start; inum_ixfrs++; + /* start RR iterator over chunklist of packets */ chunk_rrlist_start(xfr, &rr_chunk, &rr_num, &rr_pos); while(!chunk_rrlist_end(rr_chunk, rr_num)) { @@ -5015,16 +5169,11 @@ apply_axfr(struct auth_xfer* xfr, struct size_t rr_counter = 0; int have_end_soa = 0; - /* clear the data tree */ - traverse_postorder(&z->data, auth_data_del, NULL); - rbtree_init(&z->data, &auth_data_cmp); - /* clear the RPZ policies */ - if(z->rpz) - rpz_clear(z->rpz); - + auth_zone_clear_data(z); xfr->have_zone = 0; xfr->serial = 0; xfr->soa_zone_acquired = 0; + xfr->num_ixfrs = 0; /* insert all RRs in to the zone */ /* insert the SOA only once, skip the last one */ @@ -5117,16 +5266,11 @@ apply_http(struct auth_xfer* xfr, struct return 0; } - /* clear the data tree */ - traverse_postorder(&z->data, auth_data_del, NULL); - rbtree_init(&z->data, &auth_data_cmp); - /* clear the RPZ policies */ - if(z->rpz) - rpz_clear(z->rpz); - + auth_zone_clear_data(z); xfr->have_zone = 0; xfr->serial = 0; xfr->soa_zone_acquired = 0; + xfr->num_ixfrs = 0; chunk = xfr->task_transfer->chunks_first; chunk_pos = 0; @@ -5172,7 +5316,7 @@ apply_http(struct auth_xfer* xfr, struct /** write http chunks to zonefile to create downloaded file */ static int -auth_zone_write_chunks(struct auth_xfer* xfr, const char* fname) +auth_zone_write_chunks(struct auth_chunk* chunk_list, const char* fname) { FILE* out; struct auth_chunk* p; @@ -5181,7 +5325,7 @@ auth_zone_write_chunks(struct auth_xfer* log_err("could not open %s: %s", fname, strerror(errno)); return 0; } - for(p = xfr->task_transfer->chunks_first; p ; p = p->next) { + for(p = chunk_list; p ; p = p->next) { if(!write_out(out, (char*)p->data, p->len)) { log_err("could not write http download to %s", fname); fclose(out); @@ -5192,34 +5336,18 @@ auth_zone_write_chunks(struct auth_xfer* return 1; } -/** write to zonefile after zone has been updated */ +/** write to zonefile after zone has been updated, z has rdlock by caller. */ static void -xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env) +zone_write_after_update(struct auth_zone* z, struct module_env* env, + struct auth_chunk* chunk_list) { struct config_file* cfg = env->cfg; - struct auth_zone* z; char tmpfile[1024]; char* zfilename; - lock_basic_unlock(&xfr->lock); - - /* get lock again, so it is a readlock and concurrently queries - * can be answered */ - lock_rw_rdlock(&env->auth_zones->lock); - z = auth_zone_find(env->auth_zones, xfr->name, xfr->namelen, - xfr->dclass); - if(!z) { - lock_rw_unlock(&env->auth_zones->lock); - /* the zone is gone, ignore xfr results */ - lock_basic_lock(&xfr->lock); - return; - } - lock_rw_rdlock(&z->lock); - lock_basic_lock(&xfr->lock); - lock_rw_unlock(&env->auth_zones->lock); if(z->zonefile == NULL || z->zonefile[0] == 0) { - lock_rw_unlock(&z->lock); /* no write needed, no zonefile set */ + auth_chunk_list_delete(chunk_list); return; } zfilename = z->zonefile; @@ -5236,21 +5364,21 @@ xfr_write_after_update(struct auth_xfer* if((size_t)strlen(zfilename) + 16 > sizeof(tmpfile)) { verbose(VERB_ALGO, "tmpfilename too long, cannot update " " zonefile %s", zfilename); - lock_rw_unlock(&z->lock); + auth_chunk_list_delete(chunk_list); return; } snprintf(tmpfile, sizeof(tmpfile), "%s.tmp%u", zfilename, (unsigned)getpid()); - if(xfr->task_transfer->master->http) { + if(chunk_list) { /* use the stored chunk list to write them */ - if(!auth_zone_write_chunks(xfr, tmpfile)) { + if(!auth_zone_write_chunks(chunk_list, tmpfile)) { unlink(tmpfile); - lock_rw_unlock(&z->lock); + auth_chunk_list_delete(chunk_list); return; } + auth_chunk_list_delete(chunk_list); } else if(!auth_zone_write_file(z, tmpfile)) { unlink(tmpfile); - lock_rw_unlock(&z->lock); return; } #ifdef UB_ON_WINDOWS @@ -5260,9 +5388,57 @@ xfr_write_after_update(struct auth_xfer* log_err("could not rename(%s, %s): %s", tmpfile, zfilename, strerror(errno)); unlink(tmpfile); - lock_rw_unlock(&z->lock); return; } +} + +/** write to zonefile after zone has updated, reacquires z readlock. */ +static void +zone_write_after_update_reacq(uint8_t* bakname, size_t baknamelen, + uint16_t bakdclass, struct module_env* env, + struct auth_chunk* chunk_list) +{ + struct auth_zone* z; + /* get lock again, so it is a readlock and concurrently queries + * can be answered */ + lock_rw_rdlock(&env->auth_zones->lock); + z = auth_zone_find(env->auth_zones, bakname, baknamelen, bakdclass); + if(!z) { + lock_rw_unlock(&env->auth_zones->lock); + /* the zone is gone, ignore xfr results */ + return; + } + lock_rw_rdlock(&z->lock); + lock_rw_unlock(&env->auth_zones->lock); + + zone_write_after_update(z, env, chunk_list); + lock_rw_unlock(&z->lock); +} + +/** write to zonefile after zone has been updated */ +static void +xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env, + struct auth_chunk* chunk_list) +{ + struct auth_zone* z; + lock_basic_unlock(&xfr->lock); + + /* get lock again, so it is a readlock and concurrently queries + * can be answered */ + lock_rw_rdlock(&env->auth_zones->lock); + z = auth_zone_find(env->auth_zones, xfr->name, xfr->namelen, + xfr->dclass); + if(!z) { + lock_rw_unlock(&env->auth_zones->lock); + /* the zone is gone, ignore xfr results */ + lock_basic_lock(&xfr->lock); + return; + } + lock_rw_rdlock(&z->lock); + lock_basic_lock(&xfr->lock); + lock_rw_unlock(&env->auth_zones->lock); + + zone_write_after_update(z, env, chunk_list); lock_rw_unlock(&z->lock); } @@ -5295,6 +5471,8 @@ xfr_process_chunk_list(struct auth_xfer* int* ixfr_fail) { struct auth_zone* z; + int zonemd_in_progress; + struct auth_chunk* current_chunk_list = NULL; /* obtain locks and structures */ lock_basic_unlock(&xfr->lock); @@ -5307,6 +5485,7 @@ xfr_process_chunk_list(struct auth_xfer* /* apply data */ if(xfr->task_transfer->master->http) { if(!apply_http(xfr, z, env->scratch_buffer)) { + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); verbose(VERB_ALGO, "http from %s: could not store data", xfr->task_transfer->master->host); @@ -5315,6 +5494,7 @@ xfr_process_chunk_list(struct auth_xfer* } else if(xfr->task_transfer->on_ixfr && !xfr->task_transfer->on_ixfr_is_axfr) { if(!apply_ixfr(xfr, z, env->scratch_buffer)) { + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); verbose(VERB_ALGO, "xfr from %s: could not store IXFR" " data", xfr->task_transfer->master->host); @@ -5323,6 +5503,7 @@ xfr_process_chunk_list(struct auth_xfer* } } else { if(!apply_axfr(xfr, z, env->scratch_buffer)) { + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); verbose(VERB_ALGO, "xfr from %s: could not store AXFR" " data", xfr->task_transfer->master->host); @@ -5339,6 +5520,7 @@ xfr_process_chunk_list(struct auth_xfer* } z->soa_zone_acquired = *env->now; xfr->soa_zone_acquired = *env->now; + xfr->is_rpz = (z->rpz!=NULL); /* release xfr lock while verifying zonemd because it may have * to spawn lookups in the state machines */ @@ -5374,6 +5556,25 @@ xfr_process_chunk_list(struct auth_xfer* if(z->rpz) rpz_finish_config(z->rpz); + if(z->zonemd_check && z->zonemd_callback_env) { + zonemd_in_progress = 1; + z->zonemd_callback_perform_write = 1; + auth_chunk_list_delete(z->perform_write_chunk_list); + z->perform_write_chunk_list = NULL; + if(xfr->task_transfer->master->http) { + z->perform_write_chunk_list = xfr->task_transfer->chunks_first; + xfr->task_transfer->chunks_first = NULL; + auth_chunks_delete(xfr->task_transfer); + } + } else { + zonemd_in_progress = 0; + z->zonemd_callback_perform_write = 0; + if(xfr->task_transfer->master->http) { + current_chunk_list = xfr->task_transfer->chunks_first; + xfr->task_transfer->chunks_first = NULL; + auth_chunks_delete(xfr->task_transfer); + } + } /* unlock */ lock_rw_unlock(&z->lock); @@ -5384,20 +5585,56 @@ xfr_process_chunk_list(struct auth_xfer* (unsigned)xfr->serial); } /* see if we need to write to a zonefile */ - xfr_write_after_update(xfr, env); + if(!zonemd_in_progress) { + xfr_write_after_update(xfr, env, current_chunk_list); + } return 1; } +/** Stop lookup using callback */ +static void +xfr_stop_lookup(struct auth_master** lookup_target, void* lookup_unique_info, + int lookup_aaaa, uint16_t dclass, struct mesh_area* mesh, + mesh_cb_func_type cb, void* cb_arg) +{ + struct query_info qinfo; + uint8_t dname[LDNS_MAX_DOMAINLEN+1]; + if(!*lookup_target) return; + qinfo.qname_len = sizeof(dname); + if(sldns_str2wire_dname_buf((*lookup_target)->host, dname, + &qinfo.qname_len) != 0) { + *lookup_target = NULL; + return; + } + qinfo.qname = dname; + qinfo.qclass = dclass; + qinfo.qtype = lookup_aaaa ? LDNS_RR_TYPE_AAAA : LDNS_RR_TYPE_A; + qinfo.local_alias = NULL; + log_query_info(VERB_ALGO, "removing xfr callback", &qinfo); + + mesh_remove_callback(mesh, &qinfo, BIT_RD, cb, cb_arg, + lookup_unique_info); + *lookup_target = NULL; +} + /** disown task_transfer. caller must hold xfr.lock */ static void xfr_transfer_disown(struct auth_xfer* xfr) { + /* remove data chunks */ + auth_chunks_delete(xfr->task_transfer); /* remove timer (from this worker's event base) */ comm_timer_delete(xfr->task_transfer->timer); xfr->task_transfer->timer = NULL; /* remove the commpoint */ comm_point_delete(xfr->task_transfer->cp); xfr->task_transfer->cp = NULL; + if(xfr->task_transfer->env) + xfr_stop_lookup(&xfr->task_transfer->lookup_target, + xfr->task_transfer->lookup_unique_info, + xfr->task_transfer->lookup_aaaa, xfr->dclass, + xfr->task_transfer->env->mesh, + &auth_xfer_transfer_lookup_callback, xfr); /* we don't own this item anymore */ xfr->task_transfer->worker = NULL; xfr->task_transfer->env = NULL; @@ -5464,7 +5701,8 @@ xfr_transfer_lookup_host(struct auth_xfe * called straight away */ lock_basic_unlock(&xfr->lock); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, - &auth_xfer_transfer_lookup_callback, xfr, 0)) { + &auth_xfer_transfer_lookup_callback, xfr, 0, + &xfr->task_transfer->lookup_unique_info)) { lock_basic_lock(&xfr->lock); log_err("out of memory lookup up master %s", master->host); return 0; @@ -5522,6 +5760,7 @@ xfr_transfer_init_fetch(struct auth_xfer t.tv_sec = timeout/1000; t.tv_usec = (timeout%1000)*1000; #endif + xfr->task_transfer->start_time = *env->now_tv; if(master->http) { /* perform http fetch */ @@ -5691,10 +5930,34 @@ xfr_master_add_addrs(struct auth_master* } } +/** check if the lookup target name equals the found answer name. */ +static int +xfer_target_equals_answer_name(struct auth_master* lookup_target, + struct ub_packed_rrset_key* answer, struct query_info* rq, + struct reply_info* rep) +{ + uint8_t qname[LDNS_MAX_DOMAINLEN+1]; + size_t qname_len; + if(!lookup_target) return 0; + if(!answer) return 0; + qname_len = sizeof(qname); + if(sldns_str2wire_dname_buf(lookup_target->host, qname, &qname_len) + != 0) { + verbose(VERB_ALGO, "xfer_target_equals_answer_name: could not parse auth host name"); + return 0; + } + if(query_dname_compare(answer->rk.dname, qname) == 0) + return 1; + /* It could be a CNAME. */ + if(reply_find_rrset_section_an(rep, qname, qname_len, + LDNS_RR_TYPE_CNAME, rq->qclass)) + return 1; + return 0; +} + /** callback for task_transfer lookup of host name, of A or AAAA */ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), - int ATTR_UNUSED(was_ratelimited)) + enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited)) { struct auth_xfer* xfr = (struct auth_xfer*)arg; struct module_env* env; @@ -5707,7 +5970,16 @@ void auth_xfer_transfer_lookup_callback( } /* process result */ - if(rcode == LDNS_RCODE_NOERROR) { + if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) { + if(verbosity >= VERB_OPS) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_OPS, "auth zone %s: primary %s address lookup is DNSSEC bogus: %s", + zname, xfr->task_transfer->lookup_target->host, + (why_bogus?why_bogus:"")); + } + /* fall through to next-lookup / next-master */ + } else if(rcode == LDNS_RCODE_NOERROR) { uint16_t wanted_qtype = LDNS_RR_TYPE_A; struct regional* temp = env->scratch; struct query_info rq; @@ -5721,21 +5993,29 @@ void auth_xfer_transfer_lookup_callback( /* parsed successfully */ struct ub_packed_rrset_key* answer = reply_find_answer_rrset(&rq, rep); - if(answer) { + if(answer && xfer_target_equals_answer_name( + xfr->task_transfer->lookup_target, answer, + &rq, rep)) { xfr_master_add_addrs(xfr->task_transfer-> lookup_target, answer, wanted_qtype); + } else if(answer) { + if(verbosity >= VERB_ALGO) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has mismatch in answer name", zname, ((xfr->task_transfer->lookup_target && xfr->task_transfer->lookup_target->host) ? xfr->task_transfer->lookup_target->host : "null"), (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); + } } else { if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has nodata", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has nodata", zname, ((xfr->task_transfer->lookup_target && xfr->task_transfer->lookup_target->host) ? xfr->task_transfer->lookup_target->host : "null"), (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); } } } else { if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has no answer", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has no answer", zname, ((xfr->task_transfer->lookup_target && xfr->task_transfer->lookup_target->host) ? xfr->task_transfer->lookup_target->host : "null"), (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); } } regional_free_all(temp); @@ -5743,10 +6023,11 @@ void auth_xfer_transfer_lookup_callback( if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup failed", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup failed", zname, ((xfr->task_transfer->lookup_target && xfr->task_transfer->lookup_target->host) ? xfr->task_transfer->lookup_target->host : "null"), (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); } } - if(xfr->task_transfer->lookup_target->list && + if(xfr->task_transfer->lookup_target && + xfr->task_transfer->lookup_target->list && xfr->task_transfer->lookup_target == xfr_transfer_current_master(xfr)) xfr->task_transfer->scan_addr = xfr->task_transfer->lookup_target->list; @@ -6076,6 +6357,7 @@ xfer_link_data(sldns_buffer* pkt, struct if(xfr->task_transfer->chunks_last) xfr->task_transfer->chunks_last->next = e; xfr->task_transfer->chunks_last = e; + xfr->task_transfer->chunks_total += e->len; return 1; } @@ -6171,6 +6453,15 @@ auth_xfer_transfer_timer_callback(void* xfr_transfer_nexttarget_or_end(xfr, env); } +/** return the time taken by the transfer */ +static int +auth_xfer_transfer_time_taken(struct auth_xfer* xfr, struct module_env* env) +{ + struct timeval delta; + timeval_subtract(&delta, env->now_tv, &xfr->task_transfer->start_time); + return ((int)delta.tv_sec)*1000 + ((int)delta.tv_usec)/1000; +} + /** callback for task_transfer tcp connections */ int auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err, @@ -6237,6 +6528,15 @@ auth_xfer_transfer_tcp_callback(struct c xfr->task_transfer->master->host); goto failed; } + if(xfr->max_transfer_size > 0 && + xfr->task_transfer->chunks_total > xfr->max_transfer_size) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + log_err("auth zone %s transfer from %s exceeded %u bytes, aborting", + zname, xfr->task_transfer->master->host, + (unsigned)xfr->max_transfer_size); + goto failed; + } /* if the transfer is done now, disconnect and process the list */ if(transferdone) { comm_point_delete(xfr->task_transfer->cp); @@ -6245,6 +6545,16 @@ auth_xfer_transfer_tcp_callback(struct c return 0; } + if(xfr->max_transfer_time > 0 && + auth_xfer_transfer_time_taken(xfr, env) > xfr->max_transfer_time) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + log_err("auth zone %s transfer from %s exceeded %u msec total running time, aborting", + zname, xfr->task_transfer->master->host, + (unsigned)xfr->max_transfer_time); + goto failed; + } + /* if we want to read more messages, setup the commpoint to read * a DNS packet, and the timeout */ lock_basic_unlock(&xfr->lock); @@ -6300,6 +6610,16 @@ auth_xfer_transfer_http_callback(struct xfr->task_transfer->master->host); goto failed; } + if(xfr->max_transfer_size > 0 && + xfr->task_transfer->chunks_total > xfr->max_transfer_size) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + log_err("auth zone %s http %s/%s exceeded %u bytes, aborting", + zname, xfr->task_transfer->master->host, + xfr->task_transfer->master->file, + (unsigned)xfr->max_transfer_size); + goto failed; + } } /* if the transfer is done now, disconnect and process the list */ if(err == NETEVENT_DONE) { @@ -6311,6 +6631,17 @@ auth_xfer_transfer_http_callback(struct return 0; } + if(xfr->max_transfer_time > 0 && + auth_xfer_transfer_time_taken(xfr, env) > xfr->max_transfer_time) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + log_err("auth zone %s transfer http %s/%s exceeded %u msec total running time, aborting", + zname, xfr->task_transfer->master->host, + xfr->task_transfer->master->file, + (unsigned)xfr->max_transfer_time); + goto failed; + } + /* if we want to read more messages, setup the commpoint to read * a DNS packet, and the timeout */ lock_basic_unlock(&xfr->lock); @@ -6353,6 +6684,12 @@ xfr_probe_disown(struct auth_xfer* xfr) /* remove the commpoint */ comm_point_delete(xfr->task_probe->cp); xfr->task_probe->cp = NULL; + if(xfr->task_probe->env) + xfr_stop_lookup(&xfr->task_probe->lookup_target, + xfr->task_probe->lookup_unique_info, + xfr->task_probe->lookup_aaaa, xfr->dclass, + xfr->task_probe->env->mesh, + &auth_xfer_probe_lookup_callback, xfr); /* we don't own this item anymore */ xfr->task_probe->worker = NULL; xfr->task_probe->env = NULL; @@ -6659,7 +6996,8 @@ xfr_probe_lookup_host(struct auth_xfer* * called straight away */ lock_basic_unlock(&xfr->lock); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, - &auth_xfer_probe_lookup_callback, xfr, 0)) { + &auth_xfer_probe_lookup_callback, xfr, 0, + &xfr->task_probe->lookup_unique_info)) { lock_basic_lock(&xfr->lock); log_err("out of memory lookup up master %s", master->host); return 0; @@ -6668,6 +7006,18 @@ xfr_probe_lookup_host(struct auth_xfer* return 1; } +/** return true if there are probe (SOA UDP query) targets in the master list*/ +static int +have_probe_targets(struct auth_master* list) +{ + struct auth_master* p; + for(p=list; p; p = p->next) { + if(!p->allow_notify && p->host) + return 1; + } + return 0; +} + /** move to sending the probe packets, next if fails. task_probe */ static void xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) @@ -6707,6 +7057,16 @@ xfr_probe_send_or_end(struct auth_xfer* verbose(VERB_ALGO, "auth zone %s probe: finished only_lookup", zname); } xfr_probe_disown(xfr); + if(!have_probe_targets(xfr->task_probe->masters)) { + /* If there are no masters to probe, go to transfer. */ + if(xfr->task_transfer->worker == NULL) { + xfr_start_transfer(xfr, env, NULL); + return; + } + /* The transfer is already in progress. */ + lock_basic_unlock(&xfr->lock); + return; + } if(xfr->task_nextprobe->worker == NULL) xfr_set_timeout(xfr, env, 0, 0); lock_basic_unlock(&xfr->lock); @@ -6756,8 +7116,7 @@ xfr_probe_send_or_end(struct auth_xfer* /** callback for task_probe lookup of host name, of A or AAAA */ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), - int ATTR_UNUSED(was_ratelimited)) + enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited)) { struct auth_xfer* xfr = (struct auth_xfer*)arg; struct module_env* env; @@ -6770,7 +7129,16 @@ void auth_xfer_probe_lookup_callback(voi } /* process result */ - if(rcode == LDNS_RCODE_NOERROR) { + if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) { + if(verbosity >= VERB_OPS) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_OPS, "auth zone %s: primary %s address probe lookup is DNSSEC bogus: %s", + zname, xfr->task_probe->lookup_target->host, + (why_bogus?why_bogus:"")); + } + /* fall through to next-lookup / next-master */ + } else if(rcode == LDNS_RCODE_NOERROR) { uint16_t wanted_qtype = LDNS_RR_TYPE_A; struct regional* temp = env->scratch; struct query_info rq; @@ -6784,21 +7152,29 @@ void auth_xfer_probe_lookup_callback(voi /* parsed successfully */ struct ub_packed_rrset_key* answer = reply_find_answer_rrset(&rq, rep); - if(answer) { + if(answer && xfer_target_equals_answer_name( + xfr->task_probe->lookup_target, answer, + &rq, rep)) { xfr_master_add_addrs(xfr->task_probe-> lookup_target, answer, wanted_qtype); + } else if(answer) { + if(verbosity >= VERB_ALGO) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has mismatch in answer name", zname, ((xfr->task_probe->lookup_target && xfr->task_probe->lookup_target->host) ? xfr->task_probe->lookup_target->host : "null"), (xfr->task_probe->lookup_aaaa?"AAAA":"A")); + } } else { if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has nodata", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has nodata", zname, ((xfr->task_probe->lookup_target && xfr->task_probe->lookup_target->host) ? xfr->task_probe->lookup_target->host : "null"), (xfr->task_probe->lookup_aaaa?"AAAA":"A")); } } } else { if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has no address", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has no address", zname, ((xfr->task_probe->lookup_target && xfr->task_probe->lookup_target->host) ? xfr->task_probe->lookup_target->host : "null"), (xfr->task_probe->lookup_aaaa?"AAAA":"A")); } } regional_free_all(temp); @@ -6806,10 +7182,11 @@ void auth_xfer_probe_lookup_callback(voi if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup failed", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup failed", zname, ((xfr->task_probe->lookup_target && xfr->task_probe->lookup_target->host) ? xfr->task_probe->lookup_target->host : "null"), (xfr->task_probe->lookup_aaaa?"AAAA":"A")); } } - if(xfr->task_probe->lookup_target->list && + if(xfr->task_probe->lookup_target && + xfr->task_probe->lookup_target->list && xfr->task_probe->lookup_target == xfr_probe_current_master(xfr)) xfr->task_probe->scan_addr = xfr->task_probe->lookup_target->list; @@ -6863,18 +7240,6 @@ auth_xfer_timer(void* arg) } } -/** return true if there are probe (SOA UDP query) targets in the master list*/ -static int -have_probe_targets(struct auth_master* list) -{ - struct auth_master* p; - for(p=list; p; p = p->next) { - if(!p->allow_notify && p->host) - return 1; - } - return 0; -} - /** start task_probe if possible, if no masters for probe start task_transfer * returns true if task has been started, and false if the task is already * in progress. */ @@ -6886,8 +7251,10 @@ xfr_start_probe(struct auth_xfer* xfr, s * progress (due to notify)) */ if(xfr->task_probe->worker == NULL) { if(!have_probe_targets(xfr->task_probe->masters) && - !(xfr->task_probe->only_lookup && - xfr->task_probe->masters != NULL)) { + xfr->task_probe->masters != NULL) + xfr->task_probe->only_lookup = 1; + if(!xfr->task_probe->only_lookup && + !have_probe_targets(xfr->task_probe->masters)) { /* useless to pick up task_probe, no masters to * probe. Instead attempt to pick up task transfer */ if(xfr->task_transfer->worker == NULL) { @@ -7090,6 +7457,8 @@ auth_xfer_new(struct auth_zone* z) xfr->namelen = z->namelen; xfr->namelabs = z->namelabs; xfr->dclass = z->dclass; + xfr->max_transfer_size = z->max_transfer_size; + xfr->max_transfer_time = z->max_transfer_time; xfr->task_nextprobe = (struct auth_nextprobe*)calloc(1, sizeof(struct auth_nextprobe)); @@ -7299,35 +7668,48 @@ xfer_set_masters(struct auth_master** li { struct auth_master* m; struct config_strlist* p; + struct auth_master** tail; /* list points to the first, or next pointer for the new element */ while(*list) { list = &( (*list)->next ); } if(with_http) for(p = c->urls; p; p = p->next) { + tail = list; m = auth_master_new(&list); if(!m) return 0; m->http = 1; - if(!parse_url(p->str, &m->host, &m->file, &m->port, &m->ssl)) + if(!parse_url(p->str, &m->host, &m->file, &m->port, &m->ssl)) { + free(m->host); + free(m->file); + free(m); + *tail = NULL; return 0; + } } for(p = c->masters; p; p = p->next) { + tail = list; m = auth_master_new(&list); if(!m) return 0; m->ixfr = 1; /* this flag is not configurable */ m->host = strdup(p->str); if(!m->host) { log_err("malloc failure"); + free(m); + *tail = NULL; return 0; } } for(p = c->allow_notify; p; p = p->next) { + tail = list; m = auth_master_new(&list); if(!m) return 0; m->allow_notify = 1; m->host = strdup(p->str); if(!m->host) { log_err("malloc failure"); + free(m); + *tail = NULL; return 0; } } @@ -7852,7 +8234,8 @@ static int zonemd_dnssec_verify_rrset(st "zonemd: verify %s RRset with DNSKEY", typestr); } sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL, - LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, reasonlen); + LDNS_SECTION_ANSWER, NULL, NULL, &verified, reasonbuf, + reasonlen); if(sec == sec_status_secure) { return 1; } @@ -8201,8 +8584,8 @@ zonemd_get_dnskey_from_anchor(struct aut auth_zone_log(z->name, VERB_QUERY, "zonemd: verify DNSKEY RRset with trust anchor"); sec = val_verify_DNSKEY_with_TA(env, ve, keystorage, anchor->ds_rrset, - anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, reasonbuf, - reasonlen); + anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, NULL, + reasonbuf, reasonlen); regional_free_all(env->scratch); if(sec == sec_status_secure) { /* success */ @@ -8262,7 +8645,7 @@ auth_zone_verify_zonemd_key_with_ds(stru keystorage->rk.rrset_class = htons(z->dclass); auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS"); sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg, - why_bogus, NULL, NULL, reasonbuf, reasonlen); + why_bogus, NULL, NULL, NULL, reasonbuf, reasonlen); regional_free_all(env->scratch); if(sec == sec_status_secure) { /* success */ @@ -8291,9 +8674,13 @@ void auth_zonemd_dnskey_lookup_callback( char reasonbuf[256]; char* reason = NULL, *ds_bogus = NULL, *typestr="DNSKEY"; struct ub_packed_rrset_key* dnskey = NULL, *ds = NULL; - int is_insecure = 0, downprot; + int is_insecure = 0, downprot, perform_write = 0; struct ub_packed_rrset_key keystorage; uint8_t sigalg[ALGO_NEEDS_MAX+1]; + uint8_t bakname[LDNS_MAX_DOMAINLEN]; + size_t baknamelen; + uint16_t bakdclass; + struct auth_chunk* chunk_list = NULL; lock_rw_wrlock(&z->lock); env = z->zonemd_callback_env; @@ -8416,7 +8803,37 @@ void auth_zonemd_dnskey_lookup_callback( auth_zone_verify_zonemd_with_key(z, env, &env->mesh->mods, dnskey, is_insecure, NULL, downprot?sigalg:NULL); regional_free_all(env->scratch); + + if(z->zonemd_callback_perform_write) { + if(!z->zone_expired) { + /* Write to zonefile if the ZONEMD is okay. */ + perform_write = 1; + /* copy the key to lookup the z structure. + * The new lookup is readonly so concurrent + * queries can continue. */ + if(z->namelen > sizeof(bakname)) { + perform_write = 0; + auth_chunk_list_delete(z->perform_write_chunk_list); + z->perform_write_chunk_list = NULL; + } else { + memcpy(bakname, z->name, z->namelen); + baknamelen = z->namelen; + bakdclass = z->dclass; + chunk_list = z->perform_write_chunk_list; + z->perform_write_chunk_list = NULL; + } + } else { + auth_chunk_list_delete(z->perform_write_chunk_list); + z->perform_write_chunk_list = NULL; + } + z->zonemd_callback_perform_write = 0; + } lock_rw_unlock(&z->lock); + + if(perform_write) { + zone_write_after_update_reacq(bakname, baknamelen, bakdclass, + env, chunk_list); + } } /** lookup DNSKEY for ZONEMD verification */ @@ -8481,8 +8898,12 @@ zonemd_lookup_dnskey(struct auth_zone* z /* the callback can be called straight away */ lock_rw_unlock(&z->lock); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, - &auth_zonemd_dnskey_lookup_callback, z, 0)) { + &auth_zonemd_dnskey_lookup_callback, z, 0, + &z->zonemd_callback_unique_info)) { lock_rw_wrlock(&z->lock); + /* no callback will run; do not leave the pending + * marker set */ + z->zonemd_callback_env = NULL; log_err("out of memory lookup of %s for zonemd", (fetch_ds?"DS":"DNSKEY")); return 0; Index: sbin/unwind/libunbound/services/authzone.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/authzone.h,v diff -u -p -r1.10 authzone.h --- sbin/unwind/libunbound/services/authzone.h 29 Sep 2025 14:53:38 -0000 1.10 +++ sbin/unwind/libunbound/services/authzone.h 21 Sep 2026 16:27:58 -0000 @@ -144,6 +144,12 @@ struct auth_zone { struct module_env* zonemd_callback_env; /** for the zonemd callback, the type of data looked up */ uint16_t zonemd_callback_qtype; + /** for the zonemd callback, the unique info */ + void* zonemd_callback_unique_info; + /** if the zonemd callback should write to file */ + int zonemd_callback_perform_write; + /** chunklist to write for chunked transfer. */ + struct auth_chunk* perform_write_chunk_list; /** zone has been deleted */ int zone_deleted; /** deletelist pointer, unused normally except during delete */ @@ -153,6 +159,10 @@ struct auth_zone { struct auth_zone* rpz_az_next; /** previous auth zone containing RPZ data, or NULL */ struct auth_zone* rpz_az_prev; + /** The maximum auth zone transfer size, in bytes. */ + size_t max_transfer_size; + /** The maximum auth zone transfer time taken, in msec. */ + int max_transfer_time; }; /** @@ -283,6 +293,15 @@ struct auth_xfer { * this is renewed every SOA probe and transfer. On zone load * from zonefile it is also set (with probe set soon to check) */ time_t lease_time; + + /** The maximum auth zone transfer size, in bytes. */ + size_t max_transfer_size; + /** The maximum auth zone transfer time taken, in msec. */ + int max_transfer_time; + /** the zone is an rpz zone */ + int is_rpz; + /** the number of IXFRs since the last full transfer. */ + int num_ixfrs; }; /** @@ -331,6 +350,8 @@ struct auth_probe { /** for the hostname lookups, which master is current */ struct auth_master* lookup_target; + /** for the lookup, the callback unique info */ + void* lookup_unique_info; /** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */ int lookup_aaaa; /** we only want to do lookups for making config work (for notify), @@ -379,12 +400,18 @@ struct auth_transfer { struct auth_chunk* chunks_first; /** last element in chunks list (to append new data at the end) */ struct auth_chunk* chunks_last; + /** running total of bytes held in chunks_first..chunks_last */ + size_t chunks_total; + /** start time of the transfer */ + struct timeval start_time; /** list of upstream masters for this zone, from config */ struct auth_master* masters; /** for the hostname lookups, which master is current */ struct auth_master* lookup_target; + /** for the lookup, the callback unique info */ + void* lookup_unique_info; /** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */ int lookup_aaaa; @@ -827,5 +854,11 @@ void auth_xfer_delete(struct auth_xfer* * @param worker: the worker for which to stop tasks. */ void xfr_disown_tasks(struct auth_xfer* xfr, struct worker* worker); + +/** count number of open and closed parenthesis in a chunkline */ +int chunkline_count_parens(struct sldns_buffer* buf, size_t start); + +/** Clear data in auth zone */ +void auth_zone_clear_data(struct auth_zone* z); #endif /* SERVICES_AUTHZONE_H */ Index: sbin/unwind/libunbound/services/listen_dnsport.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/listen_dnsport.c,v diff -u -p -r1.21 listen_dnsport.c --- sbin/unwind/libunbound/services/listen_dnsport.c 29 Sep 2025 14:53:38 -0000 1.21 +++ sbin/unwind/libunbound/services/listen_dnsport.c 21 Sep 2026 16:27:58 -0000 @@ -42,7 +42,6 @@ #ifdef HAVE_SYS_TYPES_H # include #endif -#include #include #ifdef USE_TCP_FASTOPEN #include @@ -1126,7 +1125,7 @@ make_sock_port(int stype, const char* if int use_systemd, int dscp, struct unbound_socket* ub_sock, const char* additional) { - char* s = strchr(ifname, '@'); + const char* s = strchr(ifname, '@'); if(s) { /* override port with ifspec@port */ int port; @@ -1564,7 +1563,7 @@ listen_create(struct comm_base* base, st cp = comm_point_create_udp(base, ports->fd, front->udp_buff, ports->pp2_enabled, cb, cb_arg, ports->socket); - } else if(ports->ftype == listen_type_doq) { + } else if(ports->ftype == listen_type_doq && doq_table) { #ifndef HAVE_NGTCP2 log_warn("Unbound is not compiled with " "ngtcp2. This is required to use DNS " @@ -2134,7 +2133,7 @@ void listen_start_accept(struct listen_d } struct tcp_req_info* -tcp_req_info_create(struct sldns_buffer* spoolbuf) +tcp_req_info_create(struct comm_base* base, struct sldns_buffer* spoolbuf) { struct tcp_req_info* req = (struct tcp_req_info*)malloc(sizeof(*req)); if(!req) { @@ -2142,6 +2141,12 @@ tcp_req_info_create(struct sldns_buffer* return NULL; } memset(req, 0, sizeof(*req)); + req->read_again_timer = comm_timer_create(base, tcp_read_again_cb, req); + if(!req->read_again_timer) { + log_err("malloc failure"); + free(req); + return NULL; + } req->spool_buffer = spoolbuf; return req; } @@ -2151,6 +2156,7 @@ tcp_req_info_delete(struct tcp_req_info* { if(!req) return; tcp_req_info_clear(req); + comm_timer_delete(req->read_again_timer); /* cp is pointer back to commpoint that owns this struct and * called delete on us */ /* spool_buffer is shared udp buffer, not deleted here */ @@ -2167,7 +2173,8 @@ void tcp_req_info_clear(struct tcp_req_i open = req->open_req_list; while(open) { nopen = open->next; - mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp); + mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp, + NULL, NULL); free(open); open = nopen; } @@ -2189,6 +2196,9 @@ void tcp_req_info_clear(struct tcp_req_i req->done_req_list = NULL; req->num_done_req = 0; req->read_is_closed = 0; + + if(comm_timer_is_set(req->read_again_timer)) + comm_timer_disable(req->read_again_timer); } void @@ -2300,21 +2310,8 @@ int tcp_req_info_handle_read_close(struct tcp_req_info* req) { verbose(VERB_ALGO, "tcp channel read side closed %d", req->cp->fd); - /* reset byte count for (potential) partial read */ - req->cp->tcp_byte_count = 0; - /* if we still have results to write, pick up next and write it */ - if(req->num_done_req != 0) { - tcp_req_pickup_next_result(req); - tcp_req_info_setup_listen(req); - return 1; - } - /* if nothing to do, this closes the connection */ - if(req->num_open_req == 0 && req->num_done_req == 0) - return 0; - /* otherwise, we must be waiting for dns resolve, wait with timeout */ - req->read_is_closed = 1; - tcp_req_info_setup_listen(req); - return 1; + /* RFC 7766 6.2.4 says to drop pending replies when client closes. */ + return 0; /* drop connection */ } void @@ -2884,6 +2881,7 @@ submit_http_error: sldns_buffer_flip(h2_stream->qbuffer); h2_session->postpone_drop = 1; query_read_done = http2_query_read_done(h2_session, h2_stream); + h2_session->postpone_drop = 0; if(query_read_done < 0) return NGHTTP2_ERR_CALLBACK_FAILURE; else if(!query_read_done) { @@ -2893,11 +2891,9 @@ submit_http_error: * failure will result in reclaiming (and closing) * of comm point. */ verbose(VERB_QUERY, "http2 query dropped in worker cb"); - h2_session->postpone_drop = 0; return NGHTTP2_ERR_CALLBACK_FAILURE; } /* nothing to submit right now, query added to mesh. */ - h2_session->postpone_drop = 0; return 0; } if(!http2_submit_dns_response(h2_session)) { @@ -3275,14 +3271,18 @@ nghttp2_session_callbacks* http2_req_cal struct doq_table* doq_table_create(struct config_file* cfg, struct ub_randstate* rnd) { - struct doq_table* table = calloc(1, sizeof(*table)); + struct doq_table* table; + + if (!cfg->quic_port) + return NULL; + table = calloc(1, sizeof(*table)); if(!table) return NULL; #ifdef USE_NGTCP2_CRYPTO_OSSL /* Initialize the ossl crypto, it is harmless to call twice, * and this is before use of doq connections. */ if(ngtcp2_crypto_ossl_init() != 0) { - log_err("ngtcp2_crypto_oss_init failed"); + log_err("ngtcp2_crypto_ossl_init failed"); free(table); return NULL; } @@ -3354,7 +3354,7 @@ conn_tree_del(rbnode_type* node, void* a { struct doq_table* table = (struct doq_table*)arg; struct doq_conn* conn; - if(!node) + if(!node || !table) return; conn = (struct doq_conn*)node->key; if(conn->timer.timer_in_list) { @@ -3409,13 +3409,13 @@ doq_table_delete(struct doq_table* table } struct doq_timer* -doq_timer_find_time(struct doq_table* table, struct timeval* tv) +doq_timer_find_time(struct doq_table* table, ngtcp2_tstamp ts) { struct doq_timer key; struct rbnode_type* node; + log_assert(table != NULL); memset(&key, 0, sizeof(key)); - key.time.tv_sec = tv->tv_sec; - key.time.tv_usec = tv->tv_usec; + key.time_mono = ts; node = rbtree_search(table->timer_tree, &key); if(node) return (struct doq_timer*)node->key; @@ -3463,7 +3463,7 @@ doq_timer_list_remove(struct doq_table* if(!timer->timer_in_list) return; /* The item in the rbtree has the list start and end. */ - rb_timer = doq_timer_find_time(table, &timer->time); + rb_timer = doq_timer_find_time(table, timer->time_mono); if(rb_timer) { if(timer->setlist_prev) timer->setlist_prev->setlist_next = timer->setlist_next; @@ -3509,7 +3509,8 @@ doq_timer_unset(struct doq_table* table, } void doq_timer_set(struct doq_table* table, struct doq_timer* timer, - struct doq_server_socket* worker_doq_socket, struct timeval* tv) + struct doq_server_socket* worker_doq_socket, struct timeval* tv, + ngtcp2_tstamp ts) { struct doq_timer* rb_timer; if(verbosity >= VERB_ALGO && timer->conn) { @@ -3523,14 +3524,14 @@ void doq_timer_set(struct doq_table* tab (int)rel.tv_sec, (int)rel.tv_usec); } if(timer->timer_in_tree || timer->timer_in_list) { - if(timer->time.tv_sec == tv->tv_sec && - timer->time.tv_usec == tv->tv_usec) + if(timer->time_mono == ts) return; /* already set on that time */ doq_timer_unset(table, timer); } - timer->time.tv_sec = tv->tv_sec; - timer->time.tv_usec = tv->tv_usec; - rb_timer = doq_timer_find_time(table, tv); + timer->time_real.tv_sec = tv->tv_sec; + timer->time_real.tv_usec = tv->tv_usec; + timer->time_mono = ts; + rb_timer = doq_timer_find_time(table, ts); if(rb_timer) { /* There is a timeout already with this value. Timer is * added to the setlist. */ @@ -3606,15 +3607,29 @@ doq_conn_create(struct comm_point* c, st return conn; } +/** The arguments for doq stream tree del. */ +struct doq_stream_tree_del_args { + /** The doq table. */ + struct doq_table* table; + /** The doq connection for the stream. */ + struct doq_conn* conn; +}; + /** delete stream tree node */ static void stream_tree_del(rbnode_type* node, void* arg) { - struct doq_table* table = (struct doq_table*)arg; + struct doq_stream_tree_del_args* args = (struct doq_stream_tree_del_args*)arg; + struct doq_table* table = args->table; struct doq_stream* stream; if(!node) return; stream = (struct doq_stream*)node; + if(stream->mesh_state) { + mesh_state_remove_reply(stream->mesh, stream->mesh_state, + args->conn->doq_socket->cp, NULL, stream); + stream->mesh_state = NULL; + } if(stream->in) doq_table_quic_size_subtract(table, stream->inlen); if(stream->out) @@ -3634,9 +3649,14 @@ doq_conn_delete(struct doq_conn* conn, s lock_rw_unlock(&conn->table->conid_lock); /* Remove the app data from ngtcp2 before SSL_free of conn->ssl, * because the ngtcp2 conn is deleted. */ - SSL_set_app_data(conn->ssl, NULL); + if(conn->ssl) + SSL_set_app_data(conn->ssl, NULL); if(conn->stream_tree.count != 0) { - traverse_postorder(&conn->stream_tree, stream_tree_del, table); + struct doq_stream_tree_del_args args; + memset(&args, 0, sizeof(args)); + args.table = table; + args.conn = conn; + traverse_postorder(&conn->stream_tree, stream_tree_del, &args); } free(conn->key.dcid); SSL_free(conn->ssl); @@ -3709,13 +3729,9 @@ int doq_timer_cmp(const void* key1, cons { struct doq_timer* e = (struct doq_timer*)key1; struct doq_timer* f = (struct doq_timer*)key2; - if(e->time.tv_sec < f->time.tv_sec) - return -1; - if(e->time.tv_sec > f->time.tv_sec) - return 1; - if(e->time.tv_usec < f->time.tv_usec) + if(e->time_mono < f->time_mono) return -1; - if(e->time.tv_usec > f->time.tv_usec) + if(e->time_mono > f->time_mono) return 1; return 0; } @@ -3776,7 +3792,7 @@ doq_repinfo_retrieve_localaddr(struct co memset(sa6, 0, *localaddrlen); sa6->sin6_family = AF_INET6; memmove(&sa6->sin6_addr, &repinfo->pktinfo.v6info.ipi6_addr, - *localaddrlen); + sizeof(struct in6_addr)); sa6->sin6_port = repinfo->doq_srcport; #endif } else { @@ -3786,7 +3802,7 @@ doq_repinfo_retrieve_localaddr(struct co memset(sa, 0, *localaddrlen); sa->sin_family = AF_INET; memmove(&sa->sin_addr, &repinfo->pktinfo.v4info.ipi_addr, - *localaddrlen); + sizeof(struct in_addr)); sa->sin_port = repinfo->doq_srcport; #elif defined(IP_RECVDSTADDR) struct sockaddr_in* sa = (struct sockaddr_in*)localaddr; @@ -3949,6 +3965,11 @@ doq_stream_close(struct doq_conn* conn, if(stream->is_closed) return 1; stream->is_closed = 1; + if(stream->mesh_state) { + mesh_state_remove_reply(stream->mesh, stream->mesh_state, + conn->doq_socket->cp, NULL, stream); + stream->mesh_state = NULL; + } doq_stream_off_write_list(conn, stream); if(send_shutdown) { verbose(VERB_ALGO, "doq: shutdown stream_id %d with app_error_code %d", @@ -3978,7 +3999,8 @@ doq_stream_close(struct doq_conn* conn, /** doq stream pick up answer data from buffer */ static int -doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf) +doq_stream_pickup_answer(struct doq_conn* conn, struct doq_stream* stream, + struct sldns_buffer* buf) { stream->is_answer_available = 1; if(stream->out) { @@ -3988,6 +4010,11 @@ doq_stream_pickup_answer(struct doq_stre } stream->nwrite = 0; stream->outlen = sldns_buffer_limit(buf); + if(!doq_table_quic_size_available(conn->doq_socket->table, + conn->doq_socket->cfg, stream->outlen)) { + verbose(VERB_ALGO, "doq stream: no space for reply length"); + return 0; + } /* For quic the output bytes have to stay allocated and available, * for potential resends, until the remote end has acknowledged them. * This includes the tcplen start uint16_t, in outlen_wire. */ @@ -4014,24 +4041,56 @@ doq_stream_send_reply(struct doq_conn* c if(stream->out) doq_table_quic_size_subtract(conn->doq_socket->table, stream->outlen); - if(!doq_stream_pickup_answer(stream, buf)) + if(!doq_stream_pickup_answer(conn, stream, buf)) return 0; doq_table_quic_size_add(conn->doq_socket->table, stream->outlen); doq_stream_on_write_list(conn, stream); doq_conn_write_enable(conn); return 1; } +#endif /* HAVE_NGTCP2 */ + +void +doq_stream_add_meshstate(struct doq_stream* stream, + struct mesh_area* mesh, struct mesh_state* m) +{ +#ifdef HAVE_NGTCP2 + stream->mesh = mesh; + stream->mesh_state = m; +#else + (void)stream; (void)mesh; (void)m; +#endif +} + +void +doq_stream_remove_mesh_state(struct doq_stream* stream) +{ +#ifdef HAVE_NGTCP2 + if(!stream) + return; + stream->mesh_state = NULL; +#else + (void)stream; +#endif +} +#ifdef HAVE_NGTCP2 /** doq stream data length has completed, allocations can be done. False on * allocation failure. */ static int -doq_stream_datalen_complete(struct doq_stream* stream, struct doq_table* table) +doq_stream_datalen_complete(struct doq_conn* conn, struct doq_stream* stream, + struct doq_table* table) { if(stream->inlen > 1024*1024) { log_err("doq stream in length too large %d", (int)stream->inlen); return 0; } + if(!doq_table_quic_size_available(table, conn->doq_socket->cfg, + stream->inlen)) { + verbose(VERB_ALGO, "doq stream: no space for query length"); + return 0; + } stream->in = calloc(1, stream->inlen); if(!stream->in) { log_err("doq could not read stream, calloc failed: " @@ -4076,6 +4135,7 @@ doq_stream_data_complete(struct doq_conn return 0; } c->repinfo.doq_streamid = stream->stream_id; + c->repinfo.doq_stream = stream; conn->doq_socket->current_conn = conn; fptr_ok(fptr_whitelist_comm_point(c->callback)); if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo)) { @@ -4092,8 +4152,9 @@ doq_stream_data_complete(struct doq_conn /** doq receive data for a stream, more bytes of the incoming data */ static int -doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data, - size_t datalen, int* recv_done, struct doq_table* table) +doq_stream_recv_data(struct doq_conn* conn, struct doq_stream* stream, + const uint8_t* data, size_t datalen, int* recv_done, + struct doq_table* table) { int got_data = 0; /* read the tcplength uint16_t at the start */ @@ -4114,7 +4175,7 @@ doq_stream_recv_data(struct doq_stream* if(stream->nread == 2) { /* the initial length value is completed */ stream->inlen = ntohs(tcplen); - if(!doq_stream_datalen_complete(stream, table)) + if(!doq_stream_datalen_complete(conn, stream, table)) return 0; } else { /* store for later */ @@ -4263,12 +4324,11 @@ doq_submit_new_token(struct doq_conn* co ngtcp2_ssize tokenlen; int ret; const ngtcp2_path* path = ngtcp2_conn_get_path(conn->conn); - ngtcp2_tstamp ts = doq_get_timestamp_nanosec(); tokenlen = ngtcp2_crypto_generate_regular_token(token, conn->doq_socket->static_secret, conn->doq_socket->static_secret_len, path->remote.addr, - path->remote.addrlen, ts); + path->remote.addrlen, doq_get_timestamp_nanosec()); if(tokenlen < 0) { log_err("doq ngtcp2_crypto_generate_regular_token failed"); return 1; @@ -4331,8 +4391,7 @@ doq_stream_open_cb(ngtcp2_conn* ATTR_UNU verbose(VERB_ALGO, "doq: stream with this id already exists"); return 0; } - if(stream_id != 0 && stream_id != 4 && /* allow one stream on a new connection */ - !doq_table_quic_size_available(doq_conn->doq_socket->table, + if(!doq_table_quic_size_available(doq_conn->doq_socket->table, doq_conn->doq_socket->cfg, sizeof(*stream) + 100 /* estimated query in */ + 512 /* estimated response out */ @@ -4390,8 +4449,8 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATT return 0; } if(datalen != 0) { - if(!doq_stream_recv_data(stream, data, datalen, &recv_done, - doq_conn->doq_socket->table)) + if(!doq_stream_recv_data(doq_conn, stream, data, datalen, + &recv_done, doq_conn->doq_socket->table)) return NGTCP2_ERR_CALLBACK_FAILURE; } if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) { @@ -4455,11 +4514,34 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UN "unknown stream %d", (int)stream_id); return 0; } - if(!doq_stream_close(doq_conn, stream, 0)) + if(!doq_stream_close(doq_conn, stream, 1)) return NGTCP2_ERR_CALLBACK_FAILURE; return 0; } +/** ngtcp2 extend_max_stream_data function */ +int doq_extend_max_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), + int64_t stream_id, uint64_t max_data, void* user_data, + void* ATTR_UNUSED(stream_user_data)) +{ + struct doq_conn* doq_conn = (struct doq_conn*)user_data; + struct doq_stream* stream; + verbose(VERB_ALGO, "doq extend_max_stream_data stream id %d " + "max_data %d ", (int)stream_id, (int)max_data); + if(max_data == 0) + return 0; + stream = doq_stream_find(doq_conn, stream_id); + if(!stream) { + verbose(VERB_ALGO, "doq: unknown stream %d", (int)stream_id); + return 0; + } + if(!stream->is_answer_available) + return 0; + doq_stream_on_write_list(doq_conn, stream); + doq_conn_write_enable(doq_conn); + return 0; +} + /** ngtcp2 acked_stream_data_offset callback function */ static int doq_acked_stream_data_offset_cb(ngtcp2_conn* ATTR_UNUSED(conn), @@ -4780,7 +4862,7 @@ doq_ssl_server_setup(SSL_CTX* ctx, struc SSL_set_app_data(ssl, conn); #endif SSL_set_accept_state(ssl); -#ifdef USE_NGTCP2_CRYPTO_OSSL +#ifdef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED SSL_set_quic_tls_early_data_enabled(ssl, 1); #else SSL_set_quic_early_data_enabled(ssl, 1); @@ -4834,6 +4916,7 @@ doq_conn_setup(struct doq_conn* conn, ui callbacks.stream_open = doq_stream_open_cb; callbacks.stream_close = doq_stream_close_cb; callbacks.stream_reset = doq_stream_reset_cb; + callbacks.extend_max_stream_data = doq_extend_max_stream_data_cb; callbacks.acked_stream_data_offset = doq_acked_stream_data_offset_cb; callbacks.recv_stream_data = doq_recv_stream_data_cb; @@ -4888,6 +4971,7 @@ doq_conn_setup(struct doq_conn* conn, ui rv = ngtcp2_conn_server_new(&conn->conn, &scid_cid, &sv_scid, &path, conn->version, &callbacks, &settings, ¶ms, NULL, conn); if(rv != 0) { + conn->conn = NULL; lock_rw_unlock(&conn->table->conid_lock); log_err("ngtcp2_conn_server_new failed: %s", ngtcp2_strerror(rv)); @@ -4922,6 +5006,7 @@ doq_conid_find(struct doq_table* table, key.node.key = &key; key.cid = (void*)data; key.cidlen = datalen; + log_assert(table != NULL); node = rbtree_search(table->conid_tree, &key); if(node) return (struct doq_conid*)node->key; @@ -5109,23 +5194,30 @@ doq_conn_clear_conids(struct doq_conn* c ngtcp2_tstamp doq_get_timestamp_nanosec(void) { -#ifdef CLOCK_REALTIME struct timespec tp; memset(&tp, 0, sizeof(tp)); - /* Get a nanosecond time, that can be compared with the event base. */ - if(clock_gettime(CLOCK_REALTIME, &tp) == -1) { - log_err("clock_gettime failed: %s", strerror(errno)); +#ifdef CLOCK_BOOTTIME + if(clock_gettime(CLOCK_BOOTTIME, &tp) == -1) { +#endif + if(clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { + log_err("clock_gettime failed: %s", strerror(errno)); + } +#ifdef CLOCK_BOOTTIME } +#endif return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) + ((uint64_t)tp.tv_nsec); -#else +} + +static struct timeval doq_get_timevalue(void) +{ struct timeval tv; + memset(&tv, 0, sizeof(tv)); if(gettimeofday(&tv, NULL) < 0) { log_err("gettimeofday failed: %s", strerror(errno)); + memset(&tv, 0, sizeof(tv)); } - return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) + - ((uint64_t)tv.tv_usec)*((uint64_t)1000); -#endif /* CLOCK_REALTIME */ + return tv; } /** doq start the closing period for the connection. */ @@ -5248,18 +5340,17 @@ doq_conn_recv(struct comm_point* c, stru int* err_drop) { int ret; - ngtcp2_tstamp ts; struct ngtcp2_path path; memset(&path, 0, sizeof(path)); path.remote.addr = (struct sockaddr*)&paddr->addr; path.remote.addrlen = paddr->addrlen; path.local.addr = (struct sockaddr*)&paddr->localaddr; path.local.addrlen = paddr->localaddrlen; - ts = doq_get_timestamp_nanosec(); ret = ngtcp2_conn_read_pkt(conn->conn, &path, pi, sldns_buffer_begin(c->doq_socket->pkt_buf), - sldns_buffer_limit(c->doq_socket->pkt_buf), ts); + sldns_buffer_limit(c->doq_socket->pkt_buf), + doq_get_timestamp_nanosec()); if(ret != 0) { if(err_retry) *err_retry = 0; @@ -5347,7 +5438,6 @@ doq_conn_write_streams(struct comm_point { struct doq_stream* stream = conn->stream_write_first; ngtcp2_path_storage ps; - ngtcp2_tstamp ts = doq_get_timestamp_nanosec(); size_t num_packets = 0, max_packets = 65535; ngtcp2_path_storage_zero(&ps); @@ -5400,7 +5490,8 @@ doq_conn_write_streams(struct comm_point ret = ngtcp2_conn_writev_stream(conn->conn, &ps.path, &pi, sldns_buffer_begin(c->doq_socket->pkt_buf), sldns_buffer_remaining(c->doq_socket->pkt_buf), - &ndatalen, flags, stream_id, datav, datav_count, ts); + &ndatalen, flags, stream_id, datav, datav_count, + doq_get_timestamp_nanosec()); if(ret < 0) { if(ret == NGTCP2_ERR_WRITE_MORE) { verbose(VERB_ALGO, "doq: write more, ndatalen %d", (int)ndatalen); @@ -5415,26 +5506,20 @@ doq_conn_write_streams(struct comm_point continue; } else if(ret == NGTCP2_ERR_STREAM_DATA_BLOCKED) { verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_DATA_BLOCKED"); -#ifdef HAVE_NGTCP2_CCERR_DEFAULT - ngtcp2_ccerr_set_application_error( - &conn->ccerr, -1, NULL, 0); -#else - ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0); -#endif - if(err_drop) - *err_drop = 0; - if(!doq_conn_close_error(c, conn)) { - if(err_drop) - *err_drop = 1; + if(stream) { + doq_stream_off_write_list(conn, stream); + stream = stream->write_next; + continue; + } else { + break; } - return 0; } else if(ret == NGTCP2_ERR_STREAM_SHUT_WR) { verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_SHUT_WR"); #ifdef HAVE_NGTCP2_CCERR_DEFAULT ngtcp2_ccerr_set_application_error( - &conn->ccerr, -1, NULL, 0); + &conn->ccerr, DOQ_APP_ERROR_CODE, NULL, 0); #else - ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0); + ngtcp2_connection_close_error_set_application_error(&conn->last_error, DOQ_APP_ERROR_CODE, NULL, 0); #endif if(err_drop) *err_drop = 0; @@ -5472,7 +5557,8 @@ doq_conn_write_streams(struct comm_point if(ret == 0) { /* congestion limited */ doq_conn_write_disable(conn); - ngtcp2_conn_update_pkt_tx_time(conn->conn, ts); + ngtcp2_conn_update_pkt_tx_time(conn->conn, + doq_get_timestamp_nanosec()); return 1; } sldns_buffer_set_position(c->doq_socket->pkt_buf, ret); @@ -5486,7 +5572,7 @@ doq_conn_write_streams(struct comm_point if(stream) stream = stream->write_next; } - ngtcp2_conn_update_pkt_tx_time(conn->conn, ts); + ngtcp2_conn_update_pkt_tx_time(conn->conn, doq_get_timestamp_nanosec()); return 1; } @@ -5563,32 +5649,35 @@ doq_table_pop_first(struct doq_table* ta } int -doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv) +doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, ngtcp2_tstamp* ts) { - ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(conn->conn); - ngtcp2_tstamp now = doq_get_timestamp_nanosec(); + ngtcp2_tstamp doq_expiry = ngtcp2_conn_get_expiry(conn->conn); + ngtcp2_tstamp doq_now = doq_get_timestamp_nanosec(); ngtcp2_tstamp t; + struct timeval now = doq_get_timevalue(); - if(expiry <= now) { + if(doq_expiry <= doq_now || doq_expiry == UINT64_MAX) { + /* UINT64_MAX means there is no next expiry. */ /* The timer has already expired, add with zero timeout. * This should call the callback straight away. Calling it * from the event callbacks is cleaner than calling it here, * because then it is always called with the same locks and * so on. This routine only has the conn.lock. */ - t = now; + t = doq_now; + memcpy(tv, &now, sizeof(*tv)); } else { - t = expiry; + t = doq_expiry; + memset(tv, 0, sizeof(*tv)); + tv->tv_sec = (doq_expiry - doq_now) / NGTCP2_SECONDS; + tv->tv_usec = ((doq_expiry - doq_now) / NGTCP2_MICROSECONDS)%1000000; + timeval_add(tv, &now); } - /* convert to timeval */ - memset(tv, 0, sizeof(*tv)); - tv->tv_sec = t / NGTCP2_SECONDS; - tv->tv_usec = (t / NGTCP2_MICROSECONDS)%1000000; + *ts = t; /* If we already have a timer, is it the right value? */ if(conn->timer.timer_in_tree || conn->timer.timer_in_list) { - if(conn->timer.time.tv_sec == tv->tv_sec && - conn->timer.time.tv_usec == tv->tv_usec) + if(conn->timer.time_mono == *ts) return 0; } return 1; @@ -5609,13 +5698,12 @@ doq_conn_log_line(struct doq_conn* conn, int doq_conn_handle_timeout(struct doq_conn* conn) { - ngtcp2_tstamp now = doq_get_timestamp_nanosec(); int rv; if(verbosity >= VERB_ALGO) doq_conn_log_line(conn, "timeout"); - rv = ngtcp2_conn_handle_expiry(conn->conn, now); + rv = ngtcp2_conn_handle_expiry(conn->conn, doq_get_timestamp_nanosec()); if(rv != 0) { verbose(VERB_ALGO, "ngtcp2_conn_handle_expiry failed: %s", ngtcp2_strerror(rv)); @@ -5662,6 +5750,8 @@ doq_table_quic_size_available(struct doq struct config_file* cfg, size_t mem) { size_t cur; + if (!table) + return 0; lock_basic_lock(&table->size_lock); cur = table->current_size; lock_basic_unlock(&table->size_lock); Index: sbin/unwind/libunbound/services/listen_dnsport.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/listen_dnsport.h,v diff -u -p -r1.14 listen_dnsport.h --- sbin/unwind/libunbound/services/listen_dnsport.h 29 Sep 2025 14:53:38 -0000 1.14 +++ sbin/unwind/libunbound/services/listen_dnsport.h 21 Sep 2026 16:27:58 -0000 @@ -61,6 +61,8 @@ struct config_file; struct addrinfo; struct sldns_buffer; struct tcl_list; +struct mesh_area; +struct mesh_state; /** * Listening for queries structure. @@ -345,6 +347,10 @@ struct tcp_req_info { int num_done_req; /** list of pending writable result packets, malloced one at a time */ struct tcp_req_done_item* done_req_list; + /** the read again timer, when the number of pipelined TCP queries + * is large, it waits, zero time, for a new event loop to service + * the remainder of the TCP traffic on the fd. */ + struct comm_timer* read_again_timer; }; /** @@ -375,10 +381,12 @@ struct tcp_req_done_item { * Create tcp request info structure that keeps track of open * requests on the TCP channel that are resolved at the same time, * and the pending results that have to get written back to that client. + * @param base: comm base for read again timer. * @param spoolbuf: shared buffer * @return new structure or NULL on alloc failure. */ -struct tcp_req_info* tcp_req_info_create(struct sldns_buffer* spoolbuf); +struct tcp_req_info* tcp_req_info_create(struct comm_base* base, + struct sldns_buffer* spoolbuf); /** * Delete tcp request structure. Called by owning commpoint. @@ -538,8 +546,11 @@ void doq_table_delete(struct doq_table* struct doq_timer { /** The rbnode in the tree sorted by timeout value. Key this struct. */ struct rbnode_type node; + /** The timeout value. Monotonic value used with ngtcp2. + * This time value is used for the tree operations. */ + ngtcp2_tstamp time_mono; /** The timeout value. Absolute time value. */ - struct timeval time; + struct timeval time_real; /** If the timer is in the time tree, with the node. */ int timer_in_tree; /** If there are more timers with the exact same timeout value, @@ -689,6 +700,11 @@ struct doq_stream { uint8_t* out; /** if the stream is on the write list */ uint8_t on_write_list; + /** The mesh area and mesh state, set when this stream's query was + * dispatched into the mesh; used to detach the reply on stream close */ + struct mesh_area* mesh; + /** the mesh state for the query, is nonNULL when there is one. */ + struct mesh_state* mesh_state; /** the prev and next on the write list, if on the list */ struct doq_stream* write_prev, *write_next; }; @@ -791,7 +807,16 @@ int doq_stream_close(struct doq_conn* co /** send reply for a connection */ int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream, struct sldns_buffer* buf); +#endif /* HAVE_NGTCP2 */ +/** add mesh state to doq stream */ +void doq_stream_add_meshstate(struct doq_stream* stream, + struct mesh_area* mesh, struct mesh_state* m); + +/** remove mesh state from doq stream */ +void doq_stream_remove_mesh_state(struct doq_stream* stream); + +#ifdef HAVE_NGTCP2 /** the connection has write interest, wants to write packets */ void doq_conn_write_enable(struct doq_conn* conn); @@ -813,10 +838,12 @@ struct doq_conn* doq_table_pop_first(str * doq check if the timer for the conn needs to be changed. * @param conn: connection, caller must hold lock on it. * @param tv: time value, absolute time, returned. + * @param ts: time stamp, absolute time, returned. * @return true if timer needs to be set to tv, false if no change is needed * to the timer. The timer is already set to the right time in that case. */ -int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv); +int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, + ngtcp2_tstamp* ts); /** doq remove timer from tree */ void doq_timer_tree_remove(struct doq_table* table, struct doq_timer* timer); @@ -829,11 +856,12 @@ void doq_timer_unset(struct doq_table* t /** doq set the timer and add it. */ void doq_timer_set(struct doq_table* table, struct doq_timer* timer, - struct doq_server_socket* worker_doq_socket, struct timeval* tv); + struct doq_server_socket* worker_doq_socket, struct timeval* tv, + ngtcp2_tstamp ts); /** doq find a timeout in the timer tree */ struct doq_timer* doq_timer_find_time(struct doq_table* table, - struct timeval* tv); + ngtcp2_tstamp ts); /** doq handle timeout for a connection. Pass conn locked. Returns false for * deletion. */ @@ -851,6 +879,9 @@ int doq_table_quic_size_available(struct /** doq get the quic size value */ size_t doq_table_quic_size_get(struct doq_table* table); + +/** get a timestamp in nanoseconds */ +ngtcp2_tstamp doq_get_timestamp_nanosec(void); #endif /* HAVE_NGTCP2 */ char* set_ip_dscp(int socket, int addrfamily, int ds); @@ -866,8 +897,4 @@ void doq_client_event_cb(int fd, short e /** timer event callback for testcode/doqclient */ void doq_client_timer_cb(int fd, short event, void* arg); -#ifdef HAVE_NGTCP2 -/** get a timestamp in nanoseconds */ -ngtcp2_tstamp doq_get_timestamp_nanosec(void); -#endif #endif /* LISTEN_DNSPORT_H */ Index: sbin/unwind/libunbound/services/localzone.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/localzone.c,v diff -u -p -r1.16 localzone.c --- sbin/unwind/libunbound/services/localzone.c 14 Sep 2025 15:16:53 -0000 1.16 +++ sbin/unwind/libunbound/services/localzone.c 21 Sep 2026 16:27:58 -0000 @@ -56,6 +56,24 @@ * with 16 bytes for an A record, a 64K packet has about 4000 max */ #define LOCALZONE_RRSET_COUNT_MAX 4096 +static const char* default_zones_reverse_array[] = { + "127.in-addr.arpa.", /* reverse ip4 zone */ + "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", /* reverse ip6 zone */ + 0 +}; +const char** local_zones_default_reverse = default_zones_reverse_array; + +static const char* default_zones_special_array[] = { + "test.", /* RFC 6761 */ + "invalid.", /* RFC 6761 */ + "onion.", /* RFC 7686 */ + "home.arpa.", /* RFC 8375 */ + "resolver.arpa.", /* RFC 9462 */ + "service.arpa.", /* RFC 9665 */ + 0 +}; +const char** local_zones_default_special = default_zones_special_array; + /** print all RRsets in local zone */ static void local_zone_out(struct local_zone* z) @@ -368,8 +386,6 @@ new_local_rrset(struct regional* region, log_err("out of memory"); return NULL; } - rrset->next = node->rrsets; - node->rrsets = rrset; rrset->rrset = (struct ub_packed_rrset_key*) regional_alloc_zero(region, sizeof(*rrset->rrset)); if(!rrset->rrset) { @@ -390,6 +406,8 @@ new_local_rrset(struct regional* region, rrset->rrset->rk.dname_len = node->namelen; rrset->rrset->rk.type = htons(rrtype); rrset->rrset->rk.rrset_class = htons(rrclass); + rrset->next = node->rrsets; + node->rrsets = rrset; return rrset; } @@ -413,6 +431,10 @@ rrset_insert_rr(struct regional* region, pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count); pd->rr_data = regional_alloc(region, sizeof(*pd->rr_data)*pd->count); if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) { + pd->count--; + pd->rr_len = oldlen; + pd->rr_ttl = oldttl; + pd->rr_data = olddata; log_err("out of memory"); return 0; } @@ -428,6 +450,10 @@ rrset_insert_rr(struct regional* region, pd->rr_ttl[0] = ttl; pd->rr_data[0] = regional_alloc_init(region, rdata, rdata_len); if(!pd->rr_data[0]) { + pd->count--; + pd->rr_len = oldlen; + pd->rr_ttl = oldttl; + pd->rr_data = olddata; log_err("out of memory"); return 0; } @@ -650,10 +676,12 @@ lz_enter_rr_str(struct local_zones* zone } labs = dname_count_size_labels(rr_name, &len); lock_rw_rdlock(&zones->lock); - z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type); + z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type, 1); if(!z) { lock_rw_unlock(&zones->lock); - fatal_exit("internal error: no zone for rr %s", rr); + log_err("internal error: no zone for rr %s", rr); + free(rr_name); + return 0; } lock_rw_wrlock(&z->lock); lock_rw_unlock(&zones->lock); @@ -834,7 +862,7 @@ lz_nodefault(struct config_file* cfg, co for(p = cfg->local_zones_nodefault; p; p = p->next) { /* compare zone name, lowercase, compare without ending . */ - if(strncasecmp(p->str, name, len) == 0 && + if(strncasecmp(p->str, name, len) == 0 && (strlen(p->str) == len || (strlen(p->str)==len+1 && p->str[len] == '.'))) return 1; @@ -842,6 +870,45 @@ lz_nodefault(struct config_file* cfg, co return 0; } +/** enter reverse default zone */ +static int +add_reverse_default(struct local_zones* zones, struct config_file* cfg, + const char* name) +{ + struct local_zone* z; + char str[1024]; /* known long enough */ + if(lz_exists(zones, name) || lz_nodefault(cfg, name)) + return 1; /* do not enter default content */ + if(!(z=lz_enter_zone(zones, name, "static", LDNS_RR_CLASS_IN))) + return 0; + snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. " + "nobody.invalid. 1 3600 1200 604800 10800", name); + if(!lz_enter_rr_into_zone(z, str)) { + lock_rw_unlock(&z->lock); + return 0; + } + snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name); + if(!lz_enter_rr_into_zone(z, str)) { + lock_rw_unlock(&z->lock); + return 0; + } + if(strncasecmp("127.in-addr.arpa.", name, 17) == 0) { + if(!lz_enter_rr_into_zone(z, + "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) { + lock_rw_unlock(&z->lock); + return 0; + } + } else if(strncasecmp("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", name, 73) == 0) { + snprintf(str, sizeof(str), "%s 10800 IN PTR localhost.", name); + if(!lz_enter_rr_into_zone(z, str)) { + lock_rw_unlock(&z->lock); + return 0; + } + } + lock_rw_unlock(&z->lock); + return 1; +} + /** enter (AS112) empty default zone */ static int add_empty_default(struct local_zones* zones, struct config_file* cfg, @@ -902,72 +969,23 @@ int local_zone_enter_defaults(struct loc } lock_rw_unlock(&z->lock); } - /* reverse ip4 zone */ - if(!lz_exists(zones, "127.in-addr.arpa.") && - !lz_nodefault(cfg, "127.in-addr.arpa.")) { - if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static", - LDNS_RR_CLASS_IN)) || - !lz_enter_rr_into_zone(z, - "127.in-addr.arpa. 10800 IN NS localhost.") || - !lz_enter_rr_into_zone(z, - "127.in-addr.arpa. 10800 IN SOA localhost. " - "nobody.invalid. 1 3600 1200 604800 10800") || - !lz_enter_rr_into_zone(z, - "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) { + + /* ip4 and ip6 reverse */ + for(zstr = local_zones_default_reverse; *zstr; zstr++) { + if(!add_reverse_default(zones, cfg, *zstr)) { log_err("out of memory adding default zone"); - if(z) { lock_rw_unlock(&z->lock); } return 0; } - lock_rw_unlock(&z->lock); } - /* reverse ip6 zone */ - if(!lz_exists(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") && - !lz_nodefault(cfg, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.")) { - if(!(z=lz_enter_zone(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", "static", - LDNS_RR_CLASS_IN)) || - !lz_enter_rr_into_zone(z, - "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN NS localhost.") || - !lz_enter_rr_into_zone(z, - "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN SOA localhost. " - "nobody.invalid. 1 3600 1200 604800 10800") || - !lz_enter_rr_into_zone(z, - "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN PTR localhost.")) { + + /* special-use zones */ + for(zstr = local_zones_default_special; *zstr; zstr++) { + if(!add_empty_default(zones, cfg, *zstr)) { log_err("out of memory adding default zone"); - if(z) { lock_rw_unlock(&z->lock); } return 0; } - lock_rw_unlock(&z->lock); - } - /* home.arpa. zone (RFC 8375) */ - if(!add_empty_default(zones, cfg, "home.arpa.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* resolver.arpa. zone (RFC 9462) */ - if(!add_empty_default(zones, cfg, "resolver.arpa.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* service.arpa. zone (draft-ietf-dnssd-srp-25) */ - if(!add_empty_default(zones, cfg, "service.arpa.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* onion. zone (RFC 7686) */ - if(!add_empty_default(zones, cfg, "onion.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* test. zone (RFC 6761) */ - if(!add_empty_default(zones, cfg, "test.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* invalid. zone (RFC 6761) */ - if(!add_empty_default(zones, cfg, "invalid.")) { - log_err("out of memory adding default zone"); - return 0; } + /* block AS112 zones, unless asked not to */ if(!cfg->unblock_lan_zones) { for(zstr = as112_zones; *zstr; zstr++) { @@ -998,23 +1016,23 @@ static struct local_zone* find_closest_p struct local_zone* prev) { struct local_zone* p; - int m; + int m; if(!prev || prev->dclass != curr->dclass) return NULL; (void)dname_lab_cmp(prev->name, prev->namelabs, curr->name, curr->namelabs, &m); /* we know prev is smaller */ - /* sort order like: . com. bla.com. zwb.com. net. */ - /* find the previous, or parent-parent-parent */ + /* sort order like: . com. bla.com. zwb.com. net. */ + /* find the previous, or parent-parent-parent */ for(p = prev; p; p = p->parent) { - /* looking for name with few labels, a parent */ - if(p->namelabs <= m) { - /* ==: since prev matched m, this is closest*/ - /* <: prev matches more, but is not a parent, - * this one is a (grand)parent */ + /* looking for name with few labels, a parent */ + if(p->namelabs <= m) { + /* ==: since prev matched m, this is closest*/ + /* <: prev matches more, but is not a parent, + * this one is a (grand)parent */ return p; } } return NULL; - } +} /** setup parent pointers, so that a lookup can be done for closest match */ void @@ -1029,7 +1047,7 @@ lz_init_parents(struct local_zones* zone if(node->override_tree) addr_tree_init_parents(node->override_tree); lock_rw_unlock(&node->lock); - } + } lock_rw_unlock(&zones->lock); } @@ -1062,14 +1080,15 @@ lz_setup_implicit(struct local_zones* zo labs = dname_count_size_labels(rr_name, &len); lock_rw_rdlock(&zones->lock); if(!local_zones_lookup(zones, rr_name, len, labs, rr_class, - rr_type)) { + rr_type, 1)) { /* Check if there is a zone that this could go * under but for different class; created zones are * always for LDNS_RR_CLASS_IN. Create the zone with * a different class but the same configured * local_zone_type. */ struct local_zone* z = local_zones_lookup(zones, - rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type); + rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type, + 1); if(z) { uint8_t* name = memdup(z->name, z->namelen); size_t znamelen = z->namelen; @@ -1231,28 +1250,48 @@ local_zones_apply_cfg(struct local_zones struct local_zone* local_zones_lookup(struct local_zones* zones, - uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype) + uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype, + int foradd) { return local_zones_tags_lookup(zones, name, len, labs, - dclass, dtype, NULL, 0, 1); + dclass, dtype, NULL, 0, 1, foradd); } struct local_zone* local_zones_tags_lookup(struct local_zones* zones, uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype, - uint8_t* taglist, size_t taglen, int ignoretags) + uint8_t* taglist, size_t taglen, int ignoretags, int foradd) { rbnode_type* res = NULL; struct local_zone *result; struct local_zone key; int m; + key.node.key = &key; + key.dclass = dclass; /* for type DS use a zone higher when on a zonecut */ if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) { - dname_remove_label(&name, &len); - labs--; + /* If this is at a zone cut, of a local-zone, and it is + * of type always_refuse. Then also refuse the type DS + * for it. That could make it DNSSEC bogus, but it is + * REFUSED anyway. It stops CNAME type answers in the + * type DS lookup. */ + key.name = name; + key.namelen = len; + key.namelabs = labs; + /* For additions and removals, use the ordinary rule, + * to remove a label for type DS to locate the parent zone. + * That is where the DS RR needs to be put. */ + if(!foradd && + (result=(struct local_zone*)rbtree_search( + &zones->ztree, &key)) != NULL && + result->type == local_zone_always_refuse) { + /* The type DS does not go up one label. */ + return result; + } else { + dname_remove_label(&name, &len); + labs--; + } } - key.node.key = &key; - key.dclass = dclass; key.name = name; key.namelen = len; key.namelabs = labs; @@ -1471,8 +1510,10 @@ find_tag_datas(struct query_info* qinfo, return 0; /* out of memory */ qinfo->local_alias->rrset = regional_alloc_init(temp, r, sizeof(*r)); - if(!qinfo->local_alias->rrset) + if(!qinfo->local_alias->rrset) { + qinfo->local_alias = NULL; return 0; /* out of memory */ + } } return result; } @@ -1538,13 +1579,17 @@ local_data_answer(struct local_zone* z, return 0; /* out of memory */ qinfo->local_alias->rrset = regional_alloc_init( temp, lr->rrset, sizeof(*lr->rrset)); - if(!qinfo->local_alias->rrset) + if(!qinfo->local_alias->rrset) { + qinfo->local_alias = NULL; return 0; /* out of memory */ + } qinfo->local_alias->rrset->rk.dname = qinfo->qname; qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len; get_cname_target(lr->rrset, &ctarget, &ctargetlen); - if(!ctargetlen) + if(!ctargetlen) { + qinfo->local_alias = NULL; return 0; /* invalid cname */ + } if(dname_is_wild(ctarget)) { /* synthesize cname target */ struct packed_rrset_data* d, *lr_d; @@ -1573,8 +1618,10 @@ local_data_answer(struct local_zone* z, sizeof(struct packed_rrset_data) + sizeof(size_t) + sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t) + newtargetlen); - if(!d) + if(!d) { + qinfo->local_alias = NULL; return 0; /* out of memory */ + } lr_d = (struct packed_rrset_data*)lr->rrset->entry.data; qinfo->local_alias->rrset->entry.data = d; d->ttl = lr_d->rr_ttl[0]; /* RFC6672-like behavior: @@ -1621,7 +1668,7 @@ local_zone_does_not_cover(struct local_z struct local_data key; struct local_data* ld = NULL; struct local_rrset* lr = NULL; - if(z->type == local_zone_always_transparent || z->type == local_zone_block_a) + if(z->type == local_zone_always_transparent || z->type == local_zone_block_a || z->type == local_zone_block_aaaa) return 1; if(z->type != local_zone_transparent && z->type != local_zone_typetransparent @@ -1632,7 +1679,9 @@ local_zone_does_not_cover(struct local_z key.namelen = qinfo->qname_len; key.namelabs = labs; ld = (struct local_data*)rbtree_search(&z->data, &key.node); - if(z->type == local_zone_transparent || z->type == local_zone_inform) + if(z->type == local_zone_transparent || z->type == local_zone_inform + || z->type == local_zone_block_a_wdata + || z->type == local_zone_block_aaaa_wdata) return (ld == NULL); if(ld) lr = local_data_find_type(ld, qinfo->qtype, 1); @@ -1698,7 +1747,8 @@ local_zones_zone_answer(struct local_zon || lz_type == local_zone_always_transparent) { /* no NODATA or NXDOMAINS for this zone type */ return 0; - } else if(lz_type == local_zone_block_a) { + } else if(lz_type == local_zone_block_a || + lz_type == local_zone_block_a_wdata) { /* Return NODATA for all A queries */ if(qinfo->qtype == LDNS_RR_TYPE_A) { local_error_encode(qinfo, env, edns, repinfo, buf, temp, @@ -1708,6 +1758,17 @@ local_zones_zone_answer(struct local_zon } return 0; + } else if(lz_type == local_zone_block_aaaa || + lz_type == local_zone_block_aaaa_wdata) { + /* Return NODATA for all AAAA queries */ + if(qinfo->qtype == LDNS_RR_TYPE_AAAA) { + local_error_encode(qinfo, env, edns, repinfo, buf, temp, + LDNS_RCODE_NOERROR, (LDNS_RCODE_NOERROR|BIT_AA), + LDNS_EDE_NONE, NULL); + return 1; + } + + return 0; } else if(lz_type == local_zone_always_null) { /* 0.0.0.0 or ::0 or noerror/nodata for this zone type, * used for blocklists. */ @@ -1863,7 +1924,7 @@ local_zones_answer(struct local_zones* z if(view->local_zones && (z = local_zones_lookup(view->local_zones, qinfo->qname, qinfo->qname_len, labs, - qinfo->qclass, qinfo->qtype))) { + qinfo->qclass, qinfo->qtype, 0))) { lock_rw_rdlock(&z->lock); lzt = z->type; } @@ -1875,7 +1936,10 @@ local_zones_answer(struct local_zones* z lzt == local_zone_typetransparent || lzt == local_zone_inform || lzt == local_zone_always_transparent || - lzt == local_zone_block_a) && + lzt == local_zone_block_a || + lzt == local_zone_block_aaaa || + lzt == local_zone_block_a_wdata || + lzt == local_zone_block_aaaa_wdata) && local_zone_does_not_cover(z, qinfo, labs)) { lock_rw_unlock(&z->lock); z = NULL; @@ -1897,7 +1961,7 @@ local_zones_answer(struct local_zones* z lock_rw_rdlock(&zones->lock); if(!(z = local_zones_tags_lookup(zones, qinfo->qname, qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype, - taglist, taglen, 0))) { + taglist, taglen, 0, 0))) { lock_rw_unlock(&zones->lock); return 0; } @@ -1924,6 +1988,7 @@ local_zones_answer(struct local_zones* z if(lzt != local_zone_always_refuse && lzt != local_zone_always_transparent && lzt != local_zone_block_a + && lzt != local_zone_block_aaaa && lzt != local_zone_always_nxdomain && lzt != local_zone_always_nodata && lzt != local_zone_always_deny @@ -1955,6 +2020,9 @@ const char* local_zone_type2str(enum loc case local_zone_inform_redirect: return "inform_redirect"; case local_zone_always_transparent: return "always_transparent"; case local_zone_block_a: return "block_a"; + case local_zone_block_aaaa: return "block_aaaa"; + case local_zone_block_a_wdata: return "block_a_wdata"; + case local_zone_block_aaaa_wdata: return "block_aaaa_wdata"; case local_zone_always_refuse: return "always_refuse"; case local_zone_always_nxdomain: return "always_nxdomain"; case local_zone_always_nodata: return "always_nodata"; @@ -1991,6 +2059,12 @@ int local_zone_str2type(const char* type *t = local_zone_always_transparent; else if(strcmp(type, "block_a") == 0) *t = local_zone_block_a; + else if(strcmp(type, "block_aaaa") == 0) + *t = local_zone_block_aaaa; + else if(strcmp(type, "block_a_wdata") == 0) + *t = local_zone_block_a_wdata; + else if(strcmp(type, "block_aaaa_wdata") == 0) + *t = local_zone_block_aaaa_wdata; else if(strcmp(type, "always_refuse") == 0) *t = local_zone_always_refuse; else if(strcmp(type, "always_nxdomain") == 0) @@ -2102,7 +2176,8 @@ local_zones_add_RR(struct local_zones* z /* could first try readlock then get writelock if zone does not exist, * but we do not add enough RRs (from multiple threads) to optimize */ lock_rw_wrlock(&zones->lock); - z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type); + z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type, + 1); if(!z) { z = local_zones_add_zone(zones, rr_name, len, labs, rr_class, local_zone_transparent); @@ -2180,7 +2255,8 @@ void local_zones_del_data(struct local_z /* remove DS */ lock_rw_rdlock(&zones->lock); - z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS); + z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS, + 1); if(z) { lock_rw_wrlock(&z->lock); d = local_zone_find_data(z, name, len, labs); @@ -2194,7 +2270,7 @@ void local_zones_del_data(struct local_z /* remove other types */ lock_rw_rdlock(&zones->lock); - z = local_zones_lookup(zones, name, len, labs, dclass, 0); + z = local_zones_lookup(zones, name, len, labs, dclass, 0, 1); if(!z) { /* no such zone, we're done */ lock_rw_unlock(&zones->lock); Index: sbin/unwind/libunbound/services/localzone.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/localzone.h,v diff -u -p -r1.9 localzone.h --- sbin/unwind/libunbound/services/localzone.h 14 Sep 2025 15:16:53 -0000 1.9 +++ sbin/unwind/libunbound/services/localzone.h 21 Sep 2026 16:27:58 -0000 @@ -57,6 +57,9 @@ struct sldns_buffer; struct comm_reply; struct config_strlist; +extern const char** local_zones_default_special; +extern const char** local_zones_default_reverse; + /** * Local zone type * This type determines processing for queries that did not match @@ -90,6 +93,12 @@ enum localzone_type { local_zone_always_transparent, /** resolve normally, even when there is local data but return NODATA for A queries */ local_zone_block_a, + /** resolve normally, even when there is local data, but return NODATA for AAAA queries */ + local_zone_block_aaaa, + /** resolve normally, use local data, else return NODATA for A queries */ + local_zone_block_a_wdata, + /** resolve normally, use local data, else return NODATA for AAAA queries */ + local_zone_block_aaaa_wdata, /** answer with error, even when there is local data */ local_zone_always_refuse, /** answer with nxdomain, even when there is local data */ @@ -262,11 +271,13 @@ void local_zone_delete(struct local_zone * @param taglen: length of taglist. * @param ignoretags: lookup zone by name and class, regardless the * local-zone's tags. + * @param foradd: if the lookup is for addition or removal of the type. + * Used for type DS. The lookup for answers turns this off. * @return closest local_zone or NULL if no covering zone is found. */ struct local_zone* local_zones_tags_lookup(struct local_zones* zones, uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype, - uint8_t* taglist, size_t taglen, int ignoretags); + uint8_t* taglist, size_t taglen, int ignoretags, int foradd); /** * Lookup zone that contains the given name, class. @@ -278,10 +289,13 @@ struct local_zone* local_zones_tags_look * @param dclass: class to lookup. * @param dtype: type of the record, if type DS then a zone higher up is found * pass 0 to just plain find a zone for a name. + * @param foradd: if the lookup is for addition or removal of the type. + * Used for type DS. The lookup for answers turns this off. * @return closest local_zone or NULL if no covering zone is found. */ struct local_zone* local_zones_lookup(struct local_zones* zones, - uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype); + uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype, + int foradd); /** * Debug helper. Print all zones @@ -565,7 +579,7 @@ enum respip_action { respip_always_nxdomain = local_zone_always_nxdomain, /** answer with nodata response */ respip_always_nodata = local_zone_always_nodata, - /** answer with nodata response */ + /** drop query */ respip_always_deny = local_zone_always_deny, /** RPZ: truncate answer in order to force switch to tcp */ respip_truncate = local_zone_truncate, Index: sbin/unwind/libunbound/services/mesh.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/mesh.c,v diff -u -p -r1.23 mesh.c --- sbin/unwind/libunbound/services/mesh.c 29 Sep 2025 14:53:38 -0000 1.23 +++ sbin/unwind/libunbound/services/mesh.c 21 Sep 2026 16:27:58 -0000 @@ -231,6 +231,7 @@ mesh_create(struct module_stack* stack, mesh->ans_expired = 0; mesh->ans_cachedb = 0; mesh->num_queries_discard_timeout = 0; + mesh->num_queries_replyaddr_limit = 0; mesh->num_queries_wait_limit = 0; mesh->num_dns_error_reports = 0; mesh->max_reply_states = env->cfg->num_queries_per_thread; @@ -296,12 +297,14 @@ int mesh_make_new_space(struct mesh_area if(mesh->num_reply_states < mesh->max_reply_states) return 1; /* try to kick out a jostle-list item */ - if(m && m->reply_list && m->list_select == mesh_jostle_list) { + if(m && m->list_select == mesh_jostle_list) { /* how old is it? */ struct timeval age; - timeval_subtract(&age, mesh->env->now_tv, - &m->reply_list->start_time); - if(timeval_smaller(&mesh->jostle_max, &age)) { + if(m->has_first_reply_time) + timeval_subtract(&age, mesh->env->now_tv, + &m->first_reply_time); + if(!m->has_first_reply_time || + timeval_smaller(&mesh->jostle_max, &age)) { /* its a goner */ log_nametypeclass(VERB_ALGO, "query jostled out to " "make space for a new one", @@ -348,7 +351,7 @@ mesh_serve_expired_lookup(struct module_ key = (struct msgreply_entry*)e->key; data = (struct reply_info*)e->data; - if(data->ttl < timenow) *is_expired = 1; + if(TTL_IS_EXPIRED(data->ttl, timenow)) *is_expired = 1; msg = tomsg(qstate->env, &key->key, data, qstate->region, timenow, qstate->env->cfg->serve_expired, qstate->env->scratch); if(!msg) @@ -370,7 +373,7 @@ mesh_serve_expired_lookup(struct module_ "validation"); goto bail_out; /* need to validate cache entry first */ } else if(msg->rep->security == sec_status_secure && - !reply_all_rrsets_secure(msg->rep) && must_validate) { + !reply_an_ns_rrsets_secure(msg->rep) && must_validate) { verbose(VERB_ALGO, "Serve expired: secure entry" " changed status"); goto bail_out; /* rrset changed, re-verify */ @@ -421,6 +424,44 @@ mesh_serve_expired_init(struct mesh_stat return 1; } +/** remove a reply without accounting, rollback the add reply. */ +static void +mesh_remove_reply_without_accounting(struct mesh_state* s, + struct mesh_reply* todel) +{ + struct mesh_reply* r, *prev = NULL; + for(r = s->reply_list; r; r = r->next) { + if(r == todel) { + if(prev) + prev->next = r->next; + else s->reply_list = r->next; + r->next = NULL; + /* todel is allocated in region */ + return; + } + prev = r; + } +} + +/** remove a callback without accounting, rollback the add reply. */ +static void +mesh_remove_callback_without_accounting(struct mesh_state* s, + struct mesh_cb* todel) +{ + struct mesh_cb* r, *prev = NULL; + for(r = s->cb_list; r; r = r->next) { + if(r == todel) { + if(prev) + prev->next = r->next; + else s->cb_list = r->next; + r->next = NULL; + /* todel is allocated in region */ + return; + } + prev = r; + } +} + void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, struct respip_client_info* cinfo, uint16_t qflags, struct edns_data* edns, struct comm_reply* rep, uint16_t qid, @@ -430,7 +471,8 @@ void mesh_new_client(struct mesh_area* m int unique = unique_mesh_state(edns->opt_list_in, mesh->env); int was_detached = 0; int was_noreply = 0; - int added = 0; + int added = 0, added_reply_without_accounting = 0, added_tcp = 0; + struct mesh_reply* repadded = NULL; int timeout = mesh->env->cfg->serve_expired? mesh->env->cfg->serve_expired_client_timeout:0; struct sldns_buffer* r_buffer = rep->c->buffer; @@ -441,9 +483,18 @@ void mesh_new_client(struct mesh_area* m if(!infra_wait_limit_allowed(mesh->env->infra_cache, rep, edns->cookie_valid, mesh->env->cfg)) { verbose(VERB_ALGO, "Too many queries waiting from the IP. " - "dropping incoming query."); - comm_point_drop_reply(rep); + "servfail incoming query."); mesh->num_queries_wait_limit++; + edns_opt_list_append_ede(&edns->opt_list_out, + mesh->env->scratch, LDNS_EDE_OTHER, + "Too many queries queued up and waiting from the IP"); + if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL, + LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) + edns->opt_list_inplace_cb_out = NULL; + error_encode(r_buffer, LDNS_RCODE_SERVFAIL, + qinfo, qid, qflags, edns); + regional_free_all(mesh->env->scratch); + comm_point_send_reply(rep); return; } if(!unique) @@ -453,6 +504,10 @@ void mesh_new_client(struct mesh_area* m if(!mesh_make_new_space(mesh, rep->c->buffer)) { verbose(VERB_ALGO, "Too many queries. dropping " "incoming query."); + if(rep->c->use_h2) + http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_drop_reply(rep); mesh->stats_dropped++; return; @@ -464,8 +519,12 @@ void mesh_new_client(struct mesh_area* m if(mesh->num_reply_addrs > mesh->max_reply_states*16) { verbose(VERB_ALGO, "Too many requests queued. " "dropping incoming query."); + if(rep->c->use_h2) + http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_drop_reply(rep); - mesh->stats_dropped++; + mesh->num_queries_replyaddr_limit++; return; } } @@ -524,18 +583,22 @@ void mesh_new_client(struct mesh_area* m } } /* add reply to s */ - if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) { + if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo, &repadded)) { log_err("mesh_new_client: out of memory; SERVFAIL"); goto servfail_mem; } + added_reply_without_accounting = 1; if(rep->c->tcp_req_info) { if(!tcp_req_info_add_meshstate(rep->c->tcp_req_info, mesh, s)) { log_err("mesh_new_client: out of memory add tcpreqinfo"); goto servfail_mem; } } + added_tcp = 1; if(rep->c->use_h2) { http2_stream_add_meshstate(rep->c->h2_stream, mesh, s); + } else if(rep->c->type == comm_doq && rep->doq_stream) { + doq_stream_add_meshstate(rep->doq_stream, mesh, s); } /* add serve expired timer if required and not already there */ if(timeout && !mesh_serve_expired_init(s, timeout)) { @@ -553,6 +616,8 @@ void mesh_new_client(struct mesh_area* m } } #endif + /* Since the acccounting now happens, + * added_reply_without_accounting = 0; but that is not used. */ infra_wait_limit_inc(mesh->env->infra_cache, rep, *mesh->env->now, mesh->env->cfg); /* update statistics */ @@ -589,7 +654,14 @@ servfail_mem: qinfo, qid, qflags, edns); if(rep->c->use_h2) http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_send_reply(rep); + if(added_reply_without_accounting) { + mesh_remove_reply_without_accounting(s, repadded); + if(added_tcp && rep->c->tcp_req_info) + tcp_req_info_remove_mesh_state(rep->c->tcp_req_info, s); + } if(added) mesh_state_delete(&s->s); return; @@ -598,7 +670,8 @@ servfail_mem: int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, struct edns_data* edns, sldns_buffer* buf, - uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru) + uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru, + void** unique_info) { struct mesh_state* s = NULL; int unique = unique_mesh_state(edns->opt_list_in, mesh->env); @@ -607,6 +680,7 @@ mesh_new_callback(struct mesh_area* mesh int was_detached = 0; int was_noreply = 0; int added = 0; + struct mesh_cb* add_cb = NULL; uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD); if(!unique) s = mesh_area_find(mesh, NULL, qinfo, mesh_flags, 0, 0); @@ -652,13 +726,14 @@ mesh_new_callback(struct mesh_area* mesh } } /* add reply to s */ - if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) { + if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags, &add_cb)) { if(added) mesh_state_delete(&s->s); return 0; } /* add serve expired timer if not already there */ if(timeout && !mesh_serve_expired_init(s, timeout)) { + mesh_remove_callback_without_accounting(s, add_cb); if(added) mesh_state_delete(&s->s); return 0; @@ -669,6 +744,7 @@ mesh_new_callback(struct mesh_area* mesh (mesh->env->cachedb_enabled && mesh->env->cfg->cachedb_check_when_serve_expired)) { if(!mesh_serve_expired_init(s, -1)) { + mesh_remove_callback_without_accounting(s, add_cb); if(added) mesh_state_delete(&s->s); return 0; @@ -684,6 +760,8 @@ mesh_new_callback(struct mesh_area* mesh mesh->num_reply_states ++; } mesh->num_reply_addrs++; + if(unique_info) + *unique_info = s->unique; if(added) mesh_run(mesh, s, module_event_new, NULL); return 1; @@ -887,33 +965,9 @@ void mesh_report_reply(struct mesh_area* mesh_run(mesh, e->qstate->mesh_info, event, e); } -/** copy strlist to region */ -static struct config_strlist* -cfg_region_strlist_copy(struct regional* region, struct config_strlist* list) -{ - struct config_strlist* result = NULL, *last = NULL, *s = list; - while(s) { - struct config_strlist* n = regional_alloc_zero(region, - sizeof(*n)); - if(!n) - return NULL; - n->str = regional_strdup(region, s->str); - if(!n->str) - return NULL; - if(last) - last->next = n; - else result = n; - last = n; - s = s->next; - } - return result; -} - -/** Copy the client info to the query region. */ -static struct respip_client_info* +struct respip_client_info* mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo) { - size_t i; struct respip_client_info* client_info; client_info = regional_alloc_init(region, cinfo, sizeof(*cinfo)); if(!client_info) @@ -932,20 +986,13 @@ mesh_copy_client_info(struct regional* r if(!client_info->tag_actions) return NULL; } - if(cinfo->tag_datas) { - client_info->tag_datas = regional_alloc_zero(region, - sizeof(struct config_strlist*)*cinfo->tag_datas_size); - if(!client_info->tag_datas) - return NULL; - for(i=0; itag_datas_size; i++) { - if(cinfo->tag_datas[i]) { - client_info->tag_datas[i] = cfg_region_strlist_copy( - region, cinfo->tag_datas[i]); - if(!client_info->tag_datas[i]) - return NULL; - } - } - } + /* tag_datas is owned by the matched acl_addr in config_file; its + * lifetime is until config reload, which tears down all mesh states + * first. Keep the original pointer so client_info_compare() + * can recognise two states from the same ACL entry. */ + /* fast reload insists on dropping the queries when interface-tag-data + * or access-control-tag-data are changed. */ + /* client_info->tag_datas already copied by regional_alloc_init above */ if(cinfo->view) { /* Do not copy the view pointer but store a name instead. * The name is looked up later when done, this means that @@ -955,6 +1002,11 @@ mesh_copy_client_info(struct regional* r cinfo->view->name); if(!client_info->view_name) return NULL; + } else if(cinfo->view_name) { + client_info->view_name = regional_strdup(region, + cinfo->view_name); + if(!client_info->view_name) + return NULL; } return client_info; } @@ -1022,6 +1074,7 @@ mesh_state_create(struct module_env* env mstate->s.no_cache_store = 0; mstate->s.need_refetch = 0; mstate->s.was_ratelimited = 0; + mstate->s.error_response_cache = 0; mstate->s.qstarttime = *env->now; /* init modules */ @@ -1044,6 +1097,18 @@ mesh_state_make_unique(struct mesh_state mstate->unique = mstate; } +/** pop a reply from the reply list, if there are any. */ +static struct mesh_reply* +mesh_reply_list_pop_first(struct mesh_state* mstate) +{ + if(mstate->reply_list) { + struct mesh_reply* r = mstate->reply_list; + mstate->reply_list = r->next; + return r; + } + return NULL; +} + void mesh_state_cleanup(struct mesh_state* mstate) { @@ -1059,17 +1124,30 @@ mesh_state_cleanup(struct mesh_state* ms } /* drop unsent replies */ if(!mstate->replies_sent) { - struct mesh_reply* rep = mstate->reply_list; + struct mesh_reply* rep; struct mesh_cb* cb; - /* in tcp_req_info, the mstates linked are removed, but - * the reply_list is now NULL, so the remove-from-empty-list - * takes no time and also it does not do the mesh accounting */ - mstate->reply_list = NULL; - for(; rep; rep=rep->next) { + /* Pop items from the list, that means there is no iterator. + * And then items can be removed from the reply list, from + * like comm_point_drop_reply and comm_point_close calls. + * As the tcp_req_info and http2 code drops the entire + * connection. That could delete mesh_reply items previous and + * after the current state. The previous items are already + * popped. And the next items can be altered, like to when a + * connection has more replies on the reply list. + * The current item is also popped so the code needs to + * remove its references. */ + while((rep = mesh_reply_list_pop_first(mstate)) != NULL) { infra_wait_limit_dec(mesh->env->infra_cache, &rep->query_reply, mesh->env->cfg); - if(rep->query_reply.c->use_h2) + if(rep->query_reply.c->tcp_req_info) + tcp_req_info_remove_mesh_state( + rep->query_reply.c->tcp_req_info, + mstate); + else if(rep->query_reply.c->use_h2) http2_stream_remove_mesh_state(rep->h2_stream); + else if(rep->query_reply.doq_stream) + doq_stream_remove_mesh_state( + rep->query_reply.doq_stream); comm_point_drop_reply(&rep->query_reply); log_assert(mesh->num_reply_addrs > 0); mesh->num_reply_addrs--; @@ -1152,8 +1230,7 @@ mesh_detect_cycle_found(struct module_qs { struct mesh_state* cyc_m = qstate->mesh_info; size_t counter = 0; - if(!dep_m) - return 0; + log_assert(dep_m); if(dep_m == cyc_m || find_in_subsub(dep_m, cyc_m, &counter)) { if(counter > MESH_MAX_SUBSUB) return 2; @@ -1190,28 +1267,26 @@ void mesh_detach_subs(struct module_qsta } int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq, - struct mesh_state** sub) + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq, struct mesh_state** sub) { /* find it, if not, create it */ struct mesh_area* mesh = qstate->env->mesh; - *sub = mesh_area_find(mesh, NULL, qinfo, qflags, - prime, valrec); - if(mesh_detect_cycle_found(qstate, *sub)) { - verbose(VERB_ALGO, "attach failed, cycle detected"); - return 0; - } + *sub = mesh_area_find(mesh, cinfo, qinfo, qflags, prime, valrec); if(!*sub) { #ifdef UNBOUND_DEBUG struct rbnode_type* n; #endif /* create a new one */ - *sub = mesh_state_create(qstate->env, qinfo, NULL, qflags, prime, - valrec); + *sub = mesh_state_create(qstate->env, qinfo, cinfo, qflags, + prime, valrec); if(!*sub) { log_err("mesh_attach_sub: out of memory"); return 0; } + /* inherit RPZ passthru from the parent so respip on the sub + * sees the same client-IP/qname PASSTHRU decision */ + (*sub)->s.rpz_passthru = qstate->rpz_passthru; #ifdef UNBOUND_DEBUG n = #else @@ -1230,18 +1305,25 @@ int mesh_add_sub(struct module_qstate* q rbtree_insert(&mesh->run, &(*sub)->run_node); log_assert(n != NULL); *newq = &(*sub)->s; - } else + } else { *newq = NULL; + if(mesh_detect_cycle_found(qstate, *sub)) { + verbose(VERB_ALGO, "attach failed, cycle detected"); + return 0; + } + } return 1; } int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq) + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq) { struct mesh_area* mesh = qstate->env->mesh; struct mesh_state* sub = NULL; int was_detached; - if(!mesh_add_sub(qstate, qinfo, qflags, prime, valrec, newq, &sub)) + if(!mesh_add_sub(qstate, qinfo, cinfo, qflags, prime, valrec, newq, + &sub)) return 0; was_detached = (sub->super_set.count == 0); if(!mesh_state_attachment(qstate->mesh_info, sub)) @@ -1429,12 +1511,6 @@ mesh_send_reply(struct mesh_state* m, in struct timeval end_time; struct timeval duration; int secure; - /* briefly set the replylist to null in case the - * meshsendreply calls tcpreqinfo sendreply that - * comm_point_drops because of size, and then the - * null stops the mesh state remove and thus - * reply_list modification and accounting */ - struct mesh_reply* rlist = m->reply_list; /* rpz: apply actions */ rcode = mesh_is_udp(r) && mesh_is_rpz_respip_tcponly_action(m) @@ -1460,6 +1536,10 @@ mesh_send_reply(struct mesh_state* m, in * for HTTP/2 stream to refer to mesh state, in case * connection gets cleanup before HTTP/2 stream close. */ r->h2_stream->mesh_state = NULL; +#ifdef HAVE_NGTCP2 + } else if(r->query_reply.doq_stream) { + r->query_reply.doq_stream->mesh_state = NULL; +#endif } /* send the reply */ /* We don't reuse the encoded answer if: @@ -1487,9 +1567,7 @@ mesh_send_reply(struct mesh_state* m, in sldns_buffer_write_at(r_buffer, 0, &r->qid, sizeof(uint16_t)); sldns_buffer_write_at(r_buffer, 12, r->qname, m->s.qinfo.qname_len); - m->reply_list = NULL; comm_point_send_reply(&r->query_reply); - m->reply_list = rlist; } else if(rcode) { m->s.qinfo.qname = r->qname; m->s.qinfo.local_alias = r->local_alias; @@ -1511,9 +1589,7 @@ mesh_send_reply(struct mesh_state* m, in } error_encode(r_buffer, rcode, &m->s.qinfo, r->qid, r->qflags, &r->edns); - m->reply_list = NULL; comm_point_send_reply(&r->query_reply); - m->reply_list = rlist; } else { size_t udp_size = r->edns.udp_size; r->edns.edns_version = EDNS_ADVERTISED_VERSION; @@ -1549,9 +1625,7 @@ mesh_send_reply(struct mesh_state* m, in error_encode(r_buffer, LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, r->qflags, &r->edns); } - m->reply_list = NULL; comm_point_send_reply(&r->query_reply); - m->reply_list = rlist; } infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply, m->s.env->cfg); @@ -1614,9 +1688,9 @@ static void dns_error_reporting(struct m opt = edns_opt_list_find(qstate->edns_opts_back_in, LDNS_EDNS_REPORT_CHANNEL); if(!opt) return; - agent_domain_len = opt->opt_len; agent_domain = opt->opt_data; - if(dname_valid(agent_domain, agent_domain_len) < 3) { + agent_domain_len = dname_valid(agent_domain, opt->opt_len); + if(agent_domain_len < 3) { /* The agent domain needs to be a valid dname that is not the * root; from RFC9567. */ return; @@ -1684,7 +1758,7 @@ static void dns_error_reporting(struct m log_query_info(VERB_ALGO, "DNS Error Reporting: generating report " "query for", &qinfo); - if(mesh_add_sub(qstate, &qinfo, BIT_RD, 0, 0, &newq, &sub)) { + if(mesh_add_sub(qstate, &qinfo, NULL, BIT_RD, 0, 0, &newq, &sub)) { qstate->env->mesh->num_dns_error_reports++; } return; @@ -1703,6 +1777,7 @@ void mesh_query_done(struct mesh_state* struct reply_info* rep = (mstate->s.return_msg? mstate->s.return_msg->rep:NULL); struct timeval tv = {0, 0}; + struct mesh_area* mesh = mstate->s.env->mesh; int i = 0; /* No need for the serve expired timer anymore; we are going to reply. */ if(mstate->s.serve_expired_data) { @@ -1723,32 +1798,53 @@ void mesh_query_done(struct mesh_state* } } - if(mstate->reply_list && mstate->s.env->cfg->dns_error_reporting) + if(mstate->reply_list && mstate->s.env->cfg->dns_error_reporting + && (!rep || rep->security != sec_status_secure)) dns_error_reporting(&mstate->s, rep); - for(r = mstate->reply_list; r; r = r->next) { - struct timeval old; - timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); - if(mstate->s.env->cfg->discard_timeout != 0 && - ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > - mstate->s.env->cfg->discard_timeout) { - /* Drop the reply, it is too old */ - /* briefly set the reply_list to NULL, so that the - * tcp req info cleanup routine that calls the mesh - * to deregister the meshstate for it is not done - * because the list is NULL and also accounting is not - * done there, but instead we do that here. */ - struct mesh_reply* reply_list = mstate->reply_list; - verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); - infra_wait_limit_dec(mstate->s.env->infra_cache, - &r->query_reply, mstate->s.env->cfg); - mstate->reply_list = NULL; - if(r->query_reply.c->use_h2) - http2_stream_remove_mesh_state(r->h2_stream); - comm_point_drop_reply(&r->query_reply); - mstate->reply_list = reply_list; - mstate->s.env->mesh->num_queries_discard_timeout++; - continue; + while((r = mesh_reply_list_pop_first(mstate)) != NULL) { + + /* it was not detached (because it had a reply list), could be now */ + if(!mstate->reply_list && !mstate->cb_list + && mstate->super_set.count == 0) { + mesh->num_detached_states++; + } + /* if not replies any more in mstate, it is no longer a reply_state */ + if(!mstate->reply_list && !mstate->cb_list) { + log_assert(mesh->num_reply_states > 0); + mesh->num_reply_states--; + } + if(mesh_is_udp(r)) { + /* For UDP queries, the old replies are discarded. + * This stops a large volume of old replies from + * building up. + * The stream replies, are not discarded. The + * stream is open, the other side is waiting. + * Some answer is needed, even if servfail, but the + * real reply is ready to go, so that is given. */ + struct timeval old; + timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); + if(mstate->s.env->cfg->discard_timeout != 0 && + ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > + mstate->s.env->cfg->discard_timeout) { + /* Drop the reply, it is too old */ + verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); + infra_wait_limit_dec(mstate->s.env->infra_cache, + &r->query_reply, mstate->s.env->cfg); + if(r->query_reply.c->tcp_req_info) + tcp_req_info_remove_mesh_state( + r->query_reply.c->tcp_req_info, + mstate); + else if(r->query_reply.c->use_h2) + http2_stream_remove_mesh_state(r->h2_stream); + else if(r->query_reply.doq_stream) + doq_stream_remove_mesh_state(r->query_reply.doq_stream); + comm_point_drop_reply(&r->query_reply); + log_assert(mstate->s.env->mesh->num_reply_addrs > 0); + mstate->s.env->mesh->num_reply_addrs--; + mstate->s.env->mesh->num_queries_discard_timeout++; + continue; + } } i++; @@ -1768,20 +1864,19 @@ void mesh_query_done(struct mesh_state* /* if this query is determined to be dropped during the * mesh processing, this is the point to take that action. */ if(mstate->s.is_drop) { - /* briefly set the reply_list to NULL, so that the - * tcp req info cleanup routine that calls the mesh - * to deregister the meshstate for it is not done - * because the list is NULL and also accounting is not - * done there, but instead we do that here. */ - struct mesh_reply* reply_list = mstate->reply_list; infra_wait_limit_dec(mstate->s.env->infra_cache, &r->query_reply, mstate->s.env->cfg); - mstate->reply_list = NULL; - if(r->query_reply.c->use_h2) { + if(r->query_reply.c->tcp_req_info) { + tcp_req_info_remove_mesh_state( + r->query_reply.c->tcp_req_info, mstate); + } else if(r->query_reply.c->use_h2) { http2_stream_remove_mesh_state(r->h2_stream); + } else if(r->query_reply.doq_stream) { + doq_stream_remove_mesh_state(r->query_reply.doq_stream); } comm_point_drop_reply(&r->query_reply); - mstate->reply_list = reply_list; + log_assert(mstate->s.env->mesh->num_reply_addrs > 0); + mstate->s.env->mesh->num_reply_addrs--; } else { struct sldns_buffer* r_buffer = r->query_reply.c->buffer; if(r->query_reply.c->tcp_req_info) { @@ -1820,18 +1915,6 @@ void mesh_query_done(struct mesh_state* } } - /* Mesh area accounting */ - if(mstate->reply_list) { - mstate->reply_list = NULL; - if(!mstate->reply_list && !mstate->cb_list) { - /* was a reply state, not anymore */ - log_assert(mstate->s.env->mesh->num_reply_states > 0); - mstate->s.env->mesh->num_reply_states--; - } - if(!mstate->reply_list && !mstate->cb_list && - mstate->super_set.count == 0) - mstate->s.env->mesh->num_detached_states++; - } mstate->replies_sent = 1; while((c = mstate->cb_list) != NULL) { @@ -1889,6 +1972,25 @@ struct mesh_state* mesh_area_find(struct return result; } +struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh, + struct respip_client_info* cinfo, struct query_info* qinfo, + uint16_t qflags, int prime, int valrec, void* unique_info) +{ + struct mesh_state key; + struct mesh_state* result; + + key.node.key = &key; + key.s.is_priming = prime; + key.s.is_valrec = valrec; + key.s.qinfo = *qinfo; + key.s.query_flags = qflags; + key.unique = (struct mesh_state*)unique_info; + key.s.client_info = cinfo; + + result = (struct mesh_state*)rbtree_search(&mesh->all, &key); + return result; +} + /** remove mesh state callback */ int mesh_state_del_cb(struct mesh_state* s, mesh_cb_func_type cb, void* cb_arg) { @@ -1910,7 +2012,7 @@ int mesh_state_del_cb(struct mesh_state* int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg, - uint16_t qid, uint16_t qflags) + uint16_t qid, uint16_t qflags, struct mesh_cb** result) { struct mesh_cb* r = regional_alloc(s->s.region, sizeof(struct mesh_cb)); @@ -1934,13 +2036,14 @@ int mesh_state_add_cb(struct mesh_state* r->qflags = qflags; r->next = s->cb_list; s->cb_list = r; + *result = r; return 1; } int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, struct comm_reply* rep, uint16_t qid, uint16_t qflags, - const struct query_info* qinfo) + const struct query_info* qinfo, struct mesh_reply** result) { struct mesh_reply* r = regional_alloc(s->s.region, sizeof(struct mesh_reply)); @@ -1960,6 +2063,10 @@ int mesh_state_add_reply(struct mesh_sta r->qid = qid; r->qflags = qflags; r->start_time = *s->s.env->now_tv; + if(s->reply_list == NULL && !s->has_first_reply_time) { + s->first_reply_time = r->start_time; + s->has_first_reply_time = 1; + } r->next = s->reply_list; r->qname = regional_alloc_init(s->s.region, qinfo->qname, s->s.qinfo.qname_len); @@ -1968,6 +2075,8 @@ int mesh_state_add_reply(struct mesh_sta if(rep->c->use_h2) r->h2_stream = rep->c->h2_stream; else r->h2_stream = NULL; + if(rep->c->type != comm_doq) + r->query_reply.doq_stream = NULL; /* Data related to local alias stored in 'qinfo' (if any) is ephemeral * and can be different for different original queries (even if the @@ -2015,6 +2124,7 @@ int mesh_state_add_reply(struct mesh_sta r->local_alias = NULL; s->reply_list = r; + *result = r; return 1; } @@ -2172,8 +2282,29 @@ void mesh_run(struct mesh_area* mesh, st enum module_ev ev, struct outbound_entry* e) { enum module_ext_state s; + int numrun = 0; verbose(VERB_ALGO, "mesh_run: start"); while(mstate) { + if(numrun++ > MESH_MAX_RUN_ITER) { + /* These modules are too much to activate, stop them.*/ + log_err("Too many module run iterations, deleting"); + while(mstate) { + /* notify supers */ + if(mstate->super_set.count > 0) { + verbose(VERB_ALGO, "notify supers of failure"); + mstate->s.return_msg = NULL; + mstate->s.return_rcode = LDNS_RCODE_SERVFAIL; + mesh_walk_supers(mesh, mstate); + } + mesh_state_delete(&mstate->s); + if(mesh->run.count > 0) { + /* pop random element off the runnable tree */ + mstate = (struct mesh_state*)mesh->run.root->key; + (void)rbtree_delete(&mesh->run, mstate); + } else mstate = NULL; + } + break; + } /* run the module */ fptr_ok(fptr_whitelist_mod_operate( mesh->mods.mod[mstate->s.curmod]->operate)); @@ -2272,6 +2403,7 @@ mesh_stats_clear(struct mesh_area* mesh) memset(&mesh->rpz_action[0], 0, sizeof(size_t)*UB_STATS_RPZ_ACTION_NUM); mesh->ans_nodata = 0; mesh->num_queries_discard_timeout = 0; + mesh->num_queries_replyaddr_limit = 0; mesh->num_queries_wait_limit = 0; mesh->num_dns_error_reports = 0; } @@ -2297,7 +2429,7 @@ mesh_detect_cycle(struct module_qstate* struct mesh_area* mesh = qstate->env->mesh; struct mesh_state* dep_m = NULL; dep_m = mesh_area_find(mesh, NULL, qinfo, flags, prime, valrec); - return mesh_detect_cycle_found(qstate, dep_m); + return dep_m?mesh_detect_cycle_found(qstate, dep_m):0; } void mesh_list_insert(struct mesh_state* m, struct mesh_state** fp, @@ -2324,7 +2456,8 @@ void mesh_list_remove(struct mesh_state* } void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, - struct comm_point* cp) + struct comm_point* cp, struct http2_stream* h2_stream, + struct doq_stream* doq_stream) { struct mesh_reply* n, *prev = NULL; n = m->reply_list; @@ -2332,7 +2465,9 @@ void mesh_state_remove_reply(struct mesh * there is no accounting twice */ if(!n) return; /* nothing to remove, also no accounting needed */ while(n) { - if(n->query_reply.c == cp) { + if(n->query_reply.c == cp + && (!h2_stream || n->h2_stream == h2_stream) + && (!doq_stream || n->query_reply.doq_stream == doq_stream)) { /* unlink it */ if(prev) prev->next = n->next; else m->reply_list = n->next; @@ -2341,6 +2476,14 @@ void mesh_state_remove_reply(struct mesh mesh->num_reply_addrs--; infra_wait_limit_dec(mesh->env->infra_cache, &n->query_reply, mesh->env->cfg); + /* We may be removing more than one http2 stream (they + * share the same comm_point); make sure the streams + * don't point back. */ + if(n->h2_stream) n->h2_stream->mesh_state = NULL; +#ifdef HAVE_NGTCP2 + if(n->query_reply.doq_stream) + n->query_reply.doq_stream->mesh_state = NULL; +#endif /* prev = prev; */ n = n->next; @@ -2361,7 +2504,6 @@ void mesh_state_remove_reply(struct mesh } } - static int apply_respip_action(struct module_qstate* qstate, const struct query_info* qinfo, struct respip_client_info* cinfo, @@ -2381,9 +2523,10 @@ apply_respip_action(struct module_qstate /* xxx_deny actions mean dropping the reply, unless the original reply * was redirected to response-ip data. */ - if((actinfo->action == respip_deny || + if(actinfo->action == respip_always_deny || + ((actinfo->action == respip_deny || actinfo->action == respip_inform_deny) && - *encode_repp == rep) + *encode_repp == rep)) *encode_repp = NULL; return 1; @@ -2448,12 +2591,15 @@ mesh_serve_expired_callback(void* arg) qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep, qstate->env->auth_zones)) { return; - } else if(partial_rep && - !respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep, + } else if(partial_rep) { + if(!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep, qstate->client_info, must_validate, &encode_rep, qstate->region, qstate->env->auth_zones, qstate->env->views, qstate->env->respip_set)) { - return; + return; + } + /* merge succeeded; final reply, no further alias pass */ + partial_rep = NULL; } if(!encode_rep || alias_rrset) { if(!encode_rep) { @@ -2464,6 +2610,7 @@ mesh_serve_expired_callback(void* arg) partial_rep = encode_rep; } } + msg->rep = encode_rep; /* We've found a partial reply ending with an * alias. Replace the lookup qinfo for the * alias target and lookup the cache again to @@ -2489,29 +2636,41 @@ mesh_serve_expired_callback(void* arg) if(verbosity >= VERB_ALGO) log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep); - for(r = mstate->reply_list; r; r = r->next) { - struct timeval old; - timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); - if(mstate->s.env->cfg->discard_timeout != 0 && + while((r = mesh_reply_list_pop_first(mstate)) != NULL) { + + /* it was not detached (because it had a reply list), could be now */ + if(!mstate->reply_list && !mstate->cb_list + && mstate->super_set.count == 0) { + mesh->num_detached_states++; + } + /* if not replies any more in mstate, it is no longer a reply_state */ + if(!mstate->reply_list && !mstate->cb_list) { + log_assert(mesh->num_reply_states > 0); + mesh->num_reply_states--; + } + if(mesh_is_udp(r)) { + struct timeval old; + timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); + if(mstate->s.env->cfg->discard_timeout != 0 && ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > mstate->s.env->cfg->discard_timeout) { /* Drop the reply, it is too old */ - /* briefly set the reply_list to NULL, so that the - * tcp req info cleanup routine that calls the mesh - * to deregister the meshstate for it is not done - * because the list is NULL and also accounting is not - * done there, but instead we do that here. */ - struct mesh_reply* reply_list = mstate->reply_list; verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); infra_wait_limit_dec(mstate->s.env->infra_cache, &r->query_reply, mstate->s.env->cfg); - mstate->reply_list = NULL; - if(r->query_reply.c->use_h2) + if(r->query_reply.c->tcp_req_info) + tcp_req_info_remove_mesh_state( + r->query_reply.c->tcp_req_info, mstate); + else if(r->query_reply.c->use_h2) http2_stream_remove_mesh_state(r->h2_stream); + else if(r->query_reply.doq_stream) + doq_stream_remove_mesh_state(r->query_reply.doq_stream); comm_point_drop_reply(&r->query_reply); - mstate->reply_list = reply_list; + log_assert(mstate->s.env->mesh->num_reply_addrs > 0); + mstate->s.env->mesh->num_reply_addrs--; mstate->s.env->mesh->num_queries_discard_timeout++; continue; + } } i++; @@ -2544,8 +2703,7 @@ mesh_serve_expired_callback(void* arg) if(r->query_reply.c->tcp_req_info) tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); /* mesh_send_reply removed mesh state from http2_stream. */ - infra_wait_limit_dec(mstate->s.env->infra_cache, - &r->query_reply, mstate->s.env->cfg); + /* mesh_send_reply decremented wait_limit. */ prev = r; prev_buffer = r_buffer; } @@ -2564,18 +2722,6 @@ mesh_serve_expired_callback(void* arg) } } - /* Mesh area accounting */ - if(mstate->reply_list) { - mstate->reply_list = NULL; - if(!mstate->reply_list && !mstate->cb_list) { - log_assert(mesh->num_reply_states > 0); - mesh->num_reply_states--; - if(mstate->super_set.count == 0) { - mesh->num_detached_states++; - } - } - } - while((c = mstate->cb_list) != NULL) { /* take this cb off the list; so that the list can be * changed, eg. by adds from the callback routine */ @@ -2608,13 +2754,30 @@ int mesh_jostle_exceeded(struct mesh_are } void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo, - uint16_t qflags, mesh_cb_func_type cb, void* cb_arg) + uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info) { struct mesh_state* s = NULL; s = mesh_area_find(mesh, NULL, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); - if(!s) return; - if(!mesh_state_del_cb(s, cb, cb_arg)) return; + if(s && mesh_state_del_cb(s, cb, cb_arg)) + goto removed; + if(unique_info) { + s = mesh_area_find_unique(mesh, NULL, qinfo, + qflags&(BIT_RD|BIT_CD), 0, 0, unique_info); + if(s && mesh_state_del_cb(s, cb, cb_arg)) + goto removed; + } + /* mesh_area_find builds key.unique=NULL and cannot match a state + * created with mesh_state_make_unique (e.g. subnetcache sets + * env->unique_mesh). Fall back to a linear scan; cb+cb_arg is an + * exact key (mesh_state_del_cb compares both). + * This works for both lookups for zonemd and for hostname authzone. */ + RBTREE_FOR(s, struct mesh_state*, &mesh->all) { + if(s->cb_list && mesh_state_del_cb(s, cb, cb_arg)) + goto removed; + } + return; +removed: /* It was in the list and removed. */ log_assert(mesh->num_reply_addrs > 0); mesh->num_reply_addrs--; Index: sbin/unwind/libunbound/services/mesh.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/mesh.h,v diff -u -p -r1.11 mesh.h --- sbin/unwind/libunbound/services/mesh.h 29 Sep 2025 14:53:38 -0000 1.11 +++ sbin/unwind/libunbound/services/mesh.h 21 Sep 2026 16:27:58 -0000 @@ -70,6 +70,13 @@ struct respip_client_info; #define MESH_MAX_ACTIVATION 10000 /** + * Maximum number of mesh state run items. These are different modules + * activated during a mesh run. Any more is likely an infinite loop + * in the module. It is then terminated, and states are deleted. + */ +#define MESH_MAX_RUN_ITER 10000 + +/** * Max number of references-to-references-to-references.. search size. * Any more is treated like 'too large', and the creation of a new * dependency is failed (so that no loops can be created). @@ -141,6 +148,8 @@ struct mesh_area { size_t rpz_action[UB_STATS_RPZ_ACTION_NUM]; /** stats, number of queries removed due to discard-timeout */ size_t num_queries_discard_timeout; + /** stats, number of queries removed due to replyaddr limit */ + size_t num_queries_replyaddr_limit; /** stats, number of queries removed due to wait-limit */ size_t num_queries_wait_limit; /** stats, number of dns error reports generated */ @@ -189,6 +198,12 @@ struct mesh_state { struct module_qstate s; /** the list of replies to clients for the results */ struct mesh_reply* reply_list; + /** if it has a first reply time */ + int has_first_reply_time; + /** wall-clock time the first client reply was attached; + * used by mesh_make_new_space() so duplicate retransmits + * cannot reset jostle aging. */ + struct timeval first_reply_time; /** the list of callbacks for the results */ struct mesh_cb* cb_list; /** set of superstates (that want this state's result) @@ -334,11 +349,14 @@ void mesh_new_client(struct mesh_area* m * @param cb_arg: callback user arg. * @param rpz_passthru: if true, the rpz passthru was previously found and * further rpz processing is stopped. + * @param unique_info: if nonnull, unique info is passed back to be used + * for the callback remove call. It does not need to be deallocated. * @return 0 on error. */ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, struct edns_data* edns, struct sldns_buffer* buf, - uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru); + uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru, + void** unique_info); /** * New prefetch message. Create new query state if needed. @@ -399,6 +417,8 @@ void mesh_detach_subs(struct module_qsta * @param qstate: the state to find mesh state, and that wants to receive * the results from the new subquery. * @param qinfo: what to query for (copied). + * @param cinfo: if non-NULL client specific info that may affect IP-based + * actions that apply to the query result. It is copied. * @param qflags: what flags to use (RD / CD flag or not). * @param prime: if it is a (stub) priming query. * @param valrec: if it is a validation recursion query (lookup of key, DS). @@ -407,7 +427,8 @@ void mesh_detach_subs(struct module_qsta * @return: false on error, true if success (and init may be needed). */ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq); + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq); /** * Add detached query. @@ -426,6 +447,8 @@ int mesh_attach_sub(struct module_qstate * @param qstate: the state to find mesh state, and that wants to receive * the results from the new subquery. * @param qinfo: what to query for (copied). + * @param cinfo: if non-NULL client specific info that may affect IP-based + * actions that apply to the query result. It is copied. * @param qflags: what flags to use (RD / CD flag or not). * @param prime: if it is a (stub) priming query. * @param valrec: if it is a validation recursion query (lookup of key, DS). @@ -435,8 +458,8 @@ int mesh_attach_sub(struct module_qstate * @return: false on error, true if success (and init may be needed). */ int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq, - struct mesh_state** sub); + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq, struct mesh_state** sub); /** * Query state is done, send messages to reply entries. @@ -531,6 +554,23 @@ struct mesh_state* mesh_area_find(struct uint16_t qflags, int prime, int valrec); /** + * Find a unique mesh state in the mesh area. Pass relevant flags. + * + * @param mesh: the mesh area to look in. + * @param cinfo: if non-NULL client specific info that may affect IP-based + * actions that apply to the query result. + * @param qinfo: what query + * @param qflags: if RD / CD bit is set or not. + * @param prime: if it is a priming query. + * @param valrec: if it is a validation-recursion query. + * @param unique_info: the unique info for the state. NULL can be passed. + * @return: mesh state or NULL if not found. + */ +struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh, + struct respip_client_info* cinfo, struct query_info* qinfo, + uint16_t qflags, int prime, int valrec, void* unique_info); + +/** * Setup attachment super/sub relation between super and sub mesh state. * The relation must not be present when calling the function. * Does not update stat items in mesh_area. @@ -549,11 +589,12 @@ int mesh_state_attachment(struct mesh_st * @param qid: ID of reply. * @param qflags: original query flags. * @param qinfo: original query info. + * @param result: the allocated reply structure, for rollback. * @return: 0 on alloc error. */ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, struct comm_reply* rep, uint16_t qid, uint16_t qflags, - const struct query_info* qinfo); + const struct query_info* qinfo, struct mesh_reply** result); /** * Create new callback structure and attach it to a mesh state. @@ -565,11 +606,12 @@ int mesh_state_add_reply(struct mesh_sta * @param cb_arg: callback user arg. * @param qid: ID of reply. * @param qflags: original query flags. + * @param result: the allocated callback structure, for rollback. * @return: 0 on alloc error. */ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, struct sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg, - uint16_t qid, uint16_t qflags); + uint16_t qid, uint16_t qflags, struct mesh_cb** result); /** * Run the mesh. Run all runnable mesh states. Which can create new @@ -670,9 +712,14 @@ void mesh_list_remove(struct mesh_state* * @param mesh: to update the counters. * @param m: the mesh state. * @param cp: the comm_point to remove from the list. + * @param h2_stream: if not NULL, it specifies the h2_stream to match + * for the delete. + * @param doq_stream: if not NULL, it specifies the doq_stream to match + * for the delete. */ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, - struct comm_point* cp); + struct comm_point* cp, struct http2_stream* h2_stream, + struct doq_stream* doq_stream); /** Callback for when the serve expired client timer has run out. Tries to * find an expired answer in the cache and reply that to the client. @@ -719,8 +766,13 @@ void mesh_respond_serve_expired(struct m * @param qflags: flags from client query. * @param cb: callback function. * @param cb_arg: callback user arg. + * @param unique_info: if not NULL, used to find a unique state for removal. */ void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo, - uint16_t qflags, mesh_cb_func_type cb, void* cb_arg); + uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info); + +/** Copy the client info to the query region. */ +struct respip_client_info* mesh_copy_client_info(struct regional* region, + struct respip_client_info* cinfo); #endif /* SERVICES_MESH_H */ Index: sbin/unwind/libunbound/services/modstack.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/modstack.c,v diff -u -p -r1.9 modstack.c --- sbin/unwind/libunbound/services/modstack.c 29 Sep 2025 14:53:38 -0000 1.9 +++ sbin/unwind/libunbound/services/modstack.c 21 Sep 2026 16:27:58 -0000 @@ -232,7 +232,7 @@ module_func_block* module_factory(const return NULL; } -int +int modstack_call_startup(struct module_stack* stack, const char* module_conf, struct module_env* env) { @@ -262,6 +262,7 @@ int modstack_call_init(struct module_stack* stack, const char* module_conf, struct module_env* env) { + const char* orig_module_conf = module_conf; int i, changed = 0; env->need_to_validate = 0; /* set by module init below */ for(i=0; inum; i++) { @@ -276,11 +277,13 @@ modstack_call_init(struct module_stack* changed = 1; } } - module_conf += strlen(stack->mod[i]->name); + /* Skip this module name in module_conf. */ + while(*module_conf && !isspace((unsigned char)*module_conf)) + module_conf++; } if(changed) { modstack_free(stack); - if(!modstack_config(stack, module_conf)) { + if(!modstack_config(stack, orig_module_conf)) { return 0; } } @@ -298,7 +301,7 @@ modstack_call_init(struct module_stack* return 1; } -void +void modstack_call_deinit(struct module_stack* stack, struct module_env* env) { int i; @@ -320,7 +323,7 @@ modstack_call_destartup(struct module_st } } -int +int modstack_find(struct module_stack* stack, const char* name) { int i; Index: sbin/unwind/libunbound/services/outside_network.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/outside_network.c,v diff -u -p -r1.20 outside_network.c --- sbin/unwind/libunbound/services/outside_network.c 29 Sep 2025 14:53:38 -0000 1.20 +++ sbin/unwind/libunbound/services/outside_network.c 21 Sep 2026 16:27:58 -0000 @@ -160,6 +160,19 @@ reuse_cmp_addrportssl(const void* key1, return 1; if(!r1->is_ssl && r2->is_ssl) return -1; + + /* compare tls_auth_name if SSL-enabled */ + if(r1->is_ssl) { + if(r1->tls_auth_name && !r2->tls_auth_name) + return 1; + if(!r1->tls_auth_name && r2->tls_auth_name) + return -1; + if(r1->tls_auth_name && r2->tls_auth_name) { + r = strcmp(r1->tls_auth_name, r2->tls_auth_name); + if(r != 0) + return r; + } + } return 0; } @@ -195,6 +208,7 @@ static void waiting_tcp_delete(struct waiting_tcp* w) { if(!w) return; + free(w->tls_auth_name); if(w->timer) comm_timer_delete(w->timer); free(w); @@ -531,7 +545,7 @@ reuse_tcp_insert(struct outside_network* /** find reuse tcp stream to destination for query, or NULL if none */ static struct reuse_tcp* reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr, - socklen_t addrlen, int use_ssl) + socklen_t addrlen, int use_ssl, char* tls_auth_name) { struct waiting_tcp key_w; struct pending_tcp key_p; @@ -545,8 +559,10 @@ reuse_tcp_find(struct outside_network* o key_p.c = &c; key_p.reuse.pending = &key_p; key_p.reuse.node.key = &key_p.reuse; - if(use_ssl) + if(use_ssl) { key_p.reuse.is_ssl = 1; + key_p.reuse.tls_auth_name = tls_auth_name; + } if(addrlen > (socklen_t)sizeof(key_p.reuse.addr)) return NULL; memmove(&key_p.reuse.addr, addr, addrlen); @@ -646,6 +662,7 @@ static int outnet_tcp_take_into_use(struct waiting_tcp* w) { struct pending_tcp* pend = w->outnet->tcp_free; + char* tls_auth_name = NULL; int s; log_assert(pend); log_assert(w->pkt); @@ -746,7 +763,22 @@ outnet_tcp_take_into_use(struct waiting_ comm_point_tcp_win_bio_cb(pend->c, pend->c->ssl); #endif pend->c->ssl_shake_state = comm_ssl_shake_write; - if(!set_auth_name_on_ssl(pend->c->ssl, w->tls_auth_name, + if(w->tls_auth_name) { + /* strdup the auth name, while not linked the list yet, + * in case of failure, easy cleanup. */ + tls_auth_name = strdup(w->tls_auth_name); + if(!tls_auth_name) { + log_err("out of memory: alloc tls auth name"); + pend->c->fd = s; +#ifdef HAVE_SSL + SSL_free(pend->c->ssl); +#endif + pend->c->ssl = NULL; + comm_point_close(pend->c); + return 0; + } + } + if(!set_auth_name_on_ssl(pend->c->ssl, tls_auth_name, w->outnet->tls_use_sni)) { pend->c->fd = s; #ifdef HAVE_SSL @@ -754,6 +786,7 @@ outnet_tcp_take_into_use(struct waiting_ #endif pend->c->ssl = NULL; comm_point_close(pend->c); + free(tls_auth_name); return 0; } } @@ -778,9 +811,20 @@ outnet_tcp_take_into_use(struct waiting_ if(pend->reuse.node.key) reuse_tcp_remove_tree_list(w->outnet, &pend->reuse); - if(pend->c->ssl) + if(pend->c->ssl) { pend->reuse.is_ssl = 1; - else pend->reuse.is_ssl = 0; + if(pend->reuse.tls_auth_name) + free(pend->reuse.tls_auth_name); + pend->reuse.tls_auth_name = tls_auth_name; + tls_auth_name = NULL; + } else { + pend->reuse.is_ssl = 0; + if(pend->reuse.tls_auth_name) + free(pend->reuse.tls_auth_name); + pend->reuse.tls_auth_name = NULL; + } + /* free tls auth name if nonNULL */ + free(tls_auth_name); /* insert in reuse by address tree if not already inserted there */ (void)reuse_tcp_insert(w->outnet, pend); reuse_tree_by_id_insert(&pend->reuse, w); @@ -969,7 +1013,7 @@ use_free_buffer(struct outside_network* (!outnet->tcp_reuse_first && !outnet->tcp_reuse_last) || (outnet->tcp_reuse_first && outnet->tcp_reuse_last)); reuse = reuse_tcp_find(outnet, &w->addr, w->addrlen, - w->ssl_upstream); + w->ssl_upstream, w->tls_auth_name); /* re-select an ID when moving to a new TCP buffer */ w->id = tcp_select_id(outnet, reuse); LDNS_ID_SET(w->pkt, w->id); @@ -1198,6 +1242,10 @@ decommission_pending_tcp(struct outside_ /* needs unlink from the reuse tree to get deleted */ reuse_tcp_remove_tree_list(outnet, &pend->reuse); } + if(pend->reuse.tls_auth_name) { + free(pend->reuse.tls_auth_name); + pend->reuse.tls_auth_name = NULL; + } /* free SSL structure after remove from outnet tcp reuse tree, * because the c->ssl null or not is used for sorting in the tree */ if(pend->c->ssl) { @@ -1433,7 +1481,7 @@ portcomm_loweruse(struct outside_network pif = pc->pif; log_assert(pif->inuse > 0); #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pif->avail_ports[pif->avail_total - pif->inuse] = pc->number; + shared_ports_return_port(outnet->shared_ports, pif->shpif, pc->number); #endif pif->inuse--; pif->out[pc->index] = pif->out[pif->inuse]; @@ -1647,19 +1695,25 @@ create_pending_tcp(struct outside_networ } /** setup an outgoing interface, ready address */ -static int setup_if(struct port_if* pif, const char* addrstr, - int* avail, int numavail, size_t numfd) +static int setup_if(struct port_if* pif, const char* addrstr, size_t numfd, + struct shared_ports* shp) { -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pif->avail_total = numavail; - pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int)); - if(!pif->avail_ports) - return 0; -#endif if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) && !netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen, &pif->pfxlen)) return 0; +#ifdef INT_MAX + if(numfd > (size_t)INT_MAX) { + log_err("num_ports exceeds INT_MAX"); + return 0; + } +#endif +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + pif->shpif = shared_ports_find_if(shp, &pif->addr, pif->addrlen, + pif->pfxlen); +#else + (void)shp; +#endif pif->maxout = (int)numfd; pif->inuse = 0; pif->out = (struct port_comm**)calloc(numfd, @@ -1673,12 +1727,12 @@ struct outside_network* outside_network_create(struct comm_base *base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, - struct ub_randstate* rnd, int use_caps_for_id, int* availports, - int numavailports, size_t unwanted_threshold, int tcp_mss, + struct ub_randstate* rnd, int use_caps_for_id, + size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv, int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout, - int tcp_auth_query_timeout) + int tcp_auth_query_timeout, struct shared_ports* shared_ports) { struct outside_network* outnet = (struct outside_network*) calloc(1, sizeof(struct outside_network)); @@ -1713,6 +1767,7 @@ outside_network_create(struct comm_base outnet->do_udp = do_udp; outnet->tcp_mss = tcp_mss; outnet->ip_dscp = dscp; + outnet->shared_ports = shared_ports; #ifndef S_SPLINT_S if(delayclose) { outnet->delayclose = 1; @@ -1723,11 +1778,18 @@ outside_network_create(struct comm_base if(udp_connect) { outnet->udp_connect = 1; } - if(numavailports == 0 || num_ports == 0) { + if(num_ports == 0) { log_err("no outgoing ports available"); outside_network_delete(outnet); return NULL; } +#ifdef INT_MAX + if(num_ports > (size_t)INT_MAX) { + log_err("outgoing num_ports exceeds INT_MAX"); + outside_network_delete(outnet); + return NULL; + } +#endif #ifndef INET6 do_ip6 = 0; #endif @@ -1784,13 +1846,13 @@ outside_network_create(struct comm_base /* allocate interfaces */ if(num_ifs == 0) { if(do_ip4 && !setup_if(&outnet->ip4_ifs[0], "0.0.0.0", - availports, numavailports, num_ports)) { + num_ports, outnet->shared_ports)) { log_err("malloc failed"); outside_network_delete(outnet); return NULL; } if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::", - availports, numavailports, num_ports)) { + num_ports, outnet->shared_ports)) { log_err("malloc failed"); outside_network_delete(outnet); return NULL; @@ -1801,7 +1863,7 @@ outside_network_create(struct comm_base for(i=0; iip6_ifs[done_6], ifs[i], - availports, numavailports, num_ports)){ + num_ports, outnet->shared_ports)){ log_err("malloc failed"); outside_network_delete(outnet); return NULL; @@ -1810,7 +1872,7 @@ outside_network_create(struct comm_base } if(!str_is_ip6(ifs[i]) && do_ip4) { if(!setup_if(&outnet->ip4_ifs[done_4], ifs[i], - availports, numavailports, num_ports)){ + num_ports, outnet->shared_ports)){ log_err("malloc failed"); outside_network_delete(outnet); return NULL; @@ -1888,9 +1950,6 @@ outside_network_delete(struct outside_ne comm_point_delete(pc->cp); free(pc); } -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - free(outnet->ip4_ifs[i].avail_ports); -#endif free(outnet->ip4_ifs[i].out); } free(outnet->ip4_ifs); @@ -1904,9 +1963,6 @@ outside_network_delete(struct outside_ne comm_point_delete(pc->cp); free(pc); } -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - free(outnet->ip6_ifs[i].avail_ports); -#endif free(outnet->ip6_ifs[i].out); } free(outnet->ip6_ifs); @@ -1922,6 +1978,10 @@ outside_network_delete(struct outside_ne * the tcp conn is working on */ decommission_pending_tcp(outnet, pend); } + if(pend->reuse.tls_auth_name) { + free(pend->reuse.tls_auth_name); + pend->reuse.tls_auth_name = NULL; + } comm_point_delete(outnet->tcp_conns[i]->c); free(outnet->tcp_conns[i]); outnet->tcp_conns[i] = NULL; @@ -2112,7 +2172,10 @@ static int select_ifport(struct outside_network* outnet, struct pending* pend, int num_if, struct port_if* ifs) { - int my_if, my_port, fd, portno, inuse, tries=0; + int my_if, fd, portno, inuse, tries=0; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int reused; +#endif struct port_if* pif; /* randomly select interface and port */ if(num_if == 0) { @@ -2126,37 +2189,35 @@ select_ifport(struct outside_network* ou my_if = ub_random_max(outnet->rnd, num_if); pif = &ifs[my_if]; #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - if(outnet->udp_connect) { - /* if we connect() we cannot reuse fds for a port */ - if(pif->inuse >= pif->avail_total) { - tries++; - if(tries < MAX_PORT_RETRY) - continue; - log_err("failed to find an open port, drop msg"); - return 0; - } - my_port = pif->inuse + ub_random_max(outnet->rnd, - pif->avail_total - pif->inuse); - } else { - my_port = ub_random_max(outnet->rnd, pif->avail_total); - if(my_port < pif->inuse) { - /* port already open */ - pend->pc = pif->out[my_port]; - verbose(VERB_ALGO, "using UDP if=%d port=%d", - my_if, pend->pc->number); - break; - } + if(!shared_ports_fetch_random(outnet->shared_ports, + pif->shpif, outnet->rnd, outnet->udp_connect, + pif->inuse, &portno, &reused)) { + tries++; + if(tries < MAX_PORT_RETRY) + continue; + log_err("failed to find an open port, drop msg"); + return 0; + } + if(reused) { + /* port already open */ + log_assert(portno < pif->inuse); + pend->pc = pif->out[portno]; + verbose(VERB_ALGO, "using UDP if=%d port=%d", + my_if, pend->pc->number); + break; } - /* try to open new port, if fails, loop to try again */ - log_assert(pif->inuse < pif->maxout); - portno = pif->avail_ports[my_port - pif->inuse]; #else - my_port = portno = 0; + portno = 0; #endif + /* try to open new port, if fails, loop to try again */ fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen, portno, &inuse, outnet->rnd, outnet->ip_dscp); if(fd == -1 && !inuse) { /* nonrecoverable error making socket */ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + shared_ports_return_port(outnet->shared_ports, + pif->shpif, portno); +#endif return 0; } if(fd != -1) { @@ -2173,6 +2234,11 @@ select_ifport(struct outside_network* ou pend->addrlen); } sock_close(fd); +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + shared_ports_return_port( + outnet->shared_ports, + pif->shpif, portno); +#endif return 0; } } @@ -2190,14 +2256,14 @@ select_ifport(struct outside_network* ou /* grab port in interface */ pif->out[pif->inuse] = pend->pc; -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pif->avail_ports[my_port - pif->inuse] = - pif->avail_ports[pif->avail_total-pif->inuse-1]; -#endif pif->inuse++; break; } /* failed, already in use */ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + shared_ports_return_port(outnet->shared_ports, pif->shpif, + portno); +#endif verbose(VERB_QUERY, "port %d in use, trying another", portno); tries++; if(tries == MAX_PORT_RETRY) { @@ -2447,7 +2513,7 @@ pending_tcp_query(struct serviced_query* /* find out if a reused stream to the target exists */ /* if so, take it into use */ reuse = reuse_tcp_find(sq->outnet, &sq->addr, sq->addrlen, - sq->ssl_upstream); + sq->ssl_upstream, sq->tls_auth_name); if(reuse) { log_reuse_tcp(VERB_CLIENT, "pending_tcp_query: found reuse", reuse); log_assert(reuse->pending); @@ -2489,7 +2555,16 @@ pending_tcp_query(struct serviced_query* w->cb = callback; w->cb_arg = callback_arg; w->ssl_upstream = sq->ssl_upstream; - w->tls_auth_name = sq->tls_auth_name; + if(sq->tls_auth_name) { + w->tls_auth_name = strdup(sq->tls_auth_name); + if(!w->tls_auth_name) { + comm_timer_delete(w->timer); + free(w); + return NULL; + } + } else { + w->tls_auth_name = NULL; + } w->timeout = timeout; w->id_node.key = NULL; w->write_wait_prev = NULL; @@ -3287,9 +3362,9 @@ serviced_udp_callback(struct comm_point* if(error == NETEVENT_TIMEOUT) { if(sq->status == serviced_query_UDP_EDNS && sq->last_rtt < 5000 && (serviced_query_udp_size(sq, serviced_query_UDP_EDNS_FRAG) < serviced_query_udp_size(sq, serviced_query_UDP_EDNS))) { - /* fallback to 1480/1280 */ + /* fallback to 1472/1232 */ sq->status = serviced_query_UDP_EDNS_FRAG; - log_name_addr(VERB_ALGO, "try edns1xx0", sq->qbuf+10, + log_name_addr(VERB_ALGO, "try edns1xx2", sq->qbuf+10, &sq->addr, sq->addrlen); if(!serviced_udp_send(sq, c->buffer)) { serviced_callbacks(sq, NETEVENT_CLOSED, c, rep); @@ -3426,7 +3501,8 @@ outnet_serviced_query(struct outside_net char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, struct module_qstate* qstate, comm_point_callback_type* callback, void* callback_arg, - sldns_buffer* buff, struct module_env* env, int* was_ratelimited) + sldns_buffer* buff, struct module_env* env, int* was_ratelimited, + int* ratelimit_incremented) { struct serviced_query* sq; struct service_callback* cb; @@ -3498,6 +3574,7 @@ outnet_serviced_query(struct outside_net "delegation point", zone, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN); } + *ratelimit_incremented = 1; } /* make new serviced query entry */ sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps, @@ -3579,13 +3656,16 @@ fd_for_dest(struct outside_network* outn { struct sockaddr_storage* addr; socklen_t addrlen; - int i, try, pnum, dscp; + int i, try, dscp; struct port_if* pif; /* create fd */ dscp = outnet->ip_dscp; for(try = 0; try<1000; try++) { int port = 0; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int reused = 0; +#endif int freebind = 0; int noproto = 0; int inuse = 0; @@ -3614,16 +3694,18 @@ fd_for_dest(struct outside_network* outn addr = &pif->addr; addrlen = pif->addrlen; #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pnum = ub_random_max(outnet->rnd, pif->avail_total); - if(pnum < pif->inuse) { - /* port already open */ - port = pif->out[pnum]->number; - } else { - /* unused ports in start part of array */ - port = pif->avail_ports[pnum - pif->inuse]; + if(!shared_ports_fetch_random(outnet->shared_ports, + pif->shpif, outnet->rnd, 0, pif->inuse, + &port, &reused)) { + /* try again, perhaps another interface. */ + continue; + } + if(reused) { + log_assert(port < pif->inuse); + port = pif->out[port]->number; } #else - pnum = port = 0; + port = 0; #endif if(addr_is_ip6(to_addr, to_addrlen)) { struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; @@ -3638,6 +3720,14 @@ fd_for_dest(struct outside_network* outn (struct sockaddr*)addr, addrlen, 1, &inuse, &noproto, 0, 0, 0, NULL, 0, freebind, 0, dscp); } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + if(!reused) { + /* Return the port to the pool, since the caller does + * not keep track of it, also have done fd, and bind. */ + shared_ports_return_port(outnet->shared_ports, + pif->shpif, port); + } +#endif if(fd != -1) { return fd; } @@ -3690,7 +3780,33 @@ setup_comm_ssl(struct comm_point* cp, st (void)SSL_set_tlsext_host_name(cp->ssl, host); } #endif -#ifdef HAVE_SSL_SET1_HOST +#ifdef HAVE_SSL_SET1_DNSNAME + if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) { + /* because we set SSL_VERIFY_PEER, in netevent in + * ssl_handshake, it'll check if the certificate + * verification has succeeded */ + /* SSL_VERIFY_PEER is set on the sslctx */ + /* and the certificates to verify with are loaded into + * it with SSL_load_verify_locations or + * SSL_CTX_set_default_verify_paths */ + /* setting the hostname makes openssl verify the + * host name in the x509 certificate in the + * SSL connection*/ + struct sockaddr_storage tmpaddr; + socklen_t tmpaddrlen = (socklen_t)sizeof(tmpaddr); + if(ipstrtoaddr(host, UNBOUND_DNS_PORT, &tmpaddr, &tmpaddrlen)) { + if(!SSL_set1_ipaddr(cp->ssl, host)) { + log_err("SSL_set1_ipaddr failed"); + return 0; + } + } else { + if(!SSL_set1_dnsname(cp->ssl, host)) { + log_err("SSL_set1_dnsname failed"); + return 0; + } + } + } +#elif defined(HAVE_SSL_SET1_HOST) if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) { /* because we set SSL_VERIFY_PEER, in netevent in * ssl_handshake, it'll check if the certificate @@ -3819,7 +3935,8 @@ outnet_comm_point_for_http(struct outsid /* outnet_tcp_connect has closed fd on error for us */ return 0; } - cp = comm_point_create_http_out(outnet->base, 65552, cb, cb_arg, + cp = comm_point_create_http_out(outnet->base, + sldns_buffer_capacity(outnet->udp_buff), cb, cb_arg, outnet->udp_buff); if(!cp) { log_err("malloc failure"); @@ -3868,11 +3985,7 @@ if_get_mem(struct port_if* pif) { size_t s; int i; - s = sizeof(*pif) + -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - sizeof(int)*pif->avail_total + -#endif - sizeof(struct port_comm*)*pif->maxout; + s = sizeof(*pif) + sizeof(struct port_comm*)*pif->maxout; for(i=0; iinuse; i++) s += sizeof(*pif->out[i]) + comm_point_get_mem(pif->out[i]->cp); @@ -3960,3 +4073,250 @@ serviced_get_mem(struct serviced_query* return s; } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION +/** Setup shared port interface */ +static int shared_ports_setup_if(struct shared_ports_if* shpif, char* str, + int* availports, int numavailports) +{ + shpif->avail_ports = (int*)memdup(availports, + (size_t)numavailports*sizeof(int)); + if(!shpif->avail_ports) + return 0; + shpif->avail_total = numavailports; + shpif->inuse = 0; + shpif->pfxlen = 0; + if(!ipstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, &shpif->addrlen) && + !netblockstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, + &shpif->addrlen, &shpif->pfxlen)) + return 0; + return 1; +} +#endif + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION +/** Allocate shared ports interfaces */ +static int shared_ports_alloc_ifs(struct shared_ports* shp, char** ifs, + int num_ifs, int do_ip4, int do_ip6, int* availports, + int numavailports) +{ +#ifndef INET6 + do_ip6 = 0; +#endif + calc_num46(ifs, num_ifs, do_ip4, do_ip6, + &shp->num_ip4, &shp->num_ip6); + if(shp->num_ip4 != 0) { + if(!(shp->ip4_ifs = (struct shared_ports_if*)calloc( + (size_t)shp->num_ip4, + sizeof(struct shared_ports_if)))) + return 0; + } + if(shp->num_ip6 != 0) { + if(!(shp->ip6_ifs = (struct shared_ports_if*)calloc( + (size_t)shp->num_ip6, + sizeof(struct shared_ports_if)))) + return 0; + } + if(num_ifs == 0) { + if(do_ip4 && !shared_ports_setup_if(&shp->ip4_ifs[0], + "0.0.0.0", availports, numavailports)) + return 0; + if(do_ip6 && !shared_ports_setup_if(&shp->ip6_ifs[0], + "::", availports, numavailports)) + return 0; + } else { + size_t done_4 = 0, done_6 = 0; + int i; + for(i=0; inum_ip6) { + if(!shared_ports_setup_if(&shp->ip6_ifs[done_6], + ifs[i], availports, numavailports)) + return 0; + done_6++; + } + if(!str_is_ip6(ifs[i]) && do_ip4 && + (int)done_4 < shp->num_ip4) { + if(!shared_ports_setup_if(&shp->ip4_ifs[done_4], + ifs[i], availports, numavailports)) + return 0; + done_4++; + } + } + } + return 1; +} +#endif + +struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4, + int do_ip6, int* availports, int numavailports) +{ + struct shared_ports* shp = calloc(1, sizeof(*shp)); + if(!shp) { + log_err("malloc failed"); + return NULL; + } + lock_basic_init(&shp->lock); + lock_protect(&shp->lock, &shp->ip4_ifs, sizeof(shp->ip4_ifs)); + lock_protect(&shp->lock, &shp->num_ip4, sizeof(shp->num_ip4)); + lock_protect(&shp->lock, &shp->ip6_ifs, sizeof(shp->ip6_ifs)); + lock_protect(&shp->lock, &shp->num_ip6, sizeof(shp->num_ip6)); + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + /* Allocate interfaces */ + lock_basic_lock(&shp->lock); + if(!shared_ports_alloc_ifs(shp, ifs, num_ifs, do_ip4, do_ip6, + availports, numavailports)) { + log_err("malloc failed"); + shared_ports_delete(shp); + return NULL; + } + lock_basic_unlock(&shp->lock); +#else + (void)ifs; (void)num_ifs; (void)do_ip4; (void)do_ip6; + (void)availports; (void)numavailports; +#endif + return shp; +} + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION +/** Delete shared ports interface structure */ +static void shared_ports_if_delete(struct shared_ports_if* shpif) +{ + if(!shpif) + return; + free(shpif->avail_ports); +} +#endif + +void shared_ports_delete(struct shared_ports* shp) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int i; +#endif + if(!shp) + return; + lock_basic_destroy(&shp->lock); +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + for(i=0; inum_ip4; i++) { + shared_ports_if_delete(&shp->ip4_ifs[i]); + } + free(shp->ip4_ifs); + for(i=0; inum_ip6; i++) { + shared_ports_if_delete(&shp->ip6_ifs[i]); + } + free(shp->ip6_ifs); +#endif + free(shp); +} + +struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp, + struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + struct shared_ports_if* ret, *ifs = NULL; + int i, num_ifs = 0; + lock_basic_lock(&shp->lock); + if(addr_is_ip6(addr, addrlen)) { + ifs = shp->ip6_ifs; + num_ifs = shp->num_ip6; + } else { + ifs = shp->ip4_ifs; + num_ifs = shp->num_ip4; + } + for(i=0; ilock); + return ret; + } + } + lock_basic_unlock(&shp->lock); + return NULL; +#else + (void)shp; (void)addr; (void)addrlen; (void)pfxlen; + return NULL; +#endif +} + +int shared_ports_fetch_random(struct shared_ports* shp, + struct shared_ports_if* shpif, struct ub_randstate* rnd, + int udp_connect, int reusenum, int* port, int* reused) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int portno = 0, my_port = 0; + if(!shpif) + return 0; +# ifdef THREADS_DISABLED + (void)shp; +# endif + lock_basic_lock(&shp->lock); + if(udp_connect) { + /* if we connect() we cannot reuse fds for a port. */ + if(shpif->inuse >= shpif->avail_total) { + lock_basic_unlock(&shp->lock); + return 0; + } + my_port = ub_random_max(rnd, + shpif->avail_total - shpif->inuse); + } else { + /* select from free ports and open ports on this thread. */ + if(shpif->inuse >= shpif->avail_total) { + lock_basic_unlock(&shp->lock); + if(reusenum == 0) { + return 0; + } + my_port = ub_random_max(rnd, reusenum); + *port = my_port; + *reused = 1; + return 1; + } + my_port = ub_random_max(rnd, shpif->avail_total - shpif->inuse + + reusenum); + if(my_port < reusenum) { + /* port already open */ + lock_basic_unlock(&shp->lock); + *port = my_port; + *reused = 1; + return 1; + } + my_port -= reusenum; + } + log_assert(shpif->inuse < shpif->avail_total); + log_assert(my_port >= 0 && my_port < shpif->avail_total); + portno = shpif->avail_ports[my_port]; + shpif->avail_ports[my_port] = + shpif->avail_ports[shpif->avail_total-shpif->inuse-1]; + shpif->inuse++; + lock_basic_unlock(&shp->lock); + *port = portno; + *reused = 0; + return 1; +#else + (void)shp; (void)shpif; (void)rnd; (void)udp_connect; + (void)reusenum; + *port = 0; + *reused = 0; + return 1; +#endif +} + +void shared_ports_return_port(struct shared_ports* shp, + struct shared_ports_if* shpif, int port) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + if(!shpif) + return; +# ifdef THREADS_DISABLED + (void)shp; +# endif + lock_basic_lock(&shp->lock); + log_assert(shpif->inuse > 0); + shpif->avail_ports[shpif->avail_total - shpif->inuse] = port; + shpif->inuse--; + lock_basic_unlock(&shp->lock); +#else + (void)shp; (void)shpif; (void)port; +#endif +} Index: sbin/unwind/libunbound/services/outside_network.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/outside_network.h,v diff -u -p -r1.11 outside_network.h --- sbin/unwind/libunbound/services/outside_network.h 14 Sep 2025 15:16:53 -0000 1.11 +++ sbin/unwind/libunbound/services/outside_network.h 21 Sep 2026 16:27:58 -0000 @@ -48,6 +48,10 @@ #include "util/regional.h" #include "util/netevent.h" #include "dnstap/dnstap_config.h" +#ifdef __QNX__ +/* For struct timeval */ +#include +#endif /* __QNX__ */ struct pending; struct pending_timeout; struct ub_randstate; @@ -66,6 +70,8 @@ struct module_env; struct module_qstate; struct query_info; struct config_file; +struct shared_ports; +struct shared_ports_if; /** * Send queries to outside servers and wait for answers from servers. @@ -115,6 +121,9 @@ struct outside_network { int udp_connect; /** number of udp packets sent. */ size_t num_udp_outgoing; + /** the shared ports structure, with random ports numbers. + * This is a reference to the member in the daemon structure. */ + struct shared_ports* shared_ports; /** array of outgoing IP4 interfaces */ struct port_if* ip4_ifs; @@ -207,11 +216,8 @@ struct port_if { int pfxlen; #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - /** the available ports array. These are unused. - * Only the first total-inuse part is filled. */ - int* avail_ports; - /** the total number of available ports (size of the array) */ - int avail_total; + /** the shared port numbers for this interface. */ + struct shared_ports_if* shpif; #endif /** array of the commpoints currently in use. @@ -242,6 +248,42 @@ struct port_comm { }; /** + * Shared ports, the list of ports shared across threads + */ +struct shared_ports { + /** mutex on the ports */ + lock_basic_type lock; + /** array of IP4 interfaces */ + struct shared_ports_if* ip4_ifs; + /** number of outgoing IP4 interfaces */ + int num_ip4; + /** array of IP6 interfaces */ + struct shared_ports_if* ip6_ifs; + /** number of outgoing IP6 interfaces */ + int num_ip6; +}; + +/** + * Shared ports for an interface. + */ +struct shared_ports_if { + /** address ready to allocate new socket (except port no). */ + struct sockaddr_storage addr; + /** length of addr field */ + socklen_t addrlen; + /** if a netblock, the prefix */ + int pfxlen; + + /** the available ports array. These are unused. + * Only the first total-inuse part is filled. */ + int* avail_ports; + /** the total number of available ports (size of the array) */ + int avail_total; + /** the number in use. */ + int inuse; +}; + +/** * Reuse TCP connection, still open can be used again. */ struct reuse_tcp { @@ -260,6 +302,9 @@ struct reuse_tcp { socklen_t addrlen; /** also key for tcp_reuse tree, if ssl is used */ int is_ssl; + /** If is_ssl is enabled, tls_auth_name is part of the key for + * tcp_reuse tree. If the string is NULL, it without a tls_auth_name */ + char* tls_auth_name; /** lru chain, so that the oldest can be removed to get a new * connection when all are in (re)use. oldest is last in list. * The lru only contains empty connections waiting for reuse, @@ -412,7 +457,7 @@ struct waiting_tcp { void* cb_arg; /** if it uses ssl upstream */ int ssl_upstream; - /** ref to the tls_auth_name from the serviced_query */ + /** owned copy of the tls_auth_name (malloced) */ char* tls_auth_name; /** the packet was involved in an error, to stop looping errors */ int error_count; @@ -493,7 +538,7 @@ struct serviced_query { serviced_query_UDP_EDNS_fallback, /** probe to test TCP noEDNS0 (EDNS gives FORMERRorNOTIMP) */ serviced_query_TCP_EDNS_fallback, - /** send UDP query with EDNS1480 (or 1280) */ + /** send UDP query with EDNS1472 (or 1232) */ serviced_query_UDP_EDNS_FRAG } /** variable with current status */ @@ -544,8 +589,6 @@ struct serviced_query { * @param infra: pointer to infra cached used for serviced queries. * @param rnd: stored to create random numbers for serviced queries. * @param use_caps_for_id: enable to use 0x20 bits to encode id randomness. - * @param availports: array of available ports. - * @param numavailports: number of available ports in array. * @param unwanted_threshold: when to take defensive action. * @param unwanted_action: the action to take. * @param unwanted_param: user parameter to action. @@ -560,17 +603,18 @@ struct serviced_query { * @param max_reuse_tcp_queries: max number of queries on a reuse connection. * @param tcp_reuse_timeout: timeout for REUSE entries in milliseconds. * @param tcp_auth_query_timeout: timeout in milliseconds for TCP queries to auth servers. + * @param shared_ports: the shared_ports structure. * @return: the new structure (with no pending answers) or NULL on error. */ struct outside_network* outside_network_create(struct comm_base* base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, - struct ub_randstate* rnd, int use_caps_for_id, int* availports, - int numavailports, size_t unwanted_threshold, int tcp_mss, + struct ub_randstate* rnd, int use_caps_for_id, + size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv, int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout, - int tcp_auth_query_timeout); + int tcp_auth_query_timeout, struct shared_ports* shared_ports); /** * Delete outside_network structure. @@ -653,6 +697,8 @@ void pending_delete(struct outside_netwo * @param env: the module environment. * @param was_ratelimited: it will signal back if the query failed to pass the * ratelimit check. + * @param ratelimit_incremented: set to true if the ratelimit counter + * was increased. * @return 0 on error, or pointer to serviced query that is used to answer * this serviced query may be shared with other callbacks as well. */ @@ -662,7 +708,8 @@ struct serviced_query* outnet_serviced_q char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, struct module_qstate* qstate, comm_point_callback_type* callback, void* callback_arg, - struct sldns_buffer* buff, struct module_env* env, int* was_ratelimited); + struct sldns_buffer* buff, struct module_env* env, int* was_ratelimited, + int* ratelimit_incremented); /** * Remove service query callback. @@ -811,6 +858,54 @@ struct comm_point* outnet_comm_point_for /** connect tcp connection to addr, 0 on failure */ int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen); + +/** + * Create new shared ports structure. + * @param ifs: interface names (or NULL for default interface). + * These interfaces must be able to access all authoritative servers. + * @param num_ifs: number of names in array ifs. + * @param do_ip4: service IP4. + * @param do_ip6: service IP6. + * @param availports: array of available ports. + * @param numavailports: number of available ports in array. + * @return new, or NULL on failure. + */ +struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4, + int do_ip6, int* availports, int numavailports); + +/** + * Delete shared ports structure. + * @param shp: shared ports structure. + */ +void shared_ports_delete(struct shared_ports* shp); + +/** Find interface in shared ports. */ +struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp, + struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen); + +/** + * Get a shared port from the list of random ports. + * @param shp: shared ports structure. + * @param shpif: the shared ports interface. + * @param rnd: used to make random numbers. + * @param udp_connect: set to true if no reuse is possible. + * @param reusenum: number of ports that can be reused (already open). + * @param port: the port number is returned. + * @param reused: if the port numer is reused, returned. + * @return false on failure. That can mean no more free ports to use. + */ +int shared_ports_fetch_random(struct shared_ports* shp, + struct shared_ports_if* shpif, struct ub_randstate* rnd, + int udp_connect, int reusenum, int* port, int* reused); + +/** + * Return a shared port to the list of random ports. + * @param shp: shared ports structure. + * @param shpif: the shared ports interface. + * @param port: port number to return to be used again. + */ +void shared_ports_return_port(struct shared_ports* shp, + struct shared_ports_if* shpif, int port); /** callback for incoming udp answers from the network */ int outnet_udp_cb(struct comm_point* c, void* arg, int error, Index: sbin/unwind/libunbound/services/rpz.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/rpz.c,v diff -u -p -r1.16 rpz.c --- sbin/unwind/libunbound/services/rpz.c 29 Sep 2025 14:53:38 -0000 1.16 +++ sbin/unwind/libunbound/services/rpz.c 21 Sep 2026 16:27:59 -0000 @@ -153,6 +153,7 @@ rpz_type_ignored(uint16_t rr_type) case LDNS_RR_TYPE_SOA: case LDNS_RR_TYPE_NS: case LDNS_RR_TYPE_DNAME: + case LDNS_RR_TYPE_ZONEMD: /* all DNSSEC-related RRs must be ignored */ case LDNS_RR_TYPE_DNSKEY: case LDNS_RR_TYPE_DS: @@ -720,13 +721,22 @@ rpz_insert_local_zones_trigger(struct lo char* rrstr = sldns_wire2str_rr(rr, rr_len); if(rrstr == NULL) { log_err("malloc error while inserting rpz nsdname trigger"); - free(dname); + if(!newzone) + free(dname); lock_rw_unlock(&lz->lock); return; } lock_rw_wrlock(&z->lock); - local_zone_enter_rr(z, dname, dnamelen, dnamelabs, rrtype, - rrclass, ttl, rdata, rdata_len, rrstr); + if(!local_zone_enter_rr(z, dname, dnamelen, dnamelabs, rrtype, + rrclass, ttl, rdata, rdata_len, rrstr)) { + log_err("rpz: could not enter local-data: %s", rrstr); + if(!newzone) + free(dname); + lock_rw_unlock(&z->lock); + lock_rw_unlock(&lz->lock); + free(rrstr); + return; + } lock_rw_unlock(&z->lock); free(rrstr); } @@ -804,8 +814,9 @@ rpz_insert_nsdname_trigger(struct rpz* r uint8_t* dname_stripped = NULL; size_t dnamelen_stripped = 0; - rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped, - &dnamelen_stripped); + if(!rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped, + &dnamelen_stripped)) + return; if(a == RPZ_INVALID_ACTION) { verbose(VERB_ALGO, "rpz: skipping invalid action"); free(dname_stripped); @@ -903,8 +914,8 @@ rpz_report_rrset_error(const char* msg, /* from localzone.c; difference is we don't have a dname */ static struct local_rrset* -rpz_clientip_new_rrset(struct regional* region, - struct clientip_synthesized_rr* raddr, uint16_t rrtype, uint16_t rrclass) +rpz_clientip_new_rrset(struct regional* region, uint16_t rrtype, + uint16_t rrclass) { struct packed_rrset_data* pd; struct local_rrset* rrset = (struct local_rrset*) @@ -913,8 +924,6 @@ rpz_clientip_new_rrset(struct regional* log_err("out of memory"); return NULL; } - rrset->next = raddr->data; - raddr->data = rrset; rrset->rrset = (struct ub_packed_rrset_key*) regional_alloc_zero(region, sizeof(*rrset->rrset)); if(rrset->rrset == NULL) { @@ -953,12 +962,18 @@ rpz_clientip_enter_rr(struct regional* r return 0; } - rrset = rpz_clientip_new_rrset(region, raddr, rrtype, rrclass); - if(raddr->data == NULL) { + rrset = rpz_clientip_new_rrset(region, rrtype, rrclass); + if(rrset == NULL) { return 0; } - return rrset_insert_rr(region, rrset->rrset->entry.data, rdata, rdata_len, ttl, ""); + if(!rrset_insert_rr(region, rrset->rrset->entry.data, rdata, rdata_len, ttl, "")) + return 0; + + /* Link in now that the allocations have succeeded. */ + rrset->next = raddr->data; + raddr->data = rrset; + return 1; } static int @@ -981,7 +996,6 @@ rpz_clientip_insert_trigger_rr(struct cl lock_rw_wrlock(&node->lock); lock_rw_unlock(&set->lock); - node->action = a; if(a == RPZ_LOCAL_DATA_ACTION) { if(!rpz_clientip_enter_rr(set->region, node, rrtype, rrclass, ttl, rdata, rdata_len)) { @@ -991,6 +1005,7 @@ rpz_clientip_insert_trigger_rr(struct cl } } + node->action = a; lock_rw_unlock(&node->lock); @@ -1976,8 +1991,9 @@ rpz_synthesize_nodata(struct rpz* ATTR_U 0, /* total */ sec_status_insecure, LDNS_EDE_NONE); - if(msg->rep) - msg->rep->authoritative = 1; + if(!msg->rep) + return NULL; + msg->rep->authoritative = 1; if(!rpz_add_soa(msg->rep, ms, az)) return NULL; return msg; @@ -2007,8 +2023,9 @@ rpz_synthesize_nxdomain(struct rpz* r, s 0, /* total */ sec_status_insecure, LDNS_EDE_NONE); - if(msg->rep) - msg->rep->authoritative = 1; + if(!msg->rep) + return NULL; + msg->rep->authoritative = 1; if(!rpz_add_soa(msg->rep, ms, az)) return NULL; return msg; @@ -2468,6 +2485,7 @@ rpz_callback_from_iterator_module(struct { struct auth_zones* az; struct auth_zone* a; + struct dns_msg* ret = NULL; struct clientip_synthesized_rr* raddr = NULL; struct rpz* r = NULL; struct local_zone* z = NULL; @@ -2511,13 +2529,11 @@ rpz_callback_from_iterator_module(struct z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones, is->qchase.qclass, &match); if(z != NULL) { - lock_rw_unlock(&a->lock); break; } raddr = rpz_delegation_point_ipbased_trigger_lookup(r, is); if(raddr != NULL) { - lock_rw_unlock(&a->lock); break; } lock_rw_unlock(&a->lock); @@ -2532,9 +2548,12 @@ rpz_callback_from_iterator_module(struct if(z) { lock_rw_unlock(&z->lock); } - return rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a); + ret = rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a); + } else { + ret = rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a); } - return rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a); + lock_rw_unlock(&a->lock); + return ret; } struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, Index: sbin/unwind/libunbound/services/cache/dns.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/cache/dns.c,v diff -u -p -r1.16 dns.c --- sbin/unwind/libunbound/services/cache/dns.c 14 Sep 2025 15:16:53 -0000 1.16 +++ sbin/unwind/libunbound/services/cache/dns.c 21 Sep 2026 16:27:59 -0000 @@ -43,6 +43,7 @@ #include "iterator/iter_utils.h" #include "validator/val_nsec.h" #include "validator/val_utils.h" +#include "iterator/iter_utils.h" #include "services/cache/dns.h" #include "services/cache/rrset.h" #include "util/data/msgparse.h" @@ -60,10 +61,10 @@ * @param rep: contains list of rrsets to store. * @param now: current time. * @param leeway: during prefetch how much leeway to update TTLs. - * This makes rrsets (other than type NS) timeout sooner so they get - * updated with a new full TTL. - * Type NS does not get this, because it must not be refreshed from the - * child domain, but keep counting down properly. + * This makes rrsets expire sooner so they get updated with a new full + * TTL. + * Child side type NS does get this but TTL checks are done using the time + * the query was created rather than the time the answer was received. * @param pside: if from parentside discovered NS, so that its NS is okay * in a prefetch situation to be updated (without becoming sticky). * @param qrep: update rrsets here if cache is better @@ -100,11 +101,20 @@ store_rrsets(struct module_env* env, str rep->ref[i].id != rep->ref[i].key->id) ck = NULL; else ck = packed_rrset_copy_region( - rep->ref[i].key, region, now); + rep->ref[i].key, region, + ((ntohs(rep->ref[i].key->rk.type)== + LDNS_RR_TYPE_NS && !pside)?qstarttime:now)); lock_rw_unlock(&rep->ref[i].key->entry.lock); if(ck) { /* use cached copy if memory allows */ qrep->rrsets[i] = ck; + ttl = ((struct packed_rrset_data*) + ck->entry.data)->ttl; + if(ttl < qrep->ttl) { + qrep->ttl = ttl; + qrep->prefetch_ttl = PREFETCH_TTL_CALC(qrep->ttl); + qrep->serve_expired_ttl = qrep->ttl + SERVE_EXPIRED_TTL; + } } } /* no break: also copy key item */ @@ -122,8 +132,8 @@ store_rrsets(struct module_env* env, str rep->ref[i].id == rep->ref[i].key->id) { ttl = ((struct packed_rrset_data*) rep->rrsets[i]->entry.data)->ttl; - if(ttl < min_ttl) min_ttl = ttl; - } + if(ttl < min_ttl) min_ttl = ttl; + } lock_rw_unlock(&rep->ref[i].key->entry.lock); } } @@ -169,10 +179,12 @@ dns_cache_store_msg(struct module_env* e /* there was a reply_info_sortref(rep) here but it seems to be * unnecessary, because the cache gets locked per rrset. */ - reply_info_set_ttls(rep, *env->now); + if((flags & DNSCACHE_STORE_EXPIRED_MSG_CACHEDB)) { + reply_info_absolute_ttls(rep, *env->now, *env->now - ttl); + } else reply_info_set_ttls(rep, *env->now); store_rrsets(env, rep, *env->now, leeway, pside, qrep, region, qstarttime); - if(ttl == 0 && !(flags & DNSCACHE_STORE_ZEROTTL)) { + if(ttl == 0) { /* we do not store the message, but we did store the RRs, * which could be useful for delegation information */ verbose(VERB_ALGO, "TTL 0: dropped msg from cache"); @@ -221,8 +233,15 @@ find_closest_of_type(struct module_env* /* snip off front part of qname until the type is found */ while(qnamelen > 0) { - if((rrset = rrset_cache_lookup(env->rrset_cache, qname, - qnamelen, searchtype, qclass, 0, now, 0))) { + rrset = rrset_cache_lookup(env->rrset_cache, qname, + qnamelen, searchtype, qclass, 0, now, 0); + if(!rrset && searchtype == LDNS_RR_TYPE_DNAME) + /* If not found, for type DNAME, try 0TTL stored, + * for its grace period. */ + rrset = rrset_cache_lookup(env->rrset_cache, qname, + qnamelen, searchtype, qclass, + PACKED_RRSET_UPSTREAM_0TTL, now, 0); + if(rrset) { uint8_t* origqname = qname; size_t origqnamelen = qnamelen; if(!noexpiredabove) @@ -259,6 +278,8 @@ find_closest_of_type(struct module_env* /* snip off front label */ lablen = *qname; + if(lablen == 0) + break; qname += lablen + 1; qnamelen -= lablen + 1; } @@ -272,8 +293,10 @@ addr_to_additional(struct ub_packed_rrse { if((msg->rep->rrsets[msg->rep->rrset_count] = packed_rrset_copy_region(rrset, region, now))) { + struct packed_rrset_data* d = rrset->entry.data; msg->rep->ar_numrrsets++; msg->rep->rrset_count++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); } } @@ -456,8 +479,10 @@ find_add_ds(struct module_env* env, stru /* add it to auth section. This is the second rrset. */ if((msg->rep->rrsets[msg->rep->rrset_count] = packed_rrset_copy_region(rrset, region, now))) { + struct packed_rrset_data* d = rrset->entry.data; msg->rep->ns_numrrsets++; msg->rep->rrset_count++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); } lock_rw_unlock(&rrset->entry.lock); } @@ -487,6 +512,8 @@ dns_msg_create(uint8_t* qname, size_t qn return NULL; /* integer overflow protection */ msg->rep->flags = BIT_QR; /* with QR, no AA */ msg->rep->qdcount = 1; + msg->rep->ttl = MAX_TTL; /* will be updated (brought down) while we add + * rrsets to the message */ msg->rep->reason_bogus = LDNS_EDE_NONE; msg->rep->rrsets = (struct ub_packed_rrset_key**) regional_alloc(region, @@ -497,24 +524,28 @@ dns_msg_create(uint8_t* qname, size_t qn } int -dns_msg_authadd(struct dns_msg* msg, struct regional* region, +dns_msg_authadd(struct dns_msg* msg, struct regional* region, struct ub_packed_rrset_key* rrset, time_t now) { - if(!(msg->rep->rrsets[msg->rep->rrset_count++] = + struct packed_rrset_data* d = rrset->entry.data; + if(!(msg->rep->rrsets[msg->rep->rrset_count++] = packed_rrset_copy_region(rrset, region, now))) return 0; msg->rep->ns_numrrsets++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); return 1; } int -dns_msg_ansadd(struct dns_msg* msg, struct regional* region, +dns_msg_ansadd(struct dns_msg* msg, struct regional* region, struct ub_packed_rrset_key* rrset, time_t now) { - if(!(msg->rep->rrsets[msg->rep->rrset_count++] = + struct packed_rrset_data* d = rrset->entry.data; + if(!(msg->rep->rrsets[msg->rep->rrset_count++] = packed_rrset_copy_region(rrset, region, now))) return 0; msg->rep->an_numrrsets++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); return 1; } @@ -556,8 +587,12 @@ dns_cache_find_delegation(struct module_ return NULL; } } - if(!delegpt_rrset_add_ns(dp, region, nskey, 0)) + if(!delegpt_rrset_add_ns(dp, region, nskey, 0, + deleg_port_number(env))) { + lock_rw_unlock(&nskey->entry.lock); log_err("find_delegation: addns out of memory"); + return NULL; + } lock_rw_unlock(&nskey->entry.lock); /* first unlock before next lookup*/ /* find and add DS/NSEC (if any) */ if(msg) @@ -585,6 +620,7 @@ gen_dns_msg(struct regional* region, str sizeof(struct reply_info) - sizeof(struct rrset_ref)); if(!msg->rep) return NULL; + msg->rep->ttl = MAX_TTL; msg->rep->reason_bogus = LDNS_EDE_NONE; msg->rep->reason_bogus_str = NULL; if(num > RR_COUNT_MAX) @@ -606,13 +642,13 @@ tomsg(struct module_env* env, struct que size_t i; int is_expired = 0; time_t now_control = now; - if(now > r->ttl) { + if(TTL_IS_EXPIRED(r->ttl, now)) { /* Check if we are allowed to serve expired */ if(!allow_expired || !reply_info_can_answer_expired(r, now)) return NULL; - /* Change the current time so we can pass the below TTL checks when - * serving expired data. */ - now_control = r->ttl - env->cfg->serve_expired_reply_ttl; + /* Change the current time so we can pass the below TTL checks + * when serving expired data. */ + now_control = 0; is_expired = 1; } @@ -620,15 +656,6 @@ tomsg(struct module_env* env, struct que if(!msg) return NULL; msg->rep->flags = r->flags; msg->rep->qdcount = r->qdcount; - msg->rep->ttl = is_expired - ?SERVE_EXPIRED_REPLY_TTL - :r->ttl - now; - if(r->prefetch_ttl > now) - msg->rep->prefetch_ttl = r->prefetch_ttl - now; - else - msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); - msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; - msg->rep->serve_expired_norec_ttl = 0; msg->rep->security = r->security; msg->rep->an_numrrsets = r->an_numrrsets; msg->rep->ns_numrrsets = r->ns_numrrsets; @@ -650,19 +677,36 @@ tomsg(struct module_env* env, struct que rrset_array_unlock(r->ref, r->rrset_count); return NULL; } - if(r->security == sec_status_secure && !reply_all_rrsets_secure(r)) { + if(r->security == sec_status_secure && !reply_an_ns_rrsets_secure(r)) { /* message rrsets have changed status, revalidate */ rrset_array_unlock(r->ref, r->rrset_count); return NULL; } for(i=0; irep->rrset_count; i++) { + struct packed_rrset_data* d; msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i], region, now); if(!msg->rep->rrsets[i]) { rrset_array_unlock(r->ref, r->rrset_count); return NULL; } + d = msg->rep->rrsets[i]->entry.data; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); + } + if(msg->rep->rrset_count < 1) { + msg->rep->ttl = is_expired + ?SERVE_EXPIRED_REPLY_TTL + :r->ttl - now; + if(r->prefetch_ttl > now) + msg->rep->prefetch_ttl = r->prefetch_ttl - now; + else + msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + } else { + /* msg->rep->ttl has been updated through the RRSets above */ + msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); } + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; + msg->rep->serve_expired_norec_ttl = 0; if(env) rrset_array_unlock_touch(env->rrset_cache, scratch, r->ref, r->rrset_count); @@ -675,10 +719,16 @@ struct dns_msg* dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region) { size_t i; + struct ub_packed_rrset_key** saved_rrsets; struct dns_msg* res = NULL; + size_t rep_alloc_size = sizeof(struct reply_info) + - sizeof(struct rrset_ref); /* this is the size of res->rep + allocated in gen_dns_msg() */ res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count); if(!res) return NULL; - *res->rep = *origin->rep; + saved_rrsets = res->rep->rrsets; /* save rrsets alloc by gen_dns_msg */ + memcpy(res->rep, origin->rep, rep_alloc_size); + res->rep->rrsets = saved_rrsets; if(origin->rep->reason_bogus_str) { res->rep->reason_bogus_str = regional_strdup(region, origin->rep->reason_bogus_str); @@ -701,7 +751,7 @@ rrset_msg(struct ub_packed_rrset_key* rr struct dns_msg* msg; struct packed_rrset_data* d = (struct packed_rrset_data*) rrset->entry.data; - if(now > d->ttl) + if(TTL_IS_EXPIRED(d->ttl, now)) return NULL; msg = gen_dns_msg(region, q, 1); /* only the CNAME (or other) RRset */ if(!msg) @@ -736,8 +786,20 @@ synth_dname_msg(struct ub_packed_rrset_k rrset->entry.data; uint8_t* newname, *dtarg = NULL; size_t newlen, dtarglen; - if(now > d->ttl) - return NULL; + time_t rr_ttl; + int graceperiod = 0; + if(TTL_IS_EXPIRED(d->ttl, now)) { + /* Allow TTL=0 DNAME from upstream within grace period */ + if(!(rrset->rk.flags & PACKED_RRSET_UPSTREAM_0TTL)) + return NULL; + rr_ttl = 0; + /* Since PACKED_RRSET_UPSTREAM_0TTL set the flag that + * the grace period has been applied, this stops the rrset + * from getting stored back into the cache with a bigger TTL.*/ + graceperiod = 1; + } else { + rr_ttl = d->ttl - now; + } /* only allow validated (with DNSSEC) DNAMEs used from cache * for insecure DNAMEs, query again. */ *sec_status = d->security; @@ -749,7 +811,7 @@ synth_dname_msg(struct ub_packed_rrset_k msg->rep->flags = BIT_QR; /* reply, no AA, no error */ msg->rep->authoritative = 0; /* reply stored in cache can't be authoritative */ msg->rep->qdcount = 1; - msg->rep->ttl = d->ttl - now; + msg->rep->ttl = rr_ttl; msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; msg->rep->serve_expired_norec_ttl = 0; @@ -762,6 +824,8 @@ synth_dname_msg(struct ub_packed_rrset_k msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now); if(!msg->rep->rrsets[0]) /* copy DNAME */ return NULL; + if(graceperiod) + msg->rep->rrsets[0]->rk.flags |= PACKED_RRSET_0TTL_GRACE; /* synth CNAME rrset */ get_cname_target(rrset, &dtarg, &dtarglen); if(!dtarg) @@ -801,7 +865,7 @@ synth_dname_msg(struct ub_packed_rrset_k if(!newd) return NULL; ck->entry.data = newd; - newd->ttl = d->ttl - now; /* RFC6672: synth CNAME TTL == DNAME TTL */ + newd->ttl = rr_ttl; /* RFC6672: synth CNAME TTL == DNAME TTL */ newd->count = 1; newd->rrsig_count = 0; newd->trust = rrset_trust_ans_noAA; @@ -844,6 +908,8 @@ fill_any(struct module_env* env, /* set NOTIMPL for RFC 8482 */ msg->rep->flags |= LDNS_RCODE_NOTIMPL; msg->rep->security = sec_status_indeterminate; + msg->rep->ttl = 1; /* empty NOTIMPL response will never be + * updated with rrsets, set TTL to 1 */ return msg; } @@ -1013,7 +1079,7 @@ dns_cache_lookup(struct module_env* env, if(env->cfg->harden_below_nxdomain) { while(!dname_is_root(k.qname)) { if(dpname && dpnamelen - && !dname_subdomain_c(k.qname, dpname)) + && !dname_strict_subdomain_c(k.qname, dpname)) break; /* no synth nxdomain above the stub */ dname_remove_label(&k.qname, &k.qname_len); h = query_info_hash(&k, flags); @@ -1069,7 +1135,7 @@ dns_cache_store(struct module_env* env, msgqinf->qclass, flags, 0, 1); if(e) { struct reply_info* cached = e->entry.data; - if(cached->ttl < *env->now + if(TTL_IS_EXPIRED(cached->ttl, *env->now) && reply_info_could_use_expired(cached, *env->now) /* If we are validating make sure only * validating modules can update such messages. Index: sbin/unwind/libunbound/services/cache/dns.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/cache/dns.h,v diff -u -p -r1.7 dns.h --- sbin/unwind/libunbound/services/cache/dns.h 14 Sep 2025 15:16:53 -0000 1.7 +++ sbin/unwind/libunbound/services/cache/dns.h 21 Sep 2026 16:27:59 -0000 @@ -53,7 +53,7 @@ struct delegpt; * Must be an unsigned 32-bit value larger than 0xffff */ /** Allow caching a DNS message with a zero TTL. */ -#define DNSCACHE_STORE_ZEROTTL 0x100000 +#define DNSCACHE_STORE_EXPIRED_MSG_CACHEDB 0x100000 /** * Region allocated message reply Index: sbin/unwind/libunbound/services/cache/infra.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/cache/infra.c,v diff -u -p -r1.13 infra.c --- sbin/unwind/libunbound/services/cache/infra.c 29 Sep 2025 14:53:38 -0000 1.13 +++ sbin/unwind/libunbound/services/cache/infra.c 21 Sep 2026 16:27:59 -0000 @@ -1269,7 +1269,8 @@ int infra_wait_limit_allowed(struct infr int cookie_valid, struct config_file* cfg) { struct lruhash_entry* entry; - if(cfg->wait_limit == 0) + if(cfg->wait_limit == 0 || + (cookie_valid && cfg->wait_limit_cookie == 0)) return 1; entry = infra_find_ip_ratedata(infra, &rep->client_addr, Index: sbin/unwind/libunbound/services/cache/rrset.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/services/cache/rrset.c,v diff -u -p -r1.5 rrset.c --- sbin/unwind/libunbound/services/cache/rrset.c 29 Sep 2025 14:53:38 -0000 1.5 +++ sbin/unwind/libunbound/services/cache/rrset.c 21 Sep 2026 16:27:59 -0000 @@ -50,6 +50,7 @@ #include "util/regional.h" #include "util/alloc.h" #include "util/net_help.h" +#include "validator/val_utils.h" void rrset_markdel(void* key) @@ -126,12 +127,13 @@ rrset_cache_touch(struct rrset_cache* r, /** see if rrset needs to be updated in the cache */ static int -need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) +need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns, + int a_aaaa) { struct packed_rrset_data* newd = (struct packed_rrset_data*)nd; struct packed_rrset_data* cached = (struct packed_rrset_data*)cd; /* o if new data is expired, cached data is better */ - if( newd->ttl < timenow && timenow <= cached->ttl) + if( TTL_IS_EXPIRED(newd->ttl, timenow) && !TTL_IS_EXPIRED(cached->ttl, timenow)) return 0; /* o store if rrset has been validated * everything better than bogus data @@ -146,13 +148,27 @@ need_to_update_rrset(void* nd, void* cd, if( newd->trust > cached->trust ) { /* if the cached rrset is bogus, and new is equal, * do not update the TTL - let it expire. */ - if(equal && cached->ttl >= timenow && + if(equal && !TTL_IS_EXPIRED(cached->ttl, timenow) && cached->security == sec_status_bogus) return 0; + /* ghost-domain: never let an NS overwrite extend lifetime + * past the entry it replaces, regardless of trust. */ + /* Also for A/AAAA and it is glue. */ + if((ns || + (a_aaaa && cached->trust==rrset_trust_add_noAA)) + && !TTL_IS_EXPIRED(cached->ttl, timenow) && + newd->ttl > cached->ttl) { + size_t i; + if(a_aaaa) newd->trust=rrset_trust_add_noAA; + newd->ttl = cached->ttl; + for(i=0; i<(newd->count+newd->rrsig_count); i++) + if(newd->rr_ttl[i] > newd->ttl) + newd->rr_ttl[i] = newd->ttl; + } return 1; } /* o item in cache has expired */ - if( cached->ttl < timenow ) + if( TTL_IS_EXPIRED(cached->ttl, timenow) ) return 1; /* o same trust, but different in data - insert it */ if( newd->trust == cached->trust && !equal ) { @@ -199,6 +215,13 @@ rrset_cache_update(struct rrset_cache* r int equal = 0; log_assert(ref->id != 0 && k->id != 0); log_assert(k->rk.dname != NULL); + if((k->rk.flags&PACKED_RRSET_0TTL_GRACE) !=0) { + log_nametypeclass(VERB_ALGO, "rrset store of PACKED_RRSET_0TTL_GRACE rrset skipped", k->rk.dname, rrset_type, ntohs(k->rk.rrset_class)); + ub_packed_rrset_parsedelete(k, alloc); + return 0; /* Do not store 0TTL items after apply of + the grace ttl amount. + This means the ref was not changed by the call. */ + } /* looks up item with a readlock - no editing! */ if((e=slabhash_lookup(&r->table, h, k, 0)) != 0) { /* return id and key as they will be used in the cache @@ -213,7 +236,8 @@ rrset_cache_update(struct rrset_cache* r equal = rrsetdata_equal((struct packed_rrset_data*)k->entry. data, (struct packed_rrset_data*)e->data); if(!need_to_update_rrset(k->entry.data, e->data, timenow, - equal, (rrset_type==LDNS_RR_TYPE_NS))) { + equal, (rrset_type==LDNS_RR_TYPE_NS), + (rrset_type==LDNS_RR_TYPE_A || rrset_type==LDNS_RR_TYPE_AAAA))) { /* cache is superior, return that value */ lock_rw_unlock(&e->lock); ub_packed_rrset_parsedelete(k, alloc); @@ -245,12 +269,45 @@ rrset_cache_update(struct rrset_cache* r return 0; } +/** See if the name is a within signer authority */ +static int +dname_subdomain_rrsig_signers(uint8_t* dname, + struct ub_packed_rrset_key* rrset) +{ + struct packed_rrset_data* d = (struct packed_rrset_data*) + rrset->entry.data; + size_t i; + if(!d || !d->rrsig_count) + return 0; + for(i=0; irrsig_count; i++) { + uint8_t* sname = NULL; + size_t slen = 0; + rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i], + &sname, &slen); + if(!sname || !slen) + return 0; /* malformed */ + if(!dname_subdomain_c(dname, sname)) + return 0; /* not a subdomain */ + } + return 1; +} + void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache, struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len, struct alloc_cache* alloc, time_t timenow) { struct rrset_ref ref; uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3]; + uint8_t* new_dname; + size_t new_dname_len; + + /* See if the RRSIG signer name allows this wildcard, + * the new rrset should fall within the zone of the RRSIG signer(s). */ + if(!dname_subdomain_rrsig_signers(ce, rrset)) { + verbose(VERB_ALGO, "wildcard canonical parent outside signer authority"); + return; + } + rrset = packed_rrset_copy_alloc(rrset, alloc, timenow); if(!rrset) { log_err("malloc failure in rrset_cache_update_wildcard"); @@ -262,14 +319,16 @@ void rrset_cache_update_wildcard(struct wc_dname[1] = (uint8_t)'*'; memmove(wc_dname+2, ce, ce_len); - free(rrset->rk.dname); - rrset->rk.dname_len = ce_len + 2; - rrset->rk.dname = (uint8_t*)memdup(wc_dname, rrset->rk.dname_len); - if(!rrset->rk.dname) { - alloc_special_release(alloc, rrset); + new_dname_len = ce_len + 2; + new_dname = (uint8_t*)memdup(wc_dname, new_dname_len); + if(!new_dname) { + ub_packed_rrset_parsedelete(rrset, alloc); log_err("memdup failure in rrset_cache_update_wildcard"); return; } + free(rrset->rk.dname); + rrset->rk.dname = new_dname; + rrset->rk.dname_len = new_dname_len; rrset->entry.hash = rrset_key_hash(&rrset->rk); ref.key = rrset; @@ -278,6 +337,10 @@ void rrset_cache_update_wildcard(struct (void)rrset_cache_update(rrset_cache, &ref, alloc, timenow); } +/** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache). + * Allows synthesis from cache within this window to reduce recursion load. */ +#define DNAME_TTL0_GRACE_SECONDS 1 + struct ub_packed_rrset_key* rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow, @@ -300,27 +363,36 @@ rrset_cache_lookup(struct rrset_cache* r /* check TTL */ struct packed_rrset_data* data = (struct packed_rrset_data*)e->data; - if(timenow > data->ttl) { - lock_rw_unlock(&e->lock); - return NULL; + struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key; + if(TTL_IS_EXPIRED(data->ttl, timenow)) { + /* Allow TTL=0 DNAME within grace period for synthesis */ + if(qtype == LDNS_RR_TYPE_DNAME && + (k->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) && + (timenow - data->ttl_add) <= DNAME_TTL0_GRACE_SECONDS) { + /* within grace: allow for synthesis */ + } else { + lock_rw_unlock(&e->lock); + return NULL; + } } /* we're done */ - return (struct ub_packed_rrset_key*)e->key; + return k; } return NULL; } -int +int rrset_array_lock(struct rrset_ref* ref, size_t count, time_t timenow) { size_t i; + struct packed_rrset_data* d; for(i=0; i0 && ref[i].key == ref[i-1].key) continue; /* only lock items once */ lock_rw_rdlock(&ref[i].key->entry.lock); - if(ref[i].id != ref[i].key->id || timenow > - ((struct packed_rrset_data*)(ref[i].key->entry.data)) - ->ttl) { + d = ref[i].key->entry.data; + if(ref[i].id != ref[i].key->id || + TTL_IS_EXPIRED(d->ttl, timenow)) { /* failure! rollback our readlocks */ rrset_array_unlock(ref, i+1); return 0; @@ -511,7 +583,7 @@ rrset_cache_expired_above(struct rrset_c *qnamelen, searchtype, qclass, 0, 0, 0))) { struct packed_rrset_data* data = (struct packed_rrset_data*)rrset->entry.data; - if(now > data->ttl) { + if(TTL_IS_EXPIRED(data->ttl, now)) { /* it is expired, this is not wanted */ lock_rw_unlock(&rrset->entry.lock); log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass); Index: sbin/unwind/libunbound/sldns/keyraw.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/sldns/keyraw.c,v diff -u -p -r1.7 keyraw.c --- sbin/unwind/libunbound/sldns/keyraw.c 29 Sep 2025 14:53:38 -0000 1.7 +++ sbin/unwind/libunbound/sldns/keyraw.c 21 Sep 2026 16:27:59 -0000 @@ -67,19 +67,28 @@ sldns_rr_dnskey_key_size_raw(const unsig case LDNS_RSASHA512: #endif if (len > 0) { + size_t nlen, offset; if (keydata[0] == 0) { /* big exponent */ if (len > 3) { memmove(&int16, keydata + 1, 2); exp = ntohs(int16); - return (len - exp - 3)*8; + offset = 3; } else { return 0; } } else { exp = keydata[0]; - return (len-exp-1)*8; + offset = 1; } + if(exp+offset > len) + return 0; + nlen = len - exp - offset; + /* prefixed zeroes mean a smaller value */ + while(nlen > 0 && + keydata[len-nlen] == 0) + nlen--; + return nlen*8; } else { return 0; } Index: sbin/unwind/libunbound/sldns/rrdef.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/sldns/rrdef.h,v diff -u -p -r1.8 rrdef.h --- sbin/unwind/libunbound/sldns/rrdef.h 14 Sep 2025 15:16:53 -0000 1.8 +++ sbin/unwind/libunbound/sldns/rrdef.h 21 Sep 2026 16:27:59 -0000 @@ -480,11 +480,13 @@ enum sldns_enum_ede_code LDNS_EDE_TOO_EARLY = 26, LDNS_EDE_UNSUPPORTED_NSEC3_ITERATIONS = 27, LDNS_EDE_BADPROXYPOLICY = 28, - LDNS_EDE_SYNTHESIZED = 29 + LDNS_EDE_SYNTHESIZED = 29, + LDNS_EDE_INVALID_QUERY_TYPE = 30 }; typedef enum sldns_enum_ede_code sldns_ede_code; #define LDNS_EDNS_MASK_DO_BIT 0x8000 +#define LDNS_EDNS_MASK_CO_BIT 0x4000 /** TSIG and TKEY extended rcodes (16bit), 0-15 are the normal rcodes. */ #define LDNS_TSIG_ERROR_NOERROR 0 Index: sbin/unwind/libunbound/sldns/str2wire.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/sldns/str2wire.c,v diff -u -p -r1.12 str2wire.c --- sbin/unwind/libunbound/sldns/str2wire.c 29 Sep 2025 14:53:38 -0000 1.12 +++ sbin/unwind/libunbound/sldns/str2wire.c 21 Sep 2026 16:27:59 -0000 @@ -842,7 +842,8 @@ rrinternal_parse_rdata(sldns_buffer* str sldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10)); *rr_len = rr_cur_len; /* SVCB/HTTPS handling */ - if (rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) { + if ((rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) + && !was_unknown_rr_format) { size_t rdata_len = rr_cur_len - dname_len - 10; uint8_t *rdata = rr+dname_len + 10; @@ -1201,7 +1202,7 @@ sldns_str2wire_svcbparam_ipv4hint(const { size_t count; char ip_str[INET_ADDRSTRLEN+1]; - char *next_ip_str; + const char *next_ip_str; size_t i; for (i = 0, count = 1; val[i]; i++) { @@ -1256,7 +1257,7 @@ sldns_str2wire_svcbparam_ipv6hint(const { size_t count; char ip_str[INET6_ADDRSTRLEN+1]; - char *next_ip_str; + const char *next_ip_str; size_t i; for (i = 0, count = 1; val[i]; i++) { @@ -1317,7 +1318,7 @@ static int sldns_str2wire_svcbparam_mandatory(const char* val, uint8_t* rd, size_t* rd_len) { size_t i, count, val_len; - char* next_key; + const char* next_key; val_len = strlen(val); @@ -1410,6 +1411,7 @@ sldns_str2wire_svcbparam_ech_value(const return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; sldns_write_uint16(rd, SVCB_KEY_ECH); sldns_write_uint16(rd + 2, 0); + *rd_len = 4; return LDNS_WIREPARSE_ERR_OK; } Index: sbin/unwind/libunbound/sldns/wire2str.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/sldns/wire2str.c,v diff -u -p -r1.11 wire2str.c --- sbin/unwind/libunbound/sldns/wire2str.c 14 Sep 2025 15:16:53 -0000 1.11 +++ sbin/unwind/libunbound/sldns/wire2str.c 21 Sep 2026 16:27:59 -0000 @@ -233,6 +233,7 @@ static sldns_lookup_table sldns_edns_ede { LDNS_EDE_UNSUPPORTED_NSEC3_ITERATIONS, "Unsupported NSEC3 Iterations Value" }, { LDNS_EDE_BADPROXYPOLICY, "Unable to Conform to Policy" }, { LDNS_EDE_SYNTHESIZED, "Synthesized Answer" }, + { LDNS_EDE_INVALID_QUERY_TYPE, "Invalid Query Type" }, { 0, NULL} }; sldns_lookup_table* sldns_edns_ede_codes = sldns_edns_ede_codes_data; @@ -2485,6 +2486,8 @@ int sldns_wire2str_edns_scan(uint8_t** d w += sldns_str_print(str, str_len, " flags:"); if((edns_bits & LDNS_EDNS_MASK_DO_BIT)) w += sldns_str_print(str, str_len, " do"); + if((edns_bits & LDNS_EDNS_MASK_CO_BIT)) + w += sldns_str_print(str, str_len, " co"); /* the extended rcode is the value set, shifted four bits, * and or'd with the original rcode */ if(ext_rcode) { Index: sbin/unwind/libunbound/util/alloc.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/alloc.c,v diff -u -p -r1.7 alloc.c --- sbin/unwind/libunbound/util/alloc.c 23 Feb 2025 07:53:40 -0000 1.7 +++ sbin/unwind/libunbound/util/alloc.c 21 Sep 2026 16:27:59 -0000 @@ -328,7 +328,7 @@ size_t alloc_get_mem(struct alloc_cache* struct regional* alloc_reg_obtain(struct alloc_cache* alloc) { - if(alloc->num_reg_blocks > 0) { + if(alloc->num_reg_blocks > 0 && alloc->reg_list) { struct regional* r = alloc->reg_list; alloc->reg_list = (struct regional*)r->next; r->next = NULL; Index: sbin/unwind/libunbound/util/config_file.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/config_file.c,v diff -u -p -r1.21 config_file.c --- sbin/unwind/libunbound/util/config_file.c 28 Nov 2025 07:37:51 -0000 1.21 +++ sbin/unwind/libunbound/util/config_file.c 21 Sep 2026 16:27:59 -0000 @@ -46,6 +46,7 @@ #ifdef HAVE_TIME_H #include #endif +#include #include "util/log.h" #include "util/configyyrename.h" #include "util/config_file.h" @@ -62,6 +63,9 @@ #include "sldns/wire2str.h" #include "sldns/parseutil.h" #include "iterator/iterator.h" +#ifdef HAVE_SYS_STAT_H +#include +#endif #ifdef HAVE_GLOB_H # include #endif @@ -90,7 +94,7 @@ struct config_parser_state* cfg_parser = static void init_outgoing_availports(int* array, int num); /** init cookie with random data */ -static void init_cookie_secret(uint8_t* cookie_secret, size_t cookie_secret_len); +static int init_cookie_secret(struct config_file* cfg); struct config_file* config_create(void) @@ -129,6 +133,7 @@ config_create(void) cfg->tls_cert_bundle = NULL; cfg->tls_win_cert = 0; cfg->tls_use_sni = 1; + if(!(cfg->tls_protocols = strdup("TLSv1.2 TLSv1.3"))) goto error_exit; cfg->https_port = UNBOUND_DNS_OVER_HTTPS_PORT; if(!(cfg->http_endpoint = strdup("/dns-query"))) goto error_exit; cfg->http_max_streams = 100; @@ -147,6 +152,7 @@ config_create(void) cfg->log_local_actions = 0; cfg->log_servfail = 0; cfg->log_destaddr = 0; + cfg->log_thread_id = 0; #ifndef USE_WINSOCK # ifdef USE_MINI_EVENT /* select max 1024 sockets */ @@ -272,7 +278,7 @@ config_create(void) cfg->val_sig_skew_min = 3600; /* at least daylight savings trouble */ cfg->val_sig_skew_max = 86400; /* at most timezone settings trouble */ cfg->val_max_restart = 5; - cfg->val_clean_additional = 1; + cfg->val_clean_additional = 0; /* off to protect against much data. */ cfg->val_log_level = 0; cfg->val_log_squelch = 0; cfg->val_permissive_mode = 0; @@ -384,8 +390,7 @@ config_create(void) #endif cfg->do_answer_cookie = 0; memset(cfg->cookie_secret, 0, sizeof(cfg->cookie_secret)); - cfg->cookie_secret_len = 16; - init_cookie_secret(cfg->cookie_secret, cfg->cookie_secret_len); + cfg->cookie_secret_len = 0; /* not set yet */ cfg->cookie_secret_file = NULL; #ifdef USE_CACHEDB if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit; @@ -421,8 +426,11 @@ config_create(void) cfg->dns_error_reporting = 0; cfg->iter_scrub_ns = 20; cfg->iter_scrub_cname = 11; + cfg->iter_scrub_rrsig = 8; cfg->iter_scrub_promiscuous = 1; cfg->max_global_quota = 200; + cfg->val_validation_attempts = 32; + cfg->val_hash_attempts = 32; return cfg; error_exit: config_delete(cfg); @@ -527,7 +535,11 @@ probe_maxrto(int useful_server_top_timeo int config_apply_max_rtt(int max_rtt) { USEFUL_SERVER_TOP_TIMEOUT = max_rtt; - BLACKLIST_PENALTY = max_rtt*4; + BLACKLIST_PENALTY = +#ifdef INT_MAX + (max_rtt > INT_MAX/4) ? INT_MAX : +#endif + max_rtt*4; PROBE_MAXRTO = probe_maxrto(max_rtt); return max_rtt; } @@ -629,6 +641,11 @@ int config_set_option(struct config_file else S_STR("tls-ciphers:", tls_ciphers) else S_STR("tls-ciphersuites:", tls_ciphersuites) else S_YNO("tls-use-sni:", tls_use_sni) + else if(strcmp(opt, "tls-protocols:") == 0) { + if(!cfg_tls_protocols_is_valid(val)) return 0; + free(cfg->tls_protocols); + return (cfg->tls_protocols = strdup(val)) != NULL; + } else S_NUMBER_NONZERO("https-port:", https_port) else S_STR("http-endpoint:", http_endpoint) else S_NUMBER_NONZERO("http-max-streams:", http_max_streams) @@ -746,6 +763,7 @@ int config_set_option(struct config_file else S_YNO("log-local-actions:", log_local_actions) else S_YNO("log-servfail:", log_servfail) else S_YNO("log-destaddr:", log_destaddr) + else S_YNO("log-thread-id:", log_thread_id) else S_YNO("val-permissive-mode:", val_permissive_mode) else S_YNO("aggressive-nsec:", aggressive_nsec) else S_YNO("ignore-cd-flag:", ignore_cd) @@ -764,10 +782,13 @@ int config_set_option(struct config_file else S_YNO("ede:", ede) else S_YNO("ede-serve-expired:", ede_serve_expired) else S_YNO("dns-error-reporting:", dns_error_reporting) - else S_NUMBER_OR_ZERO("iter-scrub-ns:", iter_scrub_ns) + else S_NUMBER_NONZERO("iter-scrub-ns:", iter_scrub_ns) else S_NUMBER_OR_ZERO("iter-scrub-cname:", iter_scrub_cname) + else S_NUMBER_OR_ZERO("iter-scrub-rrsig:", iter_scrub_rrsig) else S_YNO("iter-scrub-promiscuous:", iter_scrub_promiscuous) else S_NUMBER_OR_ZERO("max-global-quota:", max_global_quota) + else S_NUMBER_OR_ZERO("val-validation-attempts:", val_validation_attempts) + else S_NUMBER_OR_ZERO("val-hash-attempts:", val_hash_attempts) else S_YNO("serve-original-ttl:", serve_original_ttl) else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations) else S_YNO("zonemd-permissive-mode:", zonemd_permissive_mode) @@ -1181,6 +1202,7 @@ config_get_option(struct config_file* cf else O_STR(opt, "tls-ciphers", tls_ciphers) else O_STR(opt, "tls-ciphersuites", tls_ciphersuites) else O_YNO(opt, "tls-use-sni", tls_use_sni) + else O_STR(opt, "tls-protocols", tls_protocols) else O_DEC(opt, "https-port", https_port) else O_STR(opt, "http-endpoint", http_endpoint) else O_UNS(opt, "http-max-streams", http_max_streams) @@ -1202,6 +1224,7 @@ config_get_option(struct config_file* cf else O_YNO(opt, "log-local-actions", log_local_actions) else O_YNO(opt, "log-servfail", log_servfail) else O_YNO(opt, "log-destaddr", log_destaddr) + else O_YNO(opt, "log-thread-id", log_thread_id) else O_STR(opt, "pidfile", pidfile) else O_YNO(opt, "hide-identity", hide_identity) else O_YNO(opt, "hide-version", hide_version) @@ -1243,8 +1266,11 @@ config_get_option(struct config_file* cf else O_YNO(opt, "dns-error-reporting", dns_error_reporting) else O_DEC(opt, "iter-scrub-ns", iter_scrub_ns) else O_DEC(opt, "iter-scrub-cname", iter_scrub_cname) + else O_DEC(opt, "iter-scrub-rrsig", iter_scrub_rrsig) else O_YNO(opt, "iter-scrub-promiscuous", iter_scrub_promiscuous) else O_DEC(opt, "max-global-quota", max_global_quota) + else O_DEC(opt, "val-validation-attempts", val_validation_attempts) + else O_DEC(opt, "val-hash-attempts", val_hash_attempts) else O_YNO(opt, "serve-original-ttl", serve_original_ttl) else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations) else O_YNO(opt, "zonemd-permissive-mode", zonemd_permissive_mode) @@ -1556,6 +1582,8 @@ config_read(struct config_file* cfg, con } globfree(&g); config_auto_slab_values(cfg); + if(!init_cookie_secret(cfg)) + return 0; return 1; } #endif /* HAVE_GLOB */ @@ -1580,6 +1608,8 @@ config_read(struct config_file* cfg, con } config_auto_slab_values(cfg); + if(!init_cookie_secret(cfg)) + return 0; return 1; } @@ -1750,6 +1780,7 @@ config_delete(struct config_file* cfg) config_delstrlist(cfg->tls_session_ticket_keys.first); free(cfg->tls_ciphers); free(cfg->tls_ciphersuites); + free(cfg->tls_protocols); free(cfg->http_endpoint); if(cfg->log_identity) { log_ident_revert_to_default(); @@ -1853,18 +1884,33 @@ config_delete(struct config_file* cfg) free(cfg); } -static void -init_cookie_secret(uint8_t* cookie_secret, size_t cookie_secret_len) +static int +init_cookie_secret(struct config_file* cfg) { - struct ub_randstate *rand = ub_initstate(NULL); + struct ub_randstate* rand; + size_t cookie_secret_len; + uint8_t* cookie_secret; + if(!cfg->do_answer_cookie) + return 1; + if(cfg->cookie_secret_file && cfg->cookie_secret_file[0]) + return 1; + if(cfg->cookie_secret_len != 0) + return 1; - if (!rand) - fatal_exit("could not init random generator"); + rand = ub_initstate(NULL); + if(!rand) { + log_err("init_cookie_secret: could not init random generator"); + return 0; + } + cfg->cookie_secret_len = 16; + cookie_secret_len = cfg->cookie_secret_len; + cookie_secret = cfg->cookie_secret; while (cookie_secret_len) { *cookie_secret++ = (uint8_t)ub_random(rand); cookie_secret_len--; } ub_randfree(rand); + return 1; } static void @@ -1927,7 +1973,7 @@ extract_port_from_str(const char* str, i int cfg_mark_ports(const char* str, int allow, int* avail, int num) { - char* mid = strchr(str, '-'); + const char* mid = strchr(str, '-'); #ifdef DISABLE_EXPLICIT_PORT_RANDOMISATION log_warn("Explicit port randomisation disabled, ignoring " "outgoing-port-permit and outgoing-port-avoid configuration " @@ -1935,7 +1981,7 @@ cfg_mark_ports(const char* str, int allo #endif if(!mid) { int port = extract_port_from_str(str, num); - if(port < 0) { + if (port < 0) { log_err("Failed to parse the port number"); return 0; } @@ -1945,7 +1991,7 @@ cfg_mark_ports(const char* str, int allo char buf[16]; int i, low; int high = extract_port_from_str(mid+1, num); - if(high < 0) { + if (high < 0) { log_err("Failed to parse the port number"); return 0; } @@ -1959,7 +2005,7 @@ cfg_mark_ports(const char* str, int allo memcpy(buf, str, (size_t)(mid-str)); buf[mid-str] = 0; low = extract_port_from_str(buf, num); - if(low < 0) { + if (low < 0) { log_err("Failed to parse the port number"); return 0; } @@ -2630,10 +2676,10 @@ fname_after_chroot(const char* fname, st } /** return next space character in string */ -static char* next_space_pos(const char* str) +static const char* next_space_pos(const char* str) { - char* sp = strchr(str, ' '); - char* tab = strchr(str, '\t'); + const char* sp = strchr(str, ' '); + const char* tab = strchr(str, '\t'); if(!tab && !sp) return NULL; if(!sp) return tab; @@ -2642,10 +2688,10 @@ static char* next_space_pos(const char* } /** return last space character in string */ -static char* last_space_pos(const char* str) +static const char* last_space_pos(const char* str) { - char* sp = strrchr(str, ' '); - char* tab = strrchr(str, '\t'); + const char* sp = strrchr(str, ' '); + const char* tab = strrchr(str, '\t'); if(!tab && !sp) return NULL; if(!sp) return tab; @@ -2703,8 +2749,8 @@ cfg_parse_local_zone(struct config_file* char* cfg_ptr_reverse(char* str) { - char* ip, *ip_end; - char* name; + const char* ip, *ip_end; + const char* name; char* result; char buf[1024]; struct sockaddr_storage addr; @@ -2855,7 +2901,7 @@ if_listens_on(const char* ifname, int de struct config_strlist* additional_ports) { struct config_strlist* s; - char* p = strchr(ifname, '@'); + const char* p = strchr(ifname, '@'); int if_port; if(p) if_port = atoi(p+1); else if_port = default_port; @@ -2923,6 +2969,29 @@ if_is_quic(const char* ifname, int defau } int +cfg_ports_list_contains(char* ports, int p) +{ + char* now = ports, *after; + int extraport; + while(now && *now) { + while(isspace((unsigned char)*now)) + now++; + if(!now) + break; + after = now; + extraport = (int)strtol(now, &after, 10); + if(extraport < 0 || extraport > 65535) + continue; /* Out of range. */ + if(extraport == 0 && now == after) + return 0; /* Number could not be parsed. */ + now = after; + if(extraport == p) + return 1; + } + return 0; +} + +int cfg_has_https(struct config_file* cfg) { int i; @@ -2930,6 +2999,8 @@ cfg_has_https(struct config_file* cfg) if(if_is_https(cfg->ifs[i], cfg->port, cfg->https_port)) return 1; } + if(cfg_ports_list_contains(cfg->if_automatic_ports, cfg->https_port)) + return 1; return 0; } @@ -2942,9 +3013,83 @@ cfg_has_quic(struct config_file* cfg) if(if_is_quic(cfg->ifs[i], cfg->port, cfg->quic_port)) return 1; } + if(cfg_ports_list_contains(cfg->if_automatic_ports, cfg->quic_port)) + return 1; return 0; #else (void)cfg; return 0; #endif +} + +int +cfg_tls_protocols_is_valid(const char* tls_protocols) +{ + const char* s = tls_protocols; + while(*s && isspace((unsigned char)*s)) s++; + while(*s && !isspace((unsigned char)*s)) { + if(strncmp(s, "TLSv1.2", 7) == 0 || + strncmp(s, "TLSv1.3", 7) == 0) { + s += 7; + if(*s && !isspace((unsigned char)*s)) { + /* something is attached; fail */ + return 0; + } + while(*s && isspace((unsigned char)*s)) + s++; + continue; + } + return 0; + } + return 1; +} + +void +cfg_tls_protocols_allowed(const char* tls_protocols, int* allow12, int* allow13) +{ + const char* s = tls_protocols; + *allow12 = 0; + *allow13 = 0; + if(tls_protocols == NULL) return; + while(*s && isspace((unsigned char)*s)) s++; + while(*s && !isspace((unsigned char)*s)) { + if(strncmp(s, "TLSv1.2", 7) == 0) { + *allow12 = 1; + s += 7; + } else if(strncmp(s, "TLSv1.3", 7) == 0) { + *allow13 = 1; + s += 7; + } else { + /* Unknown word, this should never happen but skip to + * be safe */ + while(*s && !isspace((unsigned char)*s)) + s++; + } + while(*s && isspace((unsigned char)*s)) + s++; + } +} + +int +file_get_mtime(const char* file, time_t* mtime, long* ns, int* nonexist) +{ + struct stat s; + if(stat(file, &s) != 0) { + *mtime = 0; + *ns = 0; + if(nonexist) + *nonexist = (errno == ENOENT); + return 0; + } + if(nonexist) + *nonexist = 0; + *mtime = s.st_mtime; +#ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC + *ns = s.st_mtimensec; +#elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) + *ns = s.st_mtim.tv_nsec; +#else + *ns = 0; +#endif + return 1; } Index: sbin/unwind/libunbound/util/config_file.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/config_file.h,v diff -u -p -r1.21 config_file.h --- sbin/unwind/libunbound/util/config_file.h 28 Nov 2025 07:37:51 -0000 1.21 +++ sbin/unwind/libunbound/util/config_file.h 21 Sep 2026 16:27:59 -0000 @@ -148,6 +148,8 @@ struct config_file { char* tls_ciphersuites; /** if SNI is to be used */ int tls_use_sni; + /** TLS protocols */ + char* tls_protocols; /** port on which to provide DNS over HTTPS service */ int https_port; @@ -365,6 +367,8 @@ struct config_file { char* log_identity; /** log dest addr for log_replies */ int log_destaddr; + /** log linux thread ID */ + int log_thread_id; /** do not report identity (id.server, hostname.bind) */ int hide_identity; @@ -790,8 +794,14 @@ struct config_file { size_t iter_scrub_ns; /** limit on CNAME, DNAME RRs in answer for the iterator scrubber. */ int iter_scrub_cname; + /** limit on RRSIGs for an RRset for the iterator scrubber. */ + int iter_scrub_rrsig; /** limit on upstream queries for an incoming query and subqueries. */ int max_global_quota; + /** limit on validator validation attempts. */ + int val_validation_attempts; + /** limit on validator hash attempts. */ + int val_hash_attempts; /** Should the iterator scrub promiscuous NS rrsets, from positive * answers. */ int iter_scrub_promiscuous; @@ -878,6 +888,10 @@ struct config_auth { int zonemd_check; /** Reject absence of ZONEMD records, zone must have one */ int zonemd_reject_absence; + /** The maximum auth zone transfer size, in bytes. */ + size_t max_transfer_size; + /** The maximum auth zone transfer time taken, in msec. */ + int max_transfer_time; }; /** @@ -1480,5 +1494,31 @@ int cfg_has_quic(struct config_file* cfg /** get memory for string */ size_t getmem_str(char* str); + +/** + * See if the if_automatic_ports list contains the value. + * @param ports: String with port numbers. + * @param p: number looked for. + * @return true if found, false if not found or parse failure. + */ +int cfg_ports_list_contains(char* ports, int p); + +/** + * Check if the configured string contains supported TLS protocols. + * @param tls_protocols: String with TLS protocols. + * @return true if all options are valid, else false. + */ +int cfg_tls_protocols_is_valid(const char* tls_protocols); + +/** + * Based on the configured TLS protocols fill which ones are allowed. + * @param tls_protocols: String with TLS protocols. + * @param allow12: will be true if TLSv1.2 is configured. + * @param allow13: will be true if TLSv1.3 is configured. + */ +void cfg_tls_protocols_allowed(const char* tls_protocols, int* allow12, int* allow13); + +/** get the file mtime stat (or error, with errno and nonexist) */ +int file_get_mtime(const char* file, time_t* mtime, long* ns, int* nonexist); #endif /* UTIL_CONFIG_FILE_H */ Index: sbin/unwind/libunbound/util/configlexer.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/configlexer.c,v diff -u -p -r1.24 configlexer.c --- sbin/unwind/libunbound/util/configlexer.c 28 Nov 2025 07:37:51 -0000 1.24 +++ sbin/unwind/libunbound/util/configlexer.c 21 Sep 2026 16:28:00 -0000 @@ -5,7 +5,7 @@ #define YY_INT_ALIGNED short int -/* $OpenBSD: configlexer.c,v 1.24 2025/11/28 07:37:51 florian Exp $ */ +/* $OpenBSD: configlexer.c,v 1.27 2026/09/21 06:29:04 florian Exp $ */ /* A lexical scanner generated by flex */ @@ -27,7 +27,7 @@ /* end standard C headers. */ -/* $OpenBSD: configlexer.c,v 1.24 2025/11/28 07:37:51 florian Exp $ */ +/* $OpenBSD: configlexer.c,v 1.27 2026/09/21 06:29:04 florian Exp $ */ /* flex integer type definitions */ @@ -368,8 +368,8 @@ static void yy_fatal_error (yyconst char *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 413 -#define YY_END_OF_BUFFER 414 +#define YY_NUM_RULES 420 +#define YY_END_OF_BUFFER 421 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -377,462 +377,471 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[4130] = +static yyconst flex_int16_t yy_accept[4207] = { 0, - 1, 1, 387, 387, 391, 391, 395, 395, 399, 399, - 1, 1, 403, 403, 407, 407, 414, 411, 1, 385, - 385, 412, 2, 412, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 387, 388, 388, - 389, 412, 391, 392, 392, 393, 412, 398, 395, 396, - 396, 397, 412, 399, 400, 400, 401, 412, 410, 386, - 2, 390, 412, 410, 406, 403, 404, 404, 405, 412, - 407, 408, 408, 409, 412, 411, 0, 1, 2, 2, - 2, 2, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 387, 0, 391, 0, 398, 0, - 395, 399, 0, 410, 0, 2, 2, 410, 406, 0, - 403, 407, 0, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 410, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 378, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 140, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 150, 411, 411, 411, 411, - 411, 411, 411, 411, 410, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 122, 411, 411, 377, 411, - 411, 411, 411, 411, 411, 411, 411, 8, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 141, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 155, 411, 411, 411, 410, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 367, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 410, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 73, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 277, 411, 14, 15, 411, 411, 20, 19, 411, - 411, 251, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 148, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 249, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 3, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 410, 411, - 411, 411, 411, 411, 411, 411, 411, 346, 411, 411, - 411, 345, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 394, 411, 411, - 411, 411, 411, 411, 411, 411, 72, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 76, 411, 315, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 368, 369, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 77, 411, 411, 149, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 144, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 238, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 22, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 176, 411, 411, 411, 411, 411, 411, - 410, 394, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 120, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 323, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 16, 411, 411, 411, 411, 411, 411, 411, 411, 204, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 175, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 119, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 37, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 38, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 74, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 147, 411, 411, 411, 410, - 411, 411, 411, 411, 411, 411, 139, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 75, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 281, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 205, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 62, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 58, 59, 411, 301, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 67, 411, 68, 411, 411, 411, 411, 411, 411, 123, - 411, 124, 411, 411, 411, 411, 411, 121, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 7, 411, 411, 411, 411, 411, 410, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 266, 411, 411, 411, 411, 411, 411, 179, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 282, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 51, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 63, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 229, 411, - 228, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 17, 18, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 78, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 237, 411, 411, 411, 411, 411, 411, 411, 126, - 411, 125, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 218, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 156, 411, - 257, 411, 411, 411, 410, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 114, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 100, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 250, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 105, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 71, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 222, 223, 411, 411, 411, 411, 317, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 6, 411, 411, - 411, 411, 411, 411, 411, 336, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 321, - 411, 411, 411, 411, 411, 411, 411, 347, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 48, 411, 411, 411, 411, 411, 50, - - 411, 411, 411, 101, 411, 411, 411, 411, 411, 60, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 410, 411, 214, 411, 411, 411, 151, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 242, 411, 411, 215, 411, 411, - 411, 411, 411, 411, 262, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 61, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 153, 132, - 411, 133, 411, 411, 411, 411, 131, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 172, 411, - 411, 56, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 299, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 216, 411, 411, 411, 411, - 411, 227, 219, 411, 226, 411, 411, 221, 411, 411, - 411, 411, 411, 411, 411, 261, 411, 411, 411, 411, - 411, 411, 265, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 118, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 145, - 411, 411, 411, 411, 411, 411, 411, 411, 69, 411, - 411, 411, 411, 31, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 21, 411, 411, 411, - 411, 411, 411, 411, 32, 41, 411, 184, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 212, 411, 411, 410, 411, 411, - 411, 411, 372, 411, 411, 86, 411, 89, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 373, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 325, 411, - - 411, 411, 411, 278, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 134, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 171, 411, 52, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 272, 411, 411, 411, 411, - 411, 411, 411, 411, 340, 411, 411, 411, 411, 411, - 381, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 178, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 334, 411, 411, 411, 411, 248, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 358, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 197, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 127, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 191, 411, 206, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 410, 411, 159, 411, 411, - - 411, 411, 411, 411, 411, 411, 113, 411, 411, 411, - 411, 240, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 263, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 290, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 152, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 195, 411, 411, 411, 411, 411, 411, 411, - 90, 411, 91, 411, 411, 411, 411, 411, 275, 411, - 411, 411, 411, 411, 70, 343, 411, 411, 411, 411, - - 411, 411, 411, 99, 207, 411, 230, 411, 267, 411, - 411, 220, 318, 411, 411, 411, 411, 411, 313, 411, - 411, 411, 82, 411, 209, 411, 411, 411, 411, 411, - 411, 9, 411, 411, 411, 411, 411, 117, 411, 411, - 411, 411, 411, 411, 305, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 239, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 410, 411, 411, 411, - 411, 194, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 196, 256, 180, 411, - 411, 324, 411, 411, 411, 411, 411, 289, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 252, 411, 411, 411, 411, 411, 411, 316, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 177, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 344, - 411, 411, 411, 208, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 81, 83, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 116, 411, 411, 411, - 411, 411, 411, 303, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 320, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 244, 411, 39, 33, 35, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 40, - 411, 34, 36, 411, 42, 411, 411, 411, 411, 411, - - 411, 411, 112, 411, 190, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 410, 411, 411, 411, 411, 411, - 411, 411, 411, 348, 411, 411, 411, 411, 411, 246, - 243, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 80, 411, 411, 411, 154, 411, 135, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 173, 53, 411, 411, 411, 402, 13, 411, - 411, 411, 411, 411, 411, 411, 160, 411, 411, 411, - 411, 411, 411, 411, 411, 338, 411, 341, 411, 382, - - 411, 411, 411, 411, 411, 411, 383, 411, 411, 411, - 411, 411, 411, 411, 12, 411, 411, 23, 411, 411, - 411, 411, 411, 411, 411, 309, 411, 411, 411, 411, - 365, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 322, 411, 411, 411, 411, 84, 411, 254, 411, 411, - 411, 411, 411, 245, 411, 411, 411, 411, 79, 411, - 411, 411, 411, 411, 411, 24, 411, 411, 49, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 189, 188, 411, 411, 411, 411, 402, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 247, - - 241, 411, 411, 411, 264, 411, 411, 326, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 202, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 92, 411, 411, - 411, 411, 411, 411, 411, 411, 304, 411, 411, 411, - 411, 411, 225, 411, 411, 411, 411, 411, 411, 253, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 311, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 350, 411, 354, 352, 186, 411, 411, 411, 85, - - 411, 411, 411, 411, 198, 411, 411, 411, 411, 411, - 128, 130, 129, 411, 411, 411, 26, 411, 411, 181, - 411, 183, 411, 231, 411, 411, 411, 411, 187, 411, - 411, 258, 411, 411, 411, 411, 268, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 162, 374, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 297, - 411, 411, 280, 411, 411, 411, 411, 411, 411, 411, - 375, 411, 28, 411, 319, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 97, 232, 411, 411, 274, 411, - - 411, 411, 302, 411, 342, 411, 411, 224, 411, 411, - 314, 411, 411, 411, 312, 64, 411, 411, 411, 411, - 411, 411, 411, 4, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 143, 411, 161, 411, - 411, 411, 203, 30, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 271, 43, 44, 411, 411, - 411, 411, 411, 411, 411, 379, 411, 411, 327, 411, - 411, 411, 411, 411, 411, 411, 288, 411, 411, 411, - 411, 411, 411, 411, 411, 235, 411, 411, 411, 411, - - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 96, 95, 411, 411, 65, 411, 411, 300, - 308, 411, 411, 276, 411, 411, 411, 411, 411, 11, - 411, 411, 411, 411, 380, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 142, 411, 411, - 411, 411, 411, 411, 233, 102, 411, 411, 46, 411, - 411, 411, 411, 411, 411, 411, 411, 193, 411, 259, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 164, - 411, 411, 411, 411, 279, 411, 411, 411, 411, 411, - 287, 411, 411, 411, 411, 157, 411, 411, 411, 136, - - 138, 137, 411, 411, 411, 104, 109, 103, 411, 411, - 174, 411, 411, 411, 411, 93, 411, 273, 310, 411, - 411, 411, 411, 411, 411, 411, 10, 411, 411, 411, - 411, 411, 306, 411, 411, 364, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 371, - 45, 411, 411, 411, 411, 411, 192, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 110, 108, 411, 411, 411, - 57, 411, 411, 94, 411, 339, 411, 411, 411, 411, - - 411, 25, 411, 411, 411, 411, 411, 217, 411, 411, - 360, 362, 411, 411, 411, 411, 411, 359, 356, 411, - 411, 411, 411, 234, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 213, 411, 411, 182, 87, 88, - 411, 411, 411, 411, 411, 411, 328, 411, 411, 411, - 411, 411, 411, 411, 284, 411, 411, 283, 158, 411, - 411, 107, 411, 106, 54, 411, 411, 384, 165, 166, - 169, 170, 167, 168, 98, 337, 411, 411, 307, 411, - 411, 411, 411, 411, 411, 146, 411, 411, 411, 411, - 27, 411, 185, 411, 411, 411, 411, 411, 211, 411, - - 270, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 200, 199, 236, 47, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 335, 411, 411, 411, 366, 411, 411, 411, 411, - 411, 411, 411, 115, 411, 411, 269, 411, 411, 298, - 332, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 376, 411, 111, 55, 66, 5, 411, 411, - - 351, 411, 355, 353, 411, 411, 255, 411, 411, 411, - 411, 333, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 285, 29, 411, 411, 411, 411, 411, 411, 260, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 286, 411, 411, 411, 411, 411, 411, 411, 163, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 201, 411, 210, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 361, 363, 357, 411, 411, 329, 411, 411, - 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, - 411, 411, 411, 411, 411, 411, 370, 349, 411, 411, - - 293, 411, 411, 411, 411, 411, 330, 411, 411, 411, - 411, 411, 411, 331, 411, 411, 411, 291, 411, 294, - 295, 411, 411, 411, 411, 411, 292, 296, 0 + 1, 1, 394, 394, 398, 398, 402, 402, 406, 406, + 1, 1, 410, 410, 414, 414, 421, 418, 1, 392, + 392, 419, 2, 419, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 394, 395, 395, + 396, 419, 398, 399, 399, 400, 419, 405, 402, 403, + 403, 404, 419, 406, 407, 407, 408, 419, 417, 393, + 2, 397, 419, 417, 413, 410, 411, 411, 412, 419, + 414, 415, 415, 416, 419, 418, 0, 1, 2, 2, + 2, 2, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 394, 0, 398, 0, 405, 0, + 402, 406, 0, 417, 0, 2, 2, 417, 413, 0, + 410, 414, 0, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 417, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 380, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 141, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 151, 418, 418, 418, 418, + 418, 418, 418, 418, 417, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 123, 418, 418, 379, + 418, 418, 418, 418, 418, 418, 418, 418, 8, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 142, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 156, 418, + 418, 418, 417, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 369, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 417, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 74, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 279, + 418, 14, 15, 418, 418, 20, 19, 418, 418, 253, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 149, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 251, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 3, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 417, 418, 418, 418, 418, 418, 418, 418, 418, + 348, 418, 418, 418, 347, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 401, 418, 418, 418, 418, 418, 418, 418, 418, 73, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 77, + 418, 317, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 370, 371, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 78, 418, 418, 150, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 145, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 240, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 22, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 177, 418, 418, 418, 418, 418, 418, 417, 401, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 121, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 325, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 16, 418, + 418, 418, 418, 418, 418, 418, 418, 205, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 176, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 120, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 37, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 38, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 75, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 148, 418, + + 418, 418, 417, 418, 418, 418, 418, 418, 418, 140, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 76, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 283, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 206, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 63, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 59, 60, 418, + 303, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 68, 418, 69, 418, 418, + + 418, 418, 418, 418, 124, 418, 125, 418, 418, 418, + 418, 418, 122, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 7, + 418, 418, 418, 418, 418, 417, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 268, + 418, 418, 418, 418, 418, 418, 180, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 284, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 52, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 64, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 231, 418, 230, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 17, 18, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 79, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 239, 418, 418, 418, 418, 418, 418, 418, 127, + 418, 126, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 219, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 157, 418, 259, 418, 418, 418, 417, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 115, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 101, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 252, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 106, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 72, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 223, 224, 418, + 418, 418, 418, 418, 319, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 6, 418, 418, 418, 418, 418, 418, + 418, 338, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 323, 418, 418, 418, 418, + + 418, 418, 418, 349, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 48, + 418, 418, 418, 418, 418, 418, 50, 418, 418, 418, + 102, 418, 418, 418, 418, 418, 61, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 417, 418, 215, 418, 418, 418, 152, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 244, 418, 418, 216, 418, 418, 418, + 418, 418, 418, 264, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 62, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 154, 133, 418, + 134, 418, 418, 418, 418, 132, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 173, 418, 418, + 57, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 301, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 217, 418, 418, 418, 418, + 418, 228, 220, 418, 227, 418, 418, 418, 222, 418, + + 418, 418, 418, 418, 418, 418, 418, 263, 418, 418, + 418, 418, 418, 418, 267, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 119, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 146, 418, 418, 418, 418, 418, 418, 418, 418, + 70, 418, 418, 418, 418, 31, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 21, 418, + 418, 418, 418, 418, 418, 418, 418, 32, 41, 418, + 185, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 213, + 418, 418, 417, 418, 418, 418, 418, 374, 418, 418, + 87, 418, 90, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 375, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 327, 418, 418, 418, 418, 280, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 135, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 172, 418, 53, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 274, 418, 418, 418, 418, 418, 418, 418, 418, 342, + 418, 418, 418, 418, 418, 383, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 229, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 179, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 336, 418, 418, 418, 418, 250, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 360, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 198, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 128, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 51, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 192, 418, 418, 207, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 417, 418, 160, + 418, 418, 418, 418, 418, 418, 418, 418, 114, 418, + 418, 418, 418, 242, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 265, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 292, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 153, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 196, 418, 418, 418, 418, 418, + 418, 418, 91, 418, 92, 418, 418, 418, 418, 418, + 277, 418, 418, 418, 418, 418, 71, 345, 418, 418, + 418, 418, 418, 418, 418, 418, 100, 208, 418, 232, + 418, 269, 418, 418, 221, 320, 418, 418, 418, 418, + 418, 315, 418, 418, 418, 418, 418, 83, 418, 210, + 418, 418, 418, 418, 418, 418, 9, 418, 418, 418, + 418, 418, 118, 418, 418, 418, 418, 418, 418, 307, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 241, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 417, 418, 418, 418, 418, 195, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 197, 258, 181, 418, 418, 326, 418, + + 418, 418, 418, 418, 291, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 254, 418, 418, + 418, 418, 418, 418, 318, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 178, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 346, 418, 418, 418, + 418, 209, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 82, 84, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 117, 418, 418, 418, + + 418, 418, 418, 305, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 322, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 246, 418, 39, 33, 35, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 40, + 418, 34, 36, 418, 42, 418, 418, 418, 418, 418, + 418, 418, 113, 418, 418, 191, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 417, 418, 418, 418, + 418, 418, 418, 418, 418, 350, 418, 418, 418, 418, + 418, 248, 245, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 81, 418, 418, 418, 155, + 418, 136, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 174, 54, 418, 418, 418, 409, + 13, 418, 418, 418, 418, 418, 418, 418, 161, 418, + 418, 418, 418, 418, 418, 418, 418, 340, 418, 343, + 418, 384, 418, 385, 418, 418, 418, 418, 418, 386, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 12, + 418, 418, 23, 418, 418, 418, 418, 418, 418, 418, + 311, 418, 418, 418, 418, 367, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 324, 418, 418, 418, 418, + 85, 418, 256, 418, 418, 418, 418, 418, 247, 418, + 418, 418, 418, 80, 418, 418, 418, 418, 418, 418, + 24, 418, 418, 49, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 190, 189, 418, + 418, 418, 418, 418, 409, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 249, 243, 418, 418, + 418, 266, 418, 418, 328, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 203, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 93, 418, 418, 418, 418, 418, + 418, 418, 418, 306, 418, 418, 418, 418, 418, 226, + 418, 418, 418, 418, 418, 389, 390, 418, 255, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 313, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 352, 418, 356, 354, 187, 418, 418, 418, 86, 418, + 418, 418, 418, 199, 418, 418, 418, 418, 418, 129, + 131, 130, 418, 418, 418, 26, 418, 418, 182, 418, + 184, 418, 233, 418, 418, 418, 388, 418, 188, 418, + + 418, 418, 260, 418, 418, 418, 418, 270, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 163, 376, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 299, 418, 418, 282, 418, 418, 418, 418, 418, 418, + 418, 377, 418, 28, 418, 321, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 98, 234, 418, 418, 276, + 418, 418, 418, 304, 418, 344, 418, 418, 225, 418, + 418, 316, 418, 418, 418, 314, 65, 418, 418, 418, + 418, 418, 418, 418, 4, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 144, 418, 162, + 418, 418, 418, 204, 30, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 273, 43, 44, + 418, 418, 418, 418, 418, 418, 418, 381, 418, 418, + 329, 418, 418, 418, 418, 418, 418, 418, 290, 418, + 418, 418, 418, 418, 418, 418, 418, 237, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 97, 96, 418, 418, 66, 418, + 418, 302, 310, 418, 418, 278, 418, 418, 418, 418, + + 418, 11, 418, 418, 418, 418, 382, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 143, + 418, 418, 418, 418, 418, 418, 235, 103, 418, 418, + 46, 418, 418, 418, 418, 418, 418, 418, 418, 194, + 418, 418, 261, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 165, 418, 418, 418, 418, 281, 418, 418, + 418, 418, 418, 289, 418, 418, 418, 418, 158, 418, + 418, 418, 137, 139, 138, 418, 418, 418, 105, 110, + 104, 418, 418, 175, 418, 418, 418, 418, 94, 418, + 275, 312, 418, 418, 418, 418, 418, 418, 418, 10, + + 418, 418, 418, 418, 418, 308, 418, 418, 366, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 373, 45, 418, 418, 418, 418, 418, 193, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 111, + 109, 418, 418, 418, 58, 418, 418, 95, 418, 341, + 418, 418, 418, 418, 418, 25, 418, 418, 418, 418, + 418, 218, 418, 418, 362, 364, 418, 418, 418, 418, + 418, 361, 358, 418, 418, 418, 418, 236, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 418, 418, 214, + 418, 418, 183, 88, 89, 418, 418, 418, 418, 418, + 418, 330, 418, 418, 418, 418, 418, 418, 418, 286, + 418, 418, 285, 159, 418, 418, 108, 418, 107, 55, + 418, 418, 391, 166, 167, 170, 171, 168, 169, 99, + 339, 418, 418, 309, 418, 418, 418, 418, 418, 418, + 147, 418, 418, 418, 418, 27, 418, 186, 418, 418, + 418, 418, 418, 418, 212, 418, 272, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + + 418, 418, 418, 418, 418, 418, 418, 201, 200, 238, + 47, 418, 418, 418, 418, 387, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 337, 418, + 418, 418, 368, 418, 418, 418, 418, 418, 418, 418, + 116, 418, 418, 271, 418, 418, 300, 334, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 378, + 418, 112, 56, 67, 5, 418, 418, 353, 418, 357, + 355, 418, 418, 257, 418, 418, 418, 418, 335, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 287, 29, + + 418, 418, 418, 418, 418, 418, 262, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 288, 418, 418, + 418, 418, 418, 418, 418, 164, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 202, 418, 211, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 363, + 365, 359, 418, 418, 331, 418, 418, 418, 418, 418, + 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, + 418, 418, 418, 372, 351, 418, 418, 295, 418, 418, + 418, 418, 418, 332, 418, 418, 418, 418, 418, 418, + 333, 418, 418, 418, 293, 418, 296, 297, 418, 418, + + 418, 418, 418, 294, 298, 0 } ; static yyconst flex_int32_t yy_ec[256] = @@ -875,17 +884,17 @@ static yyconst flex_int32_t yy_meta[41] 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; -static yyconst flex_int16_t yy_base[4148] = +static yyconst flex_int16_t yy_base[4225] = { 0, 0, 0, 38, 41, 44, 46, 59, 65, 71, 77, - 90, 112, 96, 118, 124, 136, 3759, 3487, 81, 8042, - 8042, 8042, 129, 52, 137, 63, 130, 159, 70, 132, + 90, 112, 96, 118, 124, 136, 4011, 3391, 81, 8183, + 8183, 8183, 129, 52, 137, 63, 130, 159, 70, 132, 134, 146, 57, 88, 76, 176, 178, 95, 200, 161, - 188, 202, 169, 194, 219, 97, 148, 3112, 8042, 8042, - 8042, 165, 3078, 8042, 8042, 8042, 221, 2637, 2599, 8042, - 8042, 8042, 239, 2469, 8042, 8042, 8042, 243, 1903, 8042, - 247, 8042, 251, 231, 1775, 1735, 8042, 8042, 8042, 258, - 1620, 8042, 8042, 8042, 262, 1495, 266, 198, 0, 270, + 188, 202, 169, 194, 219, 97, 148, 3359, 8183, 8183, + 8183, 165, 2999, 8183, 8183, 8183, 221, 2797, 2546, 8183, + 8183, 8183, 239, 2348, 8183, 8183, 8183, 243, 1989, 8183, + 247, 8183, 251, 231, 1900, 1884, 8183, 8183, 8183, 258, + 1737, 8183, 8183, 8183, 262, 1636, 266, 198, 0, 270, 0, 0, 223, 192, 236, 250, 255, 264, 268, 272, 92, 267, 266, 273, 277, 278, 282, 289, 290, 292, @@ -894,8 +903,8 @@ static yyconst flex_int16_t yy_base[4148 345, 152, 346, 348, 349, 353, 356, 360, 358, 363, 359, 361, 372, 371, 370, 373, 379, 167, 395, 387, 383, 400, 390, 394, 388, 403, 410, 402, 411, 405, - 408, 415, 422, 423, 1271, 434, 1215, 325, 1097, 439, - 1058, 970, 444, 941, 448, 452, 0, 377, 819, 456, + 408, 415, 422, 423, 1425, 434, 1275, 325, 1010, 439, + 982, 941, 444, 849, 448, 452, 0, 377, 819, 456, 570, 428, 460, 448, 460, 455, 456, 457, 459, 461, 458, 462, 463, 465, 464, 468, 476, 488, 475, 486, @@ -912,890 +921,908 @@ static yyconst flex_int16_t yy_base[4148 684, 715, 716, 717, 725, 718, 720, 685, 727, 730, 734, 723, 736, 738, 733, 743, 745, 746, 747, 751, - 740, 8042, 761, 752, 763, 762, 771, 768, 753, 769, + 740, 8183, 761, 752, 763, 762, 771, 768, 753, 769, 773, 776, 777, 775, 778, 779, 780, 782, 783, 784, 786, 790, 802, 791, 804, 800, 798, 812, 811, 813, 826, 787, 815, 816, 847, 817, 818, 822, 837, 829, 851, 853, 842, 855, 858, 859, 860, 827, 861, 863, 871, 879, 881, 832, 869, 883, 891, 886, 887, 889, - 890, 899, 900, 8042, 894, 892, 902, 908, 910, 917, + 890, 899, 900, 8183, 894, 892, 902, 908, 910, 917, 904, 929, 924, 907, 925, 934, 931, 932, 946, 968, - 933, 935, 936, 939, 944, 8042, 957, 948, 992, 950, + 933, 935, 936, 939, 944, 8183, 957, 948, 992, 950, 952, 978, 979, 975, 942, 966, 982, 974, 980, 996, - 849, 986, 993, 1000, 1015, 998, 1002, 1010, 1001, 1018, - 1020, 1017, 1033, 1028, 1024, 1026, 1031, 1034, 1035, 1042, - 1037, 895, 1040, 1054, 1039, 1041, 1047, 1050, 1043, 1056, - 1055, 1065, 1069, 1070, 1071, 1064, 1075, 1076, 1077, 1079, - 1078, 1101, 1088, 1094, 1091, 1080, 1099, 1110, 1081, 1105, - 1109, 1117, 1107, 1116, 1123, 1121, 1126, 1127, 1128, 1129, - 1130, 1138, 1135, 1137, 1139, 1143, 1144, 1145, 1147, 1151, - 1152, 1153, 1155, 1157, 1158, 1159, 1161, 1168, 1165, 1162, - - 1175, 1177, 1178, 1183, 1179, 8042, 1187, 1185, 8042, 1188, - 1189, 1190, 1191, 1192, 1193, 1194, 1195, 8042, 1202, 1203, - 1196, 1210, 1205, 1212, 1208, 1217, 1229, 1225, 1218, 1228, - 1231, 1233, 1235, 1237, 1244, 1240, 1242, 1249, 1241, 1248, - 1251, 1254, 1252, 1257, 1258, 1261, 1259, 1262, 1265, 1266, - 1285, 8042, 1268, 1269, 1272, 1277, 1270, 1292, 1280, 1294, - 1303, 1295, 1302, 1300, 1306, 1320, 1309, 1313, 1318, 1317, - 1322, 1282, 1323, 1330, 1326, 1332, 1328, 1333, 1335, 1336, - 1345, 1337, 1338, 1347, 1349, 8042, 1339, 1352, 1356, 1359, - 1370, 1353, 1366, 1367, 1368, 1375, 1372, 1371, 1373, 1378, - - 1374, 1379, 1380, 1384, 1396, 1385, 1398, 1399, 1394, 1401, - 1395, 1400, 1402, 1408, 1410, 1405, 1411, 1416, 1425, 1418, - 1422, 1429, 1435, 1440, 1437, 1439, 1447, 1449, 1426, 1442, - 1445, 1414, 1446, 1450, 1452, 1453, 1454, 1455, 1458, 1461, - 1468, 1464, 1466, 1467, 1471, 1472, 1473, 1475, 1479, 1482, - 1480, 1481, 1483, 1494, 1491, 1492, 1501, 1489, 1510, 1498, - 1502, 1514, 1515, 1508, 1517, 8042, 1521, 1529, 1525, 1527, - 1531, 1526, 1528, 1536, 1537, 1538, 1540, 1541, 1543, 1544, - 1546, 1551, 1552, 1553, 1547, 1555, 1559, 1563, 1565, 1564, - 1493, 1574, 1569, 1567, 1585, 1571, 1576, 1584, 1578, 1586, - - 1588, 1590, 1591, 1598, 1594, 1603, 1601, 1593, 1606, 1605, - 1613, 1609, 1608, 1615, 1614, 1628, 1625, 1616, 1617, 1629, - 1630, 1636, 1632, 1638, 1641, 1649, 1642, 1651, 1658, 1660, - 1653, 1662, 1655, 1663, 1667, 1668, 1669, 1671, 1672, 1670, - 1679, 1676, 1675, 1677, 1681, 1682, 1683, 1694, 1693, 1701, - 1685, 1698, 1699, 1703, 1704, 1707, 1709, 1710, 1714, 1715, - 1716, 1717, 1718, 1719, 1727, 1720, 1738, 1729, 1731, 1740, - 1732, 1739, 1745, 1747, 1749, 1748, 1752, 1753, 1754, 1758, - 1759, 1756, 1765, 1767, 1768, 1770, 1771, 1769, 1783, 1784, - 1785, 1786, 1773, 1791, 1792, 1793, 1794, 1795, 1798, 1801, - - 1805, 1806, 1803, 8042, 1809, 1819, 1814, 1815, 1817, 1818, - 1820, 1822, 1829, 1831, 1824, 1826, 1827, 1836, 1837, 1838, - 1863, 8042, 1842, 8042, 8042, 1846, 1839, 8042, 8042, 1844, - 1849, 8042, 1847, 1860, 1850, 1848, 1867, 1851, 1873, 1870, - 1861, 1876, 1877, 1884, 1898, 1886, 1887, 1880, 1889, 1891, - 1888, 1904, 1909, 1894, 1915, 1896, 1893, 1922, 1927, 1923, - 1928, 1931, 1932, 1933, 1935, 1936, 1938, 1942, 1945, 1944, - 1948, 1949, 1950, 1951, 1954, 1952, 1957, 1955, 1959, 1961, - 1962, 1964, 1965, 1966, 1978, 1969, 1981, 1990, 8042, 1986, - 1993, 1983, 1976, 1992, 1995, 2002, 1998, 2005, 1997, 2001, - - 2004, 2009, 2014, 2006, 2010, 2016, 2017, 2019, 2020, 2021, - 2025, 2026, 2029, 2031, 2030, 2033, 2042, 2035, 2037, 8042, - 2043, 2044, 2046, 2048, 2049, 2047, 2050, 2054, 2055, 2058, - 2063, 2068, 2061, 2051, 2069, 2070, 2080, 2077, 2081, 2084, - 2085, 2086, 2087, 2088, 2089, 8042, 2094, 2098, 2093, 2102, - 2101, 2103, 2090, 2105, 2109, 2112, 2115, 2113, 2116, 2117, - 2118, 2127, 2119, 2126, 2123, 2129, 2130, 2134, 2133, 2142, - 2145, 2147, 2143, 2149, 2151, 2152, 2153, 2154, 2155, 2157, - 2158, 2159, 2170, 2171, 2166, 2173, 2168, 2163, 2181, 2190, - 2185, 2186, 2187, 2188, 2191, 2194, 2198, 2202, 2197, 2201, - - 2203, 2210, 2206, 2209, 2211, 2214, 2213, 2217, 2231, 2221, - 2224, 2222, 2215, 2232, 2234, 2238, 2239, 8042, 2240, 2241, - 2242, 8042, 2244, 2246, 2247, 2269, 2248, 2250, 2259, 2260, - 2262, 2254, 2277, 2267, 2271, 2265, 2270, 2288, 2289, 2297, - 2292, 2294, 2295, 2298, 2304, 2300, 2302, 2306, 2315, 2310, - 2316, 2317, 2318, 2321, 2324, 2328, 2338, 2334, 2340, 2342, - 2325, 2337, 2339, 2358, 2341, 2343, 2346, 2349, 2344, 2350, - 2354, 2351, 2352, 2367, 2363, 2369, 2370, 2379, 2371, 2375, - 2374, 2380, 2383, 2385, 2390, 2391, 2393, 8042, 2400, 2273, - 2397, 2399, 2398, 2408, 2405, 2406, 8042, 2409, 2412, 2407, - - 2420, 2415, 2417, 2419, 2422, 2424, 2428, 2429, 2431, 2433, - 2432, 2434, 2440, 2435, 2453, 8042, 2439, 8042, 2448, 2437, - 2449, 2454, 2456, 2464, 2459, 2460, 2463, 2465, 2466, 2467, - 8042, 8042, 2468, 2470, 2476, 2482, 2490, 2492, 2487, 2488, - 2489, 8042, 2477, 2500, 8042, 2497, 2491, 2504, 2495, 2505, - 2508, 2510, 2514, 2515, 2511, 2516, 2517, 2520, 2519, 2529, - 2521, 2542, 2522, 2538, 2512, 8042, 2539, 2544, 2524, 2546, - 2548, 2549, 2550, 2552, 2555, 2554, 8042, 2556, 2558, 2561, - 2563, 2570, 2569, 2571, 2572, 2573, 2577, 2575, 2579, 2581, - 2582, 2583, 2592, 2594, 2595, 2597, 2599, 2606, 2603, 2611, - - 8042, 2607, 2591, 2610, 2619, 2615, 2617, 2614, 2618, 2621, - 2622, 2624, 2625, 2629, 2631, 2633, 2634, 2635, 2636, 2645, - 2650, 2641, 2646, 2649, 2653, 2654, 2657, 2658, 2663, 2660, - 2661, 2662, 2664, 8042, 2665, 2666, 2674, 2671, 2677, 2680, - 2667, 216, 2683, 2686, 2688, 2690, 2693, 2691, 2699, 2692, - 2709, 2710, 2705, 2696, 2707, 2714, 2715, 2716, 2694, 2718, - 2720, 2722, 2724, 2726, 2727, 2730, 2728, 8042, 2736, 2738, - 2740, 2733, 2731, 2754, 2741, 2751, 2739, 2750, 8042, 2758, - 2760, 2763, 2771, 2746, 2765, 2767, 2772, 2773, 2776, 2774, - 8042, 2777, 2779, 2784, 2786, 2785, 2787, 2788, 2789, 8042, - - 2803, 2795, 2804, 2791, 2805, 2793, 2806, 2807, 2812, 2813, - 2814, 2816, 2818, 2821, 2819, 2820, 2824, 2823, 2828, 2834, - 2836, 2835, 2837, 2839, 2844, 2846, 2840, 2847, 2849, 2853, - 2860, 2850, 8042, 2864, 2861, 2863, 2867, 2851, 2862, 2879, - 2869, 2886, 2872, 2873, 2882, 2888, 2896, 2890, 2893, 2894, - 2908, 2898, 2907, 2910, 2911, 2922, 2913, 2921, 2923, 2917, - 2927, 2929, 2925, 2930, 2931, 2939, 2941, 2937, 2942, 2944, - 2947, 2946, 2949, 2956, 2953, 2961, 2957, 2954, 2963, 2965, - 2966, 2968, 2969, 2975, 2977, 8042, 2980, 2978, 2986, 2987, - 2989, 2991, 2995, 3002, 2997, 2999, 3000, 3003, 2992, 3007, - - 3011, 3008, 3014, 3015, 3017, 3018, 3025, 3020, 3026, 3027, - 3028, 3039, 3031, 3024, 3030, 3040, 3041, 3043, 3047, 3049, - 3051, 3052, 3053, 8042, 3056, 3060, 3054, 3061, 3063, 3067, - 3069, 3071, 3074, 3075, 3076, 3077, 3081, 3082, 2883, 3083, - 3084, 3091, 3088, 3090, 3092, 3089, 8042, 3100, 3095, 3101, - 3106, 3105, 3108, 3109, 3115, 3118, 3122, 3123, 3125, 3116, - 3126, 3128, 3129, 8042, 3137, 3139, 3136, 3138, 3146, 3144, - 3145, 3147, 3149, 3150, 3151, 8042, 3152, 3154, 3155, 3159, - 3156, 3160, 3167, 3168, 3163, 3166, 8042, 3179, 3175, 3178, - 3180, 3187, 3182, 3184, 3186, 3188, 3190, 3193, 3194, 3197, - - 3199, 3203, 3208, 3201, 3205, 8042, 3209, 3211, 3214, 3218, - 3216, 3220, 3222, 3229, 3226, 3230, 3232, 3236, 3233, 3246, - 3235, 8042, 3257, 3223, 3252, 3243, 3259, 3255, 3260, 3261, - 3262, 3263, 3264, 3265, 3270, 3266, 3272, 8042, 3273, 3275, - 3276, 3277, 3280, 3281, 3282, 3291, 3288, 3289, 3295, 3296, - 3297, 3298, 3302, 3303, 3304, 3315, 3306, 3309, 3317, 3307, - 3316, 3318, 3326, 3327, 3329, 3330, 3338, 3339, 3334, 3342, - 3345, 3340, 3335, 3337, 3347, 3356, 3359, 3360, 3361, 3363, - 8042, 3366, 3367, 3368, 3355, 3357, 3370, 3372, 3374, 3375, - 3378, 3380, 3392, 3389, 3379, 3382, 3396, 3403, 3400, 3391, - - 3405, 3399, 3407, 3408, 3409, 3410, 3412, 3413, 3416, 3421, - 3419, 3428, 3420, 3423, 3425, 3427, 3436, 3432, 3435, 3445, - 3437, 3446, 3442, 3444, 3447, 3448, 3450, 3449, 3454, 3457, - 3459, 3452, 3460, 3465, 3473, 3475, 3476, 3478, 3480, 3468, - 3485, 3484, 8042, 8042, 3486, 8042, 3489, 3491, 3495, 3498, - 3499, 3502, 3500, 3503, 3504, 3510, 3506, 3518, 3514, 3517, - 3522, 3519, 3521, 3527, 3526, 3532, 3528, 3533, 3540, 3536, - 8042, 3538, 8042, 3545, 3541, 3542, 3543, 3554, 3549, 8042, - 3552, 8042, 3555, 3560, 3557, 3561, 3563, 8042, 3564, 3565, - 3568, 3566, 3570, 3571, 3574, 3576, 3580, 3578, 3581, 3591, - - 3592, 3587, 3582, 3594, 3598, 3584, 3601, 3603, 3606, 3605, - 3607, 3612, 3614, 3608, 3615, 3613, 3619, 3620, 3621, 3626, - 3627, 8042, 3630, 3640, 3633, 3637, 3641, 3642, 3643, 3648, - 3644, 3651, 3647, 3657, 3652, 3649, 3655, 3668, 3656, 3667, - 3659, 3680, 3660, 3677, 3671, 3681, 3684, 3692, 3674, 3693, - 3685, 8042, 3688, 3696, 3697, 3698, 3699, 3700, 8042, 3703, - 3705, 3701, 3711, 3713, 3707, 3709, 3715, 3719, 3723, 3718, - 3720, 3726, 3731, 3728, 3735, 3733, 3739, 8042, 3741, 3743, - 3744, 3751, 3753, 3747, 3761, 3762, 3759, 3765, 3767, 3763, - 3770, 3760, 3772, 3774, 3776, 3777, 3784, 3785, 3787, 3783, - - 3792, 3782, 3789, 3798, 3795, 3791, 3799, 3801, 3802, 3803, - 3804, 3807, 3811, 3812, 3810, 3806, 3813, 3827, 3814, 3808, - 8042, 3818, 3823, 3832, 3840, 3836, 3837, 3838, 3841, 3839, - 3843, 3848, 8042, 3847, 3849, 3854, 3850, 3851, 3861, 3863, - 3864, 3865, 3866, 3868, 3870, 3867, 3878, 3873, 8042, 3879, - 8042, 3880, 3872, 3892, 3901, 3903, 3881, 3886, 3905, 3891, - 3910, 3907, 3896, 3911, 3912, 3913, 3914, 3919, 3921, 3922, - 3923, 3924, 3925, 3934, 3927, 3928, 3936, 3932, 3935, 3938, - 3947, 3945, 3948, 3949, 3956, 3952, 3954, 8042, 8042, 3953, - 3959, 3967, 3961, 3969, 3970, 3971, 3973, 3975, 3980, 3983, - - 3990, 3981, 3989, 3991, 3993, 3997, 4002, 8042, 3998, 4003, - 3999, 4000, 4006, 4010, 4007, 4017, 4019, 4022, 4023, 4030, - 4026, 8042, 4008, 4011, 4029, 4039, 4034, 4035, 4042, 8042, - 4040, 8042, 4041, 4045, 4046, 4049, 4050, 4052, 4053, 4054, - 4056, 4058, 4059, 4068, 4076, 4077, 4075, 4074, 4080, 4062, - 4081, 4083, 4085, 4088, 4092, 4090, 4091, 4093, 8042, 4095, - 4096, 4100, 4098, 4097, 4105, 4108, 4106, 4109, 8042, 4119, - 8042, 4114, 4118, 4120, 4124, 4126, 4129, 4121, 4130, 4131, - 4135, 4138, 4137, 4139, 4144, 4145, 4147, 4149, 4148, 8042, - 4153, 4154, 4161, 4157, 4158, 4164, 4163, 4175, 4165, 4167, - - 8042, 4177, 4179, 4171, 4180, 4181, 4190, 4188, 4183, 4191, - 4196, 4192, 4194, 4200, 4201, 4198, 4202, 4204, 4205, 4206, - 4209, 4210, 4211, 4208, 4222, 4224, 4223, 4226, 4236, 4231, - 8042, 4232, 4235, 4237, 4239, 4240, 4241, 4245, 4246, 4250, - 4258, 4242, 4264, 4265, 4251, 4253, 4267, 4269, 4271, 4276, - 4277, 8042, 4279, 4278, 4287, 4282, 4283, 4284, 4285, 4290, - 4295, 4286, 4297, 4299, 4300, 4291, 4303, 4304, 4313, 4311, - 4307, 4317, 4318, 4319, 4320, 4327, 4322, 4323, 4325, 4328, - 8042, 4345, 4334, 4326, 4347, 4324, 4346, 4356, 4351, 4352, - 4353, 4354, 4357, 4355, 4359, 4362, 4363, 4365, 4368, 4369, - - 4378, 4380, 4366, 8042, 8042, 4382, 4371, 4374, 4392, 8042, - 4384, 4387, 4395, 4394, 4397, 4398, 4399, 4401, 4402, 4403, - 4404, 4410, 4405, 4406, 4421, 4409, 4412, 8042, 4430, 4417, - 4432, 4425, 4427, 4439, 4436, 8042, 4429, 4443, 4441, 4442, - 4444, 4446, 4449, 4451, 4452, 4450, 4454, 4456, 4458, 4459, - 4463, 4465, 4472, 4464, 4477, 4479, 4468, 4471, 4483, 8042, - 4475, 4480, 4489, 4482, 4490, 4491, 4492, 8042, 4493, 4496, - 4497, 4499, 4504, 4509, 4506, 4516, 4511, 4518, 4519, 4521, - 4523, 4524, 4525, 4526, 4528, 4536, 4531, 4532, 4533, 4537, - 4544, 4551, 4553, 8042, 4554, 4555, 4539, 4556, 4565, 8042, - - 4568, 4575, 4576, 8042, 4578, 4534, 4577, 4573, 4586, 8042, - 4579, 4558, 4581, 4583, 4587, 4594, 4589, 4596, 4592, 4595, - 4598, 4599, 4601, 4603, 4602, 8042, 4604, 4605, 4610, 8042, - 4620, 4606, 4622, 4626, 4627, 4630, 4637, 4617, 4613, 4640, - 4635, 4638, 4636, 4639, 8042, 4644, 4651, 8042, 4652, 4653, - 4646, 4647, 4654, 4660, 8042, 4656, 4658, 4666, 4663, 4664, - 4672, 4674, 4675, 4681, 4665, 4682, 4676, 4683, 4690, 4688, - 4693, 4695, 4686, 4687, 4697, 4699, 8042, 4700, 4703, 4705, - 4707, 4706, 4708, 4710, 4711, 4717, 4720, 4718, 8042, 8042, - 4728, 8042, 4729, 4724, 4730, 4733, 8042, 4722, 4734, 4741, - - 4736, 4742, 4745, 4744, 4750, 4739, 4752, 4754, 8042, 4760, - 4763, 8042, 4755, 4761, 4771, 4766, 4768, 4769, 4770, 4772, - 4776, 4774, 4781, 4782, 4783, 4784, 4779, 4788, 4786, 4808, - 4787, 4809, 8042, 4799, 4800, 4792, 4814, 4803, 4806, 4817, - 4822, 4824, 4830, 4816, 4818, 8042, 4832, 4833, 4834, 4836, - 4839, 8042, 8042, 4840, 8042, 4842, 4844, 8042, 4843, 4845, - 4848, 4850, 4851, 4862, 4854, 8042, 4857, 4858, 4864, 4861, - 4868, 4875, 8042, 4876, 4878, 4866, 4870, 4869, 4885, 4886, - 4880, 4882, 4896, 4892, 8042, 4897, 4898, 4899, 4902, 4903, - 4906, 4905, 4907, 4914, 4910, 4919, 4924, 4928, 4913, 4929, - - 4932, 4925, 4935, 4930, 4936, 4938, 4940, 4943, 4944, 8042, - 4946, 4945, 4951, 4947, 4961, 4952, 4956, 4958, 8042, 4959, - 4963, 4966, 4969, 8042, 4967, 4973, 4976, 4978, 4979, 4982, - 4983, 4986, 4984, 4989, 4990, 4987, 8042, 4994, 4995, 4988, - 4991, 4999, 5010, 4998, 8042, 8042, 5011, 8042, 5012, 5013, - 5014, 5015, 5020, 5022, 5024, 5025, 5027, 5021, 5028, 5037, - 5035, 5038, 5042, 5032, 8042, 5043, 5050, 5046, 5054, 5055, - 5064, 5056, 8042, 5061, 5060, 8042, 5063, 8042, 5065, 5066, - 5071, 5072, 5067, 5075, 5077, 5079, 5081, 5086, 8042, 5095, - 5082, 5085, 5096, 5090, 5093, 5103, 5104, 5106, 8042, 5107, - - 5110, 5112, 5113, 8042, 5114, 5115, 5117, 5119, 5118, 5121, - 5123, 5122, 5124, 5127, 5125, 5129, 5131, 5137, 5143, 5142, - 5145, 5146, 5149, 5150, 5151, 5153, 5154, 5158, 8042, 5155, - 5159, 5162, 5165, 5167, 5168, 5170, 5173, 5174, 5175, 5182, - 5179, 5183, 8042, 5180, 8042, 5185, 5187, 5191, 5200, 5193, - 5204, 5205, 5206, 5199, 5207, 5208, 5211, 5214, 5217, 5218, - 5226, 5219, 5221, 5227, 5228, 8042, 5238, 5241, 5230, 5243, - 5239, 5247, 5250, 5252, 8042, 5253, 5235, 5254, 5256, 5259, - 8042, 5260, 5262, 5264, 5265, 5267, 5269, 5271, 5275, 5276, - 5278, 5280, 5282, 5283, 5285, 5288, 5286, 5294, 5295, 5291, - - 8042, 5297, 5299, 5300, 5307, 5304, 5308, 5311, 5312, 5320, - 5324, 5314, 5301, 5325, 8042, 5326, 5318, 5329, 5338, 8042, - 5330, 5331, 5334, 5339, 5340, 5343, 5345, 5335, 5347, 5348, - 5352, 5358, 5351, 5359, 8042, 5363, 5349, 5365, 5368, 5371, - 5373, 5375, 5376, 5379, 5383, 5384, 5385, 8042, 5387, 5394, - 5393, 5395, 5396, 5397, 5399, 5404, 5407, 5408, 5409, 8042, - 5410, 5414, 5418, 5411, 5427, 5430, 5417, 5428, 5437, 5429, - 5436, 5420, 5433, 5439, 5432, 5440, 5444, 5447, 5448, 5450, - 5460, 5461, 5458, 8042, 5451, 8042, 5459, 5463, 5465, 5473, - 5468, 5470, 5474, 5475, 5482, 5480, 5478, 8042, 5486, 5487, - - 5489, 5490, 5492, 5495, 5491, 5506, 8042, 5496, 5493, 5497, - 5507, 8042, 5510, 5515, 5494, 5516, 5517, 5522, 5524, 5527, - 5518, 5530, 8042, 5533, 5534, 5535, 5542, 5545, 5541, 5544, - 5546, 5547, 5549, 5551, 5553, 5554, 5555, 5563, 5558, 5559, - 8042, 5562, 5565, 5570, 5571, 5574, 5575, 5577, 5578, 5581, - 5583, 5580, 8042, 5587, 5588, 5589, 5590, 5591, 5595, 5594, - 5596, 5603, 5600, 5611, 5602, 5615, 5604, 5613, 5617, 5618, - 5619, 5621, 8042, 5625, 5626, 5624, 5633, 5634, 5630, 5639, - 8042, 5635, 8042, 5631, 5643, 5646, 5648, 5649, 8042, 5652, - 5653, 5656, 5654, 5660, 8042, 8042, 5658, 5669, 5664, 5666, - - 5670, 5667, 5673, 8042, 8042, 5675, 8042, 5671, 8042, 5677, - 5678, 8042, 8042, 5681, 5683, 5684, 5687, 5690, 8042, 5688, - 5692, 5696, 8042, 5699, 8042, 5706, 5701, 5702, 5704, 5707, - 5708, 8042, 5712, 5714, 5710, 5715, 5719, 8042, 5716, 5724, - 5728, 5736, 5723, 5725, 8042, 5738, 5726, 5739, 5742, 5744, - 5743, 5747, 5749, 5750, 5751, 5752, 5755, 8042, 5756, 5761, - 5763, 5764, 5765, 5753, 5775, 5767, 5776, 5777, 5781, 5778, - 5779, 5784, 5787, 5786, 5788, 5795, 5797, 5801, 5798, 5805, - 5802, 5806, 5808, 5812, 5814, 5816, 5817, 5818, 5819, 5821, - 5822, 5824, 5825, 5827, 5832, 5829, 5834, 5835, 5836, 5841, - - 5845, 5846, 5848, 5849, 5855, 5850, 5857, 5852, 5860, 5858, - 5861, 5862, 5863, 5867, 5864, 5873, 5870, 5883, 5881, 5874, - 5877, 8042, 5887, 5866, 5891, 5893, 5895, 5896, 5897, 5901, - 5899, 5902, 5909, 5911, 5906, 5916, 8042, 8042, 8042, 5903, - 5920, 8042, 5922, 5914, 5924, 5925, 5926, 8042, 5927, 5928, - 5929, 5930, 5933, 5931, 5934, 5936, 5937, 5942, 5943, 5948, - 8042, 5952, 5959, 5955, 5945, 5962, 5964, 8042, 5965, 5973, - 5966, 5968, 5970, 5975, 5976, 5977, 5978, 5981, 5979, 5983, - 5985, 5992, 5994, 6001, 5990, 6002, 6003, 8042, 6005, 6007, - 6014, 6011, 6012, 6013, 6015, 6017, 6016, 6019, 6022, 6023, - - 6024, 6025, 6026, 6027, 6033, 6039, 6046, 6048, 6052, 8042, - 6035, 6056, 6040, 8042, 6049, 6053, 6057, 6060, 6061, 6063, - 6064, 6065, 6067, 6071, 8042, 8042, 6068, 6073, 6074, 6076, - 6078, 6079, 6082, 6083, 6085, 6092, 8042, 6086, 6089, 6099, - 6098, 6107, 6095, 8042, 6103, 6109, 6110, 6112, 6113, 6114, - 6115, 6117, 6118, 6120, 6123, 6124, 6129, 8042, 6134, 6132, - 6136, 6142, 6148, 6135, 6150, 6151, 6152, 6137, 6145, 6155, - 6159, 8042, 6160, 8042, 8042, 8042, 6162, 6164, 6165, 6167, - 6169, 6170, 6171, 6168, 6176, 6179, 6190, 6172, 6178, 8042, - 6195, 8042, 8042, 6186, 8042, 6196, 6197, 6198, 6199, 6200, - - 6204, 6202, 8042, 6205, 8042, 6209, 6212, 6206, 6216, 6223, - 6224, 6218, 6225, 6208, 6232, 6228, 6234, 6226, 6236, 6180, - 6237, 6238, 6241, 8042, 6245, 6247, 6248, 6250, 6252, 8042, - 8042, 6256, 6257, 6258, 6260, 6263, 6274, 6264, 6271, 6265, - 6281, 6278, 6280, 6283, 6277, 6284, 6287, 6289, 6296, 6297, - 6293, 6292, 6301, 8042, 6302, 6303, 6311, 8042, 6294, 8042, - 6307, 6313, 6315, 6305, 6316, 6317, 6319, 6321, 6324, 6327, - 6336, 6332, 8042, 8042, 6325, 6340, 6335, 8042, 8042, 6338, - 6339, 6342, 6344, 6346, 6347, 6348, 8042, 6349, 6351, 6352, - 6350, 6355, 6356, 6369, 6361, 8042, 6366, 8042, 6370, 8042, - - 6372, 6373, 6379, 6374, 6382, 6389, 8042, 6384, 6386, 6391, - 6388, 6392, 6393, 6396, 8042, 6397, 6394, 8042, 6408, 6395, - 6405, 6410, 6411, 6413, 6414, 8042, 6415, 6417, 6419, 6420, - 8042, 6421, 6423, 6426, 6427, 6431, 6433, 6430, 6440, 6442, - 8042, 6444, 6446, 6447, 6445, 8042, 6456, 8042, 6448, 6457, - 6451, 6465, 6458, 8042, 6460, 6461, 6466, 6471, 8042, 6474, - 6476, 6478, 6479, 6483, 6484, 8042, 6488, 6467, 8042, 6469, - 6491, 6492, 6495, 6498, 6500, 6501, 6502, 6503, 6510, 6506, - 6507, 8042, 8042, 6522, 6509, 6524, 6523, 123, 6531, 6515, - 6519, 6526, 6527, 6535, 6540, 6542, 6532, 6537, 6544, 8042, - - 8042, 6548, 6545, 6549, 8042, 6551, 6552, 8042, 6553, 6558, - 6562, 6554, 6560, 6564, 6567, 6568, 6569, 6574, 6570, 6576, - 6575, 6577, 6585, 8042, 6592, 6600, 6590, 6581, 6597, 6601, - 6603, 6605, 6607, 6595, 6610, 6612, 6613, 6614, 6617, 6616, - 6620, 6618, 6621, 6619, 6622, 6627, 6629, 8042, 6634, 6636, - 6638, 6631, 6644, 6645, 6648, 6640, 8042, 6655, 6650, 6660, - 6652, 6656, 8042, 6663, 6665, 6666, 6668, 6669, 6670, 8042, - 6664, 6672, 6677, 6680, 6681, 6683, 6685, 6686, 6687, 6694, - 8042, 6691, 6689, 6695, 6697, 6699, 6705, 6708, 6711, 6715, - 6709, 8042, 6716, 8042, 8042, 8042, 6717, 6719, 6721, 8042, - - 6726, 6723, 6727, 6728, 8042, 6730, 6733, 6734, 6742, 6738, - 8042, 8042, 8042, 6739, 6740, 6744, 8042, 6741, 6754, 8042, - 6747, 8042, 6749, 8042, 6751, 6755, 6757, 6762, 8042, 6763, - 6765, 8042, 6766, 6767, 6769, 6772, 8042, 6775, 6782, 6785, - 6778, 6786, 6788, 6790, 6791, 6789, 8042, 8042, 6798, 6796, - 6797, 6799, 6801, 6793, 6803, 6805, 6807, 6813, 6820, 8042, - 6816, 6818, 8042, 6819, 6822, 6824, 6832, 6821, 6828, 6830, - 8042, 6834, 8042, 6836, 8042, 6825, 6837, 6839, 6842, 6844, - 6847, 6848, 6692, 6851, 6849, 6858, 6855, 6859, 6857, 6861, - 6862, 6865, 6872, 6868, 8042, 8042, 6882, 6877, 8042, 6874, - - 6884, 6886, 8042, 6873, 8042, 6878, 6890, 8042, 6892, 6895, - 8042, 6896, 6897, 6898, 8042, 8042, 6900, 6902, 6905, 6910, - 6906, 6916, 6907, 8042, 6917, 6909, 6912, 6919, 6920, 6921, - 6924, 6930, 6925, 6928, 6932, 6937, 8042, 6944, 8042, 6934, - 6947, 6946, 8042, 8042, 6942, 6945, 6953, 6956, 6948, 6957, - 6959, 6961, 6960, 6962, 6973, 6965, 6968, 6966, 6975, 6976, - 6988, 6970, 6989, 6990, 6994, 8042, 8042, 8042, 6979, 6983, - 6996, 6997, 7004, 7000, 7005, 8042, 7007, 7006, 8042, 7009, - 7011, 7012, 7013, 7021, 7018, 7020, 8042, 7022, 7023, 7025, - 7026, 7028, 7029, 7030, 7031, 8042, 7038, 7043, 7045, 7047, - - 7049, 7051, 7054, 7058, 7060, 7055, 7061, 7066, 7062, 7067, - 7074, 7071, 8042, 8042, 7070, 7072, 8042, 7078, 7080, 8042, - 8042, 7073, 7081, 8042, 7083, 7084, 7085, 7086, 7089, 8042, - 7095, 7087, 7091, 7097, 8042, 7096, 7098, 7100, 7101, 7103, - 7115, 7118, 7109, 7112, 7125, 7117, 7126, 8042, 7120, 7133, - 7128, 7131, 7134, 7135, 8042, 8042, 7132, 7142, 8042, 7144, - 7146, 7145, 7155, 7152, 7154, 7157, 7158, 8042, 7147, 8042, - 7161, 7166, 7160, 7168, 7169, 7170, 7172, 7173, 7175, 8042, - 7177, 7176, 7178, 7179, 8042, 7183, 7186, 7187, 7189, 7192, - 8042, 7203, 7193, 7196, 7206, 8042, 7194, 7209, 7207, 8042, - - 8042, 8042, 7216, 7218, 7219, 8042, 8042, 8042, 7221, 7222, - 8042, 7225, 7226, 7228, 7230, 8042, 7233, 8042, 8042, 7235, - 7232, 7240, 7244, 7246, 7252, 7239, 8042, 7253, 7254, 7256, - 7257, 7259, 8042, 7261, 7265, 8042, 7268, 7272, 7276, 7269, - 7279, 7281, 7282, 7267, 7271, 7284, 7293, 7286, 7274, 8042, - 8042, 7288, 7290, 7295, 7296, 7300, 8042, 7298, 7301, 7302, - 7309, 7310, 7311, 7318, 7321, 7323, 7306, 7314, 7325, 7324, - 7332, 7340, 7327, 7335, 7337, 7338, 7339, 7341, 7346, 7348, - 7347, 7355, 7357, 7349, 7361, 8042, 8042, 7363, 7351, 7368, - 8042, 7370, 7371, 8042, 7359, 8042, 7373, 7375, 7379, 7382, - - 7384, 8042, 7386, 7388, 7390, 7392, 7376, 8042, 7394, 7396, - 8042, 8042, 7393, 7397, 7400, 7399, 7405, 8042, 8042, 7408, - 7401, 7409, 7398, 8042, 7411, 7416, 7412, 7423, 7419, 7424, - 7427, 7428, 7430, 7433, 8042, 7425, 7436, 8042, 8042, 8042, - 7438, 7441, 7444, 7445, 7448, 7446, 8042, 7450, 7457, 7452, - 7455, 7454, 7456, 7461, 8042, 7462, 7458, 8042, 8042, 7465, - 7463, 8042, 7475, 8042, 8042, 7470, 7472, 8042, 8042, 8042, - 8042, 8042, 8042, 8042, 8042, 8042, 7479, 7480, 8042, 7481, - 7482, 7485, 7486, 7488, 7493, 8042, 7489, 7495, 7498, 7500, - 8042, 7504, 8042, 7501, 7506, 7509, 7510, 7512, 8042, 7514, - - 8042, 7522, 7517, 7518, 7520, 7519, 7523, 7531, 7526, 7533, - 7535, 7534, 7536, 7541, 7537, 7542, 7543, 7544, 7545, 7555, - 7547, 7559, 7549, 7551, 7562, 7568, 7563, 7570, 7571, 7572, - 7573, 8042, 8042, 8042, 8042, 7574, 7576, 7581, 7577, 7582, - 7591, 7593, 7594, 7600, 7602, 7584, 7587, 7605, 7604, 7606, - 7597, 7610, 7618, 7613, 7614, 7615, 7617, 7619, 7624, 7629, - 7631, 8042, 7633, 7635, 7636, 8042, 7638, 7621, 7643, 7646, - 7634, 7647, 7651, 8042, 7648, 7653, 8042, 7652, 7654, 8042, - 8042, 7656, 7657, 7659, 7660, 7668, 7671, 7661, 7669, 7670, - 7673, 7681, 8042, 7684, 8042, 8042, 8042, 8042, 7677, 7685, - - 8042, 7686, 8042, 8042, 7674, 7687, 8042, 7688, 7691, 7693, - 7694, 8042, 7696, 7699, 7703, 7697, 7705, 7706, 7708, 7712, - 7715, 8042, 8042, 7711, 7719, 7720, 7721, 7724, 7726, 8042, - 7727, 7729, 7730, 7737, 7733, 7739, 7743, 7746, 7747, 7755, - 8042, 7750, 7752, 7753, 7759, 7756, 7763, 7760, 8042, 7764, - 7754, 7767, 7765, 7769, 7777, 7775, 7776, 7780, 7782, 7786, - 8042, 7790, 8042, 7787, 7796, 7793, 7798, 7797, 7799, 7800, - 7806, 7804, 8042, 8042, 8042, 7801, 7808, 8042, 7810, 7819, - 7811, 7821, 7823, 7826, 7825, 7815, 7828, 7838, 7835, 7839, - 7843, 7844, 7845, 7829, 7849, 7846, 8042, 8042, 7856, 7847, - - 8042, 7853, 7857, 7850, 7859, 7860, 8042, 7864, 7867, 7868, - 7870, 7873, 7874, 8042, 7876, 7880, 7877, 8042, 7883, 8042, - 8042, 7885, 7882, 7889, 7892, 7894, 8042, 8042, 8042, 7922, - 7929, 7936, 7943, 7950, 7957, 7964, 88, 7971, 7978, 7985, - 7992, 7999, 8006, 8013, 8020, 8027, 8034 + 998, 986, 993, 1001, 1023, 1019, 1002, 1009, 1003, 1020, + 1021, 1028, 1036, 1031, 1033, 1034, 1037, 1035, 1038, 1045, + 1040, 895, 1047, 1060, 1041, 1044, 1050, 1051, 1048, 1068, + 1054, 1069, 1073, 1074, 1075, 1063, 1079, 1080, 1081, 1083, + 1092, 1115, 1090, 1086, 1098, 1087, 1102, 1110, 1085, 1107, + 1105, 1116, 1117, 1088, 1123, 1118, 1126, 1121, 1130, 1134, + 1137, 1145, 1141, 1144, 1127, 1143, 1149, 1150, 1151, 1153, + 1156, 1157, 1158, 1163, 1161, 1162, 1167, 1169, 1168, 1177, + + 1178, 1179, 1182, 1171, 1184, 1188, 8183, 1195, 1193, 8183, + 1191, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 8183, 1206, + 1209, 1203, 1217, 1208, 1219, 1215, 1216, 1235, 1228, 1230, + 1232, 1236, 1237, 1238, 1241, 1248, 1245, 1246, 1258, 1247, + 1254, 1255, 1257, 1256, 1262, 1263, 1266, 1264, 1267, 1270, + 1271, 1290, 8183, 1272, 1273, 1280, 1282, 1274, 1297, 1285, + 1299, 1308, 1300, 1307, 1305, 1311, 1325, 1314, 1322, 1323, + 1327, 1328, 1287, 1331, 1333, 1336, 1335, 1339, 1337, 1341, + 1343, 1344, 1349, 1346, 1357, 1345, 1353, 1359, 8183, 1360, + 1361, 1363, 1369, 1377, 1374, 1375, 1376, 1378, 1385, 1381, + + 1380, 1383, 1384, 1389, 1382, 1393, 1400, 1394, 1402, 1409, + 1410, 1405, 1408, 1407, 1412, 1413, 1415, 1420, 1416, 1422, + 1424, 1436, 1426, 1429, 1433, 1444, 1443, 1446, 1448, 1455, + 1457, 1450, 1452, 1453, 1458, 1454, 1460, 1462, 1463, 1464, + 1467, 1472, 1471, 1480, 1476, 1477, 1482, 1478, 1484, 1485, + 1487, 1488, 1489, 1492, 1497, 1495, 1499, 1501, 1503, 1516, + 1504, 1507, 1505, 1510, 1520, 1529, 1518, 1521, 8183, 1530, + 1537, 1535, 1538, 1539, 1540, 1542, 1545, 1546, 1550, 1549, + 1553, 1552, 1555, 1556, 1554, 1558, 1562, 1563, 1564, 1572, + 1569, 1573, 1575, 1578, 1580, 1581, 1591, 1586, 1595, 1599, + + 1584, 1601, 1583, 1602, 1603, 1605, 1606, 1607, 1614, 1610, + 1618, 1613, 1609, 1622, 1621, 1629, 1625, 1624, 1631, 1630, + 1644, 1641, 1632, 1633, 1645, 1646, 1652, 1648, 1654, 1657, + 1665, 1658, 1667, 1674, 1676, 1669, 1512, 1671, 1678, 1679, + 1681, 1683, 1684, 1685, 1686, 1693, 1688, 1689, 1695, 1696, + 1691, 1697, 1705, 1703, 1713, 1712, 1714, 1715, 1719, 1720, + 1721, 1722, 1724, 1723, 1725, 1729, 1730, 1731, 1733, 1746, + 1745, 1734, 1753, 1747, 1736, 1754, 1756, 1758, 1760, 1762, + 1764, 1766, 1767, 1768, 1771, 1769, 1774, 1775, 1782, 1783, + 1784, 1785, 1788, 1786, 1789, 1791, 1805, 1792, 1801, 1806, + + 1807, 1808, 1809, 1811, 1812, 1813, 1816, 1818, 1829, 1820, + 1822, 8183, 1830, 1838, 1833, 1835, 1836, 1839, 1837, 1841, + 1848, 1850, 1845, 1843, 1847, 1846, 1856, 1857, 1882, 8183, + 1860, 8183, 8183, 1866, 1861, 8183, 8183, 1865, 1867, 8183, + 1868, 1870, 1871, 1869, 1879, 1888, 1892, 1886, 1895, 1896, + 1898, 1905, 1919, 1907, 1903, 1909, 1906, 1911, 1912, 1925, + 1917, 1914, 1934, 1928, 1916, 1932, 1948, 1944, 1949, 1946, + 1952, 1953, 1955, 1956, 1958, 1965, 1966, 1962, 1967, 1969, + 1970, 1971, 1975, 1972, 1976, 1978, 1979, 1981, 1982, 1984, + 1985, 1987, 1996, 1998, 2000, 2007, 2014, 8183, 2010, 2017, + + 2016, 2001, 2004, 1992, 2020, 2027, 2024, 2028, 2030, 2025, + 2032, 2036, 2038, 2026, 2039, 2041, 2043, 2042, 2045, 2049, + 2050, 2051, 2054, 2055, 2057, 2061, 2062, 2058, 2063, 8183, + 2068, 2069, 2071, 2072, 2073, 2074, 2075, 2078, 2079, 2080, + 2091, 2095, 2085, 2086, 2092, 2093, 2108, 2096, 2103, 2105, + 2109, 2112, 2113, 2114, 2115, 8183, 2117, 2123, 2124, 2125, + 2127, 2129, 2116, 2131, 2133, 2138, 2135, 2139, 2142, 2141, + 2147, 2149, 2152, 2153, 2140, 2150, 2154, 2157, 2164, 2160, + 2170, 2177, 2167, 2171, 2173, 2178, 2179, 2180, 2181, 2183, + 2184, 2188, 2189, 2196, 2199, 2192, 2210, 2197, 2194, 2213, + + 2218, 2215, 2202, 2216, 2217, 2220, 2223, 2225, 2232, 2235, + 2227, 2231, 2234, 2243, 2239, 2238, 2245, 2242, 2240, 2246, + 2252, 2262, 2250, 2259, 2266, 2254, 2257, 2264, 2269, 2271, + 8183, 2272, 2273, 2275, 8183, 2280, 2281, 2282, 2304, 2283, + 2284, 2291, 2297, 2299, 2286, 2314, 2302, 2306, 2292, 2294, + 2300, 2316, 2329, 2317, 2324, 2327, 2332, 2334, 2333, 2336, + 2337, 2353, 2340, 2342, 2346, 2354, 2344, 2357, 2364, 2366, + 2368, 2370, 2369, 2371, 2372, 2374, 2394, 2373, 2375, 2376, + 2377, 2378, 2381, 2388, 2383, 2382, 2387, 2384, 2399, 2405, + 2410, 2406, 2407, 2409, 2412, 2415, 2416, 2423, 2425, 2417, + + 8183, 2430, 2432, 2426, 2431, 2438, 2446, 2439, 2441, 8183, + 2443, 2447, 2442, 2454, 2449, 2450, 2453, 2457, 2455, 2463, + 2464, 2461, 2466, 2467, 2471, 2468, 2469, 2482, 2479, 8183, + 2484, 8183, 2485, 2487, 2488, 2490, 2491, 2498, 2493, 2494, + 2495, 2501, 2502, 2503, 2505, 8183, 8183, 2506, 2516, 2514, + 2524, 2526, 2528, 2518, 2529, 2530, 8183, 2531, 2538, 8183, + 2535, 2533, 2542, 2540, 2541, 2546, 2549, 2550, 2552, 2497, + 2555, 2556, 2553, 2557, 2565, 2558, 2573, 2560, 2576, 2570, + 8183, 2579, 2582, 2562, 2586, 2587, 2577, 2588, 2589, 2590, + 2596, 8183, 2598, 2599, 2600, 2601, 2609, 2611, 2605, 2602, + + 2613, 2617, 2607, 2612, 2619, 2621, 2623, 2632, 2633, 2634, + 2630, 2637, 2644, 2640, 2647, 8183, 2643, 2646, 2629, 2656, + 2652, 2654, 2651, 2658, 2659, 2655, 2661, 2662, 2669, 2670, + 2663, 2671, 2665, 2675, 2677, 2684, 2686, 2682, 2685, 2689, + 2691, 2692, 2699, 2695, 2694, 2702, 2700, 2704, 2701, 2705, + 2703, 8183, 2708, 2714, 2716, 2711, 2717, 2721, 2724, 216, + 2725, 2730, 2729, 2731, 2733, 2732, 2735, 2737, 2746, 2749, + 2748, 2738, 2750, 2754, 2758, 2762, 2751, 2755, 2763, 2761, + 2752, 2770, 2772, 2774, 2764, 8183, 2778, 2780, 2781, 2775, + 2782, 2792, 2787, 2790, 2788, 2793, 8183, 2791, 2803, 2801, + + 2811, 2813, 2805, 2814, 2816, 2815, 2799, 2821, 8183, 2822, + 2823, 2824, 2831, 2832, 2826, 2833, 2829, 8183, 2839, 2841, + 2845, 2835, 2847, 2849, 2851, 2843, 2854, 2856, 2859, 2857, + 2861, 2864, 2863, 2865, 2866, 2867, 2870, 2877, 2880, 2878, + 2881, 2883, 2879, 2887, 2890, 2889, 2891, 2895, 2903, 2893, + 8183, 2911, 2900, 2904, 2909, 2907, 2896, 2914, 2920, 2929, + 2921, 2922, 2924, 2925, 2941, 2931, 2930, 2935, 2945, 2947, + 2951, 2934, 2952, 2959, 2957, 2958, 2965, 2955, 2967, 2968, + 2970, 2972, 2978, 2974, 2985, 2987, 2980, 2982, 2984, 2989, + 2990, 2991, 2994, 3003, 2998, 3006, 3002, 3010, 3008, 3011, + + 3013, 3001, 3016, 3026, 3019, 8183, 3028, 3022, 3033, 3034, + 3035, 3039, 3041, 3048, 3036, 3043, 3045, 3046, 3050, 3051, + 3056, 3058, 3059, 3060, 3063, 3064, 3071, 3066, 3069, 3075, + 3070, 3080, 3074, 3077, 3087, 3089, 3076, 3090, 3092, 3093, + 3097, 3098, 3100, 8183, 3106, 3099, 3105, 3110, 3112, 3113, + 3115, 3116, 3118, 3120, 3121, 3122, 3126, 3127, 3128, 3129, + 3130, 3137, 3134, 3135, 3136, 3140, 8183, 3146, 3148, 3152, + 3153, 3154, 3155, 3156, 3157, 3163, 3170, 3171, 3174, 3172, + 3160, 3179, 3180, 3181, 8183, 3188, 3189, 3190, 3192, 3193, + 3201, 3196, 3184, 3199, 3206, 3209, 3200, 3202, 8183, 3211, + + 3186, 2185, 3212, 3213, 3214, 3221, 3223, 3218, 3219, 8183, + 3231, 3226, 3228, 3229, 3238, 3235, 3239, 3236, 3241, 3243, + 3245, 3247, 3249, 3252, 3253, 3261, 3254, 3258, 8183, 3256, + 3262, 3266, 3270, 3268, 3273, 3274, 3280, 3278, 3281, 3282, + 3285, 3289, 3162, 3287, 8183, 3305, 3294, 3302, 3284, 3309, + 3304, 3307, 3311, 3312, 3313, 3314, 3316, 3315, 3320, 3321, + 8183, 3322, 3324, 3326, 3327, 3339, 3330, 3331, 3338, 3337, + 3340, 3345, 3346, 3347, 3351, 3352, 3353, 3354, 3363, 3355, + 3365, 3367, 3357, 3374, 3369, 3375, 3376, 3377, 3380, 3388, + 3392, 3384, 3393, 3396, 3399, 3387, 3389, 3401, 3408, 3413, + + 3415, 3411, 3416, 8183, 3419, 3400, 3414, 3421, 3420, 3426, + 3422, 3424, 3427, 3425, 3433, 3435, 3442, 3430, 3434, 3449, + 3452, 3450, 3455, 3456, 3458, 3459, 3460, 3461, 3468, 3463, + 3464, 3465, 3470, 3473, 3471, 3480, 3472, 3479, 3481, 3484, + 3486, 3493, 3491, 3492, 3500, 3495, 3497, 3501, 3502, 3503, + 3504, 3505, 3507, 3509, 3515, 3508, 3513, 3517, 3518, 3526, + 3534, 3535, 3527, 3529, 3537, 3538, 3541, 8183, 8183, 3543, + 8183, 3550, 3539, 3546, 3553, 3548, 3555, 3558, 3559, 3561, + 3566, 3563, 3575, 3567, 3570, 3578, 3571, 3580, 3581, 3574, + 3586, 3587, 3588, 3595, 3591, 8183, 3592, 8183, 3599, 3597, + + 3598, 3600, 3611, 3602, 8183, 3607, 8183, 3609, 3614, 3615, + 3616, 3617, 8183, 3620, 3619, 3621, 3625, 3624, 3626, 3628, + 3629, 3630, 3636, 3637, 3638, 3645, 3646, 3648, 3635, 3654, + 3655, 3656, 3658, 3660, 3661, 3662, 3663, 3665, 3666, 3668, + 3671, 3673, 3675, 3677, 3681, 3682, 3683, 3684, 3685, 8183, + 3691, 3700, 3695, 3701, 3703, 3704, 3706, 3707, 3709, 3711, + 3687, 3710, 3715, 3713, 3717, 3722, 3723, 3730, 3726, 3732, + 3735, 3734, 3736, 3738, 3741, 3748, 3747, 3755, 3752, 8183, + 3750, 3754, 3751, 3758, 3760, 3762, 8183, 3761, 3769, 3759, + 3771, 3775, 3773, 3763, 3778, 3779, 3784, 3780, 3788, 3786, + + 3789, 3790, 3797, 3794, 3801, 8183, 3796, 3803, 3809, 3810, + 3812, 3814, 3821, 3822, 3818, 3824, 3826, 3835, 3828, 3817, + 3819, 3831, 3832, 3836, 3846, 3847, 3848, 3844, 3851, 3843, + 3853, 3855, 3856, 3857, 3859, 3862, 3860, 3863, 3864, 3867, + 3869, 3871, 3868, 3865, 3870, 3887, 3872, 3873, 8183, 3876, + 3892, 3893, 3900, 3895, 3896, 3897, 3899, 3898, 3902, 3905, + 8183, 3908, 3909, 3911, 3910, 3920, 3918, 3923, 3924, 3925, + 3926, 3928, 3930, 3927, 3938, 3936, 8183, 3939, 8183, 3940, + 3932, 3953, 3961, 3963, 3955, 3951, 3964, 3965, 3966, 3971, + 3972, 3974, 3975, 3977, 3978, 3976, 3982, 3984, 3986, 3987, + + 3988, 3989, 3990, 3996, 3992, 4001, 4013, 4000, 4011, 3995, + 4012, 4014, 4017, 4019, 4027, 4023, 4022, 8183, 8183, 4020, + 4024, 4029, 4033, 4037, 4038, 4039, 4048, 4043, 4046, 4051, + 4056, 4057, 4059, 4050, 4064, 4065, 4072, 8183, 4067, 4069, + 4070, 4073, 4074, 4082, 4075, 4080, 4095, 4086, 4087, 4096, + 4094, 8183, 4077, 4098, 4099, 4108, 4103, 4106, 4110, 8183, + 3941, 8183, 4105, 4107, 4111, 4112, 4114, 4122, 4121, 4123, + 4125, 4127, 4128, 4136, 4117, 4139, 4143, 4144, 4140, 4146, + 4148, 4149, 4150, 4152, 4158, 4160, 4155, 4156, 4161, 8183, + 4163, 4164, 4166, 4165, 4173, 4174, 4175, 4176, 4182, 4183, + + 4186, 8183, 4187, 8183, 4188, 4189, 4193, 4192, 4197, 4203, + 4200, 4205, 4207, 4209, 4210, 4211, 4213, 4216, 4214, 4218, + 4222, 4223, 8183, 4227, 4224, 4235, 4236, 4231, 4232, 4240, + 4234, 4241, 4251, 8183, 4242, 4258, 4245, 4253, 4254, 4263, + 4256, 4259, 4264, 4265, 4267, 4269, 4272, 4274, 4273, 4275, + 4276, 4277, 4279, 4281, 4283, 4284, 4282, 4295, 4296, 4297, + 4299, 4309, 4304, 8183, 4305, 4308, 4310, 4314, 4311, 4313, + 4318, 4316, 4320, 4323, 4324, 4336, 4337, 4326, 4328, 4333, + 4340, 4341, 4348, 4343, 8183, 4356, 4351, 4358, 4353, 4355, + 4357, 4359, 4360, 4366, 4361, 4367, 4371, 4368, 4373, 4374, + + 4375, 4377, 4382, 4391, 4386, 4388, 4389, 4390, 4401, 4392, + 4393, 4396, 4397, 8183, 4415, 4404, 4406, 4417, 4411, 4416, + 4426, 4423, 4424, 4425, 4427, 4429, 4430, 4428, 4434, 4435, + 4436, 4438, 4440, 4441, 4451, 4453, 4443, 8183, 8183, 4455, + 4445, 4456, 4457, 4465, 8183, 4459, 4467, 4475, 4471, 4472, + 4473, 4476, 4480, 4478, 4479, 4481, 4486, 4485, 4482, 4483, + 4498, 4487, 4495, 8183, 4505, 4501, 4509, 4502, 4507, 4510, + 4515, 8183, 4512, 4524, 4520, 4516, 4523, 4525, 4526, 4528, + 4527, 4529, 4533, 4534, 4535, 4537, 4539, 4542, 4550, 4545, + 4548, 4559, 4551, 4554, 4556, 8183, 4555, 4558, 4563, 4565, + + 4566, 4567, 4570, 8183, 4572, 4573, 4578, 4581, 4574, 4589, + 4584, 4592, 4594, 4598, 4582, 4595, 4599, 4601, 4600, 4602, + 4604, 4613, 4608, 4612, 4611, 4615, 4630, 4631, 4617, 8183, + 4614, 4619, 4625, 4633, 4634, 4643, 8183, 4645, 4652, 4654, + 8183, 4655, 4635, 4657, 4647, 4656, 8183, 4658, 4660, 4663, + 4665, 4666, 4669, 4678, 4671, 4679, 4674, 4675, 4676, 4683, + 4680, 4684, 4686, 4685, 8183, 4688, 4687, 4696, 8183, 4703, + 4637, 4707, 4710, 4711, 4714, 4698, 4705, 4695, 4722, 4717, + 4719, 4721, 4725, 8183, 4726, 4736, 8183, 4729, 4733, 4718, + 4728, 4738, 4741, 8183, 4743, 4744, 4745, 4747, 4748, 4749, + + 4758, 4759, 4752, 4760, 4761, 4764, 4765, 4772, 4767, 4768, + 4775, 4774, 4776, 4777, 4779, 8183, 4786, 4778, 4781, 4788, + 4783, 4799, 4801, 4794, 4791, 4802, 4804, 8183, 8183, 4809, + 8183, 4811, 4789, 4813, 4815, 8183, 4818, 4816, 4825, 4820, + 4821, 4824, 4827, 4828, 4832, 4836, 4838, 8183, 4840, 4842, + 8183, 4844, 4845, 4853, 4848, 4849, 4852, 4855, 4857, 4859, + 4861, 4854, 4864, 4863, 4865, 4869, 4870, 4871, 4889, 4873, + 4891, 8183, 4872, 4880, 4887, 4885, 4890, 4881, 4902, 4904, + 4906, 4912, 4898, 4900, 4914, 8183, 4915, 4916, 4917, 4921, + 4922, 8183, 8183, 4923, 8183, 4924, 4928, 4930, 8183, 4925, + + 4931, 4936, 4938, 4940, 4947, 4943, 4945, 8183, 4944, 4948, + 4950, 4951, 4952, 4954, 8183, 4961, 4967, 4958, 4968, 4959, + 4975, 4973, 4970, 4980, 4988, 4981, 8183, 4971, 4984, 4985, + 4994, 4995, 4991, 4999, 5000, 5007, 5003, 5004, 5011, 5015, + 5010, 5018, 5019, 5016, 5022, 5017, 5025, 5030, 5027, 5033, + 5023, 8183, 5035, 5034, 5040, 5037, 5050, 5045, 5047, 5048, + 8183, 5051, 5053, 5054, 5061, 8183, 5055, 5062, 5063, 5074, + 5067, 5069, 5071, 5075, 5052, 5076, 5078, 5079, 8183, 5080, + 5083, 5081, 5097, 5094, 5098, 5100, 5086, 8183, 8183, 5102, + 8183, 5105, 5106, 5107, 5110, 5088, 5114, 5116, 5117, 5112, + + 5119, 5120, 5124, 5127, 5130, 5132, 5133, 5134, 5136, 8183, + 5139, 5146, 5137, 5154, 5150, 5157, 5152, 8183, 5160, 5141, + 8183, 5142, 8183, 5163, 5164, 5166, 5169, 5167, 5172, 5173, + 5175, 5178, 5177, 8183, 5185, 5188, 5180, 5189, 5181, 5190, + 5193, 5197, 5204, 8183, 5201, 5206, 5207, 5208, 8183, 5209, + 5210, 5212, 5214, 5213, 5216, 5218, 5217, 5219, 5220, 5222, + 5224, 5237, 5227, 5238, 5230, 5232, 5245, 5240, 5246, 5249, + 5247, 5250, 5256, 8183, 5251, 5253, 5257, 5261, 5262, 5264, + 5267, 5266, 5269, 5270, 5277, 5273, 5284, 8183, 5274, 8183, + 5279, 5283, 5290, 5293, 5294, 5299, 5300, 5301, 5302, 5303, + + 5306, 5308, 5309, 5312, 5316, 5323, 5313, 5317, 5324, 5325, + 8183, 5331, 5333, 5335, 5338, 5336, 5341, 5343, 5344, 8183, + 5346, 5347, 5352, 5307, 5353, 8183, 5355, 5354, 5357, 5359, + 5360, 5362, 5364, 5370, 5365, 5371, 8183, 5374, 5378, 5375, + 5381, 5383, 5384, 5387, 5392, 5386, 5388, 5393, 5394, 8183, + 5396, 5399, 5400, 5406, 5402, 5409, 5410, 5408, 5417, 5422, + 5412, 5415, 5423, 8183, 5424, 5426, 5428, 5435, 8183, 5432, + 5434, 5436, 5438, 5437, 5443, 5444, 5440, 5446, 5450, 5447, + 5458, 5454, 5456, 8183, 5465, 5448, 5467, 5462, 5472, 5473, + 5479, 5475, 5480, 5483, 5482, 5485, 8183, 5493, 5486, 5495, + + 5497, 5499, 5489, 5496, 5506, 5507, 5508, 5510, 8183, 5512, + 5515, 5518, 5511, 5525, 5528, 5521, 5524, 5535, 5532, 5533, + 8183, 5530, 5531, 5540, 5534, 5541, 5547, 5548, 5549, 5545, + 5552, 5566, 5561, 8183, 5551, 5553, 8183, 5562, 5563, 5567, + 5570, 5574, 5579, 5576, 5578, 5577, 5584, 5588, 5581, 8183, + 5589, 5590, 5592, 5594, 5595, 5598, 5600, 5597, 8183, 5599, + 5596, 5610, 5614, 8183, 5613, 5615, 5617, 5618, 5619, 5622, + 5624, 5629, 5630, 5632, 8183, 5635, 5636, 5638, 5646, 5647, + 5642, 5645, 5648, 5652, 5649, 5654, 5656, 5657, 5658, 5666, + 5663, 5664, 8183, 5667, 5665, 5673, 5674, 5675, 5678, 5681, + + 5682, 5684, 5686, 5683, 8183, 5689, 5691, 5692, 5693, 5695, + 5697, 5698, 5699, 5706, 5708, 5715, 5705, 5719, 5703, 5707, + 5717, 5722, 5723, 5725, 8183, 5728, 5729, 5730, 5737, 5738, + 5733, 5746, 8183, 5734, 8183, 5739, 5742, 5749, 5751, 5757, + 8183, 5752, 5747, 5760, 5759, 5764, 8183, 8183, 5766, 5767, + 5768, 5772, 5769, 5774, 5773, 5776, 8183, 8183, 5787, 8183, + 5775, 8183, 5777, 5781, 8183, 8183, 5784, 5788, 5794, 5790, + 5792, 8183, 5796, 5798, 5799, 5800, 5802, 8183, 5807, 8183, + 5809, 5810, 5815, 5812, 5817, 5818, 8183, 5819, 5821, 5820, + 5825, 5827, 8183, 5829, 5831, 5835, 5842, 5833, 5834, 8183, + + 5844, 5846, 5847, 5850, 5852, 5848, 5857, 5859, 5858, 5860, + 5861, 5865, 8183, 5868, 5871, 5873, 5866, 5876, 5862, 5877, + 5886, 5887, 5889, 5890, 5891, 5874, 5892, 5893, 5900, 5895, + 5905, 5907, 5909, 5911, 5913, 5914, 5916, 5917, 5919, 5924, + 5922, 5926, 5927, 5928, 5929, 5931, 5936, 5930, 5938, 5941, + 5933, 5943, 5945, 5951, 5952, 5953, 5954, 5955, 5956, 5961, + 5962, 5963, 5966, 5967, 5968, 5969, 5970, 5972, 5977, 5980, + 5979, 5974, 5985, 5990, 5997, 5992, 5984, 5995, 8183, 6000, + 5981, 6004, 6006, 6008, 6005, 6009, 6013, 6014, 6015, 6017, + 6022, 6023, 6024, 8183, 8183, 8183, 6029, 6030, 8183, 6032, + + 6034, 6036, 6037, 6039, 8183, 6040, 6041, 6042, 6043, 6045, + 6044, 6046, 6048, 6049, 6055, 6057, 6061, 8183, 6067, 6077, + 6058, 6068, 6070, 6081, 8183, 6074, 6085, 6078, 6082, 6086, + 6087, 6088, 6089, 6091, 6092, 6093, 6095, 6097, 6098, 6111, + 6114, 6102, 6106, 6115, 8183, 6117, 6119, 6126, 6123, 6125, + 6127, 6128, 6130, 6129, 6132, 6133, 6135, 6136, 6137, 6138, + 6139, 6140, 6150, 6158, 6160, 6164, 8183, 6146, 6167, 6151, + 6169, 8183, 6171, 6154, 6172, 6161, 6174, 6176, 6177, 6178, + 6182, 6185, 6186, 6188, 8183, 8183, 6189, 6192, 6191, 6196, + 6193, 6198, 6200, 6201, 6202, 6211, 8183, 6203, 6204, 6214, + + 6221, 6223, 6213, 8183, 6224, 6227, 6228, 6230, 6231, 6232, + 6233, 6234, 6235, 6238, 6241, 6236, 6253, 8183, 6242, 6250, + 6258, 6260, 6264, 6246, 6267, 6268, 6269, 6270, 6271, 6272, + 6275, 8183, 6276, 8183, 8183, 8183, 6279, 6281, 6277, 6285, + 6282, 6287, 6288, 6289, 6293, 6294, 6305, 6291, 6306, 8183, + 6308, 8183, 8183, 6309, 8183, 6310, 6312, 6313, 6316, 6317, + 6319, 6322, 8183, 6320, 6323, 8183, 6327, 6329, 6325, 6338, + 6344, 6331, 6341, 6333, 6345, 6339, 6353, 6347, 6355, 6349, + 6356, 6363, 6359, 6361, 6362, 8183, 6368, 6365, 6370, 6372, + 6378, 8183, 8183, 6379, 6373, 6381, 6383, 6385, 6393, 6389, + + 6391, 6390, 6403, 6398, 6400, 6401, 6399, 6407, 6409, 6410, + 6418, 6419, 6411, 6414, 6421, 8183, 6423, 6424, 6425, 8183, + 6415, 8183, 6432, 6433, 6434, 6435, 6436, 6441, 6442, 6443, + 6445, 6448, 6446, 6455, 8183, 8183, 6447, 6462, 6457, 8183, + 8183, 6458, 6459, 6461, 6464, 6467, 6468, 6469, 8183, 6471, + 6473, 6484, 6472, 6486, 6474, 6491, 6478, 8183, 6492, 8183, + 6476, 8183, 6498, 8183, 6499, 6494, 6500, 6508, 6510, 8183, + 6505, 6509, 6512, 6514, 6521, 6517, 6518, 6506, 6523, 8183, + 6520, 6519, 8183, 6536, 6534, 6535, 6522, 6533, 6542, 6538, + 8183, 6543, 6545, 6546, 6548, 8183, 6549, 6554, 6552, 6555, + + 6558, 6557, 6559, 6565, 6570, 8183, 6572, 6574, 6575, 6567, + 8183, 6584, 8183, 6573, 6581, 6579, 6595, 6585, 8183, 6587, + 6588, 6590, 6598, 8183, 6601, 6603, 6605, 6606, 6611, 6612, + 8183, 6614, 6615, 8183, 6596, 6618, 6619, 6622, 6623, 6627, + 6628, 6629, 6630, 6632, 6640, 6636, 6639, 8183, 8183, 6637, + 6651, 6646, 6648, 6653, 123, 6660, 6652, 6656, 6661, 6662, + 6669, 6670, 6671, 6655, 6673, 6667, 8183, 8183, 6679, 6682, + 6683, 8183, 6684, 6685, 8183, 6672, 6686, 6693, 6691, 6695, + 6696, 6699, 6701, 6702, 6704, 6705, 6707, 6706, 6711, 6715, + 8183, 6728, 6732, 6717, 6713, 6724, 6733, 6737, 6739, 6741, + + 6729, 6743, 6735, 6744, 6747, 6746, 6749, 6752, 6750, 6754, + 6751, 6758, 6761, 6762, 8183, 6765, 6767, 6768, 6772, 6774, + 6777, 6775, 6776, 8183, 6785, 6779, 6789, 6790, 6791, 8183, + 6793, 6795, 6797, 6799, 6800, 8183, 8183, 6801, 8183, 6802, + 6808, 6813, 6814, 6815, 6803, 6805, 6817, 6819, 6827, 8183, + 6823, 6825, 6828, 6829, 6831, 6837, 6840, 6830, 6841, 6842, + 8183, 6847, 8183, 8183, 8183, 6848, 6850, 6851, 8183, 6855, + 6852, 6856, 6858, 8183, 6860, 6864, 6861, 6873, 6868, 8183, + 8183, 8183, 6869, 6872, 6874, 8183, 6871, 6884, 8183, 6875, + 8183, 6879, 8183, 6885, 6888, 6895, 8183, 6889, 8183, 6892, + + 6899, 6901, 8183, 6902, 6903, 6905, 6906, 8183, 6909, 6912, + 6918, 6914, 6920, 6921, 6924, 6925, 6922, 8183, 8183, 6932, + 6929, 6930, 6931, 6934, 6937, 6938, 6939, 6942, 6945, 6952, + 8183, 6948, 6954, 8183, 6882, 6951, 6957, 6958, 6949, 6961, + 6964, 8183, 6965, 8183, 6967, 8183, 6969, 6970, 6971, 6974, + 6972, 6975, 6977, 6980, 6987, 6986, 6989, 6990, 6993, 6995, + 6997, 6998, 7000, 7003, 7007, 8183, 8183, 7014, 7005, 8183, + 7011, 7021, 7023, 8183, 7009, 8183, 7012, 7029, 8183, 7016, + 7018, 8183, 7031, 7025, 7033, 8183, 8183, 7040, 7035, 7037, + 7048, 7043, 7045, 7049, 8183, 7050, 7047, 7052, 7053, 7056, + + 7057, 7059, 7063, 7054, 7058, 7060, 7070, 8183, 7082, 8183, + 7065, 7083, 7081, 8183, 8183, 7067, 7080, 7088, 7091, 7084, + 7092, 7094, 7096, 7095, 7097, 7108, 7100, 7098, 7101, 7115, + 7103, 7118, 7125, 7105, 7126, 7127, 7131, 8183, 8183, 8183, + 7122, 7128, 7133, 7135, 7142, 7138, 7141, 8183, 7145, 7143, + 8183, 7146, 7150, 7147, 7154, 7162, 7157, 7159, 8183, 7155, + 7160, 7163, 7164, 7166, 7168, 7169, 7170, 8183, 7172, 7181, + 7183, 7184, 7176, 7186, 7193, 7195, 7197, 7198, 7199, 7201, + 7202, 7203, 7210, 7206, 8183, 8183, 7209, 7205, 8183, 7213, + 7217, 8183, 8183, 7214, 7218, 8183, 7219, 7222, 7223, 7224, + + 7225, 8183, 7228, 7230, 7231, 7234, 8183, 7232, 7236, 7238, + 7235, 7240, 7254, 7243, 7249, 7251, 7264, 7257, 7261, 8183, + 7262, 7272, 7259, 7267, 7268, 7270, 8183, 8183, 7271, 7282, + 8183, 7284, 7285, 7274, 7293, 7289, 7291, 7295, 7297, 8183, + 7296, 7278, 8183, 7300, 7303, 7305, 7306, 7309, 7307, 7310, + 7311, 7315, 8183, 7316, 7313, 7317, 7318, 8183, 7323, 7320, + 7327, 7328, 7330, 8183, 7334, 7331, 7346, 7342, 8183, 7333, + 7352, 7343, 8183, 8183, 8183, 7358, 7360, 7350, 8183, 8183, + 8183, 7348, 7361, 8183, 7365, 7362, 7368, 7370, 8183, 7371, + 8183, 8183, 7373, 7374, 7378, 7382, 7384, 7391, 7377, 8183, + + 7385, 7392, 7395, 7396, 7397, 8183, 7399, 7403, 8183, 7406, + 7410, 7413, 7408, 7418, 7420, 7421, 7405, 7409, 7423, 7427, + 7412, 7415, 8183, 8183, 7431, 7432, 7433, 7434, 7436, 8183, + 7440, 7441, 7109, 7442, 7445, 7446, 7448, 7453, 7460, 7463, + 7450, 7454, 7465, 7464, 7480, 7477, 7457, 7466, 7467, 7478, + 7484, 7468, 7486, 7496, 7491, 7493, 7495, 7498, 7499, 8183, + 8183, 7501, 7502, 7506, 8183, 7508, 7503, 8183, 7509, 8183, + 7511, 7515, 7518, 7520, 7522, 8183, 7524, 7526, 7529, 7531, + 7532, 8183, 7533, 7535, 8183, 8183, 7536, 7537, 7539, 7538, + 7540, 8183, 8183, 7545, 7550, 7548, 7546, 8183, 7547, 7552, + + 7549, 7564, 7554, 7561, 7565, 7570, 7567, 7572, 7576, 8183, + 7573, 7579, 8183, 8183, 8183, 7580, 7581, 7587, 7582, 7591, + 7583, 8183, 7593, 7595, 7597, 7598, 7594, 7600, 7604, 8183, + 7606, 7605, 8183, 8183, 7615, 7602, 8183, 7609, 8183, 8183, + 7607, 7616, 8183, 8183, 8183, 8183, 8183, 8183, 8183, 8183, + 8183, 7621, 7622, 8183, 7623, 7628, 7627, 7624, 7630, 7634, + 8183, 7631, 7639, 7641, 7646, 8183, 7648, 8183, 7635, 7642, + 7653, 7654, 7656, 7660, 8183, 7659, 8183, 7667, 7662, 7665, + 7663, 7664, 7669, 7670, 7677, 7672, 7678, 7679, 7680, 7682, + 7683, 7681, 7689, 7686, 7687, 7698, 7700, 7702, 7688, 7704, + + 7709, 7711, 7706, 7712, 7713, 7714, 7715, 8183, 8183, 8183, + 8183, 7716, 7718, 7724, 7727, 8183, 7725, 7733, 7735, 7741, + 7744, 7746, 7729, 7737, 7747, 7749, 7751, 7739, 7752, 7759, + 7755, 7758, 7760, 7762, 7763, 7772, 7774, 7776, 8183, 7778, + 7779, 7780, 8183, 7782, 7766, 7787, 7791, 7788, 7792, 7794, + 8183, 7795, 7796, 8183, 7797, 7798, 8183, 8183, 7800, 7801, + 7804, 7805, 7814, 7815, 7806, 7813, 7817, 7818, 7828, 8183, + 7830, 8183, 8183, 8183, 8183, 7819, 7822, 8183, 7825, 8183, + 8183, 7831, 7833, 8183, 7832, 7839, 7835, 7841, 8183, 7842, + 7843, 7844, 7847, 7854, 7849, 7850, 7856, 7858, 8183, 8183, + + 7859, 7864, 7865, 7866, 7869, 7870, 8183, 7872, 7874, 7871, + 7884, 7890, 7877, 7888, 7892, 7875, 7901, 8183, 7879, 7896, + 7898, 7904, 7900, 7907, 7908, 8183, 7909, 7910, 7911, 7912, + 7914, 7921, 7917, 7919, 7923, 7925, 7928, 8183, 7934, 8183, + 7937, 7939, 7940, 7941, 7943, 7944, 7945, 7947, 7950, 8183, + 8183, 8183, 7951, 7953, 8183, 7930, 7959, 7954, 7965, 7967, + 7969, 7970, 7961, 7972, 7976, 7978, 7979, 7985, 7982, 7986, + 7987, 7990, 7988, 8183, 8183, 7992, 7994, 8183, 7996, 7997, + 7998, 7999, 8003, 8183, 8009, 8000, 8005, 8010, 8015, 8016, + 8183, 8021, 8026, 8022, 8183, 8027, 8183, 8183, 8028, 8012, + + 8030, 8035, 8037, 8183, 8183, 8183, 8063, 8070, 8077, 8084, + 8091, 8098, 8105, 88, 8112, 8119, 8126, 8133, 8140, 8147, + 8154, 8161, 8168, 8175 } ; -static yyconst flex_int16_t yy_def[4148] = +static yyconst flex_int16_t yy_def[4225] = { 0, - 4129, 1, 4130, 4130, 4131, 4131, 4132, 4132, 4133, 4133, - 4134, 4134, 4135, 4135, 4136, 4136, 4129, 4137, 4129, 4129, - 4129, 4129, 4138, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4139, 4129, 4129, - 4129, 4139, 4140, 4129, 4129, 4129, 4140, 4141, 4129, 4129, - 4129, 4129, 4141, 4142, 4129, 4129, 4129, 4142, 4143, 4129, - 4144, 4129, 4143, 4143, 4145, 4129, 4129, 4129, 4129, 4145, - 4146, 4129, 4129, 4129, 4146, 4137, 4137, 4129, 4147, 4138, - 4147, 4138, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4139, 4139, 4140, 4140, 4141, 4141, - 4129, 4142, 4142, 4143, 4143, 4144, 4144, 4143, 4145, 4145, - 4129, 4146, 4146, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4143, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4143, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4143, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4143, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4129, 4129, 4137, 4137, 4129, 4129, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4143, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4143, 4143, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4143, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4129, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4143, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4129, 4137, 4137, 4137, 4143, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4129, 4129, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, - - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4143, 4137, 4129, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4129, - 4137, 4129, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4129, 4129, 4137, 4129, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4129, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4143, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4129, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4143, 4137, 4129, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4129, 4129, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4129, 4129, 4137, 4129, 4137, 4129, 4137, - 4137, 4129, 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4143, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4129, 4129, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4129, 4129, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4129, 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - - 4137, 4137, 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4143, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4129, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4129, 4137, 4137, 4137, 4129, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4129, 4137, 4129, - - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4129, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4129, 4137, 4137, 4137, 4137, 4143, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - - 4129, 4137, 4137, 4137, 4129, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4129, 4129, 4129, 4137, 4137, 4137, 4129, - - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4129, 4129, 4129, 4137, 4137, 4137, 4129, 4137, 4137, 4129, - 4137, 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4129, 4137, 4137, 4129, 4137, - - 4137, 4137, 4129, 4137, 4129, 4137, 4137, 4129, 4137, 4137, - 4129, 4137, 4137, 4137, 4129, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4129, 4137, - 4137, 4137, 4129, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4129, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4129, 4137, 4137, 4129, 4137, 4137, 4129, - 4129, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4129, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4129, - - 4129, 4129, 4137, 4137, 4137, 4129, 4129, 4129, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4129, 4137, 4129, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4129, 4137, 4137, 4137, - 4129, 4137, 4137, 4129, 4137, 4129, 4137, 4137, 4137, 4137, - - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, - 4129, 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4129, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4129, 4129, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4129, 4129, 4137, - 4137, 4129, 4137, 4129, 4129, 4137, 4137, 4129, 4129, 4129, - 4129, 4129, 4129, 4129, 4129, 4129, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4129, 4129, 4129, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4129, 4137, 4137, 4129, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4137, 4129, 4129, 4129, 4129, 4137, 4137, - - 4129, 4137, 4129, 4129, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4129, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4129, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4129, 4137, 4129, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4129, 4129, 4129, 4137, 4137, 4129, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, 4137, - 4137, 4137, 4137, 4137, 4137, 4137, 4129, 4129, 4137, 4137, - - 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4137, 4137, 4137, - 4137, 4137, 4137, 4129, 4137, 4137, 4137, 4129, 4137, 4129, - 4129, 4137, 4137, 4137, 4137, 4137, 4129, 4129, 0, 4129, - 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, - 4129, 4129, 4129, 4129, 4129, 4129, 4129 + 4206, 1, 4207, 4207, 4208, 4208, 4209, 4209, 4210, 4210, + 4211, 4211, 4212, 4212, 4213, 4213, 4206, 4214, 4206, 4206, + 4206, 4206, 4215, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4216, 4206, 4206, + 4206, 4216, 4217, 4206, 4206, 4206, 4217, 4218, 4206, 4206, + 4206, 4206, 4218, 4219, 4206, 4206, 4206, 4219, 4220, 4206, + 4221, 4206, 4220, 4220, 4222, 4206, 4206, 4206, 4206, 4222, + 4223, 4206, 4206, 4206, 4223, 4214, 4214, 4206, 4224, 4215, + 4224, 4215, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4216, 4216, 4217, 4217, 4218, 4218, + 4206, 4219, 4219, 4220, 4220, 4221, 4221, 4220, 4222, 4222, + 4206, 4223, 4223, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4220, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4220, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4220, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4220, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4206, 4206, 4214, 4214, 4206, 4206, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4220, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4220, 4220, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + + 4214, 4214, 4220, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4206, 4214, 4214, + + 4214, 4214, 4214, 4214, 4206, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4220, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4206, 4214, 4206, 4214, 4214, 4214, 4220, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4220, 4214, 4206, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, + 4206, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4206, 4206, 4214, 4206, 4214, 4214, 4214, 4206, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4220, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4206, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4220, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4206, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4206, + 4214, 4206, 4214, 4214, 4206, 4206, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4220, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4206, 4206, 4214, 4214, 4206, 4214, + + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4206, 4206, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4206, 4206, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4206, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4220, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4206, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4206, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4214, 4214, 4206, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4206, + 4214, 4206, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4206, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, + 4214, 4214, 4214, 4214, 4220, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4214, + 4214, 4206, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4206, 4206, 4206, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4206, + 4206, 4206, 4214, 4214, 4214, 4206, 4214, 4214, 4206, 4214, + 4206, 4214, 4206, 4214, 4214, 4214, 4206, 4214, 4206, 4214, + + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4206, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4214, 4206, + 4214, 4214, 4214, 4206, 4214, 4206, 4214, 4214, 4206, 4214, + 4214, 4206, 4214, 4214, 4214, 4206, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4206, + 4214, 4214, 4214, 4206, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4214, 4206, 4214, + 4214, 4206, 4206, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + + 4214, 4206, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4206, 4206, 4206, 4214, 4214, 4214, 4206, 4206, + 4206, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4206, 4214, + 4206, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4206, 4206, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4206, 4214, 4214, 4214, 4206, 4214, 4214, 4206, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4206, 4206, 4214, 4214, 4214, 4214, + 4214, 4206, 4206, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4206, 4206, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4214, 4206, 4206, 4214, 4214, 4206, 4214, 4206, 4206, + 4214, 4214, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + 4206, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4214, 4206, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4206, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, 4206, + 4206, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4206, 4214, 4214, 4206, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4214, 4206, 4206, 4206, 4206, 4214, 4214, 4206, 4214, 4206, + 4206, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4206, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4206, + + 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, 4214, 4206, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4206, + 4206, 4206, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, 4214, + 4214, 4214, 4214, 4206, 4206, 4214, 4214, 4206, 4214, 4214, + 4214, 4214, 4214, 4206, 4214, 4214, 4214, 4214, 4214, 4214, + 4206, 4214, 4214, 4214, 4206, 4214, 4206, 4206, 4214, 4214, + + 4214, 4214, 4214, 4206, 4206, 0, 4206, 4206, 4206, 4206, + 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + 4206, 4206, 4206, 4206 } ; -static yyconst flex_int16_t yy_nxt[8083] = +static yyconst flex_int16_t yy_nxt[8224] = { 0, 18, 19, 20, 21, 22, 23, 22, 18, 18, 18, 18, 18, 22, 24, 25, 26, 27, 28, 29, 30, @@ -1888,807 +1915,823 @@ static yyconst flex_int16_t yy_nxt[8083] 87, 471, 458, 87, 87, 467, 465, 478, 463, 490, 464, 87, 466, 87, 470, 87, 474, 87, 472, 480, 476, 473, 475, 479, 87, 87, 87, 481, 87, 87, - 87, 87, 180, 500, 492, 87, 505, 477, 482, 87, - 87, 506, 87, 483, 501, 87, 491, 502, 484, 516, - 87, 485, 503, 504, 509, 87, 486, 487, 488, 489, - 87, 507, 87, 493, 87, 494, 87, 495, 87, 508, - 522, 87, 87, 87, 87, 518, 87, 496, 497, 498, - 596, 499, 87, 517, 87, 510, 512, 513, 511, 519, - 514, 515, 87, 520, 87, 521, 87, 523, 525, 87, - - 87, 524, 87, 87, 87, 87, 530, 87, 87, 537, - 536, 526, 87, 87, 531, 87, 532, 87, 529, 527, - 87, 87, 528, 87, 619, 533, 538, 535, 539, 549, - 87, 543, 534, 541, 540, 542, 544, 87, 87, 550, - 545, 551, 87, 552, 87, 87, 87, 87, 87, 87, - 553, 567, 87, 546, 175, 175, 547, 87, 548, 87, - 554, 87, 555, 87, 569, 87, 566, 570, 556, 568, - 87, 571, 557, 572, 584, 574, 590, 558, 583, 87, - 559, 87, 560, 173, 561, 585, 587, 87, 87, 573, - 586, 87, 87, 87, 588, 87, 593, 562, 591, 87, - - 563, 589, 564, 595, 565, 87, 87, 575, 576, 87, - 592, 87, 594, 87, 87, 87, 602, 577, 578, 579, - 580, 581, 600, 87, 582, 597, 598, 599, 87, 606, - 87, 87, 601, 87, 603, 604, 607, 87, 608, 87, - 610, 87, 611, 605, 87, 609, 87, 87, 87, 617, - 87, 613, 87, 87, 87, 87, 87, 612, 620, 171, - 87, 615, 614, 87, 621, 622, 616, 87, 87, 87, - 627, 628, 623, 629, 624, 618, 625, 87, 87, 626, - 630, 631, 87, 87, 87, 636, 633, 634, 87, 87, - 87, 87, 87, 87, 87, 652, 637, 655, 632, 642, - - 643, 87, 635, 638, 87, 639, 641, 87, 640, 654, - 170, 644, 87, 645, 87, 658, 653, 657, 87, 646, - 87, 656, 87, 87, 659, 662, 660, 647, 648, 87, - 87, 649, 650, 661, 87, 651, 87, 664, 666, 87, - 87, 87, 87, 87, 670, 671, 668, 665, 87, 663, - 87, 87, 87, 672, 673, 669, 87, 87, 87, 667, - 87, 678, 676, 677, 87, 87, 87, 674, 87, 679, - 87, 87, 87, 684, 87, 87, 680, 675, 87, 687, - 683, 87, 689, 685, 682, 681, 688, 690, 87, 691, - 87, 87, 87, 686, 696, 692, 87, 694, 87, 697, - - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 699, 703, 693, 701, 695, 87, 87, 710, 87, 712, - 705, 87, 698, 87, 700, 87, 702, 704, 168, 709, - 87, 87, 711, 706, 708, 707, 716, 713, 87, 715, - 714, 87, 87, 717, 87, 718, 87, 721, 87, 719, - 87, 725, 720, 87, 87, 87, 728, 87, 727, 724, - 722, 87, 87, 723, 87, 87, 731, 87, 730, 734, - 87, 87, 87, 726, 87, 87, 736, 738, 87, 87, - 729, 87, 87, 87, 166, 87, 732, 735, 733, 737, - 87, 739, 741, 87, 753, 87, 773, 740, 87, 742, - - 752, 750, 754, 751, 743, 87, 744, 87, 87, 756, - 755, 757, 745, 87, 746, 87, 87, 747, 748, 87, - 761, 758, 87, 760, 749, 759, 87, 766, 765, 763, - 87, 87, 764, 87, 770, 87, 87, 768, 767, 87, - 762, 87, 769, 87, 775, 87, 87, 779, 87, 87, - 87, 87, 87, 771, 776, 772, 778, 777, 87, 783, - 87, 774, 87, 782, 787, 87, 87, 780, 786, 87, - 784, 781, 175, 789, 788, 785, 790, 791, 792, 87, - 87, 87, 796, 87, 87, 87, 87, 87, 87, 801, - 799, 87, 87, 87, 793, 795, 804, 87, 87, 794, - - 797, 803, 798, 805, 800, 807, 808, 87, 87, 87, - 806, 87, 87, 87, 87, 87, 802, 810, 87, 809, - 813, 87, 811, 87, 87, 814, 815, 87, 812, 87, - 836, 87, 821, 817, 824, 87, 816, 822, 87, 87, - 818, 825, 87, 819, 823, 820, 826, 827, 87, 828, - 87, 829, 87, 87, 830, 87, 831, 833, 87, 87, - 87, 832, 87, 87, 837, 87, 87, 87, 87, 840, - 835, 87, 841, 839, 87, 845, 834, 87, 844, 87, - 87, 87, 838, 847, 87, 87, 87, 851, 87, 849, - 843, 842, 87, 87, 87, 87, 87, 846, 848, 850, - - 854, 858, 87, 852, 87, 87, 87, 87, 87, 859, - 856, 87, 855, 853, 87, 87, 857, 861, 898, 860, - 865, 87, 862, 87, 866, 863, 864, 87, 87, 867, - 87, 868, 869, 870, 87, 871, 874, 873, 87, 87, - 87, 87, 87, 876, 87, 872, 880, 875, 877, 87, - 87, 87, 881, 87, 87, 882, 87, 87, 879, 87, - 87, 885, 887, 889, 87, 87, 87, 883, 87, 886, - 878, 884, 87, 893, 890, 892, 87, 87, 87, 888, - 87, 899, 87, 901, 87, 891, 897, 87, 900, 87, - 895, 87, 905, 894, 896, 902, 903, 87, 87, 87, - - 904, 87, 906, 87, 87, 912, 87, 87, 910, 907, - 914, 87, 913, 908, 87, 909, 87, 915, 87, 87, - 919, 87, 87, 911, 917, 920, 87, 87, 87, 87, - 87, 916, 931, 183, 918, 921, 922, 923, 87, 933, - 924, 87, 87, 87, 925, 87, 926, 934, 932, 87, - 936, 87, 937, 927, 87, 87, 941, 939, 938, 928, - 929, 930, 87, 935, 87, 945, 87, 942, 87, 943, - 946, 87, 940, 87, 947, 87, 87, 949, 951, 944, - 87, 87, 87, 87, 87, 87, 958, 950, 87, 87, - 87, 948, 87, 959, 87, 87, 87, 960, 87, 953, - - 954, 952, 955, 957, 956, 961, 87, 87, 968, 962, - 965, 87, 87, 963, 87, 964, 87, 87, 969, 966, - 87, 967, 87, 87, 971, 970, 975, 87, 87, 87, - 87, 87, 87, 87, 985, 972, 181, 983, 973, 974, - 87, 976, 87, 977, 87, 87, 978, 979, 980, 981, - 982, 87, 87, 87, 984, 986, 987, 991, 87, 990, - 87, 87, 87, 988, 989, 87, 87, 87, 995, 87, - 996, 87, 87, 997, 992, 994, 999, 1000, 87, 993, - 87, 87, 87, 87, 87, 1002, 87, 1001, 180, 1003, - 1008, 998, 1005, 1006, 1007, 1004, 87, 175, 87, 87, - - 1012, 1010, 1009, 1011, 87, 87, 87, 87, 87, 1015, - 1018, 87, 1021, 1013, 87, 1019, 87, 1022, 87, 87, - 1014, 1016, 87, 1020, 1023, 1024, 1026, 87, 87, 1017, - 87, 87, 87, 87, 1029, 87, 1033, 87, 1034, 87, - 87, 1025, 87, 1030, 87, 1035, 1027, 1037, 1028, 87, - 87, 87, 87, 1032, 1036, 87, 1049, 87, 1031, 87, - 87, 87, 87, 87, 87, 1058, 1051, 1038, 1052, 1050, - 1048, 1040, 1055, 87, 87, 1039, 87, 1056, 1041, 1054, - 87, 1042, 1053, 87, 1057, 1043, 87, 1059, 1044, 87, - 87, 1064, 1061, 87, 1060, 1045, 1046, 87, 1047, 87, - - 87, 87, 87, 1062, 87, 1074, 87, 87, 1077, 87, - 1063, 87, 1065, 1066, 1075, 1067, 175, 87, 1068, 1073, - 1076, 1079, 87, 1069, 1084, 1078, 1082, 1081, 87, 1070, - 1071, 1085, 1072, 1083, 1087, 87, 87, 1080, 1086, 1088, - 87, 87, 1090, 1089, 87, 87, 87, 1093, 87, 87, - 1092, 87, 1095, 1094, 1097, 87, 1096, 87, 87, 1091, - 1098, 87, 87, 87, 87, 87, 1101, 87, 87, 1099, - 87, 1106, 87, 1105, 87, 87, 1110, 87, 87, 87, - 1100, 1102, 87, 1107, 1103, 1114, 1104, 1115, 1109, 87, - 1112, 87, 1108, 1116, 87, 1111, 87, 1117, 1121, 87, - - 1120, 1113, 1118, 87, 1119, 87, 87, 1122, 87, 1125, - 87, 87, 1127, 1128, 87, 87, 1126, 87, 87, 87, - 1129, 1131, 87, 87, 1123, 1130, 1132, 87, 1124, 87, - 87, 1134, 87, 87, 87, 1136, 1137, 1133, 87, 87, - 1138, 1142, 87, 87, 87, 1145, 87, 1135, 87, 1146, - 87, 1144, 1139, 1143, 1140, 87, 87, 87, 1141, 87, - 87, 87, 87, 87, 87, 1149, 1147, 87, 87, 1148, - 1152, 87, 1156, 1157, 87, 1150, 87, 1153, 1155, 1159, - 1158, 87, 87, 87, 1154, 1151, 1160, 1165, 1161, 1162, - 87, 1163, 1166, 87, 87, 1168, 1164, 87, 87, 87, - - 87, 87, 87, 87, 1167, 1174, 87, 87, 1171, 1176, - 1177, 87, 1169, 1175, 87, 87, 87, 1170, 87, 1173, - 1179, 1181, 87, 1182, 1172, 87, 87, 1178, 87, 87, - 87, 87, 87, 1188, 1191, 1180, 87, 1186, 1183, 87, - 87, 1192, 87, 87, 1184, 1185, 87, 87, 1189, 1187, - 1190, 1193, 1194, 1197, 1198, 87, 87, 1196, 87, 1201, - 87, 1195, 87, 1200, 87, 87, 87, 87, 87, 1199, - 87, 87, 87, 1204, 1206, 1202, 87, 1212, 1213, 87, - 1215, 87, 1203, 87, 87, 1205, 87, 1207, 1218, 1209, - 1208, 1210, 1211, 1214, 87, 1216, 1217, 1219, 87, 87, - - 87, 87, 1220, 87, 87, 1227, 1224, 87, 1226, 1228, - 87, 87, 1222, 1229, 87, 87, 87, 1232, 1221, 87, - 1223, 1234, 87, 87, 87, 1225, 87, 87, 87, 1231, - 87, 1237, 1230, 1238, 87, 87, 1245, 87, 1241, 1233, - 1236, 1244, 1235, 1242, 175, 87, 1239, 87, 1240, 1243, - 1246, 87, 87, 87, 87, 87, 1249, 87, 1253, 87, - 87, 87, 1248, 87, 1265, 1247, 1264, 87, 1252, 1254, - 1255, 1250, 87, 87, 1268, 87, 1266, 1251, 87, 1256, - 87, 1257, 87, 87, 87, 1258, 87, 1259, 1267, 1337, - 87, 1260, 1269, 1261, 1270, 1271, 1274, 1275, 1262, 1273, - - 1272, 87, 87, 1263, 1278, 87, 1276, 87, 87, 1279, - 87, 87, 1282, 87, 1280, 87, 1277, 87, 1285, 87, - 1289, 1281, 1286, 87, 1283, 1288, 1284, 1291, 87, 87, - 87, 87, 1287, 1290, 87, 1298, 1295, 87, 87, 1294, - 1296, 87, 1297, 1293, 1292, 1299, 1300, 87, 1301, 1302, - 87, 87, 87, 87, 87, 87, 87, 87, 1317, 87, - 1303, 1314, 87, 87, 87, 87, 1313, 87, 1318, 1304, - 1305, 87, 1306, 1315, 1316, 1319, 87, 1307, 1320, 1308, - 87, 1321, 87, 87, 87, 1309, 1326, 87, 87, 1327, - 1310, 1311, 87, 87, 1322, 1323, 87, 1312, 87, 1325, - - 1328, 1324, 1333, 87, 87, 1329, 87, 1336, 1334, 1330, - 87, 87, 87, 87, 1331, 1341, 1332, 1339, 87, 87, - 87, 87, 87, 1342, 1340, 87, 1335, 1347, 87, 1338, - 87, 1344, 87, 87, 1345, 87, 1346, 87, 1343, 1349, - 1351, 87, 87, 1354, 87, 87, 87, 87, 87, 1348, - 87, 1350, 87, 87, 1357, 1353, 1358, 1352, 1356, 1359, - 1361, 87, 87, 1365, 1355, 1360, 87, 87, 1362, 87, - 1364, 1368, 87, 87, 1367, 1363, 87, 87, 87, 87, - 87, 87, 173, 87, 1373, 1374, 1375, 1370, 1376, 87, - 87, 1369, 1366, 1372, 1371, 87, 1378, 1379, 1377, 1380, - - 87, 87, 87, 87, 87, 87, 1384, 1385, 87, 1381, - 87, 1387, 1386, 87, 1388, 1383, 1382, 87, 87, 1389, - 1390, 87, 1391, 87, 87, 87, 1393, 87, 87, 87, - 87, 1398, 87, 87, 87, 87, 1403, 87, 1392, 1408, - 1395, 1396, 87, 1394, 1397, 1399, 1401, 1402, 1400, 1405, - 1406, 87, 87, 1409, 1404, 87, 1407, 87, 1411, 87, - 1410, 87, 87, 87, 1412, 87, 1413, 87, 87, 87, - 1416, 87, 1415, 1417, 87, 1419, 87, 1423, 1414, 1418, - 1421, 1424, 87, 87, 87, 87, 87, 1420, 87, 1427, - 87, 1428, 87, 1425, 87, 87, 87, 1422, 1432, 1434, - - 171, 1435, 1436, 1426, 87, 87, 1429, 87, 87, 1433, - 87, 1430, 87, 1439, 1431, 1437, 87, 1438, 1441, 87, - 87, 1440, 1443, 87, 87, 1442, 1445, 87, 87, 1447, - 87, 87, 87, 1446, 87, 87, 1448, 87, 87, 1450, - 1449, 1453, 87, 1444, 87, 1454, 87, 87, 87, 87, - 170, 1456, 1460, 1451, 87, 1455, 1452, 1461, 87, 87, - 1458, 1464, 87, 87, 1463, 1457, 87, 87, 1459, 1462, - 87, 87, 1469, 87, 87, 87, 87, 87, 87, 87, - 175, 1466, 1467, 1471, 87, 1465, 1476, 87, 1475, 1468, - 87, 1470, 1477, 87, 1472, 1478, 87, 1474, 1479, 87, - - 1480, 87, 1473, 87, 87, 87, 87, 87, 1484, 87, - 1481, 1487, 87, 1483, 1482, 1485, 1489, 1490, 87, 1486, - 87, 1497, 87, 87, 1492, 1488, 1491, 87, 87, 87, - 1495, 87, 1494, 87, 1496, 87, 1493, 87, 1499, 87, - 87, 87, 1502, 87, 87, 1498, 87, 1503, 1506, 87, - 1500, 87, 87, 87, 87, 1509, 1501, 1508, 1504, 87, - 1505, 1511, 1510, 87, 87, 1507, 1523, 87, 1515, 1512, - 1513, 87, 1514, 87, 1520, 1519, 87, 1516, 87, 1517, - 87, 1521, 1518, 1522, 87, 87, 87, 87, 1526, 87, - 87, 1524, 87, 1533, 1525, 1530, 1529, 87, 87, 87, - - 87, 87, 87, 1534, 87, 1527, 87, 1528, 87, 1532, - 1543, 1531, 1536, 1539, 1535, 1538, 87, 87, 87, 87, - 87, 1537, 1540, 1542, 1541, 87, 87, 87, 1544, 87, - 1548, 87, 87, 87, 87, 1545, 87, 87, 1551, 1549, - 1546, 87, 1556, 1560, 1550, 1547, 1552, 87, 87, 87, - 87, 1553, 87, 87, 1554, 1555, 1557, 87, 1558, 87, - 87, 1563, 87, 87, 87, 1566, 87, 1570, 1561, 1559, - 1562, 1572, 1564, 87, 87, 87, 87, 87, 1565, 1567, - 87, 1569, 87, 1571, 1576, 87, 87, 1568, 1575, 1573, - 1574, 1577, 87, 1580, 1579, 87, 87, 1578, 1581, 87, - - 1583, 87, 1585, 87, 1582, 1593, 87, 87, 1584, 87, - 1586, 87, 1597, 1690, 1587, 1596, 1595, 1588, 1589, 1594, - 87, 87, 1590, 87, 87, 1598, 87, 1599, 1591, 1601, - 87, 1602, 1592, 1600, 87, 87, 87, 1604, 87, 1603, - 87, 1606, 87, 87, 87, 1608, 1613, 1609, 1614, 1607, - 87, 1605, 87, 1615, 87, 87, 1612, 87, 1610, 87, - 87, 1611, 87, 1621, 1616, 1618, 87, 87, 1623, 87, - 87, 1625, 1622, 1619, 87, 1624, 87, 1617, 87, 87, - 1620, 87, 87, 1634, 1632, 1635, 1636, 1627, 87, 1626, - 87, 87, 1628, 87, 1629, 1633, 1630, 1638, 1631, 87, - - 87, 1637, 87, 1643, 87, 87, 1639, 1644, 87, 1645, - 87, 1642, 87, 87, 1646, 87, 87, 1651, 1641, 1640, - 87, 87, 1649, 1647, 87, 1650, 1648, 87, 87, 1653, - 87, 87, 1659, 87, 1660, 1654, 1655, 87, 87, 87, - 87, 87, 1652, 87, 87, 1658, 1666, 1656, 1662, 1657, - 1667, 1661, 87, 87, 87, 1663, 87, 1664, 1665, 1671, - 87, 1670, 87, 1673, 87, 87, 87, 87, 1675, 87, - 1674, 1668, 1676, 87, 87, 1680, 87, 1672, 1677, 1669, - 87, 1682, 87, 1679, 87, 1683, 1678, 87, 87, 87, - 87, 168, 1684, 1688, 87, 87, 87, 87, 1693, 1691, - - 1681, 87, 87, 87, 87, 87, 1694, 1696, 87, 1685, - 1686, 1687, 1695, 87, 87, 1689, 1698, 1692, 87, 87, - 1697, 87, 87, 1699, 1701, 166, 1703, 1700, 87, 87, - 1704, 87, 1702, 1705, 1706, 87, 87, 1708, 87, 87, - 1707, 87, 87, 1709, 1714, 1711, 1715, 1710, 1712, 87, - 87, 87, 87, 1718, 1716, 1713, 1717, 87, 87, 87, - 87, 1722, 87, 87, 87, 87, 1719, 87, 87, 87, - 1725, 1721, 175, 87, 1731, 1732, 87, 1720, 1727, 87, - 87, 87, 1733, 1723, 1724, 1726, 1735, 1728, 87, 1729, - 1734, 87, 87, 87, 1741, 87, 1730, 87, 1740, 87, - - 87, 87, 1736, 87, 1746, 1738, 87, 87, 1737, 1743, - 87, 1739, 87, 1744, 87, 1742, 87, 1750, 87, 1745, - 1752, 87, 87, 1754, 87, 1758, 1747, 87, 1749, 87, - 1759, 87, 1748, 87, 1751, 87, 87, 1753, 1756, 87, - 1757, 1755, 87, 87, 1762, 87, 87, 1760, 87, 87, - 1763, 1761, 1774, 1764, 1768, 1770, 87, 1769, 1765, 87, - 1766, 1771, 1772, 1767, 1773, 87, 1777, 1776, 87, 1775, - 87, 1778, 87, 87, 87, 87, 87, 87, 87, 87, - 1782, 1783, 1784, 87, 1787, 87, 87, 1779, 87, 87, - 87, 1792, 1781, 87, 87, 87, 1785, 1793, 1796, 1780, - - 1789, 87, 87, 1786, 87, 1788, 1790, 1791, 87, 87, - 87, 87, 1794, 1797, 1795, 87, 87, 87, 1798, 87, - 87, 1804, 87, 1800, 1805, 1801, 1802, 1799, 87, 87, - 87, 87, 1812, 1806, 1803, 1809, 1808, 1807, 1811, 87, - 87, 1810, 87, 87, 1816, 1817, 1818, 87, 87, 1814, - 87, 87, 87, 87, 1813, 87, 1820, 1821, 87, 1822, - 87, 1819, 1815, 1826, 1823, 1825, 1827, 1828, 87, 87, - 87, 1824, 87, 87, 87, 1829, 87, 1830, 1833, 87, - 87, 87, 1837, 87, 1834, 87, 1836, 87, 87, 1841, - 1835, 87, 87, 87, 1840, 87, 1831, 1838, 1832, 1844, - - 1839, 1843, 87, 1848, 87, 87, 1846, 1845, 1849, 87, - 1850, 1842, 87, 87, 1847, 1851, 87, 1852, 87, 1854, - 87, 87, 87, 87, 1853, 87, 87, 1858, 1863, 87, - 1857, 1855, 87, 87, 87, 1865, 87, 1864, 87, 1856, - 87, 87, 1859, 1870, 1860, 87, 1861, 1862, 87, 87, - 87, 1866, 1873, 1868, 1872, 87, 1867, 87, 87, 87, - 87, 87, 87, 87, 1871, 87, 1869, 87, 1875, 1874, - 87, 1883, 87, 87, 1876, 1884, 1877, 1880, 87, 1878, - 1879, 87, 1882, 1881, 1885, 1888, 87, 1889, 87, 87, - 1887, 87, 1886, 87, 1890, 1891, 1893, 87, 87, 87, - - 87, 1896, 87, 1899, 87, 1897, 1892, 1894, 87, 1900, - 1895, 87, 87, 87, 1902, 87, 87, 87, 1898, 87, - 1904, 1903, 1908, 87, 1909, 1910, 1901, 87, 1905, 1913, - 87, 87, 87, 1907, 87, 87, 1906, 1914, 1915, 87, - 87, 87, 1911, 1912, 1916, 87, 87, 1921, 1922, 87, - 1919, 87, 1924, 87, 87, 87, 87, 1927, 87, 1917, - 1926, 1928, 87, 1918, 1930, 87, 1920, 87, 87, 1923, - 87, 1931, 1932, 87, 87, 1925, 87, 87, 87, 87, - 1936, 87, 1929, 87, 87, 1941, 1933, 87, 1939, 87, - 1934, 87, 1935, 87, 87, 87, 1945, 87, 1947, 1937, - - 87, 1938, 1942, 1940, 87, 87, 1948, 87, 1946, 1949, - 1943, 87, 1944, 1950, 87, 1954, 87, 1953, 87, 87, - 87, 87, 1951, 1957, 1959, 87, 87, 87, 87, 1962, - 1955, 1960, 87, 87, 87, 1958, 1952, 1956, 1966, 87, - 87, 1961, 1969, 87, 1965, 1968, 87, 1970, 1963, 1972, - 87, 1964, 1971, 87, 87, 175, 87, 87, 1967, 1974, - 87, 87, 87, 1973, 87, 87, 1983, 1984, 87, 87, - 87, 1975, 87, 87, 1976, 1977, 1978, 1979, 1980, 1982, - 87, 87, 1991, 1988, 87, 1981, 1986, 87, 1985, 1987, - 87, 1989, 1990, 87, 87, 1992, 1994, 87, 87, 1996, - - 1998, 87, 1995, 1999, 1993, 87, 87, 1997, 2001, 87, - 87, 87, 87, 87, 87, 2000, 87, 2004, 87, 2005, - 87, 2006, 87, 2007, 87, 2009, 87, 2010, 87, 2002, - 2003, 87, 87, 87, 2011, 2014, 87, 2015, 2008, 87, - 2012, 87, 2023, 2013, 87, 2017, 87, 2019, 87, 2016, - 2020, 2024, 87, 2022, 87, 2025, 87, 87, 4129, 2018, - 87, 2028, 2021, 2027, 87, 2031, 87, 2030, 2033, 2034, - 2038, 2026, 87, 87, 87, 87, 87, 2035, 87, 2036, - 87, 2037, 2029, 87, 2032, 87, 2040, 87, 2039, 87, - 87, 2045, 2046, 2044, 2047, 87, 87, 87, 87, 2049, - - 87, 2048, 87, 2041, 87, 87, 2042, 2051, 87, 2043, - 2052, 87, 87, 2053, 87, 87, 87, 87, 2050, 87, - 87, 87, 2054, 87, 87, 87, 87, 87, 2068, 2056, - 2065, 87, 2055, 2057, 2060, 2058, 87, 2059, 2061, 2062, - 87, 2063, 2066, 2069, 2064, 87, 2067, 2072, 2070, 87, - 87, 87, 87, 87, 87, 2077, 87, 2079, 2071, 2081, - 87, 87, 87, 87, 87, 2085, 2074, 87, 2076, 2073, - 2080, 2075, 2083, 2078, 87, 2084, 87, 87, 87, 87, - 87, 87, 2082, 87, 2091, 87, 87, 2095, 2090, 2086, - 2087, 87, 87, 87, 87, 2092, 2089, 2093, 2094, 87, - - 2096, 2088, 2098, 2097, 87, 87, 2106, 2099, 2103, 87, - 2102, 2101, 2100, 2104, 87, 2105, 87, 2107, 87, 2109, - 87, 2108, 2110, 87, 87, 87, 87, 87, 2112, 2113, - 2116, 2115, 87, 2111, 87, 87, 87, 87, 87, 2118, - 87, 87, 2114, 2127, 2128, 87, 2121, 87, 87, 87, - 2126, 87, 2120, 2117, 2119, 2129, 2123, 2122, 87, 2124, - 87, 87, 87, 2135, 2125, 87, 87, 87, 2136, 87, - 2137, 2130, 87, 2131, 87, 2133, 2132, 2142, 2134, 2138, - 87, 2141, 87, 87, 87, 2145, 87, 2147, 87, 2146, - 2140, 2139, 2144, 87, 87, 2154, 87, 2149, 2143, 2152, - - 2150, 2148, 87, 87, 87, 2155, 87, 2151, 2153, 2159, - 87, 87, 87, 87, 2160, 87, 87, 2166, 2164, 87, - 87, 87, 2156, 87, 87, 2161, 2169, 2157, 2158, 2168, - 87, 2162, 87, 2165, 2163, 87, 87, 2172, 2167, 87, - 2170, 2174, 87, 87, 2175, 2173, 2177, 87, 87, 2181, - 2171, 2179, 87, 87, 87, 87, 2176, 2180, 87, 87, - 2178, 2182, 87, 87, 4129, 87, 87, 87, 2187, 87, - 2186, 87, 87, 2183, 2188, 87, 2190, 2184, 2185, 2189, - 2194, 87, 2191, 2196, 2197, 2192, 2193, 87, 87, 87, - 87, 2198, 2200, 87, 87, 2201, 87, 2204, 87, 2206, - - 2199, 87, 2195, 87, 87, 87, 87, 2210, 87, 87, - 87, 87, 2202, 87, 2205, 2203, 2213, 2212, 87, 87, - 2208, 87, 87, 2215, 2209, 2207, 2216, 87, 2217, 2211, - 2214, 87, 87, 87, 87, 2219, 2223, 175, 2221, 87, - 2222, 2226, 87, 87, 87, 2218, 2220, 2230, 87, 2224, - 87, 87, 87, 2227, 2225, 2228, 2231, 87, 87, 2233, - 87, 87, 87, 2229, 2232, 2235, 87, 87, 2241, 2234, - 87, 87, 2236, 2237, 87, 2245, 87, 87, 87, 2248, - 87, 2238, 2242, 2244, 87, 2239, 2250, 2240, 87, 2243, - 87, 2246, 87, 87, 87, 2249, 87, 2254, 2247, 2251, - - 2255, 87, 2252, 87, 87, 87, 2257, 87, 2256, 87, - 2253, 87, 2258, 87, 87, 87, 2263, 87, 87, 87, - 2264, 87, 87, 87, 87, 2259, 2265, 2268, 2269, 2260, - 2266, 2261, 2262, 2270, 2267, 87, 87, 87, 2277, 87, - 2273, 2272, 2275, 2278, 87, 87, 2271, 2274, 87, 87, - 87, 2276, 87, 87, 87, 87, 2285, 4129, 87, 87, - 2288, 2280, 2289, 87, 87, 2279, 87, 2281, 2283, 2282, - 2290, 87, 2286, 2284, 2287, 2291, 2292, 87, 87, 2293, - 87, 2297, 87, 2299, 87, 2294, 2301, 2295, 2298, 87, - 87, 87, 87, 2300, 2303, 87, 87, 87, 87, 87, - - 87, 2296, 2306, 87, 87, 2305, 2308, 2309, 87, 2302, - 87, 2312, 87, 87, 2319, 2311, 87, 87, 2304, 2310, - 87, 2315, 2316, 2307, 87, 2314, 87, 2317, 2313, 2318, - 87, 87, 87, 87, 2327, 87, 87, 87, 87, 87, - 87, 87, 2320, 2321, 2322, 2330, 2331, 87, 2337, 2323, - 2325, 2324, 2332, 2326, 2335, 2328, 2329, 2333, 87, 87, - 87, 2334, 2336, 2339, 87, 87, 87, 87, 87, 87, - 87, 2346, 87, 2340, 2338, 87, 87, 2348, 87, 87, - 2342, 87, 87, 2351, 87, 2341, 2343, 87, 2344, 2345, - 2352, 87, 2353, 87, 2355, 87, 2357, 87, 2349, 2354, - - 87, 2347, 2361, 2350, 2358, 87, 2359, 87, 87, 2356, - 87, 87, 87, 2366, 87, 87, 87, 87, 87, 87, - 2372, 2360, 87, 87, 2369, 87, 2365, 2364, 2362, 2363, - 87, 2368, 2370, 2373, 87, 2377, 2367, 2376, 87, 2378, - 87, 2375, 87, 87, 2371, 87, 2381, 2380, 2374, 87, - 2384, 2382, 87, 2385, 87, 87, 87, 87, 2379, 87, - 2386, 2383, 87, 87, 87, 87, 2387, 87, 2391, 87, - 2393, 87, 87, 2396, 2388, 2392, 87, 87, 87, 2399, - 2397, 87, 2389, 2390, 87, 87, 2402, 2394, 87, 2400, - 87, 2401, 87, 87, 2410, 87, 87, 2395, 2398, 2404, - - 2405, 2403, 87, 87, 87, 87, 87, 2409, 2407, 87, - 87, 2416, 87, 2415, 4129, 2408, 2406, 87, 2417, 87, - 2413, 2419, 87, 2412, 87, 2414, 2418, 2411, 2420, 87, - 2424, 87, 87, 2421, 87, 2422, 87, 87, 87, 87, - 2423, 87, 2428, 2432, 87, 87, 87, 87, 2426, 87, - 87, 2435, 87, 2425, 4129, 2427, 2437, 87, 2429, 2430, - 2434, 2431, 2433, 2436, 87, 2438, 87, 87, 87, 87, - 2439, 87, 2443, 2451, 2444, 2456, 2440, 2445, 87, 2441, - 2446, 87, 2447, 2449, 2442, 2450, 87, 2448, 87, 87, - 87, 87, 87, 2454, 87, 2452, 87, 2458, 2453, 87, - - 87, 2460, 87, 2462, 2455, 87, 2457, 87, 87, 87, - 2465, 87, 87, 2464, 87, 87, 175, 87, 87, 87, - 2463, 2468, 2474, 87, 2461, 2459, 87, 2469, 2472, 2470, - 87, 2466, 2473, 87, 2467, 87, 2475, 2471, 2476, 87, - 87, 2477, 2478, 87, 2479, 2480, 2481, 2482, 87, 87, - 87, 87, 87, 87, 2483, 2485, 2484, 87, 2488, 87, - 87, 2486, 2487, 2489, 87, 87, 87, 87, 2490, 87, - 2491, 87, 2493, 87, 2495, 2499, 87, 87, 87, 87, - 2492, 2496, 2494, 2497, 2498, 87, 2500, 87, 87, 87, - 2501, 2503, 2502, 2504, 87, 87, 87, 2509, 2505, 87, - - 87, 87, 2512, 87, 2506, 2510, 87, 2507, 87, 2514, - 87, 2511, 87, 87, 2517, 2508, 87, 2513, 87, 87, - 87, 87, 2523, 87, 87, 2518, 2516, 2520, 2515, 2521, - 87, 87, 2524, 87, 2519, 87, 2525, 87, 2527, 2522, - 2529, 87, 87, 87, 2528, 2530, 87, 87, 2536, 87, - 2534, 2526, 87, 2531, 87, 87, 2538, 87, 87, 2532, - 2539, 2535, 2533, 87, 2543, 87, 2537, 87, 87, 2541, - 2542, 2540, 2545, 87, 87, 2544, 87, 2546, 2549, 87, - 2548, 87, 87, 87, 87, 87, 2554, 87, 2551, 87, - 2555, 2547, 87, 2550, 87, 87, 87, 87, 2556, 87, - - 87, 87, 4129, 2553, 2552, 87, 2558, 2559, 2557, 2561, - 2563, 2560, 87, 87, 2564, 2565, 87, 2574, 2562, 87, - 2566, 87, 87, 2567, 2568, 2569, 2575, 87, 2570, 87, - 87, 87, 2572, 2578, 2576, 87, 2573, 87, 2580, 2577, - 2579, 2571, 2581, 87, 2582, 87, 87, 87, 2585, 87, - 2584, 2583, 87, 87, 2587, 87, 87, 87, 87, 2588, - 2593, 87, 2589, 87, 87, 2586, 2591, 87, 2592, 2597, - 87, 87, 2599, 2590, 87, 87, 2601, 87, 2595, 87, - 2594, 87, 87, 87, 2596, 2600, 2603, 2598, 87, 87, - 2604, 87, 2610, 87, 2605, 87, 2606, 2607, 87, 87, - - 2602, 2608, 2609, 2614, 2611, 87, 2612, 2613, 2615, 87, - 87, 87, 87, 2616, 2620, 87, 87, 2621, 87, 87, - 87, 2625, 4129, 87, 2619, 2618, 87, 87, 2626, 2617, - 2622, 2628, 87, 2623, 2627, 2629, 2631, 87, 87, 2632, - 2624, 87, 87, 87, 2630, 87, 2633, 2635, 87, 87, - 2637, 87, 2638, 87, 2634, 2636, 87, 87, 87, 87, - 87, 2640, 2639, 2642, 87, 87, 2645, 2643, 2647, 87, - 2644, 87, 87, 2648, 87, 2641, 87, 2649, 2650, 87, - 87, 2646, 87, 2651, 2654, 2652, 87, 2655, 2653, 87, - 2660, 87, 87, 2656, 2657, 87, 87, 87, 2659, 87, - - 87, 87, 87, 87, 87, 2668, 2658, 87, 87, 2672, - 2661, 87, 87, 2662, 2663, 2664, 2666, 2673, 2667, 2669, - 2670, 2671, 2665, 87, 87, 87, 87, 87, 87, 2675, - 2676, 2678, 2674, 87, 87, 87, 2684, 87, 87, 2686, - 87, 87, 2680, 2677, 2683, 87, 2681, 2685, 87, 2679, - 87, 87, 2687, 2690, 2689, 87, 87, 2695, 2682, 175, - 2688, 2697, 2699, 87, 2691, 2693, 2698, 87, 87, 87, - 2692, 2700, 2701, 87, 87, 2694, 87, 87, 87, 87, - 87, 2696, 2702, 2707, 87, 87, 2708, 2712, 87, 2711, - 87, 2713, 87, 2703, 87, 87, 2704, 2706, 87, 87, - - 2709, 2705, 2717, 87, 2714, 2716, 87, 2722, 87, 87, - 2718, 2710, 2715, 2725, 2720, 2723, 87, 87, 2719, 87, - 87, 2721, 2724, 87, 2726, 87, 87, 87, 87, 2728, - 87, 87, 87, 2731, 87, 87, 87, 87, 87, 2735, - 87, 2741, 87, 2727, 87, 2739, 2729, 2733, 2742, 2734, - 87, 2737, 2730, 2732, 2736, 87, 87, 2738, 87, 87, - 2740, 2744, 87, 87, 87, 2743, 87, 87, 87, 2750, - 2753, 87, 87, 2745, 2748, 87, 2754, 2747, 87, 2751, - 87, 87, 2749, 87, 2746, 2752, 87, 87, 87, 2764, - 2766, 2755, 87, 87, 2756, 87, 87, 2757, 87, 2762, - - 87, 2765, 2760, 2758, 87, 2759, 87, 2761, 2767, 2763, - 2770, 2768, 87, 87, 2769, 2771, 2773, 87, 87, 87, - 87, 87, 2775, 2774, 87, 2776, 2772, 87, 2780, 2781, - 87, 87, 87, 2782, 87, 2778, 4129, 2779, 2783, 87, - 87, 87, 2787, 87, 2777, 2788, 4129, 2784, 87, 2785, - 2789, 87, 87, 2786, 87, 2790, 87, 2792, 2791, 2795, - 87, 2793, 2796, 87, 2794, 87, 87, 87, 2799, 87, - 2797, 2798, 87, 87, 2804, 87, 2805, 87, 87, 2807, - 87, 2801, 87, 2809, 87, 2802, 2803, 2800, 87, 87, - 2812, 87, 2813, 87, 2811, 87, 87, 2806, 87, 87, - - 2808, 87, 2817, 2810, 87, 2815, 2819, 87, 87, 2814, - 87, 2823, 87, 87, 87, 2822, 2818, 87, 2816, 2825, - 87, 87, 2820, 2821, 87, 87, 2827, 87, 2829, 2834, - 2828, 87, 2824, 87, 2830, 2826, 2832, 87, 87, 87, - 2835, 2838, 87, 87, 87, 2839, 2833, 87, 87, 2831, - 2837, 87, 87, 87, 2836, 2845, 87, 2844, 87, 2841, - 87, 87, 87, 2840, 87, 87, 2849, 2843, 2847, 2850, - 2842, 87, 87, 2856, 2851, 2858, 87, 2846, 87, 2855, - 2848, 87, 2859, 2852, 87, 2860, 87, 2857, 87, 87, - 2853, 2854, 87, 2866, 2872, 2861, 87, 87, 87, 2868, - - 87, 2869, 2862, 2864, 2863, 2867, 87, 87, 87, 87, - 87, 2874, 87, 2875, 2876, 2865, 2870, 87, 2871, 2873, - 87, 87, 87, 87, 87, 2878, 2881, 87, 2883, 2880, - 87, 87, 2884, 87, 2887, 2877, 2885, 2888, 2879, 2886, - 87, 87, 87, 87, 2891, 87, 87, 2892, 2882, 87, - 87, 2889, 87, 87, 2893, 2896, 2890, 87, 2894, 2895, - 87, 87, 2898, 87, 87, 2897, 2899, 2903, 2904, 2900, - 2901, 87, 87, 87, 87, 2905, 87, 2902, 87, 2909, - 2910, 87, 2911, 87, 2906, 2908, 87, 87, 87, 2914, - 2912, 87, 2907, 175, 2913, 87, 2916, 2915, 2917, 87, - - 87, 2922, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 2918, 2926, 2919, 2924, 2920, 2921, 2925, 2923, 87, - 87, 2928, 2929, 87, 2927, 2930, 2932, 2934, 87, 87, - 87, 87, 2931, 2933, 2937, 87, 2938, 87, 2935, 2939, - 87, 4129, 2936, 87, 2941, 2942, 87, 87, 87, 2945, - 2943, 2940, 2946, 2944, 87, 87, 2948, 87, 87, 87, - 87, 2950, 87, 2947, 87, 2952, 87, 87, 87, 2955, - 2956, 87, 87, 2949, 2951, 87, 87, 2958, 87, 2959, - 2953, 2960, 2961, 87, 87, 2957, 2954, 87, 87, 2962, - 87, 87, 2963, 87, 87, 2968, 87, 2964, 2967, 2965, - - 87, 87, 87, 87, 87, 2970, 2969, 87, 87, 87, - 2978, 2966, 2975, 87, 2977, 87, 87, 87, 2974, 2979, - 2981, 2971, 2972, 2973, 87, 2980, 87, 2976, 87, 2982, - 87, 87, 87, 2988, 87, 2983, 2986, 87, 87, 87, - 2992, 2993, 2991, 87, 87, 2984, 87, 87, 87, 2985, - 2989, 2994, 87, 2987, 2995, 2990, 87, 2996, 2997, 87, - 2999, 87, 87, 3001, 3000, 87, 87, 87, 3002, 87, - 2998, 87, 3004, 87, 3006, 3007, 3008, 87, 3010, 87, - 87, 3003, 87, 87, 87, 3012, 87, 3014, 87, 3009, - 87, 87, 3011, 3005, 87, 3013, 87, 87, 3020, 3018, - - 87, 87, 3015, 87, 3016, 87, 3023, 3017, 3025, 87, - 3024, 3026, 87, 3027, 87, 87, 3029, 87, 3021, 87, - 87, 87, 3019, 87, 3022, 87, 3032, 87, 87, 87, - 3034, 3037, 87, 3030, 3028, 3035, 87, 87, 87, 87, - 3036, 87, 3031, 3041, 3033, 3038, 3039, 3040, 3045, 87, - 3044, 87, 87, 3043, 3042, 87, 87, 87, 3047, 3048, - 87, 3046, 87, 87, 87, 87, 87, 3051, 87, 87, - 3057, 3049, 3052, 3058, 87, 3050, 87, 87, 87, 3062, - 87, 3059, 3064, 3053, 3054, 3055, 3056, 3061, 87, 87, - 87, 87, 87, 3063, 87, 3060, 3068, 87, 3072, 87, - - 87, 87, 4129, 3065, 3066, 3071, 3067, 3074, 87, 3075, - 87, 87, 3069, 3076, 87, 87, 3073, 3070, 87, 87, - 3078, 87, 3081, 3077, 3080, 87, 3082, 87, 3083, 87, - 87, 87, 87, 3079, 87, 87, 3090, 87, 87, 3092, - 87, 3084, 87, 3086, 3093, 87, 3095, 87, 87, 87, - 3085, 3089, 3087, 3094, 87, 3088, 3097, 3091, 87, 87, - 3096, 87, 87, 87, 3100, 87, 3098, 3103, 87, 3105, - 87, 87, 3104, 87, 87, 87, 87, 87, 3099, 87, - 87, 3101, 3102, 175, 3108, 3111, 87, 87, 3114, 3110, - 87, 3106, 3112, 3107, 87, 3115, 87, 3116, 3109, 3113, - - 87, 3121, 3118, 3117, 87, 3119, 87, 3124, 87, 87, - 87, 3123, 87, 3126, 87, 87, 87, 3128, 3120, 87, - 3129, 3130, 87, 3131, 87, 3134, 3122, 87, 3127, 87, - 3133, 3132, 3125, 87, 3135, 87, 3136, 87, 87, 87, - 87, 87, 87, 87, 87, 3137, 87, 87, 3138, 87, - 87, 3148, 4129, 3146, 3140, 87, 87, 3139, 87, 3142, - 3141, 87, 3152, 3144, 3143, 87, 3145, 3147, 87, 3153, - 3149, 3154, 87, 3150, 3151, 87, 3158, 87, 87, 87, - 3156, 87, 3155, 87, 3157, 3160, 87, 3159, 87, 87, - 87, 87, 87, 4129, 87, 3164, 87, 3161, 87, 3162, - - 3170, 3163, 3171, 87, 3165, 87, 3173, 87, 3166, 3167, - 3168, 3169, 3172, 3174, 87, 87, 87, 3178, 87, 3179, - 87, 3180, 3177, 3175, 87, 87, 87, 87, 87, 87, - 87, 3187, 87, 3176, 3186, 87, 87, 87, 87, 87, - 87, 3183, 3181, 3182, 3185, 4129, 87, 3184, 87, 3191, - 3192, 3194, 87, 87, 3195, 3188, 3189, 3190, 3196, 87, - 3193, 87, 87, 3197, 3198, 87, 87, 3199, 3200, 87, - 87, 3202, 3201, 87, 87, 3207, 87, 87, 87, 3206, - 87, 87, 3204, 3209, 87, 3203, 87, 87, 3215, 87, - 3214, 87, 87, 3205, 3218, 87, 87, 3208, 87, 87, - - 3210, 3212, 87, 3211, 3213, 87, 3216, 3219, 87, 3221, - 3217, 87, 87, 3220, 3222, 3225, 87, 3223, 3224, 3226, - 87, 3227, 87, 87, 3231, 87, 87, 87, 87, 3228, - 87, 87, 4129, 87, 3234, 3229, 87, 87, 3230, 3232, - 3233, 3241, 87, 3236, 3239, 87, 3235, 87, 87, 87, - 87, 3237, 3238, 3244, 3243, 87, 3245, 3240, 87, 3242, - 3246, 87, 3248, 87, 87, 87, 3251, 3247, 87, 3249, - 3252, 3254, 87, 87, 3250, 87, 3256, 87, 87, 3259, - 87, 87, 87, 87, 87, 87, 3257, 3293, 3253, 87, - 3263, 87, 87, 87, 3255, 3260, 3261, 3262, 3264, 87, - - 3258, 3265, 3266, 87, 3270, 3267, 3268, 3269, 87, 87, - 87, 87, 87, 87, 3271, 87, 3273, 87, 87, 87, - 3274, 87, 87, 3277, 3272, 87, 3276, 3279, 3282, 87, - 3280, 87, 3275, 3278, 3281, 3283, 87, 87, 87, 87, - 3287, 87, 3284, 3286, 3288, 175, 3285, 87, 3289, 87, - 87, 87, 3290, 4129, 87, 3294, 3295, 3291, 87, 3297, - 87, 87, 3300, 87, 3301, 87, 3299, 3292, 3296, 87, - 87, 87, 3305, 87, 3302, 3298, 87, 87, 87, 3306, - 4129, 3307, 3309, 3303, 87, 3304, 3308, 87, 3312, 3310, - 87, 87, 3311, 87, 87, 3313, 87, 87, 3314, 3316, - - 87, 3315, 87, 3320, 3321, 87, 87, 87, 3318, 87, - 87, 3322, 3317, 3324, 87, 87, 87, 3323, 87, 3328, - 87, 3326, 3325, 3319, 87, 3329, 87, 3327, 87, 87, - 87, 3330, 87, 3331, 87, 3336, 3332, 87, 87, 3334, - 87, 3335, 3333, 3339, 3338, 87, 3337, 3342, 87, 87, - 3340, 87, 87, 87, 3343, 87, 3341, 87, 3348, 87, - 87, 87, 87, 87, 87, 87, 3353, 3349, 87, 87, - 3344, 3351, 3345, 3352, 87, 3346, 3347, 3355, 3354, 87, - 3350, 3357, 87, 87, 3356, 87, 87, 87, 3361, 3365, - 3362, 3363, 87, 3358, 3359, 87, 3366, 87, 3369, 87, - - 3370, 87, 87, 3360, 87, 87, 87, 87, 87, 87, - 87, 3377, 3364, 3371, 3373, 3376, 3367, 3368, 87, 3374, - 3375, 87, 3378, 87, 87, 3381, 87, 87, 87, 3383, - 87, 3372, 87, 87, 87, 3384, 87, 3385, 3380, 87, - 87, 3379, 3382, 87, 87, 3392, 87, 3387, 3389, 3391, - 3388, 3386, 3394, 87, 3395, 87, 3396, 87, 87, 87, - 87, 87, 3390, 3397, 87, 3398, 3393, 3399, 3400, 87, - 87, 87, 3404, 87, 87, 3402, 3403, 3405, 87, 87, - 87, 3401, 87, 3406, 87, 3410, 3411, 87, 3412, 87, - 3413, 87, 87, 3407, 3408, 3414, 87, 87, 3418, 3409, - - 3417, 87, 3419, 3420, 87, 87, 3421, 3422, 87, 3415, - 3416, 87, 3424, 87, 87, 87, 87, 3428, 3429, 87, - 87, 4129, 87, 87, 3430, 3433, 3423, 3425, 87, 3431, - 3427, 3434, 87, 3426, 3432, 87, 87, 87, 3436, 87, - 87, 3435, 3442, 3437, 87, 87, 3441, 3443, 87, 3444, - 87, 3438, 3439, 87, 3446, 87, 3447, 87, 87, 3440, - 3448, 87, 87, 3449, 87, 87, 87, 87, 3452, 3450, - 3445, 87, 3451, 87, 3454, 87, 3455, 87, 3458, 3460, - 87, 87, 87, 87, 3456, 3457, 3463, 87, 87, 87, - 87, 3453, 3465, 3475, 87, 3459, 3462, 3464, 87, 3470, - - 3466, 3461, 3467, 87, 3471, 87, 3469, 3472, 87, 3468, - 87, 3476, 3473, 87, 87, 3477, 87, 3478, 87, 3479, - 87, 3480, 3474, 87, 3481, 87, 87, 87, 3482, 87, - 87, 87, 87, 87, 87, 87, 3485, 3486, 3488, 3490, - 87, 3491, 87, 3487, 87, 3483, 3495, 87, 3496, 87, - 3489, 87, 3484, 87, 3497, 3492, 3499, 87, 87, 3498, - 3493, 87, 3494, 87, 3500, 87, 3501, 3503, 87, 87, - 3504, 3502, 3505, 87, 3507, 3508, 87, 87, 87, 87, - 3511, 87, 87, 87, 3515, 87, 3506, 3509, 3510, 3516, - 87, 3512, 3513, 87, 87, 3514, 87, 3517, 87, 87, - - 87, 3523, 87, 3518, 87, 87, 3524, 87, 87, 3520, - 87, 3526, 87, 3604, 3521, 3519, 3529, 3525, 87, 3530, - 3522, 87, 87, 3527, 87, 3528, 3531, 3532, 87, 87, - 87, 3537, 87, 3533, 87, 3536, 87, 3534, 3539, 87, - 87, 87, 3543, 87, 3535, 3544, 87, 87, 3538, 3546, - 3540, 87, 87, 87, 87, 87, 3545, 87, 3549, 3542, - 87, 3552, 87, 3547, 87, 3541, 3550, 87, 87, 3555, - 87, 3557, 3553, 3556, 3551, 87, 87, 3548, 87, 87, - 87, 3559, 87, 3554, 3558, 87, 3564, 3566, 87, 3565, - 3561, 87, 3560, 3562, 3567, 87, 3563, 3568, 87, 87, - - 3569, 87, 87, 87, 87, 3575, 87, 3574, 3576, 87, - 87, 87, 87, 3579, 87, 3577, 87, 3578, 87, 3570, - 87, 3571, 3572, 3573, 3580, 3583, 87, 3585, 3581, 87, - 3587, 87, 87, 87, 87, 87, 3588, 87, 87, 3582, - 3589, 87, 3590, 87, 3584, 87, 3591, 87, 3596, 87, - 87, 3597, 87, 3592, 3586, 87, 3593, 87, 3594, 3600, - 87, 87, 87, 3598, 87, 3599, 3601, 3595, 87, 3605, - 87, 87, 87, 3609, 87, 87, 3602, 3613, 87, 3610, - 3603, 87, 3606, 3607, 3614, 87, 87, 87, 3608, 3616, - 87, 87, 3611, 3619, 3617, 87, 3620, 87, 3621, 87, - - 3615, 3612, 3624, 87, 3618, 87, 3623, 3622, 87, 87, - 87, 87, 3630, 87, 3627, 87, 3629, 3633, 87, 87, - 87, 3625, 87, 87, 3626, 87, 3628, 3632, 3635, 87, - 87, 3637, 87, 87, 87, 3631, 3638, 87, 87, 3636, - 3643, 87, 3634, 87, 3644, 87, 3639, 87, 3642, 3648, - 87, 3649, 3641, 3640, 3651, 87, 3645, 87, 87, 87, - 87, 87, 3646, 3647, 3652, 3655, 87, 3650, 3656, 87, - 87, 3659, 87, 87, 87, 87, 3657, 3653, 87, 87, - 3664, 87, 3662, 87, 3654, 3661, 87, 3668, 87, 87, - 3658, 3660, 87, 3666, 3669, 3663, 87, 3665, 3671, 3667, - - 3670, 87, 87, 87, 3675, 3672, 3673, 87, 3674, 87, - 87, 3679, 3680, 87, 3682, 3678, 3676, 87, 87, 87, - 87, 3681, 87, 3685, 87, 87, 87, 3684, 3688, 3677, - 3686, 87, 3691, 87, 87, 87, 87, 3683, 87, 87, - 3696, 87, 87, 87, 87, 3687, 4129, 3692, 3689, 3690, - 3700, 87, 3695, 3699, 3693, 3701, 87, 3702, 87, 3698, - 87, 3697, 87, 3694, 87, 3703, 3706, 87, 87, 3705, - 3707, 87, 3708, 87, 87, 87, 3704, 3709, 3711, 87, - 87, 3714, 3716, 87, 87, 87, 87, 87, 3712, 3715, - 3718, 87, 3719, 87, 87, 3710, 87, 87, 87, 87, - - 87, 3717, 87, 3726, 87, 3720, 3713, 3727, 87, 87, - 87, 87, 3733, 87, 87, 3721, 87, 3724, 3722, 3723, - 3732, 3725, 87, 3729, 3730, 87, 3728, 3736, 87, 3731, - 87, 87, 3740, 87, 3734, 3737, 3735, 3739, 87, 87, - 3744, 87, 3738, 3742, 87, 87, 87, 87, 87, 4129, - 3741, 3743, 3747, 3748, 3750, 87, 3751, 87, 87, 87, - 87, 3745, 3754, 3746, 3752, 87, 3749, 87, 87, 3757, - 87, 87, 3753, 87, 87, 3756, 3758, 3755, 3760, 87, - 3759, 87, 87, 87, 3761, 87, 87, 3764, 87, 87, - 87, 87, 87, 3762, 3768, 3765, 87, 3766, 3769, 87, - - 87, 3763, 87, 3781, 3767, 87, 87, 87, 3770, 87, - 3778, 3771, 3772, 4129, 3773, 3774, 87, 3775, 3776, 87, - 87, 3779, 87, 3777, 3782, 3784, 3780, 3783, 3786, 87, - 3787, 87, 87, 3785, 87, 87, 3788, 3791, 87, 87, - 3790, 87, 3794, 87, 3792, 87, 87, 3796, 87, 3789, - 3798, 3799, 87, 87, 3800, 3801, 3805, 87, 3802, 87, - 3793, 3795, 3803, 3804, 3797, 87, 87, 87, 3808, 87, - 87, 3806, 87, 3811, 87, 3813, 3807, 3812, 87, 3814, - 87, 87, 87, 3815, 87, 87, 3810, 87, 3809, 87, - 3816, 3818, 87, 3819, 87, 87, 3820, 87, 3817, 87, - - 3821, 87, 3823, 87, 3822, 3824, 87, 3826, 87, 87, - 3828, 87, 3829, 87, 87, 87, 3833, 3825, 3830, 87, - 3834, 3835, 87, 87, 87, 3837, 3827, 87, 3831, 3832, - 3838, 87, 3836, 3839, 87, 3840, 87, 87, 87, 3846, - 87, 3841, 3842, 3843, 3847, 87, 3844, 3848, 87, 3845, - 87, 87, 87, 87, 87, 3856, 3852, 3853, 3855, 87, - 87, 87, 87, 3850, 87, 3849, 3857, 3858, 87, 3859, - 87, 3851, 87, 3854, 87, 3862, 87, 3860, 3863, 3861, - 3864, 87, 3865, 87, 87, 3868, 87, 3869, 87, 87, - 3867, 3870, 87, 3866, 3871, 87, 3872, 87, 3873, 87, - - 3874, 87, 3875, 87, 3876, 87, 87, 87, 3879, 87, - 87, 87, 87, 87, 87, 3877, 3878, 3882, 87, 3884, - 3886, 87, 87, 3887, 87, 87, 3880, 3883, 3891, 87, - 3881, 3889, 87, 3885, 3888, 3893, 87, 87, 87, 3890, - 87, 87, 3897, 87, 3892, 3899, 87, 3894, 3901, 87, - 3895, 87, 3896, 3900, 87, 3898, 3902, 87, 87, 87, - 3904, 87, 3906, 87, 3909, 87, 3908, 87, 87, 87, - 87, 87, 3903, 3911, 87, 87, 87, 3907, 87, 3910, - 3916, 3915, 3917, 87, 3905, 87, 3912, 3913, 87, 3919, - 3914, 3918, 87, 87, 87, 87, 3923, 3922, 87, 87, - - 3926, 87, 87, 3924, 3925, 3921, 87, 3932, 87, 3920, - 3933, 87, 3934, 87, 87, 3931, 3935, 87, 3927, 87, - 3928, 3929, 87, 87, 3930, 87, 3938, 87, 3937, 3942, - 87, 87, 87, 87, 3946, 87, 87, 3936, 3945, 87, - 3940, 3941, 3944, 3939, 87, 3948, 87, 87, 87, 87, - 87, 3947, 3949, 3943, 87, 87, 87, 87, 87, 3955, - 87, 3957, 87, 3952, 87, 3950, 3951, 3956, 87, 3954, - 3959, 3962, 87, 3960, 3953, 87, 87, 3964, 3958, 3961, - 3966, 87, 3963, 87, 87, 87, 87, 87, 3965, 87, - 87, 3971, 3969, 3974, 87, 87, 3967, 87, 3976, 3975, - - 87, 3972, 3968, 3977, 87, 3970, 87, 87, 3979, 3973, - 87, 3978, 3980, 87, 3981, 87, 3982, 87, 87, 87, - 3983, 3984, 3985, 87, 3986, 3989, 87, 87, 87, 3993, - 87, 87, 87, 3992, 87, 3987, 3995, 87, 3988, 3991, - 3990, 3996, 87, 3997, 87, 3998, 87, 87, 87, 87, - 4001, 87, 3994, 3999, 4000, 4003, 87, 4002, 4004, 87, - 87, 87, 4005, 4007, 87, 87, 87, 87, 4012, 87, - 87, 4013, 87, 87, 87, 4016, 4008, 4009, 4017, 4006, - 4014, 87, 87, 87, 87, 4011, 87, 87, 4018, 4010, - 87, 4021, 4015, 4022, 87, 4019, 4023, 87, 87, 87, - - 87, 87, 4020, 4030, 87, 4024, 87, 87, 4027, 87, - 87, 4032, 87, 4025, 4026, 4029, 87, 4034, 87, 87, - 4028, 87, 4031, 4036, 87, 87, 4039, 4041, 87, 4033, - 4040, 4037, 87, 87, 87, 4035, 4129, 87, 4038, 87, - 87, 4049, 87, 87, 4051, 4042, 87, 4052, 4050, 4048, - 87, 4044, 87, 4043, 4045, 4046, 87, 4053, 4047, 87, - 87, 4054, 4057, 87, 4055, 87, 87, 87, 87, 87, - 4060, 4061, 87, 87, 4062, 4063, 87, 87, 87, 4056, - 87, 4065, 87, 4058, 4070, 4059, 4066, 4067, 87, 87, - 87, 4064, 4073, 87, 4074, 87, 4129, 4068, 4075, 87, - - 87, 4069, 4072, 87, 4076, 4077, 87, 4071, 4078, 87, - 87, 87, 87, 87, 87, 4079, 4081, 87, 4080, 87, - 4085, 87, 4086, 87, 87, 4088, 4084, 4087, 87, 4082, - 4129, 4083, 87, 4090, 87, 4092, 87, 4093, 87, 87, - 4097, 87, 87, 4091, 4094, 4095, 4129, 4096, 87, 4089, - 4098, 87, 87, 4099, 4100, 4101, 87, 87, 87, 87, - 87, 4104, 87, 87, 4102, 4103, 87, 4105, 4107, 87, - 87, 4109, 87, 87, 4113, 4110, 4114, 87, 4106, 4108, - 87, 87, 4111, 87, 4117, 4118, 87, 87, 4120, 87, - 87, 4112, 4121, 87, 4119, 87, 87, 4122, 87, 4115, - - 4116, 4123, 87, 4124, 4127, 87, 4128, 87, 4129, 4129, - 4129, 4129, 4129, 4129, 4125, 4129, 4129, 4129, 4129, 4129, - 4129, 4126, 48, 48, 48, 48, 48, 48, 48, 53, - 53, 53, 53, 53, 53, 53, 58, 58, 58, 58, - 58, 58, 58, 64, 64, 64, 64, 64, 64, 64, - 69, 69, 69, 69, 69, 69, 69, 75, 75, 75, - 75, 75, 75, 75, 81, 81, 81, 81, 81, 81, - 81, 90, 90, 4129, 90, 90, 90, 90, 165, 165, - 4129, 4129, 4129, 165, 165, 167, 167, 4129, 4129, 167, - 4129, 167, 169, 4129, 4129, 4129, 4129, 4129, 169, 172, - - 172, 4129, 4129, 4129, 172, 172, 174, 4129, 4129, 4129, - 4129, 4129, 174, 176, 176, 4129, 176, 176, 176, 176, - 179, 4129, 4129, 4129, 4129, 4129, 179, 182, 182, 4129, - 4129, 4129, 182, 182, 91, 91, 4129, 91, 91, 91, - 91, 17, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, - 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, - 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, - 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, - 4129, 4129 + 87, 87, 180, 501, 492, 87, 506, 477, 482, 87, + 87, 507, 87, 483, 502, 87, 491, 503, 484, 517, + 87, 485, 504, 505, 510, 87, 486, 487, 488, 489, + 87, 508, 175, 493, 87, 494, 87, 495, 87, 509, + 523, 87, 87, 87, 87, 519, 87, 496, 497, 498, + 499, 500, 87, 518, 87, 511, 513, 514, 512, 520, + 515, 516, 87, 521, 87, 522, 87, 524, 526, 87, + + 87, 525, 87, 87, 87, 87, 531, 87, 87, 538, + 537, 527, 87, 87, 532, 87, 533, 87, 530, 528, + 87, 87, 529, 87, 622, 534, 539, 536, 540, 550, + 87, 544, 535, 542, 541, 543, 545, 87, 87, 551, + 546, 552, 87, 553, 87, 87, 87, 87, 87, 87, + 554, 568, 87, 547, 173, 175, 548, 87, 549, 87, + 555, 87, 556, 87, 570, 87, 567, 571, 557, 569, + 87, 572, 558, 573, 587, 575, 593, 559, 586, 87, + 560, 87, 561, 171, 562, 588, 590, 87, 87, 574, + 589, 87, 87, 87, 591, 87, 596, 563, 594, 87, + + 564, 592, 565, 598, 566, 87, 87, 576, 577, 87, + 595, 87, 597, 578, 87, 87, 87, 579, 580, 581, + 582, 583, 87, 170, 584, 600, 601, 585, 602, 599, + 603, 609, 87, 87, 87, 607, 87, 605, 610, 611, + 604, 87, 608, 613, 87, 614, 87, 87, 87, 87, + 87, 87, 620, 87, 87, 606, 612, 87, 87, 616, + 87, 87, 618, 87, 87, 623, 615, 87, 617, 619, + 624, 625, 632, 87, 626, 630, 87, 627, 621, 628, + 629, 87, 87, 631, 633, 634, 87, 87, 87, 639, + 636, 637, 87, 87, 87, 640, 87, 655, 87, 87, + + 87, 87, 635, 87, 658, 87, 638, 641, 656, 642, + 644, 87, 643, 645, 646, 87, 657, 660, 87, 661, + 87, 666, 663, 87, 659, 647, 662, 648, 87, 87, + 87, 87, 664, 649, 87, 665, 87, 667, 669, 87, + 87, 650, 651, 87, 668, 652, 653, 87, 671, 654, + 87, 673, 674, 670, 87, 677, 87, 87, 87, 675, + 672, 676, 87, 87, 87, 681, 87, 679, 680, 87, + 87, 87, 682, 683, 87, 87, 87, 678, 684, 688, + 87, 87, 87, 687, 87, 691, 689, 692, 686, 685, + 87, 87, 87, 696, 694, 87, 690, 87, 699, 693, + + 697, 87, 701, 695, 87, 698, 87, 702, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 704, 708, 87, + 706, 87, 87, 700, 715, 703, 717, 710, 87, 87, + 87, 705, 87, 707, 709, 716, 714, 711, 720, 712, + 713, 87, 721, 87, 718, 87, 722, 719, 87, 87, + 87, 87, 726, 724, 87, 730, 725, 723, 87, 87, + 87, 87, 732, 729, 727, 733, 728, 87, 87, 87, + 87, 87, 736, 739, 735, 87, 87, 87, 731, 87, + 87, 741, 743, 87, 87, 87, 87, 87, 168, 734, + 737, 738, 740, 87, 742, 87, 744, 746, 87, 758, + + 87, 779, 745, 87, 747, 755, 759, 756, 757, 748, + 87, 749, 87, 87, 761, 760, 762, 750, 87, 751, + 87, 87, 752, 753, 87, 767, 763, 87, 765, 754, + 764, 766, 772, 771, 769, 87, 87, 770, 87, 776, + 87, 87, 774, 773, 87, 768, 87, 781, 87, 87, + 87, 775, 87, 784, 87, 786, 87, 87, 87, 87, + 783, 778, 87, 777, 782, 785, 87, 789, 790, 780, + 87, 791, 87, 87, 87, 787, 87, 792, 794, 788, + 797, 793, 175, 796, 799, 795, 798, 87, 87, 87, + 87, 87, 804, 87, 87, 87, 87, 87, 87, 800, + + 807, 813, 87, 801, 809, 803, 87, 87, 802, 805, + 808, 806, 812, 87, 811, 87, 815, 816, 87, 810, + 87, 87, 87, 87, 818, 87, 87, 814, 87, 87, + 817, 821, 822, 87, 819, 87, 823, 87, 166, 87, + 820, 832, 87, 829, 825, 833, 87, 824, 830, 87, + 835, 826, 831, 828, 827, 834, 87, 87, 836, 87, + 837, 87, 838, 87, 839, 87, 87, 87, 87, 840, + 87, 87, 845, 87, 844, 87, 87, 87, 843, 848, + 87, 841, 849, 847, 87, 87, 842, 853, 852, 87, + 87, 87, 846, 87, 855, 87, 857, 87, 87, 859, + + 87, 87, 87, 850, 851, 87, 866, 862, 87, 854, + 87, 858, 87, 856, 87, 860, 87, 87, 87, 867, + 87, 874, 861, 87, 863, 87, 864, 959, 865, 87, + 868, 87, 869, 87, 87, 873, 875, 870, 877, 876, + 871, 872, 87, 87, 882, 879, 881, 878, 87, 880, + 87, 87, 87, 87, 884, 87, 885, 883, 87, 87, + 888, 889, 87, 87, 890, 87, 87, 87, 87, 87, + 898, 87, 887, 893, 896, 87, 87, 87, 886, 891, + 892, 895, 87, 894, 899, 87, 87, 897, 87, 905, + 902, 87, 901, 87, 87, 900, 87, 87, 909, 87, + + 904, 916, 907, 903, 87, 910, 908, 906, 87, 912, + 913, 911, 87, 914, 87, 87, 87, 915, 87, 87, + 87, 922, 87, 87, 920, 924, 87, 87, 923, 925, + 918, 87, 919, 917, 87, 87, 929, 87, 87, 921, + 927, 930, 87, 87, 87, 87, 87, 926, 941, 87, + 928, 931, 932, 933, 87, 943, 934, 87, 87, 87, + 935, 87, 936, 944, 942, 87, 946, 87, 947, 937, + 87, 87, 951, 949, 948, 938, 939, 940, 87, 945, + 87, 955, 87, 952, 87, 953, 956, 87, 950, 87, + 957, 87, 87, 961, 87, 954, 87, 87, 87, 87, + + 968, 87, 87, 960, 87, 969, 87, 958, 87, 87, + 87, 970, 963, 962, 964, 965, 87, 966, 87, 967, + 978, 975, 973, 971, 972, 87, 87, 87, 87, 974, + 976, 977, 87, 87, 87, 87, 87, 87, 87, 985, + 981, 980, 87, 87, 87, 979, 87, 87, 996, 87, + 183, 982, 987, 984, 983, 986, 988, 989, 87, 87, + 87, 990, 991, 992, 994, 993, 87, 87, 999, 87, + 997, 87, 995, 87, 998, 87, 1002, 87, 1000, 87, + 87, 87, 87, 1001, 87, 1007, 1006, 87, 87, 1003, + 1005, 1009, 1011, 1012, 1004, 87, 87, 87, 87, 87, + + 1008, 87, 87, 1014, 87, 175, 1010, 1016, 1018, 1015, + 1022, 1019, 1021, 1013, 87, 1017, 1020, 1023, 87, 87, + 87, 87, 87, 1024, 87, 87, 87, 1028, 1031, 87, + 1026, 87, 1032, 87, 1025, 87, 1034, 1027, 1036, 1029, + 1033, 1035, 87, 87, 1037, 1039, 87, 1030, 87, 87, + 87, 87, 87, 1042, 87, 1046, 87, 1047, 87, 87, + 87, 87, 1038, 87, 1043, 1040, 1048, 1050, 1041, 87, + 87, 1049, 1045, 87, 87, 1044, 1062, 1051, 87, 87, + 87, 87, 87, 87, 87, 181, 1065, 1064, 1061, 1067, + 1053, 1063, 87, 1068, 1052, 87, 1070, 1054, 1069, 87, + + 1055, 87, 1071, 1066, 1056, 87, 1072, 1057, 87, 87, + 1073, 87, 1077, 180, 1058, 1059, 87, 1060, 87, 87, + 87, 1087, 87, 1075, 87, 87, 1074, 87, 1090, 87, + 87, 1076, 87, 1078, 1079, 1094, 1080, 1089, 87, 1081, + 1086, 87, 1092, 1088, 1082, 87, 1095, 87, 1099, 1091, + 1083, 1084, 1096, 1085, 1098, 1100, 1097, 87, 1093, 87, + 1101, 87, 87, 1103, 1102, 87, 87, 1106, 87, 87, + 1105, 87, 1108, 1107, 1104, 87, 1109, 1110, 87, 87, + 87, 1111, 87, 87, 87, 87, 1114, 1112, 87, 87, + 1119, 87, 87, 1118, 87, 87, 1123, 87, 87, 1113, + + 87, 1115, 175, 1127, 1116, 87, 1120, 1117, 1122, 87, + 1125, 87, 1121, 87, 87, 1124, 1128, 87, 1129, 1130, + 87, 1131, 1126, 87, 1134, 1138, 1132, 87, 1133, 87, + 87, 1135, 1136, 87, 1140, 1142, 1137, 87, 87, 87, + 87, 87, 1141, 87, 1144, 87, 1143, 1139, 1146, 87, + 1147, 87, 87, 1145, 87, 87, 87, 1148, 87, 1152, + 1149, 1151, 87, 87, 87, 1153, 1157, 87, 87, 1161, + 87, 87, 1150, 1160, 87, 87, 87, 1158, 1159, 1155, + 1154, 87, 87, 1156, 87, 87, 87, 87, 87, 1162, + 1164, 87, 87, 87, 1167, 1163, 1171, 1172, 87, 87, + + 1165, 1168, 1173, 1170, 87, 87, 87, 1174, 87, 87, + 1166, 1169, 1176, 1175, 1178, 1180, 87, 1183, 87, 1179, + 1181, 87, 87, 1182, 1177, 87, 87, 87, 87, 87, + 87, 1189, 1191, 1184, 1186, 1192, 87, 87, 87, 1190, + 87, 1185, 87, 1194, 87, 1188, 87, 1196, 87, 1197, + 1187, 87, 87, 87, 87, 87, 1206, 1201, 1193, 1203, + 87, 1195, 87, 87, 1198, 87, 87, 87, 1199, 1209, + 87, 1200, 1204, 87, 1207, 1202, 1212, 87, 1208, 1205, + 87, 1211, 1210, 87, 87, 1213, 87, 1214, 1215, 1216, + 87, 87, 87, 87, 87, 1219, 87, 87, 87, 1217, + + 1221, 87, 87, 1228, 1218, 87, 1229, 87, 1755, 87, + 87, 1220, 87, 1222, 1223, 87, 1225, 1231, 1224, 1230, + 1234, 1226, 1227, 87, 1232, 1235, 87, 1233, 87, 87, + 87, 87, 1236, 87, 1237, 1240, 87, 1242, 87, 1244, + 87, 1238, 1245, 1246, 87, 87, 1243, 87, 87, 1239, + 1249, 87, 87, 87, 1241, 87, 87, 1252, 87, 87, + 1248, 1250, 1247, 87, 1255, 87, 1254, 87, 1256, 1259, + 87, 1251, 87, 1253, 1260, 175, 1262, 87, 1261, 87, + 1263, 1257, 87, 1258, 87, 87, 87, 1267, 87, 1264, + 1265, 1271, 1266, 87, 87, 87, 87, 87, 1283, 87, + + 1270, 1282, 1272, 1268, 87, 87, 1273, 87, 1284, 1269, + 87, 1286, 87, 87, 1274, 87, 1275, 87, 1294, 87, + 1276, 1293, 1277, 1292, 1287, 1285, 1278, 87, 1279, 87, + 87, 1288, 1289, 1280, 1291, 1290, 1296, 87, 1281, 1298, + 87, 1297, 87, 1295, 1300, 87, 87, 87, 1303, 87, + 87, 1299, 1304, 87, 1307, 87, 1301, 87, 1306, 87, + 1302, 173, 1305, 1314, 1308, 1309, 87, 87, 1312, 1311, + 87, 1316, 1313, 1317, 1310, 1315, 1320, 87, 1319, 87, + 1318, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 1335, 1332, 87, 87, 87, 87, 1331, 1336, + + 87, 87, 1334, 1333, 1322, 1323, 1321, 87, 1324, 1337, + 1338, 1339, 87, 1325, 1340, 1326, 1341, 1344, 87, 87, + 87, 1327, 87, 87, 1345, 87, 1328, 1329, 87, 87, + 87, 1342, 1346, 1330, 1343, 1351, 87, 1354, 87, 87, + 1347, 1348, 1352, 87, 87, 87, 1349, 1350, 1355, 1357, + 1353, 87, 87, 1359, 87, 87, 87, 1360, 1356, 87, + 87, 1365, 87, 87, 1358, 1362, 87, 87, 87, 1363, + 87, 1364, 1367, 1361, 87, 1369, 87, 87, 1372, 87, + 87, 87, 87, 1366, 87, 1368, 1380, 1377, 1370, 1375, + 1371, 1374, 87, 1376, 1373, 87, 1379, 87, 87, 1378, + + 87, 87, 1384, 87, 87, 1387, 87, 87, 87, 1386, + 87, 87, 1382, 1381, 87, 87, 87, 1418, 87, 87, + 1383, 1393, 1390, 1394, 1395, 1388, 1389, 87, 1385, 87, + 1392, 87, 1391, 1399, 1396, 1400, 1397, 87, 1398, 87, + 1401, 87, 87, 87, 87, 1405, 87, 171, 87, 1407, + 1406, 87, 1408, 87, 87, 87, 1403, 1402, 1410, 87, + 1404, 1409, 87, 87, 1413, 87, 87, 1411, 87, 87, + 87, 87, 1423, 87, 1412, 87, 1415, 1416, 87, 1421, + 1425, 1417, 1414, 87, 1419, 1422, 87, 1420, 1426, 87, + 87, 1424, 87, 1429, 1427, 87, 1431, 1428, 1430, 87, + + 87, 87, 87, 87, 1432, 1433, 1434, 1436, 1437, 87, + 1435, 87, 87, 87, 87, 87, 1443, 1439, 87, 1441, + 87, 1438, 87, 1444, 87, 87, 87, 1445, 1440, 1447, + 87, 1448, 87, 1446, 87, 1442, 87, 1452, 1449, 1454, + 1455, 1456, 87, 87, 1450, 87, 87, 87, 1457, 1453, + 87, 1459, 1451, 87, 1461, 1458, 87, 87, 1460, 87, + 87, 1462, 1464, 1465, 87, 87, 1467, 87, 87, 87, + 1466, 87, 87, 1471, 87, 87, 87, 1463, 87, 1468, + 1469, 1470, 87, 87, 87, 1474, 1475, 1476, 87, 1477, + 87, 1481, 1472, 1482, 1473, 87, 1478, 87, 87, 87, + + 1479, 1485, 87, 1484, 87, 87, 1488, 87, 87, 1480, + 1483, 1491, 87, 87, 87, 87, 87, 87, 87, 1487, + 1489, 87, 1495, 1486, 87, 1490, 1493, 87, 1499, 87, + 87, 1492, 1500, 1494, 87, 1501, 1498, 175, 87, 1502, + 1497, 1496, 87, 87, 87, 87, 87, 1510, 87, 1507, + 87, 87, 1504, 1512, 1506, 1508, 1513, 1503, 1505, 87, + 1509, 87, 87, 87, 87, 87, 1515, 87, 87, 1514, + 1511, 87, 1517, 1518, 87, 87, 87, 87, 1520, 1516, + 1519, 1522, 1521, 87, 1524, 87, 1525, 87, 87, 1523, + 1529, 87, 1526, 87, 87, 87, 1528, 1532, 1531, 1534, + + 87, 87, 1527, 87, 87, 87, 87, 1530, 1542, 1536, + 170, 1538, 87, 1533, 87, 1535, 87, 1543, 87, 1544, + 1539, 1537, 1540, 1545, 87, 1541, 87, 87, 87, 87, + 1551, 1547, 1549, 1546, 87, 87, 87, 87, 1556, 87, + 1553, 1548, 87, 1552, 87, 87, 87, 1550, 87, 1555, + 1557, 1561, 87, 1558, 87, 1554, 87, 1559, 87, 1562, + 87, 1560, 87, 1563, 87, 1565, 1566, 87, 1564, 87, + 87, 1568, 87, 1567, 87, 1571, 87, 87, 87, 87, + 87, 1574, 1569, 87, 1572, 1573, 1579, 1583, 1570, 1575, + 87, 87, 87, 87, 87, 1576, 87, 1578, 1580, 1577, + + 87, 1581, 87, 87, 87, 1586, 87, 1587, 87, 87, + 1593, 1584, 1582, 87, 1585, 1589, 87, 87, 1595, 1588, + 87, 1590, 87, 1592, 87, 1600, 1594, 87, 1596, 1591, + 1598, 1597, 1601, 87, 87, 87, 1603, 87, 87, 1608, + 1599, 1604, 87, 87, 87, 1602, 1616, 87, 87, 1606, + 1607, 1622, 1619, 1605, 87, 1609, 1617, 1618, 87, 1610, + 87, 1620, 1611, 1612, 87, 87, 1624, 1613, 87, 1621, + 87, 87, 87, 1614, 1623, 1625, 1626, 1615, 87, 1627, + 87, 87, 1630, 87, 1629, 87, 1632, 87, 1633, 1628, + 1631, 87, 1637, 87, 1638, 87, 1639, 87, 87, 1636, + + 87, 1640, 87, 87, 87, 1634, 1641, 87, 1643, 1635, + 1646, 87, 168, 1648, 87, 87, 87, 1647, 1644, 87, + 1649, 87, 1642, 87, 87, 1645, 87, 1650, 1658, 87, + 1659, 1657, 87, 1652, 1651, 87, 1660, 1661, 1653, 87, + 1654, 87, 1655, 1662, 1656, 1663, 87, 87, 87, 87, + 1664, 1668, 87, 1669, 87, 1670, 87, 1667, 87, 87, + 1671, 87, 1672, 87, 87, 1666, 1665, 1674, 1675, 87, + 1673, 87, 87, 87, 1678, 1676, 87, 87, 1684, 87, + 1685, 1680, 87, 87, 87, 1679, 1677, 87, 87, 87, + 87, 1683, 1681, 87, 1686, 1682, 1687, 1688, 1689, 1691, + + 87, 1690, 87, 87, 1696, 87, 87, 1692, 1695, 1698, + 87, 87, 87, 87, 1694, 1700, 1699, 1702, 87, 87, + 1693, 1697, 1701, 87, 1705, 87, 87, 1707, 87, 87, + 1708, 87, 1704, 87, 87, 87, 1709, 1703, 1713, 87, + 87, 87, 87, 87, 1718, 1716, 1706, 87, 87, 87, + 87, 1721, 1719, 87, 1710, 1711, 1712, 1720, 1715, 87, + 1714, 87, 1723, 1717, 1724, 87, 87, 87, 87, 87, + 87, 1722, 1727, 87, 1729, 87, 87, 1799, 1730, 1726, + 1725, 1731, 1728, 87, 87, 87, 1732, 87, 1734, 1733, + 1735, 1736, 87, 87, 87, 1740, 1741, 87, 1737, 87, + + 1738, 87, 87, 87, 1742, 87, 87, 1739, 1745, 87, + 1743, 1744, 87, 87, 87, 87, 1747, 1754, 1746, 87, + 1749, 1750, 87, 1748, 87, 175, 87, 87, 1759, 1753, + 1760, 87, 87, 1751, 87, 1752, 87, 1761, 1763, 87, + 1756, 87, 87, 1762, 87, 1769, 1757, 1768, 87, 87, + 1758, 87, 87, 1764, 87, 1766, 87, 1774, 87, 1765, + 87, 1767, 87, 1772, 1771, 87, 87, 87, 1770, 87, + 1778, 87, 1773, 1780, 87, 87, 1782, 1786, 1775, 87, + 1777, 87, 1787, 87, 1779, 1776, 87, 87, 1783, 1784, + 1781, 87, 1785, 87, 87, 87, 1790, 87, 87, 1788, + + 87, 1791, 87, 1796, 1789, 1792, 1797, 87, 1804, 1793, + 1794, 1798, 1801, 1795, 1800, 87, 1805, 87, 87, 1803, + 87, 1806, 87, 1802, 87, 87, 87, 87, 87, 87, + 1810, 1811, 1812, 87, 87, 87, 1807, 87, 1815, 87, + 87, 1820, 1809, 87, 87, 1824, 1808, 1813, 1814, 1817, + 87, 87, 87, 87, 1816, 1818, 1821, 1819, 87, 87, + 87, 1822, 1825, 1823, 87, 87, 87, 87, 87, 1826, + 87, 1832, 166, 1828, 1833, 1829, 87, 1827, 87, 1830, + 87, 1834, 87, 1840, 1831, 1837, 1835, 87, 87, 87, + 87, 1838, 1836, 87, 1844, 1845, 1839, 87, 1842, 1846, + + 87, 87, 87, 1841, 87, 87, 87, 1848, 1849, 87, + 1843, 1847, 87, 87, 87, 1854, 1851, 1862, 1850, 1853, + 1855, 87, 1856, 1852, 87, 1857, 87, 87, 87, 87, + 1858, 1861, 87, 87, 87, 87, 1863, 87, 87, 87, + 87, 1869, 1872, 87, 1868, 1865, 87, 87, 87, 1859, + 1867, 1860, 1864, 1866, 1871, 87, 1876, 1874, 1870, 1878, + 1873, 1877, 87, 87, 1879, 87, 1875, 1880, 87, 87, + 1882, 87, 87, 87, 87, 1887, 87, 87, 87, 1886, + 1892, 87, 1885, 87, 87, 87, 87, 1894, 1881, 1893, + 1883, 1884, 87, 87, 87, 1888, 1889, 87, 1890, 87, + + 1900, 1891, 1898, 1895, 87, 87, 87, 1903, 87, 1897, + 87, 1902, 1896, 87, 87, 87, 87, 87, 87, 1905, + 87, 87, 87, 1901, 1914, 1899, 87, 1904, 87, 1913, + 87, 87, 1910, 1906, 1907, 1908, 1909, 1912, 1918, 87, + 87, 1911, 87, 1917, 1921, 1915, 1919, 87, 87, 1916, + 87, 87, 87, 1920, 87, 1922, 87, 1930, 1926, 87, + 1924, 87, 1927, 87, 1929, 1923, 87, 1925, 87, 1932, + 1933, 87, 87, 1934, 87, 1928, 87, 1931, 1938, 87, + 87, 1939, 1940, 87, 87, 1943, 1935, 87, 87, 1944, + 1937, 87, 1936, 87, 87, 1941, 1942, 1945, 1946, 87, + + 87, 87, 1951, 1952, 87, 87, 1954, 1947, 87, 1949, + 87, 87, 87, 87, 1957, 87, 1956, 1948, 1958, 1960, + 87, 1950, 87, 1953, 87, 1961, 1962, 87, 87, 87, + 87, 1955, 87, 87, 87, 1959, 1966, 87, 87, 87, + 1971, 87, 87, 87, 1963, 1964, 1965, 1969, 87, 87, + 87, 87, 1978, 1967, 1968, 1976, 1972, 1970, 87, 87, + 1979, 87, 1974, 1973, 1975, 1977, 1981, 87, 87, 87, + 1980, 87, 1985, 87, 87, 87, 87, 1990, 87, 87, + 1988, 87, 1982, 1991, 87, 1993, 87, 1986, 87, 1984, + 87, 1989, 1987, 1983, 87, 87, 87, 87, 87, 1998, + + 87, 1992, 2000, 2002, 87, 1997, 1994, 2003, 87, 1996, + 1995, 2005, 2004, 87, 87, 1999, 87, 175, 2001, 87, + 87, 2007, 87, 87, 87, 2014, 87, 2006, 87, 2016, + 87, 2017, 2015, 2008, 2010, 87, 87, 2009, 2013, 87, + 2019, 2011, 2012, 87, 2023, 87, 2021, 87, 87, 87, + 2018, 87, 2025, 2027, 87, 2029, 2020, 2024, 2022, 2028, + 87, 87, 2031, 87, 87, 87, 2034, 87, 87, 2026, + 2032, 87, 87, 87, 87, 87, 87, 2033, 2037, 2039, + 2030, 2038, 87, 2035, 87, 2042, 87, 2040, 87, 2043, + 2036, 87, 87, 87, 2045, 2047, 2041, 87, 2048, 87, + + 2044, 87, 87, 87, 2056, 2052, 2046, 87, 2053, 87, + 87, 2049, 2057, 2050, 87, 2055, 87, 2058, 2060, 2051, + 2054, 2061, 87, 87, 2064, 87, 2063, 87, 2066, 2067, + 87, 87, 87, 2059, 87, 87, 2068, 87, 2069, 87, + 2070, 87, 2071, 2073, 87, 87, 2072, 2062, 87, 87, + 2074, 2065, 2077, 2078, 2079, 2080, 87, 87, 2082, 87, + 87, 87, 2081, 2075, 87, 2076, 87, 2085, 87, 87, + 87, 2084, 87, 87, 2086, 87, 87, 87, 87, 2083, + 87, 87, 87, 87, 87, 87, 87, 2098, 2087, 87, + 2089, 2090, 2088, 2101, 2093, 2091, 2094, 2092, 2095, 2096, + + 87, 2102, 2099, 2097, 2100, 87, 87, 2105, 87, 87, + 87, 87, 87, 87, 2110, 87, 2112, 2103, 87, 2104, + 2114, 87, 87, 87, 87, 2107, 2109, 2113, 2106, 2116, + 2108, 87, 2111, 87, 2118, 2117, 87, 87, 87, 87, + 87, 87, 2115, 87, 2124, 87, 2119, 2129, 2123, 87, + 2120, 87, 87, 87, 87, 2125, 2122, 2126, 2128, 2127, + 2130, 2121, 2218, 2131, 87, 2132, 87, 2133, 87, 2137, + 2136, 2135, 2134, 2138, 87, 2139, 87, 87, 87, 87, + 2140, 2143, 2141, 2145, 87, 87, 2142, 87, 87, 87, + 87, 87, 2151, 2148, 2144, 87, 2150, 87, 2146, 87, + + 87, 87, 87, 87, 2154, 87, 2147, 2149, 87, 87, + 4206, 2157, 2164, 87, 87, 2153, 2152, 2156, 2159, 2155, + 2163, 2160, 2158, 2162, 87, 87, 87, 87, 2166, 2161, + 87, 2165, 87, 87, 2171, 87, 87, 87, 2167, 2172, + 87, 2173, 87, 2177, 2169, 2168, 87, 2174, 2170, 2178, + 87, 87, 87, 2181, 4206, 2176, 87, 2182, 2175, 87, + 2180, 87, 2183, 87, 87, 2185, 2179, 2188, 2186, 87, + 87, 2190, 87, 2187, 2189, 2191, 2184, 87, 87, 2195, + 87, 2192, 87, 87, 2196, 87, 87, 87, 87, 2202, + 87, 2200, 2204, 87, 2197, 87, 2194, 2198, 2193, 87, + + 87, 2201, 2205, 2208, 2206, 2199, 2203, 87, 87, 87, + 2210, 87, 87, 2209, 2207, 2213, 87, 2217, 87, 87, + 87, 87, 2215, 87, 87, 87, 2212, 87, 2216, 2214, + 87, 2211, 2223, 2222, 87, 87, 87, 2219, 87, 2220, + 87, 87, 2232, 2221, 2224, 2226, 2233, 2225, 2230, 87, + 2234, 2227, 87, 87, 2228, 2229, 87, 87, 2237, 87, + 2235, 87, 87, 87, 2241, 87, 2236, 2243, 87, 87, + 2231, 87, 4206, 87, 87, 2247, 87, 87, 87, 87, + 2239, 2238, 2240, 2249, 2242, 2245, 87, 87, 87, 87, + 2244, 2251, 2246, 2253, 2254, 87, 87, 2248, 2250, 87, + + 87, 87, 87, 2258, 2255, 175, 87, 2252, 2257, 2262, + 87, 2261, 2260, 87, 2259, 2265, 87, 2263, 87, 2256, + 87, 2269, 87, 87, 87, 2264, 87, 87, 2270, 87, + 2267, 87, 2266, 2272, 2274, 87, 87, 87, 2271, 2268, + 87, 2273, 2280, 2275, 87, 87, 2276, 87, 87, 87, + 2285, 2283, 2284, 87, 87, 87, 2277, 2279, 87, 2278, + 2288, 2281, 2282, 2287, 87, 2289, 87, 87, 2294, 87, + 2293, 87, 87, 2290, 2286, 2291, 87, 87, 87, 2296, + 87, 2297, 87, 2292, 2295, 87, 87, 87, 87, 87, + 87, 2302, 87, 2303, 87, 87, 87, 87, 2304, 2307, + + 2298, 2308, 2305, 2300, 2299, 2301, 2309, 2306, 87, 87, + 87, 2316, 87, 2312, 2314, 2311, 2317, 87, 87, 2310, + 2313, 87, 87, 87, 87, 2315, 87, 87, 2324, 87, + 2327, 87, 2328, 87, 2319, 2329, 87, 87, 2318, 87, + 2320, 87, 2321, 2322, 2323, 2325, 87, 2326, 2331, 87, + 87, 2332, 2336, 87, 87, 2338, 87, 2330, 2337, 2339, + 2333, 87, 2334, 2340, 87, 2342, 87, 2335, 87, 87, + 87, 87, 87, 87, 87, 2345, 2347, 2344, 2348, 87, + 87, 87, 2341, 2351, 87, 2350, 87, 87, 87, 2343, + 87, 2356, 2354, 2355, 2349, 87, 2352, 2346, 2358, 87, + + 2357, 87, 87, 87, 87, 87, 87, 2353, 2366, 87, + 87, 2359, 2360, 2361, 87, 2370, 2369, 87, 2362, 87, + 2364, 2363, 2371, 2365, 87, 2367, 2368, 2372, 87, 87, + 87, 2373, 2375, 2378, 2374, 2376, 87, 87, 87, 87, + 87, 87, 87, 87, 2377, 2379, 2386, 87, 87, 87, + 2388, 87, 2381, 87, 87, 2391, 87, 2380, 87, 2382, + 2383, 2384, 2385, 2392, 87, 2393, 87, 2395, 87, 87, + 87, 2389, 87, 2397, 2387, 2390, 2394, 2399, 87, 2398, + 87, 2400, 2402, 2396, 87, 87, 87, 2407, 87, 87, + 2408, 87, 87, 87, 87, 87, 87, 2414, 87, 87, + + 87, 2401, 2405, 2406, 2404, 2403, 2411, 2412, 87, 2410, + 2415, 87, 2418, 2409, 87, 87, 2420, 2423, 87, 2419, + 87, 2413, 87, 87, 2417, 87, 2416, 2422, 87, 87, + 2424, 2426, 2427, 87, 2428, 2421, 87, 87, 87, 87, + 87, 87, 87, 2433, 2425, 2429, 87, 87, 87, 2435, + 87, 2438, 87, 2430, 2434, 87, 2439, 2441, 87, 2431, + 2432, 87, 2443, 87, 87, 2436, 2444, 87, 87, 87, + 2442, 87, 87, 2447, 2437, 2440, 87, 2452, 87, 87, + 87, 2451, 2446, 87, 2445, 87, 87, 87, 2449, 2448, + 2457, 87, 2458, 2450, 87, 87, 2460, 87, 2455, 2454, + + 2459, 2461, 87, 2453, 2456, 87, 2462, 87, 87, 2463, + 2466, 87, 87, 87, 87, 87, 2467, 87, 2464, 2470, + 2474, 87, 2468, 2465, 87, 87, 87, 87, 87, 2477, + 87, 2469, 87, 2471, 2481, 2472, 2482, 2473, 87, 2475, + 2476, 2478, 2479, 87, 87, 2480, 87, 87, 87, 2484, + 87, 2483, 2487, 2519, 2485, 2488, 87, 2489, 87, 2490, + 87, 2492, 2493, 2497, 2491, 87, 2486, 87, 87, 87, + 87, 87, 2496, 87, 2494, 2495, 87, 2499, 87, 87, + 2502, 2500, 87, 2498, 87, 2504, 2506, 87, 87, 87, + 2501, 87, 87, 87, 2509, 2510, 87, 87, 87, 175, + + 87, 87, 2507, 2508, 2513, 2524, 2505, 2503, 87, 87, + 2514, 87, 2511, 2515, 2517, 2518, 87, 2512, 87, 2516, + 87, 2520, 2521, 87, 87, 2522, 2523, 87, 2526, 2527, + 87, 87, 87, 2525, 87, 87, 2528, 2529, 87, 87, + 2530, 87, 87, 2533, 2532, 2535, 87, 2531, 2534, 87, + 2536, 87, 2537, 2538, 87, 2540, 87, 87, 87, 2544, + 87, 87, 87, 2543, 2549, 87, 2539, 2546, 2541, 2542, + 2545, 87, 87, 87, 87, 2548, 2547, 87, 87, 2554, + 87, 87, 2557, 2551, 2555, 87, 2556, 87, 87, 87, + 87, 87, 87, 2550, 87, 2552, 87, 2553, 2559, 87, + + 2562, 87, 87, 2565, 87, 2558, 2561, 87, 2560, 2564, + 2566, 2563, 87, 2568, 87, 87, 2567, 87, 2576, 2570, + 2572, 2574, 87, 2569, 87, 2571, 87, 2575, 87, 87, + 2573, 87, 2581, 87, 87, 2583, 4206, 87, 87, 2584, + 87, 87, 2577, 2580, 2578, 87, 2579, 2586, 2588, 87, + 2582, 87, 2590, 87, 2585, 87, 2591, 87, 87, 2589, + 2594, 87, 87, 2587, 2593, 87, 87, 87, 87, 2596, + 87, 2599, 87, 2600, 87, 2595, 87, 87, 87, 2603, + 2592, 2601, 87, 87, 87, 87, 87, 2597, 2598, 2604, + 2606, 2605, 2608, 87, 87, 2602, 2610, 2620, 87, 2609, + + 87, 2611, 87, 87, 87, 2617, 2613, 2614, 2607, 2612, + 2615, 87, 2619, 87, 2622, 87, 2618, 87, 2623, 87, + 2625, 2621, 2624, 2616, 2626, 87, 2627, 87, 87, 87, + 87, 2631, 2628, 2630, 87, 87, 87, 87, 87, 2633, + 2637, 87, 2634, 87, 87, 2635, 2640, 2629, 2632, 87, + 2639, 87, 2638, 87, 2644, 2636, 87, 87, 87, 2648, + 87, 87, 2650, 87, 87, 87, 2642, 87, 2641, 2653, + 2652, 87, 87, 2643, 87, 2649, 2645, 2646, 2647, 2654, + 87, 87, 2659, 87, 87, 2655, 87, 4206, 87, 2656, + 2651, 2660, 2658, 87, 87, 2663, 2661, 87, 87, 2657, + + 2664, 87, 2665, 2666, 87, 2662, 2669, 87, 87, 2670, + 2668, 2667, 87, 87, 2674, 2671, 87, 87, 2677, 2676, + 87, 2675, 2678, 87, 87, 2680, 2681, 2672, 87, 87, + 87, 87, 87, 2673, 2684, 87, 87, 2682, 87, 2686, + 87, 2679, 2685, 87, 2687, 2683, 87, 87, 87, 2688, + 87, 2689, 2691, 87, 2690, 2694, 2692, 2696, 87, 2693, + 87, 87, 2697, 87, 87, 87, 87, 87, 87, 2699, + 2698, 2695, 2703, 2700, 87, 87, 87, 2701, 2702, 2704, + 87, 2705, 87, 2706, 87, 2708, 2709, 87, 87, 87, + 2714, 87, 87, 87, 87, 2707, 87, 2717, 2710, 87, + + 2711, 87, 2712, 2715, 2713, 2718, 2716, 87, 2719, 2721, + 87, 87, 2722, 87, 2720, 87, 2723, 2725, 87, 87, + 87, 2726, 2724, 87, 2728, 87, 2732, 87, 2734, 87, + 87, 2737, 87, 87, 2727, 2730, 2733, 87, 2736, 2735, + 87, 2731, 2729, 87, 2740, 87, 87, 87, 2741, 87, + 175, 2738, 87, 2747, 87, 87, 2739, 2751, 2742, 87, + 2743, 2749, 2744, 87, 2752, 87, 2750, 87, 2753, 2745, + 87, 2746, 2748, 87, 2755, 2756, 87, 87, 2759, 87, + 87, 2754, 87, 2760, 2764, 87, 87, 2765, 87, 2763, + 87, 87, 2769, 87, 87, 2758, 2768, 2761, 87, 2757, + + 2766, 87, 87, 87, 2774, 2775, 87, 2772, 2762, 2767, + 87, 2777, 2773, 2771, 87, 2776, 2770, 87, 2778, 87, + 87, 87, 87, 87, 2780, 87, 87, 87, 2783, 87, + 87, 87, 87, 87, 2787, 87, 2793, 87, 2791, 2779, + 87, 2781, 2785, 87, 2786, 87, 2789, 2782, 2784, 2788, + 87, 87, 2790, 87, 2794, 2795, 2796, 2792, 87, 87, + 87, 2797, 87, 87, 87, 2800, 87, 2802, 2805, 87, + 87, 2798, 2806, 2803, 87, 87, 2799, 87, 2801, 87, + 87, 2804, 87, 87, 2816, 2807, 87, 87, 4206, 2808, + 87, 2818, 87, 2809, 2814, 2817, 87, 87, 2810, 2812, + + 2813, 2811, 2819, 87, 2815, 2820, 87, 87, 2823, 2822, + 2821, 2825, 87, 87, 87, 87, 87, 2827, 2826, 87, + 87, 87, 87, 2832, 2833, 87, 87, 2824, 2828, 87, + 87, 2834, 2853, 2830, 2831, 2835, 87, 87, 87, 2839, + 2829, 2836, 2840, 2841, 87, 2837, 87, 2842, 87, 87, + 2838, 87, 2844, 2847, 87, 2848, 87, 87, 2845, 87, + 87, 2846, 2849, 2843, 2850, 87, 87, 87, 87, 2857, + 87, 2858, 87, 87, 2860, 87, 2856, 87, 87, 2854, + 2851, 2855, 2862, 87, 87, 2852, 2865, 87, 87, 2864, + 2866, 87, 2859, 2863, 87, 2861, 87, 87, 2870, 87, + + 87, 87, 2867, 2868, 2872, 87, 87, 87, 2873, 87, + 2874, 2878, 87, 87, 2877, 87, 2869, 2871, 2880, 87, + 2875, 87, 87, 87, 2884, 87, 2876, 2882, 87, 2883, + 87, 2885, 2879, 2881, 2887, 87, 87, 87, 2890, 87, + 2893, 87, 2894, 2889, 2888, 87, 2886, 87, 87, 87, + 87, 87, 2891, 87, 2899, 2900, 87, 87, 2892, 87, + 87, 87, 2896, 87, 2905, 2895, 2898, 87, 2904, 87, + 2911, 87, 2897, 2902, 2906, 87, 2901, 2913, 87, 2903, + 87, 2914, 2910, 2907, 2912, 87, 87, 2915, 87, 2916, + 2908, 2909, 87, 87, 2921, 87, 87, 2923, 87, 87, + + 2927, 2924, 87, 2917, 2918, 2922, 87, 2919, 87, 87, + 87, 2928, 87, 2929, 2920, 2930, 2925, 2931, 2926, 87, + 87, 87, 2933, 87, 87, 87, 2936, 2932, 87, 2935, + 2938, 87, 2942, 2939, 87, 2943, 2940, 87, 87, 2941, + 2934, 87, 2946, 87, 87, 87, 87, 87, 87, 2937, + 2947, 2948, 2945, 87, 87, 2944, 2951, 2950, 87, 2958, + 87, 87, 87, 2953, 87, 87, 87, 2952, 2949, 2954, + 2955, 2956, 2957, 2959, 87, 87, 87, 2966, 2960, 87, + 87, 2965, 2962, 87, 2961, 2964, 2969, 87, 2967, 87, + 87, 87, 87, 2971, 87, 2963, 2968, 87, 2973, 2972, + + 2970, 175, 87, 87, 2979, 87, 2974, 87, 87, 87, + 87, 87, 87, 87, 2975, 2984, 2976, 2981, 2977, 2978, + 2982, 2983, 2980, 87, 2985, 2986, 87, 87, 87, 2989, + 87, 87, 87, 2990, 2994, 87, 2995, 87, 2987, 2988, + 2992, 2996, 87, 87, 2993, 87, 2998, 2999, 87, 87, + 2991, 87, 3000, 3002, 3003, 87, 3001, 3005, 87, 87, + 87, 87, 87, 2997, 3004, 87, 3007, 87, 3009, 87, + 87, 87, 3012, 3013, 3008, 3006, 87, 87, 87, 87, + 87, 3017, 3015, 3010, 3016, 3018, 87, 87, 87, 3011, + 3014, 87, 3019, 3020, 87, 87, 87, 87, 3025, 87, + + 3021, 3024, 87, 3022, 87, 87, 87, 3027, 87, 3026, + 87, 87, 87, 3035, 3032, 3023, 87, 3034, 87, 87, + 87, 87, 3031, 3038, 3028, 3029, 3030, 3036, 87, 3037, + 87, 3033, 87, 3039, 3040, 87, 87, 3045, 87, 3041, + 3043, 87, 87, 87, 3049, 3050, 87, 87, 3048, 3042, + 87, 87, 87, 3046, 3051, 87, 3053, 3044, 3047, 87, + 87, 3052, 87, 3056, 87, 87, 3054, 3057, 3059, 3055, + 87, 3058, 87, 87, 3065, 3060, 3061, 87, 3063, 87, + 87, 87, 87, 3064, 3067, 87, 87, 87, 87, 87, + 87, 3068, 3069, 3066, 87, 3070, 3071, 87, 3062, 3072, + + 87, 87, 3076, 87, 3074, 87, 3073, 87, 3078, 87, + 3075, 87, 87, 87, 3085, 87, 3087, 3083, 3084, 3086, + 87, 3079, 87, 87, 3082, 87, 3080, 3077, 87, 3089, + 87, 87, 87, 87, 87, 3081, 3092, 3094, 87, 3097, + 87, 3090, 87, 3088, 87, 3095, 87, 87, 87, 3101, + 3096, 3093, 3091, 3099, 3100, 87, 3104, 87, 3098, 87, + 87, 87, 3103, 87, 3102, 87, 3107, 3108, 3105, 3106, + 87, 87, 87, 87, 87, 87, 3109, 3111, 87, 87, + 3112, 87, 3117, 3118, 87, 3110, 87, 87, 3122, 87, + 87, 3119, 3113, 3114, 3115, 3123, 3116, 3120, 3121, 87, + + 87, 3124, 87, 87, 87, 87, 87, 3129, 87, 3128, + 4206, 3131, 3132, 87, 3125, 3127, 3126, 3134, 87, 3135, + 87, 3136, 87, 3133, 87, 3130, 87, 87, 3138, 87, + 87, 3141, 87, 3142, 3140, 87, 3137, 87, 3143, 87, + 87, 87, 87, 87, 87, 3139, 87, 3144, 3150, 87, + 3152, 87, 3146, 3153, 87, 3155, 87, 3154, 87, 3145, + 3149, 3147, 3151, 3148, 87, 87, 87, 87, 87, 87, + 3156, 3157, 3160, 3163, 87, 87, 87, 3158, 3166, 87, + 87, 87, 87, 87, 3164, 87, 3159, 87, 3161, 3162, + 87, 3172, 87, 87, 87, 3169, 3165, 87, 87, 3171, + + 3176, 3168, 3173, 175, 3174, 87, 3167, 3170, 87, 3175, + 87, 3178, 3180, 87, 3179, 3177, 3183, 87, 87, 87, + 3186, 87, 87, 3181, 3185, 3188, 87, 87, 87, 3192, + 87, 3182, 3190, 3191, 3193, 87, 87, 87, 3195, 3184, + 3189, 3187, 87, 87, 3197, 87, 3198, 87, 3194, 87, + 87, 3196, 87, 87, 87, 87, 87, 87, 87, 87, + 3200, 87, 87, 3210, 4206, 3199, 3208, 3202, 87, 3201, + 87, 87, 3204, 3203, 87, 3214, 3206, 3205, 3207, 3209, + 87, 87, 3211, 87, 3215, 3217, 3212, 87, 3213, 3216, + 87, 87, 3219, 3220, 87, 87, 3221, 3222, 87, 87, + + 87, 87, 87, 3218, 87, 87, 87, 3226, 87, 3223, + 87, 87, 3232, 3224, 3233, 87, 3227, 3225, 3234, 87, + 3228, 3230, 3229, 3235, 87, 3231, 3236, 87, 87, 3240, + 87, 3241, 87, 3242, 3239, 3237, 87, 3238, 87, 87, + 87, 87, 87, 87, 3249, 87, 87, 3248, 87, 87, + 87, 87, 87, 87, 3243, 3245, 3244, 3247, 3256, 87, + 3246, 3253, 3254, 87, 87, 3257, 3250, 87, 3251, 3252, + 3258, 87, 3255, 87, 87, 3259, 3260, 87, 3261, 3262, + 87, 3264, 87, 3263, 87, 87, 3266, 87, 3270, 87, + 87, 87, 3269, 3265, 3268, 87, 3272, 3267, 87, 87, + + 3273, 87, 87, 3274, 87, 87, 87, 3279, 3280, 87, + 3271, 87, 3283, 87, 87, 87, 87, 87, 4206, 3275, + 3276, 3281, 3277, 3278, 87, 3284, 87, 87, 3286, 3282, + 3285, 3287, 3288, 3289, 87, 3291, 87, 87, 3290, 3292, + 87, 87, 3296, 87, 87, 87, 87, 87, 87, 87, + 3293, 87, 3299, 3294, 87, 87, 3295, 3297, 3298, 87, + 3301, 4206, 3304, 87, 3300, 3306, 87, 3307, 3302, 3305, + 3303, 87, 3308, 87, 3310, 3309, 3311, 87, 3312, 3313, + 87, 87, 87, 87, 87, 87, 3314, 3319, 87, 87, + 87, 3315, 87, 3321, 87, 87, 3317, 3324, 87, 3316, + + 87, 87, 87, 3322, 87, 3318, 87, 87, 3325, 4206, + 3320, 3328, 3323, 3326, 3327, 3329, 3330, 3331, 87, 87, + 3334, 87, 87, 87, 3332, 87, 87, 3335, 3336, 87, + 87, 3338, 87, 87, 3333, 87, 87, 3339, 87, 3337, + 87, 3341, 87, 3342, 87, 3345, 87, 3346, 3343, 3340, + 3348, 87, 87, 3347, 87, 3344, 3349, 87, 87, 3351, + 87, 3352, 87, 3353, 3350, 3355, 175, 3356, 87, 87, + 3360, 3354, 87, 3357, 87, 87, 87, 3361, 87, 3362, + 3358, 87, 3364, 87, 3367, 87, 87, 3359, 3366, 3363, + 3368, 87, 87, 3365, 87, 3372, 87, 3369, 87, 3370, + + 3374, 3373, 87, 87, 87, 3375, 87, 3376, 3371, 3377, + 3379, 87, 87, 87, 87, 3380, 87, 3378, 3381, 3382, + 87, 3383, 87, 87, 87, 3387, 3388, 87, 87, 3389, + 3385, 87, 87, 3391, 87, 3384, 87, 87, 87, 3390, + 3395, 3394, 3393, 3392, 3386, 87, 87, 87, 87, 87, + 3396, 3397, 3398, 3406, 87, 87, 87, 3403, 87, 87, + 87, 87, 3400, 3401, 3402, 3405, 3399, 3404, 87, 3409, + 87, 87, 87, 3407, 87, 87, 3410, 87, 3408, 3415, + 87, 87, 87, 4206, 87, 87, 87, 87, 3416, 87, + 3411, 87, 3412, 3418, 3413, 3419, 3414, 87, 3420, 87, + + 3421, 3417, 3423, 3424, 87, 87, 3430, 87, 3422, 3427, + 3425, 87, 87, 87, 3428, 3432, 3429, 3433, 87, 87, + 3426, 87, 87, 87, 3436, 87, 3437, 87, 3438, 3439, + 87, 87, 87, 87, 87, 87, 87, 3434, 3431, 3440, + 3435, 3442, 3443, 3445, 3441, 3444, 87, 87, 87, 87, + 3446, 87, 3447, 3448, 3450, 87, 87, 3452, 87, 87, + 3449, 87, 87, 3453, 3454, 87, 3451, 87, 87, 3461, + 87, 87, 87, 4206, 3458, 3456, 3460, 3463, 87, 3455, + 87, 3457, 3464, 87, 3465, 87, 87, 87, 87, 3468, + 3459, 3466, 87, 3467, 87, 3462, 3469, 87, 87, 3471, + + 87, 87, 3473, 87, 3472, 4206, 3470, 3474, 87, 87, + 3475, 87, 3479, 3480, 87, 3481, 87, 3482, 87, 87, + 3476, 3477, 3483, 3478, 87, 87, 3486, 87, 87, 3488, + 3489, 87, 87, 3490, 3491, 87, 87, 3484, 3485, 3493, + 87, 87, 87, 87, 3497, 87, 3487, 3498, 3499, 87, + 87, 3492, 87, 87, 3494, 3505, 3500, 3496, 3502, 87, + 3495, 87, 3504, 3503, 87, 87, 87, 3507, 87, 87, + 3501, 3506, 3508, 87, 87, 87, 3513, 3514, 3515, 3518, + 87, 3512, 87, 87, 87, 87, 87, 4206, 3509, 3510, + 3517, 3519, 87, 3516, 3511, 87, 87, 87, 87, 87, + + 3520, 3523, 3525, 3521, 87, 3522, 87, 3526, 87, 87, + 3524, 3531, 87, 3529, 87, 87, 3534, 87, 87, 87, + 87, 3527, 3528, 3536, 87, 3546, 87, 3530, 87, 3533, + 87, 3537, 3535, 3538, 3532, 3541, 3540, 87, 3547, 3543, + 3542, 87, 87, 3539, 3544, 87, 87, 3548, 87, 3545, + 87, 3549, 87, 3550, 87, 3551, 87, 87, 3552, 87, + 87, 3553, 87, 87, 87, 87, 3557, 87, 3554, 3556, + 3559, 87, 3561, 3562, 87, 87, 3558, 3566, 87, 3567, + 87, 87, 3560, 3555, 3568, 87, 3570, 87, 87, 87, + 87, 3563, 87, 3572, 3564, 3565, 3571, 3574, 87, 3575, + + 3569, 3576, 87, 87, 87, 3579, 87, 3573, 87, 3578, + 87, 3582, 87, 87, 87, 87, 87, 3580, 87, 3581, + 3586, 87, 3583, 3584, 3577, 3587, 87, 87, 87, 3591, + 87, 3588, 87, 3585, 3594, 3590, 87, 3589, 87, 3595, + 87, 87, 87, 87, 87, 3592, 3603, 3597, 3600, 3596, + 87, 3601, 3593, 87, 87, 87, 3598, 3599, 3602, 3604, + 87, 87, 3608, 87, 87, 87, 3607, 3610, 87, 87, + 3605, 87, 3614, 87, 87, 3606, 3615, 87, 3609, 3611, + 3617, 87, 87, 3616, 87, 87, 87, 87, 87, 3613, + 3620, 3623, 87, 3618, 3612, 87, 3621, 87, 87, 3660, + + 3624, 87, 87, 3626, 3622, 87, 3627, 3619, 87, 3628, + 3630, 3629, 87, 3625, 87, 87, 87, 3631, 87, 87, + 3636, 3638, 87, 3637, 3639, 87, 3633, 87, 3632, 3634, + 3640, 87, 3635, 87, 87, 87, 3641, 87, 87, 3647, + 3646, 3648, 87, 87, 87, 87, 3651, 87, 3649, 3650, + 87, 87, 87, 3642, 3643, 87, 3644, 3645, 87, 3657, + 3655, 87, 87, 3653, 87, 87, 3659, 87, 3652, 3661, + 87, 87, 3663, 3654, 87, 3662, 3656, 87, 87, 3668, + 87, 3664, 87, 87, 87, 87, 3658, 87, 87, 3665, + 87, 3672, 3666, 87, 3673, 3669, 3670, 3671, 3667, 87, + + 87, 3676, 87, 87, 3674, 3677, 87, 3681, 87, 3675, + 87, 87, 3685, 87, 3679, 3686, 87, 3682, 87, 3678, + 87, 3688, 87, 3680, 87, 87, 3689, 87, 3683, 87, + 3691, 87, 3690, 3692, 87, 3693, 87, 3684, 87, 3687, + 3695, 3696, 87, 3694, 87, 3697, 87, 3698, 87, 3699, + 87, 3701, 3702, 87, 3700, 3705, 87, 3707, 87, 3704, + 87, 87, 87, 87, 3709, 87, 87, 87, 3703, 87, + 87, 87, 87, 87, 3710, 3715, 87, 3716, 87, 3706, + 87, 3708, 3720, 87, 3714, 3717, 3711, 3712, 3713, 3721, + 3723, 3719, 3718, 87, 87, 87, 87, 87, 3722, 3724, + + 3727, 87, 3725, 3728, 87, 87, 3731, 87, 87, 87, + 87, 87, 3729, 87, 87, 3736, 87, 3734, 87, 3726, + 3733, 87, 87, 3738, 3908, 3730, 3732, 3740, 87, 3741, + 3735, 87, 3737, 3744, 3739, 87, 3742, 3743, 87, 87, + 87, 87, 3745, 3746, 87, 3747, 87, 3748, 87, 3752, + 3753, 87, 3755, 3751, 87, 87, 87, 3754, 87, 87, + 87, 3749, 3758, 87, 3757, 3759, 3750, 87, 87, 3761, + 87, 3764, 87, 87, 3756, 87, 87, 87, 3769, 87, + 3765, 87, 87, 87, 3773, 87, 3760, 3762, 3763, 87, + 3768, 3766, 3772, 3774, 87, 3775, 87, 87, 3771, 87, + + 3770, 3767, 3776, 3777, 3778, 3779, 87, 3780, 87, 3781, + 87, 87, 87, 3784, 87, 87, 87, 3787, 87, 87, + 3782, 3789, 87, 87, 3788, 3791, 87, 87, 3785, 3792, + 87, 87, 87, 3783, 3790, 87, 87, 87, 87, 3799, + 3800, 87, 3786, 87, 87, 87, 3793, 87, 87, 87, + 3806, 87, 3794, 87, 3795, 3797, 87, 3796, 3805, 3798, + 3810, 3803, 87, 3802, 87, 3804, 3809, 87, 3807, 3801, + 87, 3813, 87, 3808, 87, 87, 3812, 87, 3815, 3817, + 87, 87, 3811, 87, 87, 87, 3820, 87, 3821, 4206, + 3814, 87, 3818, 3816, 3823, 87, 3824, 87, 87, 3819, + + 3827, 3826, 87, 3825, 87, 3822, 87, 3830, 87, 87, + 87, 3833, 3829, 87, 3828, 3831, 87, 3834, 87, 87, + 87, 3835, 87, 87, 87, 3832, 87, 3838, 87, 87, + 87, 87, 3839, 87, 3842, 3840, 87, 3843, 3836, 3837, + 87, 87, 3841, 87, 87, 3844, 87, 87, 3852, 3848, + 3845, 3846, 3853, 3855, 3847, 87, 87, 3849, 3850, 87, + 3856, 87, 3851, 87, 3854, 87, 3857, 3862, 3858, 3859, + 3860, 87, 3861, 87, 87, 87, 3863, 3865, 87, 3864, + 3866, 87, 3868, 87, 87, 3870, 87, 87, 3872, 3873, + 87, 87, 3874, 3875, 3879, 87, 3876, 87, 87, 3869, + + 3867, 3877, 3878, 3880, 87, 87, 3871, 3882, 87, 87, + 87, 3885, 87, 3887, 3881, 3886, 87, 3888, 87, 87, + 3889, 87, 87, 87, 3884, 87, 87, 3883, 87, 3890, + 3892, 87, 3893, 87, 87, 3894, 87, 3891, 3895, 3898, + 87, 3897, 3896, 3899, 87, 87, 87, 87, 3900, 87, + 3903, 4206, 3902, 87, 87, 87, 3904, 3910, 87, 87, + 3909, 87, 3912, 87, 3905, 3913, 87, 87, 3911, 3901, + 87, 3906, 3914, 87, 3907, 3915, 87, 87, 87, 87, + 87, 87, 3917, 3918, 3923, 3916, 3919, 3921, 4206, 3920, + 87, 87, 3922, 87, 3925, 3924, 3927, 87, 3930, 87, + + 3929, 3926, 3928, 3931, 87, 3933, 87, 3934, 87, 87, + 3932, 87, 87, 3937, 87, 87, 87, 3936, 3939, 87, + 3940, 87, 87, 3943, 87, 3941, 3935, 3944, 87, 3938, + 3945, 87, 3946, 87, 3947, 87, 3948, 87, 3949, 87, + 3942, 3950, 87, 3951, 87, 87, 87, 3954, 87, 87, + 87, 87, 87, 87, 3959, 3953, 3957, 3961, 87, 87, + 87, 87, 87, 87, 3966, 87, 3958, 87, 3960, 3955, + 3956, 3952, 3962, 3963, 87, 3965, 3968, 87, 87, 3964, + 87, 3967, 3969, 87, 3972, 87, 87, 3970, 3975, 87, + 3971, 3977, 87, 87, 87, 87, 87, 3974, 3978, 3973, + + 87, 3976, 3985, 3980, 87, 3982, 87, 87, 87, 3984, + 87, 87, 3979, 87, 3983, 87, 3987, 87, 87, 87, + 87, 3981, 87, 3995, 3986, 3991, 3988, 3992, 87, 87, + 3994, 3989, 3993, 3990, 87, 87, 87, 87, 3999, 3998, + 87, 87, 4002, 87, 87, 4000, 3996, 87, 87, 3997, + 4001, 4008, 87, 4009, 87, 87, 4003, 4007, 4010, 87, + 4011, 87, 4004, 4005, 4013, 4006, 87, 87, 4016, 87, + 4014, 4012, 87, 87, 4019, 87, 87, 87, 87, 4023, + 87, 4022, 87, 87, 4025, 87, 4018, 4015, 4017, 4021, + 87, 87, 87, 87, 87, 87, 87, 4024, 4020, 87, + + 87, 87, 87, 4026, 4027, 4032, 4033, 4034, 4029, 4028, + 4031, 87, 4036, 87, 4039, 87, 4037, 87, 4030, 87, + 4035, 4040, 87, 4043, 87, 87, 87, 87, 87, 87, + 4041, 87, 4038, 4048, 4046, 4042, 4051, 87, 87, 4044, + 87, 4053, 87, 4049, 4045, 4054, 87, 4047, 87, 4052, + 87, 4050, 87, 4055, 87, 4056, 4057, 87, 4058, 87, + 87, 4059, 87, 4061, 87, 87, 4066, 4062, 87, 4063, + 4060, 87, 87, 87, 4070, 87, 87, 4064, 4069, 87, + 4065, 4206, 4067, 4068, 4072, 87, 4073, 87, 4074, 87, + 4075, 87, 87, 87, 4078, 87, 4071, 4076, 4077, 4080, + + 87, 87, 4079, 4081, 87, 87, 4084, 87, 87, 87, + 87, 87, 4089, 87, 87, 4090, 4082, 87, 87, 87, + 4086, 4093, 4094, 4085, 4083, 4091, 87, 87, 87, 4088, + 87, 87, 87, 4095, 4087, 87, 4098, 4092, 87, 4096, + 4099, 87, 4100, 87, 87, 87, 87, 4101, 87, 4097, + 4102, 4107, 87, 4103, 87, 87, 87, 87, 4109, 4106, + 87, 4111, 87, 87, 4108, 4104, 4105, 87, 4116, 87, + 4118, 87, 87, 4113, 4117, 4110, 4112, 87, 87, 87, + 4114, 4115, 87, 87, 87, 87, 4126, 87, 87, 4127, + 87, 4128, 87, 4119, 4125, 4130, 4121, 87, 4120, 4122, + + 4123, 87, 4124, 87, 4129, 87, 4131, 4133, 4134, 87, + 4132, 87, 4135, 87, 87, 4137, 4138, 87, 4139, 4140, + 87, 87, 87, 87, 87, 87, 4142, 87, 4147, 4136, + 87, 4144, 87, 4206, 87, 4150, 87, 4151, 87, 4141, + 4152, 87, 4143, 87, 4145, 4149, 4146, 87, 4153, 4148, + 87, 4155, 87, 87, 87, 4154, 87, 87, 87, 4158, + 87, 4162, 4156, 87, 87, 4157, 87, 87, 4163, 4166, + 4165, 4161, 87, 4167, 87, 4159, 4160, 4164, 87, 4169, + 87, 4170, 87, 87, 4174, 87, 4168, 4171, 4175, 87, + 4172, 87, 87, 4173, 4177, 87, 4176, 4178, 87, 87, + + 87, 87, 4179, 87, 4184, 87, 4180, 87, 4182, 87, + 87, 87, 87, 87, 4186, 4187, 87, 4190, 87, 4181, + 4183, 4191, 87, 87, 4194, 87, 4185, 4195, 87, 87, + 4188, 4189, 4192, 4197, 87, 87, 4196, 4193, 4198, 87, + 87, 87, 4199, 87, 4202, 4200, 4201, 4204, 87, 4205, + 87, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + 4206, 4206, 4203, 48, 48, 48, 48, 48, 48, 48, + 53, 53, 53, 53, 53, 53, 53, 58, 58, 58, + 58, 58, 58, 58, 64, 64, 64, 64, 64, 64, + 64, 69, 69, 69, 69, 69, 69, 69, 75, 75, + + 75, 75, 75, 75, 75, 81, 81, 81, 81, 81, + 81, 81, 90, 90, 4206, 90, 90, 90, 90, 165, + 165, 4206, 4206, 4206, 165, 165, 167, 167, 4206, 4206, + 167, 4206, 167, 169, 4206, 4206, 4206, 4206, 4206, 169, + 172, 172, 4206, 4206, 4206, 172, 172, 174, 4206, 4206, + 4206, 4206, 4206, 174, 176, 176, 4206, 176, 176, 176, + 176, 179, 4206, 4206, 4206, 4206, 4206, 179, 182, 182, + 4206, 4206, 4206, 182, 182, 91, 91, 4206, 91, 91, + 91, 91, 17, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + + 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + 4206, 4206, 4206 } ; -static yyconst flex_int16_t yy_chk[8083] = +static yyconst flex_int16_t yy_chk[8224] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -2698,13 +2741,13 @@ static yyconst flex_int16_t yy_chk[8083] 5, 3, 6, 24, 4, 24, 24, 5, 24, 6, 7, 7, 7, 7, 24, 7, 8, 8, 8, 8, 33, 8, 7, 9, 9, 9, 26, 26, 8, 10, - 10, 10, 19, 29, 9, 33, 19, 29, 4137, 35, + 10, 10, 19, 29, 9, 33, 19, 29, 4214, 35, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 13, 34, 13, 11, 35, 101, 34, 29, 38, 13, 46, 46, 11, 12, 12, 12, 12, 12, 12, 14, 14, 14, 14, 101, 14, 12, 15, 15, 15, 38, - 23, 14, 23, 23, 12, 23, 3288, 15, 16, 16, + 23, 14, 23, 23, 12, 23, 3355, 15, 16, 16, 16, 23, 23, 27, 27, 30, 30, 31, 31, 16, 25, 27, 113, 25, 25, 27, 31, 25, 27, 32, 30, 47, 25, 32, 25, 132, 32, 31, 52, 52, @@ -2714,7 +2757,7 @@ static yyconst flex_int16_t yy_chk[8083] 43, 41, 41, 88, 36, 94, 41, 44, 36, 94, 37, 44, 37, 39, 39, 42, 41, 41, 39, 41, - 42, 44, 39, 42, 57, 44, 44, 57, 39, 1242, + 42, 44, 39, 42, 57, 44, 44, 57, 39, 1260, 42, 39, 45, 45, 42, 42, 93, 45, 39, 93, 63, 45, 63, 63, 74, 63, 68, 68, 71, 95, 71, 71, 73, 71, 73, 73, 95, 73, 74, 80, @@ -2784,9 +2827,9 @@ static yyconst flex_int16_t yy_chk[8083] 356, 357, 179, 356, 354, 358, 360, 345, 350, 351, 368, 360, 360, 351, 357, 374, 353, 358, 351, 368, 359, 351, 359, 359, 363, 363, 351, 351, 351, 351, - 355, 361, 421, 355, 361, 355, 362, 355, 364, 362, + 355, 361, 174, 355, 361, 355, 362, 355, 364, 362, 374, 365, 366, 367, 369, 370, 370, 355, 355, 355, - 421, 355, 375, 369, 371, 364, 365, 366, 364, 371, + 355, 355, 375, 369, 371, 364, 365, 366, 364, 371, 367, 367, 372, 372, 373, 373, 376, 375, 377, 378, 379, 376, 380, 381, 377, 386, 382, 385, 442, 387, @@ -2794,791 +2837,807 @@ static yyconst flex_int16_t yy_chk[8083] 394, 388, 380, 389, 442, 383, 388, 385, 389, 394, 390, 391, 383, 390, 389, 390, 392, 393, 395, 395, 393, 396, 392, 397, 397, 398, 401, 396, 402, 403, - 398, 402, 404, 393, 174, 415, 393, 405, 393, 399, + 398, 402, 404, 393, 172, 415, 393, 405, 393, 399, 399, 408, 399, 410, 403, 411, 401, 404, 399, 402, 407, 405, 399, 407, 411, 408, 415, 399, 410, 416, - 399, 400, 400, 172, 400, 412, 413, 418, 414, 407, + 399, 400, 400, 171, 400, 412, 413, 418, 414, 407, 412, 412, 413, 419, 414, 417, 418, 400, 416, 422, 400, 414, 400, 420, 400, 409, 423, 409, 409, 420, - 417, 426, 419, 424, 429, 427, 426, 409, 409, 409, - 409, 409, 425, 428, 409, 422, 423, 424, 425, 429, - 432, 430, 425, 431, 426, 427, 430, 435, 431, 436, - 433, 434, 434, 428, 437, 432, 433, 438, 439, 440, - 441, 436, 445, 443, 446, 440, 449, 435, 443, 171, - 447, 438, 437, 448, 444, 444, 439, 444, 451, 450, - 449, 450, 445, 451, 446, 441, 447, 456, 452, 448, - 452, 452, 453, 454, 455, 455, 453, 454, 457, 458, - 459, 461, 460, 466, 469, 463, 456, 466, 452, 461, - - 461, 463, 454, 457, 465, 458, 460, 464, 459, 465, - 169, 461, 467, 461, 462, 469, 464, 468, 470, 462, - 473, 467, 471, 468, 470, 473, 471, 462, 462, 474, - 472, 462, 462, 472, 476, 462, 475, 475, 477, 477, - 478, 479, 480, 481, 481, 482, 479, 476, 483, 474, - 484, 482, 485, 483, 484, 480, 486, 487, 488, 478, - 489, 489, 487, 488, 490, 491, 492, 485, 493, 489, - 494, 495, 496, 494, 497, 500, 490, 486, 499, 497, - 493, 498, 499, 495, 492, 491, 498, 500, 501, 501, - 502, 503, 505, 496, 507, 502, 504, 504, 508, 508, - - 507, 510, 511, 512, 513, 514, 515, 516, 517, 521, - 511, 515, 503, 513, 505, 519, 520, 522, 523, 524, - 517, 525, 510, 522, 512, 524, 514, 516, 167, 521, - 526, 529, 523, 519, 520, 519, 527, 525, 528, 526, - 525, 530, 527, 528, 531, 529, 532, 531, 533, 530, - 534, 535, 530, 536, 539, 537, 538, 535, 537, 534, - 532, 540, 538, 533, 541, 543, 540, 542, 539, 543, - 544, 545, 547, 536, 546, 548, 545, 547, 549, 550, - 538, 553, 554, 557, 165, 555, 541, 544, 542, 546, - 556, 548, 550, 559, 556, 572, 572, 549, 551, 551, - - 555, 553, 557, 554, 551, 558, 551, 560, 562, 559, - 558, 560, 551, 564, 551, 563, 561, 551, 551, 565, - 563, 561, 567, 562, 551, 561, 568, 566, 565, 564, - 570, 569, 564, 566, 569, 571, 573, 567, 566, 575, - 563, 577, 568, 574, 574, 576, 578, 578, 579, 580, - 582, 583, 587, 570, 575, 571, 577, 576, 581, 582, - 584, 573, 585, 581, 587, 588, 592, 579, 585, 589, - 583, 580, 590, 589, 588, 584, 590, 591, 592, 593, - 594, 595, 596, 591, 598, 597, 599, 601, 596, 601, - 599, 600, 602, 603, 593, 595, 604, 604, 606, 594, - - 597, 603, 598, 605, 600, 607, 608, 609, 611, 605, - 606, 607, 608, 612, 610, 613, 602, 610, 616, 609, - 613, 614, 611, 615, 617, 614, 615, 632, 612, 618, - 632, 620, 619, 617, 621, 621, 616, 619, 619, 629, - 617, 622, 622, 617, 620, 618, 623, 624, 623, 625, - 625, 626, 626, 624, 627, 630, 628, 629, 631, 633, - 627, 628, 628, 634, 633, 635, 636, 637, 638, 636, - 631, 639, 637, 635, 640, 641, 630, 642, 640, 643, - 644, 641, 634, 643, 645, 646, 647, 647, 648, 645, - 639, 638, 649, 651, 652, 650, 653, 642, 644, 646, - - 650, 654, 658, 648, 655, 656, 691, 654, 86, 655, - 652, 660, 651, 649, 657, 661, 653, 657, 691, 656, - 658, 664, 657, 659, 659, 657, 657, 662, 663, 660, - 665, 661, 662, 663, 667, 664, 668, 667, 669, 672, - 670, 673, 668, 670, 671, 665, 673, 669, 671, 674, - 675, 676, 674, 677, 678, 675, 679, 680, 672, 681, - 685, 678, 680, 682, 682, 683, 684, 676, 686, 679, - 671, 677, 687, 686, 683, 685, 688, 690, 689, 681, - 694, 692, 693, 694, 696, 684, 690, 692, 693, 697, - 688, 699, 697, 687, 689, 695, 695, 698, 695, 700, - - 696, 701, 698, 702, 703, 704, 708, 705, 702, 699, - 706, 704, 705, 700, 707, 701, 706, 707, 710, 709, - 711, 713, 712, 703, 709, 711, 711, 715, 714, 718, - 719, 708, 717, 81, 710, 712, 713, 714, 717, 719, - 715, 716, 720, 721, 716, 723, 716, 720, 718, 722, - 722, 724, 723, 716, 725, 727, 726, 725, 724, 716, - 716, 716, 726, 721, 728, 729, 731, 727, 733, 728, - 729, 729, 725, 730, 730, 732, 734, 732, 734, 728, - 735, 736, 737, 740, 738, 739, 741, 733, 743, 742, - 744, 731, 741, 742, 745, 746, 747, 743, 751, 736, - - 737, 735, 738, 740, 739, 744, 749, 748, 750, 745, - 748, 752, 753, 746, 750, 747, 754, 755, 751, 748, - 756, 749, 757, 758, 753, 752, 757, 759, 760, 761, - 762, 763, 764, 766, 766, 754, 76, 764, 755, 756, - 765, 758, 768, 759, 769, 771, 760, 761, 761, 762, - 763, 767, 772, 770, 765, 767, 768, 772, 773, 771, - 774, 776, 775, 769, 770, 777, 778, 779, 776, 782, - 777, 780, 781, 778, 773, 775, 780, 781, 783, 774, - 784, 785, 788, 786, 787, 783, 793, 782, 75, 784, - 789, 779, 786, 787, 788, 785, 789, 790, 791, 792, - - 793, 791, 790, 792, 794, 795, 796, 797, 798, 796, - 799, 799, 801, 794, 800, 800, 803, 801, 801, 802, - 795, 797, 805, 800, 802, 803, 806, 807, 808, 798, - 809, 810, 806, 811, 809, 812, 813, 815, 814, 816, - 817, 805, 813, 810, 814, 815, 807, 817, 808, 818, - 819, 820, 827, 812, 816, 823, 826, 830, 811, 826, - 833, 836, 831, 835, 838, 838, 830, 818, 831, 827, - 823, 820, 835, 834, 841, 819, 821, 836, 821, 834, - 837, 821, 833, 840, 837, 821, 839, 839, 821, 842, - 843, 844, 841, 848, 840, 821, 821, 844, 821, 846, - - 847, 851, 849, 842, 850, 847, 857, 854, 850, 856, - 843, 845, 845, 845, 848, 845, 69, 852, 845, 846, - 849, 852, 853, 845, 856, 851, 854, 853, 855, 845, - 845, 857, 845, 855, 859, 858, 860, 852, 858, 859, - 859, 861, 861, 860, 862, 863, 864, 864, 865, 866, - 863, 867, 866, 865, 868, 868, 867, 870, 869, 862, - 869, 871, 872, 873, 874, 876, 872, 875, 878, 870, - 877, 877, 879, 876, 880, 881, 881, 882, 883, 884, - 871, 873, 886, 878, 874, 885, 875, 886, 880, 893, - 883, 885, 879, 887, 887, 882, 892, 888, 892, 890, - - 891, 884, 888, 888, 890, 894, 891, 893, 895, 896, - 899, 897, 898, 899, 900, 896, 897, 901, 898, 904, - 900, 902, 902, 905, 894, 901, 903, 903, 895, 906, - 907, 905, 908, 909, 910, 907, 908, 904, 911, 912, - 909, 913, 913, 915, 914, 916, 916, 906, 918, 917, - 919, 915, 910, 914, 911, 917, 921, 922, 912, 923, - 926, 924, 925, 927, 934, 921, 918, 928, 929, 919, - 924, 930, 928, 929, 933, 922, 931, 925, 927, 931, - 930, 932, 935, 936, 926, 923, 932, 937, 933, 934, - 938, 935, 937, 937, 939, 939, 936, 940, 941, 942, - - 943, 944, 945, 953, 938, 945, 949, 947, 942, 947, - 948, 948, 940, 945, 951, 950, 952, 941, 954, 944, - 950, 952, 955, 953, 943, 956, 958, 949, 957, 959, - 960, 961, 963, 959, 962, 951, 965, 957, 954, 964, - 962, 963, 966, 967, 955, 956, 969, 968, 960, 958, - 961, 964, 965, 968, 969, 970, 973, 967, 971, 972, - 972, 966, 974, 971, 975, 976, 977, 978, 979, 970, - 980, 981, 982, 975, 977, 973, 988, 983, 984, 985, - 986, 987, 974, 983, 984, 976, 986, 978, 989, 980, - 979, 981, 982, 985, 989, 987, 988, 990, 991, 992, - - 993, 994, 991, 990, 995, 997, 994, 996, 996, 998, - 999, 997, 993, 999, 1000, 998, 1001, 1002, 992, 1003, - 993, 1004, 1004, 1002, 1005, 995, 1007, 1006, 1013, 1001, - 1008, 1007, 1000, 1008, 1010, 1012, 1012, 1011, 1009, 1003, - 1006, 1011, 1005, 1009, 1009, 1014, 1008, 1015, 1008, 1010, - 1013, 1016, 1017, 1019, 1020, 1021, 1016, 1023, 1021, 1024, - 1025, 1027, 1015, 1028, 1028, 1014, 1027, 1032, 1020, 1021, - 1023, 1017, 1029, 1030, 1031, 1031, 1029, 1019, 1036, 1024, - 1034, 1025, 1026, 1037, 1035, 1026, 1090, 1026, 1030, 1090, - 1033, 1026, 1032, 1026, 1033, 1033, 1036, 1037, 1026, 1035, - - 1034, 1038, 1039, 1026, 1040, 1041, 1038, 1042, 1043, 1040, - 1040, 1044, 1043, 1046, 1041, 1047, 1039, 1045, 1045, 1048, - 1047, 1042, 1045, 1050, 1043, 1046, 1044, 1049, 1049, 1051, - 1052, 1053, 1045, 1048, 1054, 1056, 1053, 1055, 1061, 1052, - 1054, 1056, 1055, 1051, 1050, 1057, 1058, 1058, 1059, 1060, - 1062, 1057, 1063, 1059, 1065, 1060, 1066, 1069, 1069, 1067, - 1061, 1066, 1068, 1070, 1072, 1073, 1065, 1071, 1070, 1062, - 1063, 1064, 1064, 1067, 1068, 1071, 1075, 1064, 1072, 1064, - 1074, 1073, 1076, 1077, 1079, 1064, 1078, 1081, 1080, 1079, - 1064, 1064, 1078, 1082, 1074, 1075, 1083, 1064, 1084, 1077, - - 1080, 1076, 1085, 1085, 1086, 1081, 1087, 1089, 1086, 1082, - 1091, 1093, 1092, 1089, 1083, 1094, 1084, 1092, 1095, 1096, - 1100, 1094, 1098, 1095, 1093, 1099, 1087, 1101, 1102, 1091, - 1103, 1098, 1104, 1101, 1099, 1105, 1100, 1106, 1096, 1103, - 1105, 1107, 1108, 1108, 1109, 1111, 1110, 1112, 1114, 1102, - 1120, 1104, 1117, 1113, 1111, 1107, 1112, 1106, 1110, 1113, - 1115, 1119, 1121, 1121, 1109, 1114, 1115, 1122, 1117, 1123, - 1120, 1124, 1125, 1126, 1123, 1119, 1127, 1124, 1128, 1129, - 1130, 1133, 64, 1134, 1129, 1130, 1133, 1126, 1134, 1135, - 1143, 1125, 1122, 1128, 1127, 1136, 1136, 1137, 1135, 1138, - - 1139, 1140, 1141, 1137, 1147, 1138, 1143, 1144, 1149, 1139, - 1146, 1146, 1144, 1144, 1146, 1141, 1140, 1148, 1150, 1147, - 1148, 1151, 1149, 1152, 1155, 1165, 1151, 1153, 1154, 1156, - 1157, 1155, 1159, 1158, 1161, 1163, 1160, 1169, 1150, 1165, - 1153, 1153, 1160, 1152, 1154, 1156, 1158, 1159, 1157, 1162, - 1163, 1164, 1167, 1167, 1161, 1162, 1164, 1168, 1169, 1170, - 1168, 1171, 1172, 1173, 1170, 1174, 1171, 1176, 1175, 1178, - 1174, 1179, 1173, 1175, 1180, 1178, 1181, 1182, 1172, 1176, - 1180, 1183, 1183, 1182, 1184, 1185, 1186, 1179, 1188, 1186, - 1187, 1187, 1189, 1184, 1190, 1191, 1192, 1181, 1191, 1193, - - 59, 1194, 1195, 1185, 1203, 1193, 1188, 1194, 1195, 1192, - 1196, 1189, 1197, 1198, 1190, 1196, 1199, 1197, 1200, 1198, - 1202, 1199, 1203, 1204, 1200, 1202, 1205, 1208, 1206, 1207, - 1207, 1209, 1205, 1206, 1210, 1211, 1208, 1212, 1213, 1210, - 1209, 1213, 1214, 1204, 1215, 1214, 1216, 1217, 1218, 1219, - 58, 1216, 1220, 1211, 1222, 1215, 1212, 1221, 1220, 1223, - 1218, 1224, 1224, 1221, 1223, 1217, 1225, 1226, 1219, 1222, - 1227, 1228, 1229, 1230, 1231, 1232, 1229, 1233, 1235, 1236, - 1241, 1226, 1227, 1231, 1238, 1225, 1237, 1237, 1236, 1228, - 1239, 1230, 1238, 1240, 1232, 1239, 1243, 1235, 1240, 1244, - - 1241, 1245, 1233, 1246, 1248, 1250, 1247, 1259, 1246, 1254, - 1243, 1249, 1249, 1245, 1244, 1247, 1251, 1252, 1253, 1248, - 1255, 1259, 1251, 1252, 1254, 1250, 1253, 1256, 1257, 1258, - 1257, 1260, 1256, 1261, 1258, 1262, 1255, 1263, 1261, 1264, - 1265, 1267, 1264, 1266, 1273, 1260, 1272, 1265, 1269, 1269, - 1262, 1270, 1277, 1271, 1275, 1272, 1263, 1271, 1266, 1284, - 1267, 1274, 1273, 1278, 1276, 1270, 1284, 1274, 1278, 1275, - 1276, 1280, 1277, 1281, 1281, 1280, 1282, 1278, 1285, 1278, - 1286, 1282, 1278, 1283, 1283, 1287, 1288, 1290, 1287, 1289, - 1292, 1285, 1293, 1295, 1286, 1292, 1290, 1294, 1296, 1295, - - 1297, 1298, 1299, 1296, 1304, 1288, 1306, 1289, 1302, 1294, - 1306, 1293, 1298, 1302, 1297, 1301, 1301, 1303, 1305, 1307, - 1308, 1299, 1303, 1305, 1304, 1309, 1310, 1311, 1307, 1312, - 1311, 1313, 1315, 1316, 1314, 1308, 1318, 1317, 1313, 1311, - 1309, 1319, 1318, 1321, 1312, 1310, 1314, 1320, 1322, 1321, - 1323, 1315, 1324, 1327, 1316, 1317, 1319, 1325, 1320, 1326, - 1328, 1324, 1329, 1332, 1338, 1327, 1330, 1331, 1322, 1320, - 1323, 1334, 1325, 1331, 1335, 1339, 1336, 1334, 1326, 1328, - 1337, 1330, 1341, 1332, 1338, 1343, 1344, 1329, 1337, 1335, - 1336, 1339, 1340, 1342, 1341, 1345, 1439, 1340, 1342, 1342, - - 1344, 1346, 1346, 1348, 1343, 1348, 1349, 1350, 1345, 1347, - 1347, 1352, 1352, 1439, 1347, 1351, 1350, 1347, 1347, 1349, - 1353, 1351, 1347, 1354, 1355, 1353, 1357, 1354, 1347, 1356, - 1360, 1357, 1347, 1355, 1358, 1356, 1359, 1359, 1363, 1358, - 1361, 1361, 1362, 1364, 1365, 1362, 1366, 1362, 1367, 1361, - 1368, 1360, 1366, 1368, 1367, 1369, 1365, 1370, 1363, 1372, - 1371, 1364, 1373, 1374, 1369, 1371, 1375, 1378, 1376, 1374, - 1377, 1378, 1375, 1372, 1376, 1377, 1379, 1370, 1380, 1381, - 1373, 1382, 1383, 1383, 1381, 1384, 1384, 1380, 1384, 1379, - 1385, 1388, 1380, 1387, 1380, 1382, 1380, 1387, 1380, 1389, - - 1390, 1385, 1391, 1392, 1392, 1399, 1388, 1393, 1393, 1394, - 1395, 1391, 1396, 1397, 1394, 1394, 1398, 1399, 1390, 1389, - 1400, 1402, 1397, 1395, 1401, 1398, 1396, 1403, 1404, 1401, - 1405, 1406, 1407, 1408, 1408, 1402, 1403, 1414, 1407, 1409, - 1410, 1411, 1400, 1415, 1413, 1406, 1414, 1404, 1410, 1405, - 1415, 1409, 1412, 1416, 1417, 1411, 1418, 1412, 1413, 1419, - 1419, 1418, 1420, 1421, 1421, 1422, 1423, 1427, 1423, 1425, - 1422, 1416, 1425, 1426, 1428, 1429, 1429, 1420, 1426, 1417, - 1430, 1431, 1431, 1428, 1432, 1432, 1427, 1433, 1434, 1435, - 1436, 53, 1433, 1437, 1437, 1438, 1440, 1441, 1442, 1440, - - 1430, 1443, 1446, 1444, 1442, 1445, 1443, 1445, 1449, 1434, - 1435, 1436, 1444, 1448, 1450, 1438, 1448, 1441, 1452, 1451, - 1446, 1453, 1454, 1449, 1451, 48, 1453, 1450, 1455, 1460, - 1454, 1456, 1452, 1455, 1456, 1457, 1458, 1458, 1459, 1461, - 1457, 1462, 1463, 1459, 1465, 1461, 1466, 1460, 1462, 1467, - 1465, 1468, 1466, 1469, 1467, 1463, 1468, 1470, 1471, 1469, - 1472, 1473, 1473, 1474, 1475, 1477, 1470, 1478, 1479, 1481, - 1477, 1472, 1480, 1482, 1483, 1484, 1485, 1471, 1479, 1486, - 1483, 1484, 1485, 1474, 1475, 1478, 1488, 1480, 1489, 1481, - 1486, 1490, 1488, 1491, 1492, 1493, 1482, 1494, 1491, 1495, - - 1492, 1496, 1489, 1497, 1497, 1490, 1498, 1499, 1489, 1494, - 1500, 1490, 1501, 1495, 1504, 1493, 1502, 1501, 1505, 1496, - 1503, 1503, 1507, 1505, 1508, 1510, 1498, 1509, 1500, 1511, - 1510, 1510, 1499, 1512, 1502, 1513, 1524, 1504, 1508, 1515, - 1509, 1507, 1514, 1516, 1513, 1517, 1519, 1511, 1521, 1518, - 1514, 1512, 1524, 1515, 1518, 1519, 1526, 1518, 1516, 1520, - 1517, 1520, 1521, 1517, 1523, 1525, 1527, 1526, 1528, 1525, - 1523, 1527, 1527, 1529, 1530, 1531, 1532, 1533, 1534, 1536, - 1531, 1532, 1533, 1535, 1536, 1537, 1539, 1528, 1540, 1541, - 1542, 1542, 1530, 1543, 1544, 1545, 1534, 1543, 1546, 1529, - - 1539, 1547, 1548, 1535, 1546, 1537, 1540, 1541, 1549, 1550, - 1551, 1552, 1544, 1547, 1545, 1553, 1554, 1555, 1548, 1557, - 1560, 1554, 1558, 1550, 1555, 1551, 1552, 1549, 1556, 1561, - 1559, 1562, 1562, 1556, 1553, 1559, 1558, 1557, 1561, 1563, - 1564, 1560, 1565, 1566, 1566, 1567, 1568, 1569, 1573, 1564, - 1574, 1567, 1568, 1572, 1563, 1570, 1570, 1571, 1571, 1572, - 1575, 1569, 1565, 1576, 1573, 1575, 1577, 1578, 1585, 1576, - 1586, 1574, 1577, 1578, 1579, 1579, 1580, 1580, 1582, 1582, - 1583, 1584, 1586, 1587, 1583, 1588, 1585, 1589, 1590, 1590, - 1584, 1591, 1595, 1592, 1589, 1596, 1580, 1587, 1580, 1593, - - 1588, 1592, 1594, 1597, 1600, 1593, 1595, 1594, 1597, 1597, - 1598, 1591, 1602, 1599, 1596, 1598, 1598, 1599, 1601, 1601, - 1603, 1604, 1605, 1606, 1600, 1607, 1608, 1605, 1610, 1609, - 1604, 1602, 1611, 1613, 1610, 1612, 1614, 1611, 1615, 1603, - 1616, 1612, 1606, 1617, 1607, 1618, 1608, 1609, 1619, 1617, - 1621, 1613, 1620, 1615, 1619, 1623, 1614, 1624, 1620, 1622, - 1625, 1626, 1628, 1627, 1618, 1632, 1616, 1629, 1622, 1621, - 1630, 1630, 1631, 1633, 1623, 1631, 1624, 1627, 1634, 1625, - 1626, 1640, 1629, 1628, 1632, 1635, 1635, 1636, 1636, 1637, - 1634, 1638, 1633, 1639, 1637, 1638, 1640, 1642, 1641, 1645, - - 18, 1645, 1647, 1647, 1648, 1645, 1639, 1641, 1649, 1648, - 1642, 1650, 1651, 1653, 1650, 1652, 1654, 1655, 1645, 1657, - 1652, 1651, 1656, 1656, 1657, 1658, 1649, 1659, 1653, 1661, - 1660, 1658, 1662, 1655, 1663, 1661, 1654, 1662, 1663, 1665, - 1664, 1667, 1659, 1660, 1664, 1666, 1668, 1669, 1670, 1670, - 1667, 1672, 1674, 1669, 1675, 1676, 1677, 1677, 1674, 1665, - 1676, 1678, 1679, 1666, 1681, 1681, 1668, 1678, 1683, 1672, - 1685, 1683, 1684, 1684, 1686, 1675, 1687, 1689, 1690, 1692, - 1689, 1691, 1679, 1693, 1694, 1694, 1685, 1695, 1692, 1696, - 1686, 1698, 1687, 1697, 1699, 1703, 1698, 1706, 1700, 1690, - - 1702, 1691, 1695, 1693, 1700, 1701, 1701, 1704, 1699, 1702, - 1696, 1705, 1697, 1703, 1707, 1707, 1708, 1706, 1710, 1709, - 1711, 1714, 1704, 1710, 1712, 1712, 1716, 1713, 1715, 1715, - 1708, 1713, 1717, 1718, 1719, 1711, 1705, 1709, 1719, 1720, - 1721, 1714, 1723, 1723, 1718, 1721, 1725, 1724, 1716, 1725, - 1726, 1717, 1724, 1724, 1727, 1728, 1729, 1731, 1720, 1727, - 1733, 1730, 1736, 1726, 1732, 1735, 1735, 1736, 1737, 1739, - 1734, 1728, 1741, 1743, 1729, 1730, 1731, 1731, 1732, 1734, - 1740, 1738, 1743, 1740, 1745, 1733, 1738, 1749, 1737, 1739, - 1744, 1741, 1742, 1742, 1746, 1744, 1746, 1747, 1751, 1748, - - 1750, 1753, 1747, 1751, 1745, 1748, 1750, 1749, 1754, 1754, - 1755, 1756, 1757, 1758, 1762, 1753, 1760, 1757, 1761, 1758, - 1765, 1760, 1766, 1761, 1763, 1763, 1764, 1764, 1767, 1755, - 1756, 1770, 1768, 1771, 1765, 1768, 1769, 1769, 1762, 1772, - 1766, 1774, 1775, 1767, 1773, 1771, 1776, 1773, 1775, 1770, - 1773, 1776, 1777, 1774, 1779, 1777, 1780, 1781, 17, 1772, - 1784, 1780, 1773, 1779, 1782, 1783, 1783, 1782, 1785, 1786, - 1790, 1777, 1787, 1792, 1785, 1786, 1790, 1787, 1788, 1788, - 1789, 1789, 1781, 1791, 1784, 1793, 1792, 1794, 1791, 1795, - 1796, 1797, 1798, 1796, 1799, 1802, 1800, 1797, 1798, 1801, - - 1799, 1800, 1803, 1793, 1806, 1801, 1794, 1803, 1805, 1795, - 1804, 1804, 1807, 1805, 1808, 1809, 1810, 1811, 1802, 1816, - 1812, 1820, 1806, 1815, 1813, 1814, 1817, 1819, 1820, 1808, - 1817, 1822, 1807, 1809, 1812, 1810, 1823, 1811, 1813, 1814, - 1818, 1815, 1818, 1822, 1816, 1824, 1819, 1825, 1823, 1826, - 1827, 1828, 1830, 1825, 1829, 1830, 1831, 1831, 1824, 1834, - 1834, 1832, 1835, 1837, 1838, 1838, 1827, 1836, 1829, 1826, - 1832, 1828, 1836, 1830, 1839, 1837, 1840, 1841, 1842, 1843, - 1846, 1844, 1835, 1845, 1844, 1853, 1848, 1846, 1843, 1839, - 1840, 1847, 1850, 1852, 1857, 1844, 1842, 1844, 1845, 1858, - - 1847, 1841, 1848, 1847, 1860, 1854, 1857, 1850, 1854, 1863, - 1853, 1852, 1850, 1855, 1855, 1856, 1856, 1858, 1859, 1860, - 1862, 1859, 1861, 1861, 1864, 1865, 1866, 1867, 1863, 1864, - 1867, 1866, 1868, 1862, 1869, 1870, 1871, 1872, 1873, 1869, - 1875, 1876, 1865, 1877, 1878, 1878, 1872, 1874, 1879, 1877, - 1876, 1880, 1871, 1868, 1870, 1879, 1874, 1873, 1882, 1874, - 1881, 1883, 1884, 1885, 1875, 1886, 1890, 1887, 1885, 1885, - 1886, 1880, 1891, 1881, 1893, 1883, 1882, 1893, 1884, 1887, - 1892, 1892, 1894, 1895, 1896, 1896, 1897, 1897, 1898, 1896, - 1891, 1890, 1895, 1899, 1902, 1902, 1900, 1898, 1894, 1900, - - 1898, 1897, 1903, 1901, 1904, 1903, 1905, 1899, 1901, 1907, - 1906, 1909, 1911, 1912, 1907, 1907, 1910, 1914, 1912, 1913, - 1915, 1923, 1904, 1914, 1924, 1909, 1917, 1905, 1906, 1916, - 1916, 1910, 1917, 1913, 1911, 1918, 1919, 1920, 1915, 1921, - 1918, 1923, 1925, 1920, 1924, 1921, 1926, 1927, 1928, 1929, - 1919, 1928, 1926, 1931, 1933, 1929, 1925, 1928, 1934, 1935, - 1927, 1931, 1936, 1937, 0, 1938, 1939, 1940, 1937, 1941, - 1936, 1942, 1943, 1933, 1938, 1950, 1940, 1934, 1935, 1939, - 1944, 1944, 1941, 1945, 1946, 1942, 1943, 1948, 1947, 1945, - 1946, 1947, 1949, 1949, 1951, 1950, 1952, 1953, 1953, 1955, - - 1948, 1954, 1944, 1956, 1957, 1955, 1958, 1960, 1960, 1961, - 1964, 1963, 1951, 1962, 1954, 1952, 1963, 1962, 1965, 1967, - 1957, 1966, 1968, 1965, 1958, 1956, 1966, 1972, 1967, 1961, - 1964, 1973, 1970, 1974, 1978, 1970, 1974, 1975, 1972, 1976, - 1973, 1977, 1977, 1979, 1980, 1968, 1970, 1981, 1981, 1975, - 1983, 1982, 1984, 1978, 1976, 1979, 1982, 1985, 1986, 1984, - 1987, 1989, 1988, 1980, 1983, 1986, 1991, 1992, 1993, 1985, - 1994, 1995, 1987, 1988, 1993, 1997, 1997, 1996, 1999, 2000, - 2000, 1989, 1994, 1996, 2004, 1991, 2003, 1992, 1998, 1995, - 2002, 1998, 2003, 2005, 2006, 2002, 2009, 2007, 1999, 2004, - - 2008, 2008, 2005, 2007, 2010, 2012, 2010, 2013, 2009, 2011, - 2006, 2016, 2011, 2014, 2015, 2017, 2016, 2018, 2019, 2020, - 2017, 2024, 2021, 2022, 2023, 2012, 2018, 2021, 2022, 2013, - 2019, 2014, 2015, 2023, 2020, 2025, 2027, 2026, 2028, 2028, - 2025, 2024, 2026, 2029, 2030, 2032, 2023, 2025, 2033, 2029, - 2034, 2027, 2035, 2036, 2037, 2042, 2037, 0, 2038, 2039, - 2039, 2032, 2040, 2040, 2045, 2030, 2046, 2033, 2035, 2034, - 2041, 2041, 2038, 2036, 2038, 2042, 2043, 2043, 2044, 2044, - 2047, 2048, 2048, 2050, 2049, 2045, 2053, 2046, 2049, 2050, - 2051, 2054, 2053, 2051, 2055, 2056, 2057, 2058, 2059, 2062, - - 2055, 2047, 2058, 2060, 2066, 2057, 2060, 2061, 2061, 2054, - 2063, 2064, 2064, 2065, 2071, 2063, 2067, 2068, 2056, 2062, - 2071, 2067, 2068, 2059, 2070, 2066, 2069, 2069, 2065, 2070, - 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2086, 2079, 2084, - 2076, 2080, 2072, 2072, 2072, 2079, 2080, 2083, 2086, 2072, - 2074, 2073, 2082, 2075, 2084, 2077, 2078, 2082, 2082, 2087, - 2085, 2083, 2085, 2088, 2089, 2090, 2091, 2092, 2094, 2088, - 2093, 2095, 2095, 2089, 2087, 2096, 2097, 2097, 2098, 2103, - 2091, 2099, 2100, 2100, 2107, 2090, 2092, 2108, 2093, 2094, - 2101, 2101, 2102, 2102, 2106, 2106, 2108, 2111, 2098, 2103, - - 2112, 2096, 2113, 2099, 2109, 2109, 2111, 2114, 2113, 2107, - 2115, 2116, 2117, 2118, 2118, 2119, 2120, 2121, 2123, 2124, - 2124, 2112, 2126, 2122, 2121, 2127, 2117, 2116, 2114, 2115, - 2130, 2120, 2122, 2125, 2125, 2130, 2119, 2129, 2132, 2131, - 2133, 2127, 2137, 2129, 2123, 2131, 2134, 2133, 2126, 2135, - 2138, 2135, 2134, 2139, 2139, 2140, 2138, 2141, 2132, 2142, - 2140, 2137, 2143, 2146, 2144, 2145, 2141, 2147, 2145, 2148, - 2147, 2149, 2150, 2150, 2142, 2146, 2151, 2154, 2152, 2153, - 2151, 2157, 2143, 2144, 2158, 2153, 2156, 2148, 2161, 2154, - 2155, 2155, 2156, 2162, 2164, 2164, 2159, 2149, 2152, 2158, - - 2159, 2157, 2163, 2165, 2166, 2167, 2169, 2163, 2161, 2170, - 2171, 2171, 2172, 2170, 0, 2162, 2159, 2173, 2172, 2175, - 2167, 2174, 2174, 2166, 2177, 2169, 2173, 2165, 2175, 2176, - 2178, 2178, 2179, 2176, 2180, 2177, 2181, 2182, 2183, 2184, - 2177, 2185, 2182, 2186, 2187, 2188, 2189, 2206, 2180, 2186, - 2190, 2189, 2197, 2179, 0, 2181, 2191, 2191, 2183, 2184, - 2188, 2185, 2187, 2190, 2192, 2192, 2193, 2195, 2196, 2198, - 2193, 2212, 2197, 2206, 2198, 2212, 2195, 2199, 2199, 2196, - 2201, 2201, 2202, 2203, 2196, 2205, 2208, 2202, 2202, 2203, - 2207, 2205, 2211, 2209, 2213, 2207, 2214, 2214, 2208, 2209, - - 2215, 2216, 2217, 2218, 2211, 2219, 2213, 2216, 2220, 2218, - 2221, 2221, 2222, 2220, 2223, 2225, 2224, 2227, 2228, 2232, - 2219, 2224, 2232, 2229, 2217, 2215, 2239, 2225, 2229, 2227, - 2238, 2222, 2231, 2231, 2223, 2233, 2233, 2228, 2234, 2234, - 2235, 2235, 2236, 2236, 2237, 2238, 2239, 2240, 2241, 2243, - 2237, 2242, 2244, 2240, 2241, 2243, 2242, 2246, 2247, 2251, - 2252, 2244, 2246, 2247, 2247, 2249, 2250, 2253, 2249, 2256, - 2250, 2257, 2252, 2254, 2254, 2259, 2259, 2260, 2265, 2258, - 2251, 2256, 2253, 2257, 2258, 2261, 2260, 2262, 2263, 2267, - 2261, 2263, 2262, 2264, 2264, 2266, 2268, 2269, 2265, 2273, - - 2274, 2270, 2272, 2269, 2266, 2270, 2271, 2267, 2272, 2274, - 2275, 2271, 2276, 2278, 2278, 2268, 2279, 2273, 2280, 2282, - 2281, 2283, 2283, 2284, 2285, 2278, 2276, 2280, 2275, 2281, - 2286, 2288, 2284, 2287, 2279, 2298, 2285, 2294, 2287, 2282, - 2291, 2291, 2293, 2295, 2288, 2293, 2296, 2299, 2300, 2301, - 2298, 2286, 2306, 2294, 2300, 2302, 2302, 2304, 2303, 2295, - 2303, 2299, 2296, 2305, 2307, 2307, 2301, 2308, 2313, 2305, - 2306, 2304, 2310, 2310, 2314, 2308, 2311, 2311, 2315, 2316, - 2314, 2317, 2318, 2319, 2315, 2320, 2320, 2322, 2317, 2321, - 2321, 2313, 2327, 2316, 2323, 2324, 2325, 2326, 2321, 2329, - - 2331, 2328, 0, 2319, 2318, 2336, 2323, 2324, 2322, 2326, - 2328, 2325, 2334, 2335, 2329, 2330, 2338, 2336, 2327, 2339, - 2330, 2330, 2332, 2331, 2332, 2332, 2337, 2337, 2332, 2344, - 2340, 2345, 2334, 2340, 2338, 2341, 2335, 2342, 2342, 2339, - 2341, 2332, 2343, 2343, 2344, 2347, 2348, 2349, 2348, 2350, - 2347, 2345, 2351, 2354, 2350, 2356, 2359, 2357, 2360, 2351, - 2360, 2361, 2354, 2362, 2363, 2349, 2357, 2365, 2359, 2364, - 2367, 2368, 2367, 2356, 2370, 2364, 2369, 2369, 2362, 2376, - 2361, 2371, 2378, 2377, 2363, 2368, 2371, 2365, 2372, 2374, - 2372, 2375, 2379, 2381, 2374, 2382, 2375, 2376, 2379, 2380, - - 2370, 2377, 2378, 2383, 2380, 2384, 2381, 2382, 2383, 2383, - 2386, 2387, 2388, 2384, 2389, 2389, 2390, 2390, 2392, 2391, - 2393, 2394, 0, 2395, 2388, 2387, 2399, 2394, 2395, 2386, - 2391, 2397, 2396, 2392, 2396, 2398, 2400, 2397, 2402, 2401, - 2393, 2398, 2400, 2404, 2399, 2401, 2402, 2403, 2403, 2405, - 2405, 2406, 2406, 2407, 2402, 2404, 2408, 2409, 2412, 2411, - 2414, 2408, 2407, 2411, 2413, 2416, 2413, 2412, 2415, 2417, - 2412, 2418, 2420, 2415, 2415, 2409, 2421, 2416, 2417, 2422, - 2425, 2414, 2423, 2418, 2422, 2420, 2426, 2423, 2421, 2427, - 2428, 2428, 2429, 2425, 2426, 2430, 2431, 2433, 2427, 2432, - - 2436, 2440, 2434, 2435, 2441, 2436, 2426, 2438, 2439, 2441, - 2429, 2444, 2442, 2430, 2431, 2432, 2434, 2442, 2435, 2438, - 2439, 2440, 2433, 2443, 2447, 2449, 2450, 2451, 2452, 2444, - 2447, 2449, 2443, 2453, 2458, 2454, 2455, 2455, 2456, 2457, - 2457, 2459, 2451, 2447, 2454, 2464, 2452, 2456, 2461, 2450, - 2460, 2462, 2458, 2461, 2460, 2463, 2466, 2467, 2453, 2468, - 2459, 2469, 2470, 2467, 2462, 2464, 2469, 2469, 2470, 2472, - 2463, 2471, 2472, 2475, 2474, 2466, 2477, 2471, 2479, 2480, - 2483, 2468, 2474, 2481, 2481, 2482, 2482, 2484, 2484, 2483, - 2485, 2485, 2486, 2475, 2487, 2491, 2477, 2480, 2492, 2488, - - 2482, 2479, 2490, 2494, 2486, 2488, 2495, 2495, 2490, 2493, - 2491, 2482, 2487, 2498, 2493, 2496, 2496, 2497, 2492, 2498, - 2500, 2494, 2497, 2501, 2500, 2502, 2503, 2505, 2506, 2502, - 2507, 2509, 2508, 2506, 2510, 2512, 2511, 2513, 2515, 2510, - 2514, 2516, 2516, 2501, 2517, 2514, 2503, 2508, 2517, 2509, - 2518, 2512, 2505, 2507, 2511, 2520, 2519, 2513, 2521, 2522, - 2515, 2519, 2523, 2524, 2525, 2518, 2526, 2527, 2530, 2525, - 2528, 2528, 2531, 2520, 2523, 2532, 2530, 2522, 2533, 2526, - 2534, 2535, 2524, 2536, 2521, 2527, 2537, 2538, 2539, 2540, - 2542, 2531, 2541, 2544, 2532, 2540, 2542, 2533, 2546, 2538, - - 2547, 2541, 2536, 2534, 2548, 2535, 2550, 2537, 2544, 2539, - 2548, 2546, 2554, 2549, 2547, 2549, 2551, 2551, 2552, 2553, - 2555, 2556, 2553, 2552, 2557, 2554, 2550, 2558, 2558, 2559, - 2559, 2560, 2562, 2560, 2563, 2556, 0, 2557, 2561, 2561, - 2564, 2565, 2565, 2569, 2555, 2565, 0, 2562, 2577, 2563, - 2567, 2567, 2571, 2564, 2568, 2568, 2570, 2570, 2569, 2572, - 2572, 2571, 2573, 2573, 2571, 2574, 2576, 2578, 2577, 2579, - 2574, 2576, 2580, 2582, 2583, 2583, 2584, 2584, 2585, 2586, - 2586, 2579, 2587, 2588, 2588, 2580, 2582, 2578, 2589, 2590, - 2591, 2591, 2592, 2592, 2590, 2593, 2594, 2585, 2595, 2597, - - 2587, 2596, 2596, 2589, 2600, 2594, 2598, 2598, 2599, 2593, - 2602, 2603, 2603, 2604, 2613, 2602, 2597, 2606, 2595, 2605, - 2605, 2607, 2599, 2600, 2608, 2609, 2607, 2612, 2609, 2613, - 2608, 2617, 2604, 2610, 2610, 2606, 2611, 2611, 2614, 2616, - 2614, 2618, 2618, 2621, 2622, 2619, 2612, 2623, 2628, 2610, - 2617, 2619, 2624, 2625, 2616, 2626, 2626, 2625, 2627, 2622, - 2629, 2630, 2637, 2621, 2633, 2631, 2630, 2624, 2628, 2631, - 2623, 2632, 2634, 2634, 2632, 2636, 2636, 2627, 2638, 2633, - 2629, 2639, 2637, 2632, 2640, 2638, 2641, 2634, 2642, 2643, - 2632, 2632, 2644, 2644, 2649, 2639, 2645, 2646, 2647, 2646, - - 2649, 2647, 2640, 2642, 2641, 2645, 2651, 2650, 2652, 2653, - 2654, 2651, 2655, 2652, 2653, 2643, 2647, 2656, 2647, 2650, - 2657, 2658, 2659, 2661, 2664, 2655, 2658, 2662, 2661, 2657, - 2667, 2663, 2662, 2672, 2665, 2654, 2663, 2666, 2656, 2664, - 2665, 2668, 2670, 2666, 2669, 2675, 2673, 2670, 2659, 2671, - 2669, 2667, 2674, 2676, 2671, 2674, 2668, 2677, 2672, 2673, - 2678, 2679, 2676, 2680, 2685, 2675, 2677, 2681, 2682, 2678, - 2679, 2683, 2687, 2681, 2682, 2683, 2688, 2680, 2689, 2689, - 2690, 2691, 2691, 2692, 2685, 2688, 2690, 2693, 2694, 2693, - 2691, 2697, 2687, 2696, 2692, 2695, 2695, 2694, 2696, 2699, - - 2700, 2701, 2701, 2702, 2705, 2703, 2709, 2715, 2704, 2708, - 2710, 2697, 2705, 2697, 2703, 2699, 2700, 2704, 2702, 2706, - 2711, 2708, 2709, 2713, 2706, 2710, 2713, 2715, 2714, 2716, - 2717, 2721, 2711, 2714, 2718, 2718, 2719, 2719, 2716, 2720, - 2720, 0, 2717, 2722, 2722, 2724, 2724, 2725, 2726, 2727, - 2725, 2721, 2728, 2726, 2729, 2727, 2730, 2730, 2728, 2731, - 2732, 2732, 2733, 2729, 2734, 2734, 2735, 2736, 2737, 2737, - 2738, 2739, 2740, 2731, 2733, 2742, 2738, 2740, 2743, 2742, - 2735, 2743, 2744, 2744, 2745, 2739, 2736, 2746, 2747, 2745, - 2748, 2749, 2746, 2752, 2750, 2751, 2751, 2747, 2750, 2748, - - 2754, 2755, 2756, 2757, 2758, 2754, 2752, 2760, 2759, 2761, - 2762, 2749, 2759, 2763, 2761, 2765, 2762, 2767, 2758, 2763, - 2765, 2755, 2756, 2757, 2764, 2764, 2768, 2760, 2766, 2766, - 2769, 2770, 2771, 2772, 2772, 2767, 2770, 2776, 2774, 2775, - 2777, 2778, 2776, 2779, 2784, 2768, 2777, 2778, 2782, 2769, - 2774, 2779, 2780, 2771, 2780, 2775, 2785, 2782, 2784, 2786, - 2786, 2787, 2788, 2788, 2787, 2790, 2791, 2793, 2790, 2792, - 2785, 2797, 2792, 2794, 2794, 2797, 2798, 2799, 2800, 2800, - 2802, 2791, 2798, 2801, 2808, 2802, 2803, 2806, 2806, 2799, - 2810, 2811, 2801, 2793, 2814, 2803, 2815, 2816, 2816, 2814, - - 2817, 2820, 2808, 2818, 2810, 2821, 2820, 2811, 2822, 2822, - 2821, 2824, 2824, 2826, 2827, 2828, 2828, 2829, 2817, 2826, - 2830, 2831, 2815, 2835, 2818, 2833, 2831, 2834, 2836, 2839, - 2834, 2837, 2837, 2829, 2827, 2835, 2843, 2840, 2844, 2847, - 2836, 2841, 2830, 2842, 2833, 2839, 2840, 2841, 2847, 2842, - 2846, 2846, 2848, 2844, 2843, 2849, 2851, 2850, 2849, 2850, - 2852, 2848, 2853, 2854, 2855, 2856, 2864, 2853, 2857, 2859, - 2859, 2851, 2854, 2860, 2860, 2852, 2861, 2862, 2863, 2864, - 2866, 2861, 2866, 2855, 2856, 2856, 2857, 2863, 2865, 2867, - 2868, 2870, 2871, 2865, 2869, 2862, 2870, 2872, 2874, 2874, - - 2873, 2875, 0, 2867, 2868, 2873, 2869, 2876, 2876, 2877, - 2877, 2879, 2871, 2878, 2878, 2881, 2875, 2872, 2880, 2882, - 2880, 2883, 2883, 2879, 2882, 2884, 2884, 2885, 2885, 2886, - 2887, 2888, 2889, 2881, 2890, 2891, 2892, 2892, 2893, 2894, - 2894, 2886, 2896, 2888, 2895, 2895, 2897, 2897, 2898, 2899, - 2887, 2891, 2889, 2896, 2900, 2890, 2899, 2893, 2901, 2902, - 2898, 2903, 2904, 2906, 2902, 2908, 2900, 2905, 2905, 2907, - 2907, 2910, 2906, 2909, 2911, 2912, 2913, 2915, 2901, 2924, - 2914, 2903, 2904, 2917, 2910, 2913, 2916, 2920, 2916, 2912, - 2921, 2908, 2914, 2909, 2919, 2917, 2918, 2918, 2911, 2915, - - 2923, 2924, 2920, 2919, 2925, 2921, 2926, 2927, 2927, 2928, - 2929, 2926, 2931, 2929, 2930, 2932, 2940, 2931, 2923, 2935, - 2932, 2933, 2933, 2934, 2934, 2940, 2925, 2944, 2930, 2936, - 2936, 2935, 2928, 2941, 2941, 2943, 2943, 2945, 2946, 2947, - 2949, 2950, 2951, 2952, 2954, 2944, 2953, 2955, 2945, 2956, - 2957, 2956, 0, 2954, 2947, 2958, 2959, 2946, 2965, 2950, - 2949, 2960, 2960, 2952, 2951, 2962, 2953, 2955, 2964, 2962, - 2957, 2963, 2963, 2958, 2959, 2966, 2967, 2967, 2969, 2971, - 2965, 2972, 2964, 2973, 2966, 2970, 2970, 2969, 2974, 2975, - 2976, 2977, 2979, 0, 2978, 2974, 2980, 2971, 2981, 2972, - - 2980, 2973, 2981, 2985, 2975, 2982, 2983, 2983, 2976, 2977, - 2978, 2979, 2982, 2984, 2984, 2986, 2987, 2989, 2989, 2990, - 2990, 2991, 2987, 2985, 2992, 2993, 2994, 2991, 2995, 2997, - 2996, 2998, 2998, 2986, 2997, 2999, 3000, 3001, 3002, 3003, - 3004, 2994, 2992, 2993, 2996, 0, 3005, 2995, 3011, 3002, - 3003, 3005, 3006, 3013, 3006, 2999, 3000, 3001, 3007, 3007, - 3004, 3008, 3015, 3008, 3009, 3009, 3016, 3011, 3012, 3012, - 3017, 3015, 3013, 3018, 3019, 3020, 3020, 3021, 3022, 3019, - 3023, 3027, 3017, 3022, 3024, 3016, 3028, 3029, 3030, 3030, - 3029, 3031, 3032, 3018, 3033, 3033, 3034, 3021, 3035, 3038, - - 3023, 3027, 3039, 3024, 3028, 3036, 3031, 3034, 3043, 3036, - 3032, 3041, 3040, 3035, 3038, 3041, 3045, 3039, 3040, 3042, - 3042, 3043, 3046, 3047, 3048, 3048, 3049, 3050, 3051, 3045, - 3052, 3053, 0, 3054, 3050, 3046, 3055, 3056, 3047, 3049, - 3049, 3057, 3057, 3052, 3055, 3060, 3051, 3059, 3064, 3061, - 3068, 3053, 3054, 3061, 3060, 3062, 3062, 3056, 3069, 3059, - 3063, 3063, 3065, 3065, 3066, 3067, 3068, 3064, 3070, 3066, - 3069, 3071, 3071, 3073, 3067, 3077, 3077, 3078, 3079, 3080, - 3080, 3084, 3081, 3082, 3083, 3088, 3078, 3120, 3070, 3085, - 3084, 3089, 3086, 3120, 3073, 3081, 3082, 3083, 3085, 3094, - - 3079, 3086, 3087, 3087, 3094, 3088, 3089, 3091, 3091, 3096, - 3097, 3098, 3099, 3100, 3096, 3102, 3098, 3101, 3104, 3108, - 3099, 3114, 3106, 3102, 3097, 3107, 3101, 3106, 3109, 3109, - 3107, 3112, 3100, 3104, 3108, 3110, 3110, 3111, 3113, 3118, - 3114, 3116, 3111, 3113, 3115, 3115, 3112, 3117, 3116, 3119, - 3121, 3122, 3117, 0, 3123, 3121, 3122, 3118, 3125, 3125, - 3126, 3127, 3128, 3128, 3129, 3129, 3127, 3119, 3123, 3132, - 3133, 3134, 3135, 3135, 3132, 3126, 3136, 3138, 3140, 3136, - 0, 3137, 3138, 3133, 3139, 3134, 3137, 3137, 3141, 3139, - 3145, 3142, 3140, 3143, 3141, 3142, 3144, 3146, 3143, 3145, - - 3147, 3144, 3148, 3149, 3150, 3152, 3151, 3159, 3147, 3149, - 3150, 3151, 3146, 3153, 3153, 3155, 3156, 3152, 3164, 3159, - 3161, 3156, 3155, 3148, 3157, 3161, 3162, 3157, 3163, 3165, - 3166, 3162, 3167, 3163, 3168, 3168, 3164, 3169, 3175, 3166, - 3170, 3167, 3165, 3171, 3170, 3172, 3169, 3176, 3177, 3171, - 3172, 3180, 3181, 3176, 3177, 3182, 3175, 3183, 3184, 3184, - 3185, 3186, 3188, 3191, 3189, 3190, 3190, 3185, 3192, 3193, - 3180, 3188, 3181, 3189, 3195, 3182, 3183, 3192, 3191, 3197, - 3186, 3194, 3194, 3199, 3193, 3201, 3202, 3204, 3201, 3205, - 3202, 3203, 3203, 3195, 3197, 3205, 3206, 3208, 3210, 3209, - - 3211, 3211, 3206, 3199, 3210, 3212, 3213, 3217, 3220, 3214, - 3216, 3220, 3204, 3212, 3214, 3219, 3208, 3209, 3221, 3216, - 3217, 3219, 3221, 3222, 3223, 3224, 3224, 3225, 3227, 3227, - 3228, 3213, 3229, 3230, 3232, 3228, 3233, 3229, 3223, 3234, - 3235, 3222, 3225, 3238, 3236, 3237, 3237, 3232, 3234, 3236, - 3233, 3230, 3239, 3239, 3240, 3240, 3242, 3242, 3245, 3243, - 3244, 3249, 3235, 3243, 3251, 3244, 3238, 3245, 3247, 3247, - 3250, 3253, 3252, 3255, 3256, 3250, 3251, 3252, 3252, 3257, - 3268, 3249, 3270, 3253, 3258, 3258, 3260, 3260, 3261, 3261, - 3262, 3262, 3263, 3255, 3256, 3263, 3264, 3265, 3268, 3257, - - 3267, 3267, 3270, 3271, 3271, 3272, 3272, 3273, 3273, 3264, - 3265, 3274, 3275, 3275, 3276, 3277, 3278, 3279, 3280, 3280, - 3281, 0, 3285, 3279, 3281, 3285, 3274, 3276, 3290, 3284, - 3278, 3286, 3291, 3277, 3284, 3284, 3287, 3286, 3289, 3292, - 3293, 3287, 3294, 3289, 3289, 3297, 3293, 3295, 3294, 3296, - 3298, 3290, 3291, 3295, 3298, 3296, 3299, 3299, 3303, 3292, - 3302, 3302, 3304, 3303, 3306, 3307, 3309, 3312, 3307, 3304, - 3297, 3310, 3306, 3313, 3310, 3311, 3311, 3314, 3313, 3315, - 3315, 3316, 3317, 3319, 3312, 3312, 3318, 3318, 3321, 3320, - 3322, 3309, 3320, 3328, 3328, 3314, 3317, 3319, 3323, 3325, - - 3320, 3316, 3321, 3327, 3325, 3325, 3323, 3326, 3334, 3322, - 3329, 3329, 3326, 3326, 3330, 3330, 3331, 3331, 3332, 3332, - 3333, 3333, 3327, 3335, 3334, 3336, 3337, 3338, 3335, 3340, - 3339, 3342, 3344, 3341, 3343, 3345, 3338, 3339, 3341, 3343, - 3346, 3344, 3347, 3340, 3352, 3336, 3349, 3349, 3350, 3350, - 3342, 3351, 3337, 3356, 3351, 3345, 3353, 3353, 3354, 3352, - 3346, 3355, 3347, 3359, 3354, 3361, 3355, 3358, 3358, 3362, - 3359, 3356, 3360, 3360, 3362, 3364, 3364, 3371, 3365, 3366, - 3367, 3367, 3368, 3369, 3372, 3372, 3361, 3365, 3366, 3373, - 3373, 3368, 3369, 3374, 3375, 3371, 3376, 3374, 3377, 3378, - - 3379, 3380, 3383, 3375, 3382, 3483, 3380, 3380, 3384, 3377, - 3385, 3383, 3386, 3483, 3378, 3376, 3386, 3382, 3387, 3387, - 3379, 3388, 3391, 3384, 3389, 3385, 3388, 3389, 3390, 3393, - 3397, 3398, 3398, 3390, 3399, 3397, 3402, 3391, 3401, 3401, - 3403, 3404, 3406, 3406, 3393, 3407, 3407, 3408, 3399, 3409, - 3402, 3410, 3414, 3415, 3418, 3409, 3408, 3416, 3415, 3404, - 3421, 3419, 3423, 3410, 3425, 3403, 3416, 3419, 3426, 3425, - 3427, 3427, 3421, 3426, 3418, 3428, 3430, 3414, 3431, 3433, - 3434, 3430, 3435, 3423, 3428, 3436, 3436, 3438, 3438, 3436, - 3433, 3441, 3431, 3434, 3439, 3439, 3435, 3440, 3440, 3442, - - 3441, 3443, 3446, 3444, 3445, 3449, 3454, 3446, 3450, 3450, - 3451, 3449, 3452, 3453, 3453, 3451, 3455, 3452, 3456, 3442, - 3457, 3443, 3444, 3445, 3454, 3457, 3458, 3459, 3455, 3461, - 3462, 3462, 3464, 3459, 3468, 3465, 3464, 3466, 3476, 3456, - 3465, 3469, 3466, 3470, 3458, 3467, 3467, 3472, 3474, 3474, - 3477, 3476, 3478, 3468, 3461, 3479, 3469, 3480, 3470, 3479, - 3481, 3482, 3485, 3477, 3484, 3478, 3480, 3472, 3487, 3484, - 3489, 3486, 3488, 3488, 3490, 3491, 3481, 3492, 3492, 3489, - 3482, 3494, 3485, 3486, 3493, 3493, 3504, 3500, 3487, 3497, - 3498, 3506, 3490, 3500, 3497, 3497, 3501, 3501, 3502, 3502, - - 3494, 3491, 3507, 3507, 3498, 3509, 3506, 3504, 3510, 3512, - 3513, 3514, 3517, 3517, 3512, 3518, 3514, 3520, 3519, 3521, - 3523, 3509, 3526, 3520, 3510, 3527, 3513, 3519, 3522, 3522, - 3525, 3525, 3528, 3529, 3530, 3518, 3526, 3531, 3533, 3523, - 3531, 3534, 3521, 3532, 3532, 3535, 3527, 3540, 3530, 3536, - 3536, 3538, 3529, 3528, 3541, 3545, 3533, 3538, 3546, 3542, - 3541, 3549, 3534, 3535, 3542, 3547, 3547, 3540, 3548, 3548, - 3550, 3551, 3551, 3553, 3552, 3554, 3549, 3545, 3556, 3558, - 3555, 3557, 3553, 3562, 3546, 3552, 3555, 3559, 3559, 3560, - 3550, 3551, 3569, 3557, 3560, 3554, 3570, 3556, 3562, 3558, - - 3561, 3561, 3563, 3564, 3569, 3563, 3564, 3565, 3565, 3571, - 3572, 3573, 3574, 3574, 3577, 3572, 3570, 3573, 3575, 3578, - 3577, 3575, 3580, 3581, 3581, 3582, 3583, 3580, 3584, 3571, - 3582, 3585, 3586, 3586, 3584, 3588, 3589, 3578, 3590, 3591, - 3592, 3592, 3593, 3594, 3595, 3583, 0, 3588, 3585, 3585, - 3597, 3597, 3591, 3595, 3589, 3598, 3598, 3599, 3599, 3594, - 3600, 3593, 3601, 3590, 3602, 3600, 3603, 3603, 3606, 3602, - 3604, 3604, 3605, 3605, 3607, 3609, 3601, 3606, 3608, 3608, - 3610, 3611, 3615, 3615, 3612, 3616, 3622, 3611, 3609, 3612, - 3618, 3618, 3619, 3619, 3623, 3607, 3625, 3626, 3627, 3628, - - 3632, 3616, 3629, 3629, 3633, 3622, 3610, 3631, 3631, 3636, - 3634, 3637, 3638, 3638, 3639, 3623, 3640, 3627, 3625, 3626, - 3637, 3628, 3643, 3633, 3634, 3644, 3632, 3641, 3641, 3636, - 3646, 3642, 3645, 3649, 3639, 3642, 3640, 3644, 3645, 3647, - 3650, 3651, 3643, 3647, 3652, 3657, 3650, 3653, 3654, 0, - 3646, 3649, 3653, 3654, 3658, 3658, 3660, 3660, 3662, 3661, - 3669, 3651, 3663, 3652, 3661, 3664, 3657, 3665, 3663, 3666, - 3666, 3667, 3662, 3673, 3671, 3665, 3667, 3664, 3671, 3672, - 3669, 3674, 3675, 3676, 3672, 3677, 3678, 3675, 3679, 3682, - 3681, 3683, 3684, 3673, 3679, 3676, 3686, 3677, 3681, 3687, - - 3688, 3674, 3689, 3694, 3678, 3690, 3693, 3697, 3682, 3694, - 3690, 3683, 3684, 0, 3686, 3687, 3692, 3688, 3688, 3695, - 3699, 3692, 3698, 3689, 3695, 3698, 3693, 3697, 3703, 3703, - 3704, 3704, 3705, 3699, 3709, 3710, 3705, 3712, 3712, 3713, - 3710, 3714, 3715, 3715, 3713, 3721, 3717, 3720, 3720, 3709, - 3722, 3722, 3726, 3722, 3723, 3723, 3726, 3723, 3724, 3724, - 3714, 3717, 3725, 3725, 3721, 3725, 3728, 3729, 3730, 3730, - 3731, 3728, 3732, 3734, 3734, 3737, 3729, 3735, 3735, 3738, - 3744, 3737, 3740, 3739, 3745, 3738, 3732, 3749, 3731, 3739, - 3740, 3741, 3741, 3742, 3742, 3743, 3743, 3746, 3740, 3748, - - 3744, 3752, 3746, 3753, 3745, 3747, 3747, 3749, 3754, 3755, - 3753, 3758, 3754, 3756, 3759, 3760, 3759, 3748, 3755, 3767, - 3760, 3761, 3761, 3762, 3763, 3763, 3752, 3768, 3756, 3758, - 3764, 3764, 3762, 3765, 3765, 3766, 3766, 3770, 3769, 3771, - 3773, 3767, 3768, 3769, 3771, 3771, 3770, 3772, 3774, 3770, - 3775, 3776, 3777, 3772, 3778, 3780, 3776, 3777, 3779, 3779, - 3781, 3780, 3784, 3774, 3789, 3773, 3781, 3782, 3782, 3783, - 3783, 3775, 3795, 3778, 3785, 3788, 3788, 3784, 3789, 3785, - 3790, 3790, 3792, 3792, 3793, 3797, 3797, 3798, 3798, 3807, - 3795, 3799, 3799, 3793, 3800, 3800, 3801, 3801, 3803, 3803, - - 3804, 3804, 3805, 3805, 3806, 3806, 3813, 3809, 3810, 3810, - 3814, 3823, 3816, 3815, 3821, 3807, 3809, 3815, 3817, 3817, - 3820, 3820, 3822, 3821, 3825, 3827, 3813, 3816, 3826, 3826, - 3814, 3823, 3829, 3817, 3822, 3828, 3828, 3830, 3836, 3825, - 3831, 3832, 3832, 3833, 3827, 3834, 3834, 3829, 3837, 3837, - 3830, 3841, 3831, 3836, 3842, 3833, 3841, 3843, 3844, 3846, - 3843, 3845, 3845, 3848, 3849, 3850, 3848, 3852, 3851, 3853, - 3849, 3857, 3842, 3851, 3854, 3856, 3861, 3846, 3860, 3850, - 3857, 3856, 3860, 3866, 3844, 3867, 3852, 3853, 3863, 3863, - 3854, 3861, 3877, 3878, 3880, 3881, 3878, 3877, 3882, 3883, - - 3882, 3884, 3887, 3880, 3881, 3867, 3885, 3888, 3888, 3866, - 3889, 3889, 3890, 3890, 3894, 3887, 3892, 3892, 3883, 3895, - 3884, 3884, 3896, 3897, 3885, 3898, 3896, 3900, 3895, 3902, - 3903, 3904, 3906, 3905, 3906, 3902, 3907, 3894, 3905, 3909, - 3898, 3900, 3904, 3897, 3908, 3908, 3910, 3912, 3911, 3913, - 3915, 3907, 3909, 3903, 3914, 3916, 3917, 3918, 3919, 3915, - 3921, 3917, 3923, 3912, 3924, 3910, 3911, 3916, 3920, 3914, - 3919, 3922, 3922, 3920, 3913, 3925, 3927, 3924, 3918, 3921, - 3926, 3926, 3923, 3928, 3929, 3930, 3931, 3936, 3925, 3937, - 3939, 3931, 3929, 3938, 3938, 3940, 3927, 3946, 3940, 3939, - - 3947, 3936, 3928, 3941, 3941, 3930, 3942, 3943, 3943, 3937, - 3951, 3942, 3944, 3944, 3945, 3945, 3946, 3949, 3948, 3950, - 3947, 3948, 3949, 3952, 3950, 3953, 3954, 3955, 3956, 3957, - 3957, 3953, 3958, 3956, 3968, 3951, 3959, 3959, 3952, 3955, - 3954, 3960, 3960, 3961, 3961, 3963, 3963, 3971, 3964, 3965, - 3967, 3967, 3958, 3964, 3965, 3969, 3969, 3968, 3970, 3970, - 3972, 3975, 3971, 3973, 3973, 3978, 3976, 3979, 3982, 3982, - 3983, 3983, 3984, 3985, 3988, 3986, 3975, 3976, 3987, 3972, - 3984, 3986, 3989, 3990, 3987, 3979, 3991, 4005, 3988, 3978, - 3999, 3991, 3985, 3992, 3992, 3989, 3994, 3994, 4000, 4002, - - 4006, 4008, 3990, 4009, 4009, 3999, 4010, 4011, 4005, 4013, - 4016, 4011, 4014, 4000, 4002, 4008, 4015, 4014, 4017, 4018, - 4006, 4019, 4010, 4016, 4024, 4020, 4019, 4021, 4021, 4013, - 4020, 4017, 4025, 4026, 4027, 4015, 0, 4028, 4018, 4029, - 4031, 4032, 4032, 4033, 4034, 4024, 4035, 4035, 4033, 4031, - 4034, 4026, 4036, 4025, 4027, 4028, 4037, 4036, 4029, 4038, - 4039, 4037, 4040, 4042, 4038, 4043, 4044, 4051, 4040, 4046, - 4044, 4045, 4045, 4048, 4046, 4047, 4047, 4050, 4053, 4039, - 4052, 4050, 4054, 4042, 4055, 4043, 4051, 4052, 4056, 4057, - 4055, 4048, 4058, 4058, 4059, 4059, 0, 4053, 4060, 4060, - - 4064, 4054, 4057, 4062, 4062, 4064, 4066, 4056, 4065, 4065, - 4068, 4067, 4069, 4070, 4076, 4066, 4067, 4072, 4066, 4071, - 4071, 4077, 4072, 4079, 4081, 4077, 4070, 4076, 4086, 4068, - 0, 4069, 4080, 4080, 4082, 4082, 4083, 4083, 4085, 4084, - 4087, 4087, 4094, 4081, 4084, 4085, 0, 4086, 4089, 4079, - 4088, 4088, 4090, 4089, 4090, 4091, 4091, 4092, 4093, 4096, - 4100, 4094, 4095, 4104, 4092, 4093, 4102, 4095, 4099, 4099, - 4103, 4102, 4105, 4106, 4106, 4103, 4108, 4108, 4096, 4100, - 4109, 4110, 4104, 4111, 4111, 4112, 4112, 4113, 4115, 4115, - 4117, 4105, 4116, 4116, 4113, 4123, 4119, 4117, 4122, 4109, - - 4110, 4119, 4124, 4122, 4125, 4125, 4126, 4126, 0, 0, - 0, 0, 0, 0, 4123, 0, 0, 0, 0, 0, - 0, 4124, 4130, 4130, 4130, 4130, 4130, 4130, 4130, 4131, - 4131, 4131, 4131, 4131, 4131, 4131, 4132, 4132, 4132, 4132, - 4132, 4132, 4132, 4133, 4133, 4133, 4133, 4133, 4133, 4133, - 4134, 4134, 4134, 4134, 4134, 4134, 4134, 4135, 4135, 4135, - 4135, 4135, 4135, 4135, 4136, 4136, 4136, 4136, 4136, 4136, - 4136, 4138, 4138, 0, 4138, 4138, 4138, 4138, 4139, 4139, - 0, 0, 0, 4139, 4139, 4140, 4140, 0, 0, 4140, - 0, 4140, 4141, 0, 0, 0, 0, 0, 4141, 4142, - - 4142, 0, 0, 0, 4142, 4142, 4143, 0, 0, 0, - 0, 0, 4143, 4144, 4144, 0, 4144, 4144, 4144, 4144, - 4145, 0, 0, 0, 0, 0, 4145, 4146, 4146, 0, - 0, 0, 4146, 4146, 4147, 4147, 0, 4147, 4147, 4147, - 4147, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, - 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, - 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, - 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, 4129, - 4129, 4129 + 417, 421, 419, 409, 424, 427, 429, 409, 409, 409, + 409, 409, 428, 169, 409, 422, 423, 409, 424, 421, + 425, 429, 426, 430, 431, 427, 425, 426, 430, 431, + 425, 432, 428, 433, 434, 434, 435, 436, 438, 433, + 437, 439, 440, 441, 445, 426, 432, 446, 440, 436, + 443, 449, 438, 447, 448, 443, 435, 451, 437, 439, + 444, 444, 451, 444, 445, 449, 456, 446, 441, 447, + 448, 450, 452, 450, 452, 452, 453, 454, 455, 455, + 453, 454, 457, 458, 459, 456, 460, 463, 469, 464, + + 466, 474, 452, 463, 466, 461, 454, 457, 464, 458, + 460, 465, 459, 461, 461, 467, 465, 468, 471, 469, + 470, 474, 471, 468, 467, 461, 470, 461, 462, 472, + 473, 476, 472, 462, 478, 473, 475, 475, 477, 477, + 485, 462, 462, 479, 476, 462, 462, 480, 479, 462, + 481, 481, 482, 478, 483, 485, 486, 484, 482, 483, + 480, 484, 487, 488, 489, 489, 490, 487, 488, 491, + 492, 493, 489, 489, 495, 496, 494, 486, 490, 494, + 497, 499, 498, 493, 504, 497, 495, 498, 492, 491, + 500, 501, 502, 502, 500, 503, 496, 505, 505, 499, + + 503, 506, 508, 501, 511, 504, 509, 509, 508, 512, + 513, 514, 515, 516, 517, 518, 522, 512, 516, 520, + 514, 524, 521, 506, 523, 511, 525, 518, 526, 527, + 523, 513, 525, 515, 517, 524, 522, 520, 527, 520, + 521, 529, 528, 530, 526, 531, 529, 526, 528, 532, + 533, 534, 532, 531, 535, 536, 531, 530, 537, 538, + 540, 536, 538, 535, 533, 539, 534, 541, 542, 544, + 543, 539, 541, 544, 540, 545, 546, 548, 537, 547, + 549, 546, 548, 550, 551, 554, 555, 558, 167, 539, + 542, 543, 545, 556, 547, 557, 549, 551, 560, 557, + + 573, 573, 550, 552, 552, 554, 558, 555, 556, 552, + 559, 552, 561, 563, 560, 559, 561, 552, 565, 552, + 564, 562, 552, 552, 566, 564, 562, 568, 563, 552, + 562, 563, 567, 566, 565, 569, 570, 565, 567, 570, + 571, 572, 568, 567, 574, 564, 575, 575, 577, 576, + 579, 569, 578, 578, 580, 580, 581, 582, 586, 584, + 577, 572, 583, 571, 576, 579, 587, 583, 584, 574, + 585, 585, 588, 590, 591, 581, 592, 586, 588, 582, + 592, 587, 593, 591, 594, 590, 593, 595, 596, 597, + 594, 598, 599, 601, 600, 605, 602, 603, 599, 595, + + 602, 608, 604, 596, 604, 598, 606, 608, 597, 600, + 603, 601, 607, 607, 606, 609, 610, 611, 612, 605, + 614, 613, 610, 611, 613, 615, 616, 609, 617, 619, + 612, 616, 617, 618, 614, 620, 618, 621, 165, 623, + 615, 624, 624, 622, 620, 625, 625, 619, 622, 622, + 627, 620, 623, 621, 620, 626, 627, 626, 628, 628, + 629, 629, 630, 632, 631, 633, 634, 636, 630, 631, + 631, 635, 636, 637, 635, 638, 639, 640, 634, 639, + 641, 632, 640, 638, 643, 642, 633, 644, 643, 645, + 646, 648, 637, 644, 646, 647, 648, 649, 650, 650, + + 651, 652, 653, 641, 642, 654, 657, 653, 656, 645, + 655, 649, 657, 647, 658, 651, 659, 661, 663, 658, + 662, 662, 652, 664, 654, 737, 655, 737, 656, 660, + 659, 667, 660, 665, 668, 661, 663, 660, 665, 664, + 660, 660, 666, 670, 671, 667, 670, 666, 672, 668, + 671, 673, 674, 675, 673, 676, 674, 672, 677, 678, + 676, 677, 680, 679, 678, 682, 681, 685, 683, 684, + 686, 686, 675, 681, 684, 687, 688, 689, 674, 679, + 680, 683, 691, 682, 687, 690, 692, 685, 693, 693, + 690, 694, 689, 695, 696, 688, 703, 701, 697, 698, + + 692, 703, 695, 691, 697, 698, 696, 694, 699, 700, + 700, 699, 700, 701, 702, 704, 705, 702, 706, 707, + 708, 709, 713, 710, 707, 711, 712, 709, 710, 712, + 705, 711, 706, 704, 715, 714, 716, 718, 717, 708, + 714, 716, 716, 720, 719, 723, 724, 713, 722, 86, + 715, 717, 718, 719, 722, 724, 720, 721, 725, 726, + 721, 728, 721, 725, 723, 727, 727, 729, 728, 721, + 730, 732, 731, 730, 729, 721, 721, 721, 731, 726, + 733, 734, 736, 732, 738, 733, 734, 734, 730, 735, + 735, 739, 740, 739, 741, 733, 742, 743, 744, 745, + + 746, 747, 748, 738, 751, 747, 746, 736, 749, 750, + 752, 748, 741, 740, 742, 743, 754, 744, 753, 745, + 755, 753, 751, 749, 750, 756, 755, 757, 758, 752, + 753, 754, 759, 760, 761, 762, 764, 763, 765, 762, + 758, 757, 766, 767, 768, 756, 769, 772, 772, 775, + 81, 759, 764, 761, 760, 763, 765, 766, 771, 770, + 774, 767, 767, 768, 770, 769, 773, 776, 775, 777, + 773, 778, 771, 779, 774, 780, 778, 781, 776, 782, + 783, 784, 786, 777, 785, 783, 782, 787, 788, 779, + 781, 785, 787, 788, 780, 789, 790, 791, 792, 794, + + 784, 793, 795, 790, 796, 798, 786, 792, 794, 791, + 798, 795, 797, 789, 799, 793, 796, 799, 797, 800, + 801, 802, 803, 800, 804, 805, 806, 804, 807, 807, + 802, 808, 808, 810, 801, 811, 809, 803, 810, 805, + 808, 809, 809, 813, 811, 814, 815, 806, 816, 817, + 819, 814, 818, 817, 820, 821, 824, 822, 823, 826, + 825, 821, 813, 822, 818, 815, 823, 825, 816, 827, + 828, 824, 820, 831, 835, 819, 834, 826, 838, 834, + 839, 841, 844, 842, 843, 76, 839, 838, 831, 842, + 828, 835, 845, 843, 827, 829, 845, 829, 844, 848, + + 829, 846, 846, 841, 829, 847, 847, 829, 849, 850, + 848, 851, 852, 75, 829, 829, 855, 829, 852, 857, + 854, 855, 856, 850, 858, 859, 849, 862, 858, 865, + 861, 851, 853, 853, 853, 861, 853, 857, 860, 853, + 854, 864, 860, 856, 853, 866, 862, 863, 866, 859, + 853, 853, 863, 853, 865, 867, 864, 868, 860, 870, + 867, 867, 869, 869, 868, 871, 872, 872, 873, 874, + 871, 875, 874, 873, 870, 878, 875, 876, 876, 877, + 879, 877, 880, 881, 882, 884, 880, 878, 883, 885, + 885, 886, 887, 884, 888, 889, 889, 890, 891, 879, + + 892, 881, 69, 893, 882, 904, 886, 883, 888, 893, + 891, 894, 887, 895, 902, 890, 894, 903, 895, 896, + 896, 897, 892, 899, 900, 904, 897, 897, 899, 901, + 900, 901, 902, 905, 906, 908, 903, 907, 910, 914, + 906, 908, 907, 909, 910, 911, 909, 905, 912, 912, + 913, 913, 915, 911, 916, 918, 917, 914, 919, 918, + 915, 917, 920, 921, 922, 919, 923, 923, 924, 927, + 925, 928, 916, 926, 926, 927, 929, 924, 925, 921, + 920, 931, 932, 922, 933, 934, 935, 936, 937, 928, + 931, 938, 939, 940, 934, 929, 938, 939, 943, 944, + + 932, 935, 940, 937, 941, 945, 946, 941, 942, 948, + 933, 936, 943, 942, 945, 947, 949, 949, 950, 946, + 947, 947, 951, 948, 944, 952, 953, 954, 955, 963, + 957, 955, 957, 950, 952, 958, 958, 959, 960, 955, + 961, 951, 962, 960, 964, 954, 965, 962, 967, 963, + 953, 966, 968, 975, 970, 969, 972, 967, 959, 969, + 971, 961, 972, 976, 964, 973, 974, 977, 965, 975, + 978, 966, 970, 980, 973, 968, 978, 979, 974, 971, + 983, 977, 976, 981, 984, 979, 985, 980, 981, 982, + 982, 986, 987, 988, 989, 985, 990, 991, 1502, 983, + + 987, 992, 993, 994, 984, 996, 995, 999, 1502, 994, + 998, 986, 995, 988, 989, 1003, 991, 997, 990, 996, + 1000, 992, 993, 997, 998, 1001, 1000, 999, 1002, 1004, + 1005, 1001, 1002, 1006, 1003, 1005, 1007, 1007, 1008, 1009, + 1011, 1004, 1010, 1011, 1012, 1009, 1008, 1013, 1010, 1004, + 1014, 1016, 1015, 1019, 1006, 1018, 1014, 1017, 1017, 1020, + 1013, 1015, 1012, 1023, 1020, 1021, 1019, 1026, 1021, 1022, + 1027, 1016, 1024, 1018, 1022, 1022, 1024, 1028, 1023, 1025, + 1025, 1021, 1029, 1021, 1030, 1032, 1033, 1029, 1034, 1026, + 1027, 1034, 1028, 1036, 1037, 1038, 1040, 1041, 1041, 1045, + + 1033, 1040, 1034, 1030, 1042, 1049, 1036, 1050, 1042, 1032, + 1043, 1044, 1044, 1051, 1037, 1047, 1038, 1039, 1051, 1048, + 1039, 1050, 1039, 1049, 1045, 1043, 1039, 1046, 1039, 1052, + 1054, 1046, 1046, 1039, 1048, 1047, 1053, 1055, 1039, 1054, + 1056, 1053, 1053, 1052, 1056, 1057, 1059, 1058, 1058, 1060, + 1061, 1055, 1058, 1063, 1060, 1064, 1056, 1067, 1059, 1065, + 1057, 64, 1058, 1067, 1061, 1062, 1062, 1066, 1065, 1064, + 1068, 1069, 1066, 1070, 1063, 1068, 1073, 1069, 1072, 1070, + 1071, 1071, 1073, 1072, 1074, 1075, 1078, 1076, 1079, 1080, + 1081, 1082, 1082, 1079, 1083, 1086, 1085, 1088, 1078, 1083, + + 1087, 1084, 1081, 1080, 1075, 1076, 1074, 1077, 1077, 1084, + 1085, 1086, 1089, 1077, 1087, 1077, 1088, 1091, 1090, 1092, + 1093, 1077, 1094, 1091, 1092, 1095, 1077, 1077, 1096, 1097, + 1100, 1089, 1093, 1077, 1090, 1098, 1098, 1102, 1099, 1104, + 1094, 1095, 1099, 1102, 1105, 1103, 1096, 1097, 1103, 1105, + 1100, 1106, 1108, 1107, 1109, 1113, 1111, 1108, 1104, 1107, + 1112, 1114, 1115, 1116, 1106, 1111, 1117, 1114, 1119, 1112, + 1118, 1113, 1116, 1109, 1122, 1118, 1120, 1121, 1121, 1123, + 1124, 1126, 1127, 1115, 1125, 1117, 1129, 1126, 1119, 1124, + 1120, 1123, 1129, 1125, 1122, 1128, 1128, 1131, 1133, 1127, + + 1134, 1135, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1137, + 1170, 1138, 1133, 1131, 1142, 1143, 1144, 1170, 1145, 1148, + 1134, 1144, 1141, 1145, 1148, 1139, 1140, 1150, 1136, 1149, + 1143, 1154, 1142, 1152, 1149, 1153, 1150, 1151, 1151, 1152, + 1154, 1153, 1155, 1156, 1158, 1159, 1162, 59, 1161, 1161, + 1159, 1159, 1161, 1164, 1165, 1163, 1156, 1155, 1163, 1166, + 1158, 1162, 1167, 1168, 1166, 1169, 1173, 1164, 1171, 1172, + 1174, 1176, 1175, 1178, 1165, 1184, 1168, 1168, 1175, 1173, + 1177, 1169, 1167, 1180, 1171, 1174, 1177, 1172, 1178, 1179, + 1187, 1176, 1182, 1182, 1179, 1183, 1184, 1180, 1183, 1185, + + 1186, 1188, 1189, 1190, 1185, 1186, 1187, 1189, 1190, 1191, + 1188, 1193, 1194, 1195, 1196, 1200, 1197, 1193, 1199, 1195, + 1203, 1191, 1197, 1198, 1198, 1204, 1201, 1199, 1194, 1201, + 1202, 1202, 1205, 1200, 1206, 1196, 1207, 1206, 1203, 1208, + 1209, 1210, 1219, 1211, 1204, 1208, 1209, 1210, 1211, 1207, + 1212, 1213, 1205, 1214, 1215, 1212, 1217, 1213, 1214, 1218, + 1215, 1217, 1219, 1220, 1223, 1221, 1222, 1222, 1226, 1220, + 1221, 1224, 1225, 1226, 1227, 1228, 1231, 1218, 1233, 1223, + 1224, 1225, 1229, 1230, 1232, 1229, 1230, 1231, 1234, 1232, + 1235, 1236, 1227, 1237, 1228, 1238, 1233, 1236, 1239, 1237, + + 1234, 1240, 1240, 1239, 1241, 1242, 1243, 1245, 1244, 1235, + 1238, 1246, 1243, 1247, 1249, 1246, 1251, 1248, 1250, 1242, + 1244, 1253, 1250, 1241, 1256, 1245, 1248, 1254, 1255, 1255, + 1257, 1247, 1256, 1249, 1258, 1257, 1254, 1259, 1261, 1258, + 1253, 1251, 1263, 1262, 1264, 1266, 1265, 1267, 1267, 1264, + 1268, 1272, 1261, 1269, 1263, 1265, 1270, 1259, 1262, 1269, + 1266, 1271, 1270, 1273, 1277, 1281, 1272, 1274, 1278, 1271, + 1268, 1275, 1274, 1275, 1280, 1276, 1279, 1285, 1277, 1273, + 1276, 1279, 1278, 1282, 1281, 1283, 1282, 1284, 1290, 1280, + 1287, 1287, 1283, 1288, 1289, 1291, 1285, 1290, 1289, 1292, + + 1293, 1295, 1284, 1294, 1298, 1292, 1296, 1288, 1298, 1294, + 58, 1296, 1307, 1291, 1300, 1293, 1299, 1299, 1303, 1300, + 1296, 1295, 1296, 1301, 1301, 1296, 1302, 1304, 1306, 1305, + 1307, 1303, 1305, 1302, 1308, 1310, 1311, 1312, 1313, 1315, + 1310, 1304, 1317, 1308, 1313, 1314, 1316, 1306, 1322, 1312, + 1314, 1319, 1319, 1315, 1320, 1311, 1326, 1316, 1321, 1320, + 1323, 1317, 1324, 1321, 1325, 1323, 1324, 1327, 1322, 1328, + 1330, 1326, 1329, 1325, 1331, 1329, 1333, 1332, 1334, 1335, + 1336, 1331, 1327, 1337, 1329, 1330, 1336, 1339, 1328, 1332, + 1338, 1340, 1343, 1339, 1341, 1333, 1342, 1335, 1337, 1334, + + 1344, 1338, 1346, 1345, 1347, 1342, 1350, 1343, 1348, 1357, + 1349, 1340, 1338, 1353, 1341, 1345, 1349, 1354, 1352, 1344, + 1356, 1346, 1355, 1348, 1352, 1357, 1350, 1358, 1353, 1347, + 1355, 1354, 1358, 1359, 1361, 1362, 1360, 1363, 1364, 1364, + 1356, 1360, 1360, 1367, 1366, 1359, 1366, 1372, 1368, 1362, + 1363, 1372, 1369, 1361, 1365, 1365, 1367, 1368, 1369, 1365, + 1370, 1370, 1365, 1365, 1371, 1373, 1374, 1365, 1378, 1371, + 1375, 1376, 1374, 1365, 1373, 1375, 1376, 1365, 1377, 1377, + 1379, 1380, 1380, 1381, 1379, 1382, 1381, 1384, 1381, 1378, + 1380, 1383, 1385, 1387, 1386, 1388, 1387, 1389, 1385, 1384, + + 1386, 1388, 1390, 1391, 1392, 1382, 1389, 1393, 1391, 1383, + 1394, 1395, 53, 1396, 1402, 1397, 1394, 1395, 1392, 1396, + 1397, 1399, 1390, 1398, 1400, 1393, 1401, 1398, 1402, 1403, + 1403, 1401, 1405, 1400, 1399, 1408, 1404, 1404, 1400, 1404, + 1400, 1407, 1400, 1405, 1400, 1407, 1409, 1410, 1411, 1415, + 1408, 1412, 1412, 1413, 1413, 1414, 1416, 1411, 1417, 1418, + 1414, 1414, 1415, 1419, 1420, 1410, 1409, 1417, 1418, 1421, + 1416, 1422, 1423, 1424, 1421, 1419, 1425, 1426, 1427, 1428, + 1428, 1423, 1429, 1431, 1427, 1422, 1420, 1433, 1430, 1437, + 1434, 1426, 1424, 1432, 1429, 1425, 1430, 1431, 1432, 1434, + + 1435, 1433, 1436, 1438, 1439, 1439, 1440, 1435, 1438, 1441, + 1441, 1442, 1446, 1443, 1437, 1443, 1442, 1446, 1447, 1445, + 1436, 1440, 1445, 1448, 1449, 1449, 1450, 1451, 1451, 1452, + 1452, 1453, 1448, 1454, 1455, 1456, 1453, 1447, 1457, 1457, + 1458, 1459, 1460, 1461, 1462, 1460, 1450, 1463, 1464, 1465, + 1462, 1465, 1463, 1466, 1454, 1455, 1456, 1464, 1459, 1468, + 1458, 1469, 1468, 1461, 1469, 1470, 1471, 1472, 1473, 1474, + 1475, 1466, 1472, 1481, 1474, 1543, 1476, 1543, 1475, 1471, + 1470, 1476, 1473, 1477, 1478, 1480, 1477, 1479, 1479, 1478, + 1480, 1481, 1482, 1483, 1484, 1486, 1487, 1493, 1482, 1501, + + 1483, 1486, 1487, 1488, 1488, 1489, 1490, 1484, 1491, 1492, + 1489, 1490, 1494, 1497, 1491, 1498, 1493, 1501, 1492, 1495, + 1495, 1496, 1496, 1494, 1500, 1503, 1504, 1505, 1506, 1500, + 1507, 1508, 1509, 1497, 1506, 1498, 1507, 1508, 1511, 1512, + 1503, 1513, 1514, 1509, 1511, 1515, 1504, 1514, 1516, 1518, + 1505, 1515, 1517, 1512, 1519, 1513, 1520, 1520, 1521, 1512, + 1522, 1513, 1523, 1518, 1517, 1524, 1525, 1527, 1516, 1530, + 1524, 1528, 1519, 1526, 1526, 1531, 1528, 1533, 1521, 1532, + 1523, 1534, 1533, 1533, 1525, 1522, 1535, 1536, 1530, 1531, + 1527, 1538, 1532, 1537, 1539, 1540, 1536, 1549, 1541, 1534, + + 1544, 1537, 1542, 1541, 1535, 1538, 1541, 1547, 1549, 1539, + 1540, 1542, 1546, 1540, 1544, 1548, 1550, 1551, 1546, 1548, + 1552, 1550, 1550, 1547, 1553, 1554, 1555, 1556, 1558, 1557, + 1554, 1555, 1556, 1559, 1560, 1562, 1551, 1563, 1559, 1564, + 1565, 1565, 1553, 1567, 1568, 1569, 1552, 1557, 1558, 1562, + 1570, 1569, 1566, 1571, 1560, 1563, 1566, 1564, 1572, 1573, + 1574, 1567, 1570, 1568, 1575, 1576, 1577, 1578, 1580, 1571, + 1583, 1577, 48, 1573, 1578, 1574, 1579, 1572, 1581, 1575, + 1582, 1579, 1585, 1585, 1576, 1582, 1580, 1584, 1586, 1587, + 1588, 1583, 1581, 1589, 1589, 1590, 1584, 1592, 1587, 1591, + + 1596, 1590, 1597, 1586, 18, 1591, 1593, 1593, 1594, 1594, + 1588, 1592, 1595, 1606, 1598, 1599, 1596, 1606, 1595, 1598, + 1600, 1599, 1601, 1597, 1602, 1602, 1600, 1607, 1601, 1603, + 1603, 1605, 1605, 1609, 1608, 1611, 1607, 1612, 1614, 1610, + 1613, 1613, 1616, 1618, 1612, 1609, 1615, 1619, 1616, 1603, + 1611, 1603, 1608, 1610, 1615, 1617, 1620, 1618, 1614, 1621, + 1617, 1620, 1620, 1622, 1621, 1621, 1619, 1622, 1623, 1624, + 1624, 1625, 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1628, + 1634, 1629, 1627, 1633, 1635, 1637, 1634, 1636, 1623, 1635, + 1625, 1626, 1638, 1636, 1639, 1630, 1631, 1640, 1632, 1641, + + 1642, 1633, 1640, 1637, 1643, 1644, 1642, 1645, 1646, 1639, + 1647, 1644, 1638, 1645, 1648, 1649, 1650, 1651, 1652, 1647, + 1653, 1656, 1654, 1643, 1656, 1641, 1657, 1646, 1655, 1655, + 1658, 1659, 1652, 1648, 1649, 1650, 1651, 1654, 1660, 1660, + 1663, 1653, 1664, 1659, 1663, 1657, 1661, 1661, 1662, 1658, + 1665, 1666, 1673, 1662, 1667, 1664, 1670, 1673, 1670, 1674, + 1666, 1676, 1670, 1672, 1672, 1665, 1675, 1667, 1677, 1675, + 1676, 1678, 1679, 1677, 1680, 1670, 1682, 1674, 1681, 1681, + 1684, 1682, 1683, 1685, 1687, 1686, 1678, 1690, 1683, 1687, + 1680, 1686, 1679, 1688, 1689, 1684, 1685, 1688, 1689, 1691, + + 1692, 1693, 1694, 1695, 1695, 1697, 1699, 1690, 1694, 1692, + 1700, 1701, 1699, 1702, 1702, 1704, 1701, 1691, 1703, 1706, + 1706, 1693, 1708, 1697, 1703, 1708, 1709, 1709, 1710, 1711, + 1712, 1700, 1715, 1714, 1716, 1704, 1714, 1718, 1717, 1719, + 1719, 1720, 1721, 1722, 1710, 1711, 1712, 1717, 1729, 1723, + 1724, 1725, 1726, 1715, 1716, 1724, 1720, 1718, 1726, 1727, + 1727, 1728, 1722, 1721, 1723, 1725, 1729, 1730, 1731, 1732, + 1728, 1733, 1733, 1734, 1735, 1736, 1737, 1738, 1738, 1739, + 1736, 1740, 1730, 1739, 1741, 1741, 1742, 1734, 1743, 1732, + 1744, 1737, 1735, 1731, 1745, 1746, 1747, 1748, 1749, 1746, + + 1761, 1740, 1748, 1751, 1751, 1745, 1742, 1752, 1753, 1744, + 1743, 1753, 1752, 1752, 1754, 1747, 1755, 1756, 1749, 1757, + 1758, 1755, 1759, 1762, 1760, 1761, 1764, 1754, 1763, 1763, + 1765, 1764, 1762, 1756, 1758, 1766, 1767, 1757, 1760, 1769, + 1766, 1759, 1759, 1768, 1770, 1770, 1768, 1772, 1771, 1773, + 1765, 1774, 1772, 1774, 1775, 1776, 1767, 1771, 1769, 1775, + 1777, 1776, 1778, 1781, 1783, 1779, 1782, 1782, 1778, 1773, + 1779, 1784, 1790, 1785, 1788, 1786, 1794, 1781, 1785, 1788, + 1777, 1786, 1789, 1783, 1791, 1791, 1793, 1789, 1792, 1792, + 1784, 1795, 1796, 1798, 1794, 1796, 1790, 1797, 1797, 1800, + + 1793, 1799, 1801, 1802, 1803, 1801, 1795, 1804, 1801, 1807, + 1803, 1798, 1804, 1799, 1805, 1802, 1808, 1805, 1807, 1800, + 1801, 1808, 1809, 1810, 1811, 1811, 1810, 1812, 1813, 1814, + 1820, 1815, 1821, 1805, 1813, 1814, 1815, 1816, 1816, 1817, + 1817, 1819, 1818, 1820, 1822, 1823, 1819, 1809, 1818, 1824, + 1821, 1812, 1824, 1825, 1826, 1827, 1830, 1828, 1829, 1825, + 1826, 1827, 1828, 1822, 1829, 1823, 1831, 1832, 1832, 1833, + 1834, 1831, 1835, 1837, 1833, 1836, 1838, 1839, 1844, 1830, + 1840, 1843, 1841, 1845, 1842, 1847, 1848, 1845, 1834, 1850, + 1836, 1837, 1835, 1848, 1840, 1838, 1841, 1839, 1842, 1843, + + 1846, 1850, 1846, 1844, 1847, 1851, 1852, 1853, 1854, 1855, + 1856, 1858, 1857, 1853, 1858, 1859, 1859, 1851, 1860, 1852, + 1862, 1862, 1863, 1865, 1864, 1855, 1857, 1860, 1854, 1864, + 1856, 1867, 1858, 1866, 1866, 1865, 1868, 1869, 1870, 1871, + 1874, 1872, 1863, 1873, 1872, 1881, 1867, 1874, 1871, 1876, + 1868, 1875, 1878, 1880, 1961, 1872, 1870, 1872, 1873, 1872, + 1875, 1869, 1961, 1875, 1886, 1876, 1882, 1878, 1885, 1882, + 1881, 1880, 1878, 1883, 1883, 1884, 1884, 1887, 1888, 1889, + 1885, 1888, 1886, 1890, 1890, 1891, 1887, 1892, 1893, 1896, + 1894, 1895, 1896, 1893, 1889, 1897, 1895, 1898, 1891, 1899, + + 1900, 1901, 1902, 1903, 1899, 1905, 1892, 1894, 1910, 1904, + 17, 1902, 1908, 1908, 1906, 1898, 1897, 1901, 1904, 1900, + 1907, 1904, 1903, 1906, 1909, 1911, 1907, 1912, 1910, 1905, + 1913, 1909, 1914, 1920, 1915, 1917, 1916, 1921, 1911, 1915, + 1915, 1916, 1922, 1922, 1913, 1912, 1923, 1917, 1914, 1923, + 1924, 1925, 1926, 1926, 0, 1921, 1928, 1926, 1920, 1929, + 1925, 1927, 1927, 1934, 1930, 1928, 1924, 1930, 1928, 1931, + 1932, 1932, 1933, 1929, 1931, 1933, 1927, 1935, 1936, 1937, + 1939, 1934, 1940, 1941, 1937, 1937, 1942, 1943, 1945, 1944, + 1953, 1942, 1946, 1946, 1939, 1944, 1936, 1940, 1935, 1948, + + 1949, 1943, 1947, 1950, 1948, 1941, 1945, 1951, 1947, 1950, + 1953, 1954, 1955, 1951, 1949, 1956, 1957, 1959, 1963, 1958, + 1964, 1956, 1958, 1959, 1965, 1966, 1955, 1967, 1958, 1957, + 1975, 1954, 1967, 1966, 1969, 1968, 1970, 1963, 1971, 1964, + 1972, 1973, 1975, 1965, 1968, 1970, 1976, 1969, 1974, 1974, + 1977, 1971, 1976, 1979, 1972, 1973, 1977, 1978, 1980, 1980, + 1978, 1981, 1982, 1983, 1984, 1984, 1979, 1986, 1987, 1988, + 1974, 1985, 0, 1986, 1989, 1991, 1991, 1992, 1994, 1993, + 1982, 1981, 1983, 1993, 1985, 1988, 1995, 1996, 1997, 1998, + 1987, 1995, 1989, 1997, 1998, 1999, 2000, 1992, 1994, 2001, + + 2003, 2005, 2006, 2003, 1999, 2008, 2007, 1996, 2001, 2007, + 2009, 2006, 2005, 2011, 2003, 2010, 2010, 2008, 2012, 2000, + 2013, 2014, 2014, 2015, 2016, 2009, 2017, 2019, 2015, 2018, + 2012, 2020, 2011, 2017, 2019, 2021, 2022, 2025, 2016, 2013, + 2024, 2018, 2026, 2020, 2028, 2029, 2021, 2031, 2026, 2027, + 2031, 2029, 2030, 2030, 2032, 2035, 2022, 2025, 2037, 2024, + 2035, 2027, 2028, 2033, 2033, 2036, 2038, 2039, 2041, 2041, + 2040, 2036, 2042, 2037, 2032, 2038, 2040, 2043, 2044, 2043, + 2045, 2044, 2046, 2039, 2042, 2047, 2049, 2048, 2050, 2051, + 2052, 2049, 2053, 2050, 2054, 2057, 2055, 2056, 2051, 2054, + + 2045, 2055, 2052, 2047, 2046, 2048, 2056, 2053, 2058, 2059, + 2060, 2061, 2061, 2058, 2059, 2057, 2062, 2063, 2065, 2056, + 2058, 2066, 2062, 2067, 2069, 2060, 2070, 2068, 2070, 2072, + 2072, 2071, 2073, 2073, 2065, 2074, 2074, 2075, 2063, 2078, + 2066, 2079, 2067, 2068, 2069, 2071, 2080, 2071, 2076, 2076, + 2077, 2077, 2081, 2081, 2082, 2083, 2084, 2075, 2082, 2084, + 2078, 2083, 2079, 2086, 2087, 2088, 2089, 2080, 2090, 2086, + 2091, 2088, 2092, 2093, 2095, 2091, 2093, 2090, 2094, 2094, + 2096, 2098, 2087, 2097, 2097, 2096, 2099, 2100, 2101, 2089, + 2102, 2102, 2100, 2101, 2095, 2103, 2098, 2092, 2104, 2105, + + 2103, 2106, 2107, 2108, 2104, 2110, 2111, 2099, 2109, 2112, + 2113, 2105, 2105, 2105, 2109, 2113, 2112, 2116, 2105, 2117, + 2107, 2106, 2115, 2108, 2119, 2110, 2111, 2115, 2115, 2120, + 2118, 2116, 2118, 2121, 2117, 2119, 2122, 2123, 2124, 2121, + 2125, 2128, 2126, 2127, 2120, 2122, 2129, 2129, 2130, 2131, + 2131, 2132, 2124, 2133, 2134, 2134, 2137, 2123, 2141, 2125, + 2126, 2127, 2128, 2135, 2135, 2136, 2136, 2140, 2140, 2142, + 2143, 2132, 2146, 2142, 2130, 2133, 2137, 2144, 2144, 2143, + 2147, 2146, 2148, 2141, 2149, 2150, 2151, 2153, 2148, 2152, + 2154, 2154, 2155, 2153, 2156, 2159, 2160, 2160, 2158, 2157, + + 2162, 2147, 2151, 2152, 2150, 2149, 2157, 2158, 2163, 2156, + 2161, 2161, 2165, 2155, 2166, 2168, 2167, 2170, 2165, 2166, + 2169, 2159, 2167, 2170, 2163, 2173, 2162, 2169, 2171, 2176, + 2171, 2174, 2175, 2175, 2176, 2168, 2177, 2174, 2178, 2179, + 2181, 2180, 2182, 2181, 2173, 2177, 2183, 2184, 2185, 2183, + 2186, 2186, 2187, 2178, 2182, 2188, 2187, 2189, 2190, 2179, + 2180, 2191, 2191, 2189, 2193, 2184, 2192, 2194, 2197, 2195, + 2190, 2198, 2192, 2195, 2185, 2188, 2199, 2200, 2200, 2201, + 2202, 2199, 2194, 2203, 2193, 2205, 2206, 2209, 2197, 2195, + 2206, 2207, 2207, 2198, 2208, 2215, 2209, 2211, 2203, 2202, + + 2208, 2210, 2210, 2201, 2205, 2212, 2211, 2213, 2216, 2212, + 2214, 2214, 2217, 2219, 2218, 2220, 2215, 2221, 2213, 2218, + 2222, 2223, 2216, 2213, 2225, 2224, 2222, 2231, 2226, 2225, + 2229, 2217, 2232, 2219, 2229, 2220, 2231, 2221, 2233, 2223, + 2224, 2226, 2227, 2227, 2228, 2228, 2234, 2235, 2243, 2233, + 2271, 2232, 2235, 2271, 2233, 2236, 2236, 2238, 2238, 2239, + 2245, 2240, 2242, 2246, 2239, 2239, 2234, 2240, 2242, 2246, + 2244, 2248, 2245, 2249, 2243, 2244, 2250, 2249, 2251, 2252, + 2252, 2250, 2253, 2248, 2255, 2254, 2256, 2257, 2258, 2259, + 2251, 2254, 2256, 2261, 2259, 2260, 2260, 2262, 2264, 2263, + + 2267, 2266, 2257, 2258, 2263, 2276, 2255, 2253, 2278, 2268, + 2264, 2276, 2261, 2266, 2268, 2270, 2270, 2262, 2277, 2267, + 2272, 2272, 2273, 2273, 2274, 2274, 2275, 2275, 2278, 2279, + 2280, 2290, 2281, 2277, 2282, 2279, 2280, 2281, 2283, 2285, + 2282, 2291, 2288, 2286, 2285, 2288, 2289, 2283, 2286, 2286, + 2289, 2292, 2290, 2291, 2293, 2293, 2295, 2296, 2297, 2298, + 2298, 2299, 2300, 2297, 2303, 2303, 2292, 2300, 2295, 2296, + 2299, 2301, 2302, 2304, 2305, 2302, 2301, 2306, 2307, 2308, + 2309, 2310, 2311, 2305, 2309, 2308, 2310, 2312, 2311, 2313, + 2314, 2318, 2315, 2304, 2319, 2306, 2321, 2307, 2313, 2317, + + 2317, 2320, 2333, 2319, 2325, 2312, 2315, 2324, 2314, 2318, + 2320, 2317, 2322, 2322, 2323, 2326, 2321, 2327, 2333, 2324, + 2326, 2330, 2330, 2323, 2332, 2325, 2334, 2332, 2335, 2338, + 2327, 2337, 2339, 2340, 2341, 2341, 0, 2342, 2339, 2342, + 2343, 2344, 2334, 2338, 2335, 2345, 2337, 2344, 2346, 2346, + 2340, 2347, 2349, 2349, 2343, 2350, 2350, 2352, 2353, 2347, + 2354, 2355, 2356, 2345, 2353, 2357, 2354, 2362, 2358, 2356, + 2359, 2359, 2360, 2360, 2361, 2355, 2364, 2363, 2365, 2362, + 2352, 2360, 2366, 2367, 2368, 2373, 2370, 2357, 2358, 2363, + 2365, 2364, 2367, 2374, 2378, 2361, 2369, 2376, 2376, 2368, + + 2375, 2369, 2369, 2377, 2371, 2373, 2371, 2371, 2366, 2370, + 2371, 2383, 2375, 2384, 2378, 2379, 2374, 2380, 2379, 2381, + 2381, 2377, 2380, 2371, 2382, 2382, 2383, 2385, 2387, 2388, + 2389, 2388, 2384, 2387, 2390, 2391, 2394, 2396, 2400, 2390, + 2397, 2397, 2391, 2398, 2401, 2394, 2401, 2385, 2389, 2402, + 2400, 2403, 2398, 2404, 2405, 2396, 2406, 2409, 2407, 2409, + 2405, 2410, 2411, 2411, 2412, 2413, 2403, 2414, 2402, 2414, + 2413, 2418, 2420, 2404, 2416, 2410, 2406, 2407, 2407, 2416, + 2417, 2419, 2421, 2423, 2428, 2417, 2422, 0, 2421, 2418, + 2412, 2422, 2420, 2424, 2426, 2425, 2423, 2429, 2430, 2419, + + 2425, 2425, 2426, 2428, 2433, 2424, 2431, 2431, 2432, 2432, + 2430, 2429, 2434, 2435, 2436, 2433, 2437, 2438, 2439, 2438, + 2436, 2437, 2440, 2441, 2439, 2442, 2443, 2434, 2440, 2444, + 2446, 2442, 2443, 2435, 2445, 2445, 2451, 2444, 2447, 2447, + 2449, 2441, 2446, 2448, 2448, 2444, 2450, 2454, 2453, 2449, + 2456, 2450, 2453, 2455, 2451, 2455, 2454, 2457, 2458, 2454, + 2459, 2460, 2457, 2457, 2462, 2475, 2463, 2464, 2467, 2459, + 2458, 2456, 2464, 2460, 2465, 2468, 2469, 2462, 2463, 2465, + 2471, 2467, 2472, 2468, 2473, 2469, 2470, 2470, 2474, 2476, + 2475, 2477, 2478, 2480, 2482, 2468, 2481, 2478, 2471, 2487, + + 2472, 2496, 2473, 2476, 2474, 2480, 2477, 2484, 2481, 2483, + 2483, 2485, 2484, 2486, 2482, 2490, 2485, 2487, 2492, 2493, + 2494, 2490, 2486, 2495, 2492, 2500, 2496, 2497, 2498, 2498, + 2499, 2501, 2501, 2502, 2490, 2494, 2497, 2503, 2500, 2499, + 2504, 2495, 2493, 2505, 2504, 2506, 2507, 2508, 2505, 2509, + 2513, 2502, 2511, 2512, 2520, 2522, 2503, 2515, 2506, 2512, + 2507, 2514, 2508, 2515, 2516, 2517, 2514, 2514, 2517, 2509, + 2516, 2511, 2513, 2519, 2520, 2522, 2524, 2525, 2526, 2526, + 2528, 2519, 2527, 2527, 2529, 2529, 2530, 2530, 2531, 2528, + 2533, 2532, 2535, 2537, 2539, 2525, 2533, 2527, 2535, 2524, + + 2531, 2536, 2538, 2540, 2540, 2541, 2541, 2538, 2527, 2532, + 2542, 2543, 2539, 2537, 2545, 2542, 2536, 2543, 2545, 2546, + 2547, 2548, 2550, 2551, 2547, 2552, 2554, 2553, 2551, 2555, + 2557, 2556, 2558, 2559, 2555, 2560, 2561, 2561, 2559, 2546, + 2563, 2548, 2553, 2565, 2554, 2566, 2557, 2550, 2552, 2556, + 2562, 2564, 2558, 2568, 2562, 2563, 2564, 2560, 2567, 2569, + 2571, 2565, 2570, 2572, 2575, 2568, 2576, 2570, 2573, 2573, + 2577, 2566, 2575, 2571, 2578, 2579, 2567, 2580, 2569, 2582, + 2581, 2572, 2583, 2584, 2585, 2576, 2586, 2589, 0, 2577, + 2585, 2587, 2591, 2578, 2583, 2586, 2592, 2587, 2579, 2581, + + 2582, 2580, 2589, 2593, 2584, 2591, 2594, 2595, 2594, 2593, + 2592, 2596, 2596, 2597, 2598, 2599, 2600, 2598, 2597, 2601, + 2624, 2602, 2603, 2603, 2604, 2604, 2607, 2595, 2599, 2605, + 2608, 2605, 2624, 2601, 2602, 2606, 2606, 2609, 2610, 2610, + 2600, 2607, 2610, 2612, 2612, 2608, 2613, 2613, 2614, 2616, + 2609, 2615, 2615, 2617, 2617, 2618, 2618, 2619, 2616, 2621, + 2622, 2616, 2619, 2614, 2621, 2623, 2625, 2628, 2627, 2629, + 2629, 2630, 2630, 2631, 2632, 2632, 2628, 2633, 2635, 2625, + 2622, 2627, 2634, 2634, 2636, 2623, 2638, 2638, 2640, 2636, + 2639, 2639, 2631, 2635, 2641, 2633, 2642, 2643, 2643, 2646, + + 2644, 2647, 2640, 2641, 2645, 2645, 2648, 2649, 2646, 2651, + 2647, 2652, 2652, 2653, 2651, 2655, 2642, 2644, 2654, 2654, + 2648, 2658, 2656, 2657, 2658, 2661, 2649, 2656, 2662, 2657, + 2659, 2659, 2653, 2655, 2660, 2660, 2663, 2665, 2663, 2666, + 2667, 2667, 2668, 2662, 2661, 2670, 2659, 2671, 2668, 2672, + 2674, 2673, 2665, 2677, 2674, 2675, 2675, 2676, 2666, 2678, + 2680, 2686, 2671, 2679, 2680, 2670, 2673, 2682, 2679, 2683, + 2683, 2681, 2672, 2677, 2681, 2688, 2676, 2685, 2685, 2678, + 2687, 2686, 2682, 2681, 2683, 2689, 2690, 2687, 2692, 2688, + 2681, 2681, 2691, 2693, 2693, 2695, 2694, 2695, 2696, 2699, + + 2698, 2696, 2703, 2689, 2690, 2694, 2698, 2691, 2700, 2704, + 2701, 2699, 2702, 2700, 2692, 2701, 2696, 2702, 2696, 2705, + 2706, 2707, 2704, 2708, 2713, 2710, 2707, 2703, 2711, 2706, + 2710, 2712, 2714, 2711, 2716, 2715, 2712, 2717, 2714, 2713, + 2705, 2715, 2718, 2722, 2723, 2719, 2720, 2725, 2718, 2708, + 2719, 2720, 2717, 2724, 2726, 2716, 2724, 2723, 2730, 2731, + 2727, 2728, 2729, 2726, 2735, 2731, 2736, 2725, 2722, 2727, + 2728, 2729, 2730, 2732, 2733, 2738, 2739, 2741, 2733, 2732, + 2740, 2740, 2736, 2741, 2735, 2739, 2743, 2742, 2742, 2744, + 2746, 2745, 2743, 2745, 2749, 2738, 2742, 2747, 2747, 2746, + + 2744, 2748, 2751, 2752, 2753, 2753, 2748, 2754, 2755, 2761, + 2758, 2756, 2760, 2757, 2749, 2758, 2749, 2755, 2751, 2752, + 2756, 2757, 2754, 2762, 2760, 2761, 2765, 2763, 2766, 2765, + 2767, 2768, 2769, 2766, 2770, 2770, 2771, 2771, 2762, 2763, + 2768, 2772, 2772, 2773, 2769, 2774, 2774, 2776, 2776, 2777, + 2767, 2778, 2777, 2779, 2780, 2781, 2778, 2782, 2782, 2779, + 2780, 2783, 2785, 2773, 2781, 2784, 2784, 2786, 2786, 2787, + 2788, 2789, 2789, 2790, 2785, 2783, 2791, 2792, 2795, 2790, + 2794, 2795, 2792, 2787, 2794, 2796, 2796, 2797, 2798, 2788, + 2791, 2799, 2797, 2798, 2800, 2801, 2804, 2802, 2803, 2803, + + 2799, 2802, 2806, 2800, 2807, 2808, 2809, 2806, 2810, 2804, + 2811, 2812, 2813, 2814, 2811, 2801, 2819, 2813, 2817, 2814, + 2820, 2815, 2810, 2817, 2807, 2808, 2809, 2815, 2816, 2816, + 2821, 2812, 2818, 2818, 2819, 2822, 2823, 2824, 2824, 2820, + 2822, 2826, 2827, 2828, 2829, 2830, 2831, 2834, 2828, 2821, + 2829, 2830, 2836, 2826, 2831, 2837, 2834, 2823, 2827, 2832, + 2843, 2832, 2838, 2838, 2839, 2842, 2836, 2839, 2842, 2837, + 2840, 2840, 2845, 2844, 2850, 2843, 2844, 2846, 2846, 2849, + 2850, 2851, 2853, 2849, 2852, 2852, 2855, 2854, 2861, 2856, + 2863, 2853, 2854, 2851, 2864, 2855, 2856, 2867, 2845, 2859, + + 2859, 2868, 2867, 2870, 2863, 2871, 2861, 2869, 2869, 2873, + 2864, 2874, 2875, 2876, 2877, 2877, 2881, 2875, 2876, 2879, + 2879, 2870, 2881, 2882, 2874, 2884, 2871, 2868, 2883, 2883, + 2885, 2886, 2888, 2890, 2889, 2873, 2886, 2889, 2891, 2892, + 2892, 2884, 2894, 2882, 2895, 2890, 2898, 2899, 2896, 2897, + 2891, 2888, 2885, 2895, 2896, 2897, 2901, 2901, 2894, 2902, + 2903, 2906, 2899, 2904, 2898, 2905, 2904, 2905, 2902, 2903, + 2907, 2909, 2908, 2910, 2911, 2919, 2906, 2908, 2912, 2917, + 2909, 2914, 2914, 2915, 2915, 2907, 2916, 2926, 2919, 2918, + 2920, 2916, 2910, 2911, 2911, 2920, 2912, 2917, 2918, 2921, + + 2922, 2921, 2923, 2924, 2925, 2927, 2928, 2926, 2930, 2925, + 0, 2928, 2929, 2929, 2922, 2924, 2923, 2931, 2931, 2932, + 2932, 2933, 2933, 2930, 2934, 2927, 2935, 2936, 2935, 2937, + 2938, 2938, 2939, 2939, 2937, 2941, 2934, 2940, 2940, 2942, + 2943, 2944, 2945, 2948, 2946, 2936, 2951, 2941, 2947, 2947, + 2949, 2949, 2943, 2950, 2950, 2952, 2952, 2951, 2953, 2942, + 2946, 2944, 2948, 2945, 2954, 2955, 2956, 2957, 2958, 2959, + 2953, 2954, 2957, 2960, 2960, 2961, 2962, 2955, 2963, 2963, + 2964, 2965, 2966, 2967, 2961, 2968, 2956, 2972, 2958, 2959, + 2969, 2969, 2971, 2970, 2981, 2966, 2962, 2977, 2973, 2968, + + 2973, 2965, 2970, 2974, 2971, 2976, 2964, 2967, 2978, 2972, + 2975, 2975, 2977, 2980, 2976, 2974, 2981, 2982, 2985, 2983, + 2984, 2984, 2986, 2978, 2983, 2986, 2987, 2988, 2989, 2990, + 2990, 2980, 2988, 2989, 2991, 2991, 2992, 2993, 2993, 2982, + 2987, 2985, 2997, 2998, 2998, 3000, 3000, 3001, 2992, 3002, + 3003, 2997, 3004, 3006, 3007, 3008, 3009, 3011, 3010, 3012, + 3002, 3013, 3014, 3013, 0, 3001, 3011, 3004, 3015, 3003, + 3016, 3021, 3007, 3006, 3017, 3017, 3009, 3008, 3010, 3012, + 3019, 3022, 3014, 3023, 3019, 3021, 3015, 3026, 3016, 3020, + 3020, 3028, 3023, 3024, 3024, 3029, 3026, 3027, 3027, 3030, + + 3031, 3032, 3033, 3022, 3034, 3035, 3036, 3031, 3037, 3028, + 3038, 3039, 3037, 3029, 3038, 3042, 3032, 3030, 3039, 3043, + 3033, 3035, 3034, 3040, 3040, 3036, 3041, 3041, 3044, 3046, + 3046, 3047, 3047, 3048, 3044, 3042, 3049, 3043, 3050, 3048, + 3051, 3052, 3054, 3053, 3055, 3055, 3056, 3054, 3057, 3058, + 3059, 3060, 3061, 3062, 3049, 3051, 3050, 3053, 3062, 3068, + 3052, 3059, 3060, 3063, 3070, 3063, 3056, 3074, 3057, 3058, + 3064, 3064, 3061, 3065, 3076, 3065, 3066, 3066, 3068, 3069, + 3069, 3071, 3071, 3070, 3073, 3075, 3074, 3077, 3078, 3078, + 3079, 3080, 3077, 3073, 3076, 3081, 3080, 3075, 3082, 3083, + + 3081, 3084, 3087, 3082, 3089, 3088, 3091, 3089, 3090, 3090, + 3079, 3092, 3093, 3093, 3094, 3095, 3098, 3099, 0, 3083, + 3084, 3091, 3087, 3088, 3096, 3094, 3103, 3100, 3096, 3092, + 3095, 3098, 3099, 3100, 3101, 3102, 3102, 3105, 3101, 3103, + 3106, 3107, 3108, 3108, 3109, 3110, 3111, 3112, 3113, 3116, + 3105, 3114, 3110, 3106, 3115, 3119, 3107, 3109, 3109, 3124, + 3112, 0, 3115, 3120, 3111, 3117, 3117, 3119, 3113, 3116, + 3114, 3121, 3120, 3122, 3122, 3121, 3123, 3123, 3124, 3125, + 3125, 3126, 3127, 3128, 3129, 3130, 3126, 3131, 3131, 3133, + 3139, 3127, 3137, 3137, 3138, 3141, 3129, 3140, 3140, 3128, + + 3142, 3143, 3144, 3138, 3148, 3130, 3145, 3146, 3141, 0, + 3133, 3144, 3139, 3142, 3143, 3145, 3146, 3147, 3147, 3149, + 3151, 3151, 3154, 3156, 3148, 3157, 3158, 3154, 3156, 3159, + 3160, 3158, 3161, 3164, 3149, 3162, 3165, 3159, 3169, 3157, + 3167, 3161, 3168, 3162, 3172, 3167, 3174, 3168, 3164, 3160, + 3170, 3170, 3176, 3169, 3173, 3165, 3171, 3171, 3175, 3173, + 3178, 3174, 3180, 3175, 3172, 3177, 3177, 3178, 3179, 3181, + 3182, 3176, 3183, 3179, 3184, 3185, 3182, 3183, 3188, 3184, + 3180, 3187, 3187, 3189, 3190, 3190, 3195, 3181, 3189, 3185, + 3191, 3191, 3194, 3188, 3196, 3197, 3197, 3194, 3198, 3195, + + 3199, 3198, 3200, 3202, 3201, 3199, 3199, 3200, 3196, 3201, + 3203, 3204, 3207, 3205, 3206, 3204, 3203, 3202, 3205, 3206, + 3208, 3207, 3209, 3210, 3213, 3211, 3212, 3214, 3221, 3213, + 3209, 3211, 3212, 3215, 3215, 3208, 3217, 3218, 3219, 3214, + 3221, 3219, 3218, 3217, 3210, 3223, 3224, 3225, 3226, 3227, + 3223, 3224, 3225, 3233, 3228, 3229, 3230, 3230, 3231, 3233, + 3237, 3232, 3227, 3228, 3229, 3232, 3226, 3231, 3234, 3238, + 3239, 3242, 3243, 3234, 3244, 3238, 3239, 3245, 3237, 3246, + 3246, 3247, 3248, 0, 3250, 3253, 3251, 3255, 3247, 3261, + 3242, 3257, 3243, 3250, 3244, 3251, 3245, 3252, 3252, 3254, + + 3253, 3248, 3255, 3256, 3256, 3259, 3266, 3266, 3254, 3261, + 3257, 3263, 3265, 3267, 3263, 3268, 3265, 3269, 3271, 3278, + 3259, 3268, 3272, 3269, 3273, 3273, 3274, 3274, 3275, 3276, + 3276, 3277, 3282, 3281, 3275, 3287, 3279, 3271, 3267, 3277, + 3272, 3279, 3281, 3284, 3278, 3282, 3288, 3285, 3286, 3284, + 3285, 3290, 3286, 3287, 3289, 3289, 3292, 3292, 3293, 3294, + 3288, 3295, 3297, 3293, 3294, 3299, 3290, 3298, 3300, 3302, + 3302, 3301, 3303, 0, 3299, 3297, 3301, 3304, 3304, 3295, + 3310, 3298, 3305, 3305, 3307, 3307, 3314, 3308, 3309, 3310, + 3300, 3308, 3316, 3309, 3315, 3303, 3312, 3312, 3318, 3315, + + 3320, 3321, 3317, 3322, 3316, 0, 3314, 3317, 3317, 3335, + 3318, 3323, 3323, 3325, 3325, 3326, 3326, 3327, 3327, 3328, + 3320, 3321, 3328, 3322, 3329, 3330, 3332, 3332, 3333, 3335, + 3336, 3336, 3337, 3337, 3338, 3338, 3339, 3329, 3330, 3340, + 3340, 3341, 3342, 3343, 3344, 3344, 3333, 3345, 3346, 3346, + 3350, 3339, 3347, 3345, 3341, 3353, 3347, 3343, 3351, 3352, + 3342, 3353, 3352, 3351, 3351, 3357, 3354, 3356, 3364, 3358, + 3350, 3354, 3356, 3356, 3359, 3360, 3361, 3362, 3363, 3366, + 3366, 3360, 3361, 3362, 3363, 3376, 3365, 0, 3357, 3358, + 3365, 3369, 3369, 3364, 3359, 3370, 3371, 3373, 3374, 3377, + + 3370, 3374, 3377, 3371, 3379, 3373, 3378, 3378, 3380, 3381, + 3376, 3382, 3382, 3380, 3383, 3384, 3385, 3385, 3386, 3388, + 3387, 3379, 3379, 3387, 3389, 3395, 3395, 3381, 3390, 3384, + 3394, 3387, 3386, 3388, 3383, 3392, 3390, 3396, 3396, 3393, + 3392, 3392, 3401, 3389, 3393, 3393, 3397, 3397, 3403, 3394, + 3398, 3398, 3399, 3399, 3400, 3400, 3402, 3404, 3401, 3406, + 3405, 3402, 3407, 3409, 3411, 3408, 3406, 3410, 3403, 3405, + 3408, 3412, 3410, 3411, 3413, 3414, 3407, 3416, 3416, 3417, + 3417, 3418, 3409, 3404, 3418, 3419, 3420, 3420, 3422, 3423, + 3421, 3412, 3426, 3422, 3413, 3414, 3421, 3425, 3425, 3426, + + 3419, 3427, 3427, 3428, 3429, 3431, 3431, 3423, 3432, 3429, + 3433, 3434, 3434, 3435, 3438, 3440, 3445, 3432, 3446, 3433, + 3441, 3441, 3435, 3438, 3428, 3442, 3442, 3443, 3444, 3446, + 3447, 3443, 3448, 3440, 3449, 3445, 3451, 3444, 3452, 3449, + 3449, 3453, 3454, 3458, 3455, 3447, 3458, 3452, 3455, 3451, + 3456, 3456, 3448, 3457, 3459, 3460, 3453, 3454, 3457, 3459, + 3462, 3466, 3467, 3467, 3468, 3471, 3466, 3470, 3470, 3472, + 3460, 3473, 3475, 3475, 3477, 3462, 3476, 3476, 3468, 3471, + 3478, 3479, 3483, 3477, 3487, 3484, 3478, 3485, 3490, 3473, + 3484, 3488, 3492, 3479, 3472, 3535, 3485, 3488, 3494, 3535, + + 3490, 3495, 3498, 3494, 3487, 3500, 3495, 3483, 3496, 3496, + 3500, 3498, 3501, 3492, 3502, 3504, 3505, 3501, 3506, 3507, + 3507, 3509, 3509, 3507, 3510, 3510, 3504, 3512, 3502, 3505, + 3511, 3511, 3506, 3513, 3514, 3517, 3512, 3515, 3516, 3520, + 3517, 3521, 3521, 3522, 3523, 3520, 3524, 3524, 3522, 3523, + 3525, 3526, 3527, 3513, 3514, 3528, 3515, 3516, 3529, 3530, + 3528, 3532, 3539, 3526, 3536, 3530, 3533, 3533, 3525, 3536, + 3537, 3538, 3538, 3527, 3540, 3537, 3529, 3541, 3543, 3545, + 3545, 3539, 3547, 3548, 3549, 3551, 3532, 3550, 3552, 3540, + 3553, 3550, 3541, 3554, 3551, 3547, 3548, 3549, 3543, 3556, + + 3555, 3554, 3557, 3558, 3552, 3555, 3559, 3559, 3560, 3553, + 3561, 3562, 3563, 3563, 3557, 3564, 3564, 3560, 3569, 3556, + 3565, 3568, 3575, 3558, 3571, 3577, 3568, 3568, 3561, 3580, + 3571, 3581, 3569, 3572, 3572, 3573, 3573, 3562, 3584, 3565, + 3577, 3578, 3578, 3575, 3583, 3580, 3585, 3581, 3589, 3583, + 3590, 3585, 3588, 3588, 3584, 3591, 3592, 3593, 3593, 3590, + 3597, 3591, 3594, 3596, 3596, 3598, 3599, 3604, 3589, 3600, + 3601, 3605, 3602, 3606, 3597, 3602, 3603, 3603, 3611, 3592, + 3616, 3594, 3607, 3607, 3601, 3604, 3598, 3599, 3600, 3609, + 3612, 3606, 3605, 3617, 3613, 3609, 3612, 3620, 3611, 3613, + + 3618, 3618, 3616, 3619, 3619, 3621, 3622, 3622, 3624, 3623, + 3625, 3628, 3620, 3627, 3629, 3626, 3631, 3624, 3634, 3617, + 3623, 3626, 3833, 3628, 3833, 3621, 3622, 3630, 3630, 3631, + 3625, 3632, 3627, 3634, 3629, 3641, 3632, 3633, 3633, 3635, + 3636, 3642, 3635, 3636, 3637, 3637, 3643, 3641, 3644, 3645, + 3646, 3646, 3649, 3644, 3647, 3645, 3650, 3647, 3649, 3652, + 3654, 3642, 3653, 3653, 3652, 3654, 3643, 3655, 3660, 3656, + 3657, 3658, 3658, 3661, 3650, 3656, 3662, 3663, 3664, 3664, + 3660, 3665, 3666, 3667, 3669, 3669, 3655, 3657, 3657, 3673, + 3663, 3661, 3667, 3670, 3670, 3671, 3671, 3672, 3666, 3674, + + 3665, 3662, 3672, 3673, 3674, 3675, 3675, 3676, 3676, 3677, + 3677, 3678, 3679, 3680, 3680, 3681, 3682, 3683, 3688, 3684, + 3678, 3687, 3687, 3683, 3684, 3690, 3690, 3694, 3681, 3691, + 3691, 3695, 3697, 3679, 3688, 3698, 3699, 3700, 3701, 3701, + 3703, 3703, 3682, 3704, 3705, 3708, 3694, 3706, 3711, 3709, + 3710, 3710, 3695, 3712, 3697, 3699, 3714, 3698, 3709, 3700, + 3714, 3706, 3715, 3705, 3716, 3708, 3713, 3713, 3711, 3704, + 3718, 3717, 3723, 3712, 3719, 3721, 3716, 3717, 3719, 3722, + 3724, 3725, 3715, 3726, 3729, 3722, 3725, 3734, 3726, 0, + 3718, 3742, 3723, 3721, 3730, 3730, 3732, 3732, 3733, 3724, + + 3735, 3734, 3736, 3733, 3737, 3729, 3735, 3738, 3738, 3741, + 3739, 3742, 3737, 3744, 3736, 3739, 3745, 3744, 3746, 3747, + 3749, 3745, 3748, 3750, 3751, 3741, 3755, 3748, 3752, 3754, + 3756, 3757, 3749, 3760, 3752, 3750, 3759, 3754, 3746, 3747, + 3761, 3762, 3751, 3763, 3766, 3755, 3770, 3765, 3763, 3760, + 3756, 3757, 3765, 3767, 3759, 3768, 3772, 3761, 3761, 3767, + 3768, 3782, 3762, 3778, 3766, 3771, 3770, 3778, 3771, 3772, + 3776, 3776, 3777, 3777, 3783, 3786, 3782, 3785, 3785, 3783, + 3786, 3787, 3788, 3788, 3790, 3793, 3793, 3794, 3795, 3795, + 3799, 3795, 3796, 3796, 3799, 3796, 3797, 3797, 3801, 3790, + + 3787, 3798, 3798, 3801, 3798, 3802, 3794, 3803, 3803, 3804, + 3805, 3807, 3807, 3810, 3802, 3808, 3808, 3811, 3817, 3810, + 3812, 3813, 3818, 3811, 3805, 3821, 3812, 3804, 3822, 3813, + 3814, 3814, 3815, 3815, 3816, 3816, 3819, 3813, 3817, 3820, + 3820, 3819, 3818, 3821, 3825, 3826, 3827, 3828, 3822, 3829, + 3827, 0, 3826, 3831, 3832, 3834, 3828, 3835, 3835, 3836, + 3834, 3837, 3837, 3841, 3829, 3838, 3838, 3842, 3836, 3825, + 3847, 3831, 3839, 3839, 3832, 3840, 3840, 3844, 3843, 3848, + 3849, 3852, 3842, 3843, 3846, 3841, 3844, 3845, 0, 3844, + 3846, 3850, 3845, 3845, 3848, 3847, 3850, 3851, 3853, 3853, + + 3852, 3849, 3851, 3854, 3855, 3856, 3856, 3857, 3857, 3854, + 3855, 3858, 3859, 3862, 3862, 3863, 3867, 3859, 3864, 3864, + 3866, 3866, 3869, 3871, 3871, 3867, 3858, 3872, 3872, 3863, + 3873, 3873, 3874, 3874, 3875, 3875, 3877, 3877, 3878, 3878, + 3869, 3879, 3879, 3880, 3880, 3881, 3883, 3884, 3884, 3887, + 3888, 3890, 3889, 3891, 3891, 3883, 3889, 3894, 3894, 3897, + 3899, 3896, 3901, 3895, 3900, 3900, 3890, 3903, 3891, 3887, + 3888, 3881, 3895, 3896, 3904, 3899, 3902, 3902, 3905, 3897, + 3907, 3901, 3903, 3906, 3906, 3908, 3911, 3904, 3909, 3909, + 3905, 3912, 3912, 3916, 3917, 3919, 3921, 3908, 3916, 3907, + + 3918, 3911, 3924, 3918, 3920, 3920, 3923, 3927, 3924, 3923, + 3925, 3926, 3917, 3928, 3921, 3936, 3926, 3929, 3932, 3931, + 3941, 3919, 3938, 3938, 3925, 3931, 3927, 3932, 3935, 3942, + 3936, 3928, 3935, 3929, 3952, 3953, 3955, 3958, 3953, 3952, + 3957, 3956, 3957, 3959, 3962, 3955, 3941, 3960, 3969, 3942, + 3956, 3963, 3963, 3964, 3964, 3970, 3958, 3962, 3965, 3965, + 3967, 3967, 3959, 3959, 3970, 3960, 3971, 3972, 3973, 3973, + 3971, 3969, 3976, 3974, 3978, 3979, 3981, 3982, 3980, 3982, + 3978, 3981, 3983, 3984, 3984, 3986, 3976, 3972, 3974, 3980, + 3985, 3987, 3988, 3989, 3992, 3990, 3991, 3983, 3979, 3994, + + 3995, 3999, 3993, 3985, 3986, 3991, 3992, 3993, 3988, 3987, + 3990, 3996, 3995, 3997, 3998, 3998, 3996, 4000, 3989, 4003, + 3994, 3999, 4001, 4002, 4002, 4004, 4005, 4006, 4007, 4012, + 4000, 4013, 3997, 4007, 4005, 4001, 4014, 4014, 4017, 4003, + 4015, 4017, 4023, 4012, 4004, 4018, 4018, 4006, 4019, 4015, + 4024, 4013, 4028, 4019, 4020, 4020, 4021, 4021, 4022, 4022, + 4025, 4023, 4026, 4025, 4027, 4029, 4030, 4026, 4031, 4027, + 4024, 4032, 4030, 4033, 4034, 4034, 4035, 4028, 4033, 4045, + 4029, 0, 4031, 4032, 4036, 4036, 4037, 4037, 4038, 4038, + 4040, 4040, 4041, 4042, 4044, 4044, 4035, 4041, 4042, 4046, + + 4046, 4048, 4045, 4047, 4047, 4049, 4050, 4050, 4052, 4053, + 4055, 4056, 4059, 4059, 4060, 4060, 4048, 4061, 4062, 4065, + 4053, 4063, 4064, 4052, 4049, 4061, 4066, 4063, 4064, 4056, + 4067, 4068, 4076, 4065, 4055, 4077, 4068, 4062, 4079, 4066, + 4069, 4069, 4071, 4071, 4082, 4085, 4083, 4076, 4087, 4067, + 4077, 4086, 4086, 4079, 4088, 4090, 4091, 4092, 4088, 4085, + 4093, 4091, 4095, 4096, 4087, 4082, 4083, 4094, 4096, 4097, + 4098, 4098, 4101, 4093, 4097, 4090, 4092, 4102, 4103, 4104, + 4094, 4095, 4105, 4106, 4110, 4108, 4109, 4109, 4116, 4110, + 4113, 4111, 4119, 4101, 4108, 4113, 4103, 4111, 4102, 4104, + + 4105, 4114, 4106, 4112, 4112, 4115, 4114, 4116, 4117, 4120, + 4115, 4121, 4119, 4123, 4117, 4121, 4122, 4122, 4123, 4124, + 4124, 4125, 4127, 4128, 4129, 4130, 4127, 4131, 4132, 4120, + 4133, 4129, 4134, 0, 4132, 4135, 4135, 4136, 4136, 4125, + 4137, 4137, 4128, 4156, 4130, 4134, 4131, 4139, 4139, 4133, + 4141, 4142, 4142, 4143, 4144, 4141, 4145, 4146, 4147, 4144, + 4148, 4148, 4143, 4149, 4153, 4143, 4154, 4158, 4149, 4156, + 4154, 4147, 4157, 4157, 4163, 4145, 4146, 4153, 4159, 4159, + 4160, 4160, 4161, 4162, 4164, 4164, 4158, 4161, 4165, 4165, + 4162, 4166, 4167, 4163, 4167, 4169, 4166, 4168, 4168, 4170, + + 4171, 4173, 4169, 4172, 4176, 4176, 4170, 4177, 4172, 4179, + 4180, 4181, 4182, 4186, 4179, 4180, 4183, 4183, 4187, 4171, + 4173, 4185, 4185, 4188, 4188, 4200, 4177, 4189, 4189, 4190, + 4181, 4182, 4186, 4192, 4192, 4194, 4190, 4187, 4193, 4193, + 4196, 4199, 4194, 4201, 4200, 4196, 4199, 4202, 4202, 4203, + 4203, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4201, 4207, 4207, 4207, 4207, 4207, 4207, 4207, + 4208, 4208, 4208, 4208, 4208, 4208, 4208, 4209, 4209, 4209, + 4209, 4209, 4209, 4209, 4210, 4210, 4210, 4210, 4210, 4210, + 4210, 4211, 4211, 4211, 4211, 4211, 4211, 4211, 4212, 4212, + + 4212, 4212, 4212, 4212, 4212, 4213, 4213, 4213, 4213, 4213, + 4213, 4213, 4215, 4215, 0, 4215, 4215, 4215, 4215, 4216, + 4216, 0, 0, 0, 4216, 4216, 4217, 4217, 0, 0, + 4217, 0, 4217, 4218, 0, 0, 0, 0, 0, 4218, + 4219, 4219, 0, 0, 0, 4219, 4219, 4220, 0, 0, + 0, 0, 0, 4220, 4221, 4221, 0, 4221, 4221, 4221, + 4221, 4222, 0, 0, 0, 0, 0, 4222, 4223, 4223, + 0, 0, 0, 4223, 4223, 4224, 4224, 0, 4224, 4224, + 4224, 4224, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + + 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, 4206, + 4206, 4206, 4206 } ; static yy_state_type yy_last_accepting_state; @@ -3613,7 +3672,6 @@ char *yytext; #pragma GCC diagnostic ignored "-Wsign-compare" #endif -#include #include #ifdef HAVE_GLOB_H # include @@ -3785,7 +3843,7 @@ static void config_end_include(void) #endif #define YY_NO_INPUT 1 -#line 191 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 190 "/usr/src/usr.sbin/unbound/util/configlexer.lex" #ifndef YY_NO_UNPUT #define YY_NO_UNPUT 1 #endif @@ -3793,7 +3851,7 @@ static void config_end_include(void) #define YY_NO_INPUT 1 #endif -#line 3795 "" +#line 3853 "" #define INITIAL 0 #define quotedstring 1 @@ -4009,9 +4067,9 @@ YY_DECL } { -#line 211 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 210 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -#line 4013 "" +#line 4071 "" while ( 1 ) /* loops until end-of-file is reached */ { @@ -4044,13 +4102,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 4130 ) + if ( yy_current_state >= 4207 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 8042 ); + while ( yy_base[yy_current_state] != 8183 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -4076,1973 +4134,2008 @@ do_action: /* This label is used only to case 1: YY_RULE_SETUP -#line 212 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 211 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("SP ")); /* ignore */ } YY_BREAK case 2: YY_RULE_SETUP -#line 214 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 213 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { /* note that flex makes the longest match and '.' is any but not nl */ LEXOUT(("comment(%s) ", yytext)); /* ignore */ } YY_BREAK case 3: YY_RULE_SETUP -#line 217 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 216 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(0, VAR_SERVER) } YY_BREAK case 4: YY_RULE_SETUP -#line 218 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 217 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_QNAME_MINIMISATION) } YY_BREAK case 5: YY_RULE_SETUP -#line 219 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 218 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_QNAME_MINIMISATION_STRICT) } YY_BREAK case 6: YY_RULE_SETUP -#line 220 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 219 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_NUM_THREADS) } YY_BREAK case 7: YY_RULE_SETUP -#line 221 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 220 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VERBOSITY) } YY_BREAK case 8: YY_RULE_SETUP -#line 222 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 221 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PORT) } YY_BREAK case 9: YY_RULE_SETUP -#line 223 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 222 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_OUTGOING_RANGE) } YY_BREAK case 10: YY_RULE_SETUP -#line 224 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 223 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_OUTGOING_PORT_PERMIT) } YY_BREAK case 11: YY_RULE_SETUP -#line 225 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 224 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_OUTGOING_PORT_AVOID) } YY_BREAK case 12: YY_RULE_SETUP -#line 226 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 225 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_OUTGOING_NUM_TCP) } YY_BREAK case 13: YY_RULE_SETUP -#line 227 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 226 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INCOMING_NUM_TCP) } YY_BREAK case 14: YY_RULE_SETUP -#line 228 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 227 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DO_IP4) } YY_BREAK case 15: YY_RULE_SETUP -#line 229 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 228 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DO_IP6) } YY_BREAK case 16: YY_RULE_SETUP -#line 230 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 229 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DO_NAT64) } YY_BREAK case 17: YY_RULE_SETUP -#line 231 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 230 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PREFER_IP4) } YY_BREAK case 18: YY_RULE_SETUP -#line 232 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 231 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PREFER_IP6) } YY_BREAK case 19: YY_RULE_SETUP -#line 233 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 232 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DO_UDP) } YY_BREAK case 20: YY_RULE_SETUP -#line 234 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 233 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DO_TCP) } YY_BREAK case 21: YY_RULE_SETUP -#line 235 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 234 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TCP_UPSTREAM) } YY_BREAK case 22: YY_RULE_SETUP -#line 236 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 235 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TCP_MSS) } YY_BREAK case 23: YY_RULE_SETUP -#line 237 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 236 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_OUTGOING_TCP_MSS) } YY_BREAK case 24: YY_RULE_SETUP -#line 238 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 237 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TCP_IDLE_TIMEOUT) } YY_BREAK case 25: YY_RULE_SETUP -#line 239 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 238 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MAX_REUSE_TCP_QUERIES) } YY_BREAK case 26: YY_RULE_SETUP -#line 240 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 239 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TCP_REUSE_TIMEOUT) } YY_BREAK case 27: YY_RULE_SETUP -#line 241 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 240 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TCP_AUTH_QUERY_TIMEOUT) } YY_BREAK case 28: YY_RULE_SETUP -#line 242 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 241 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_EDNS_TCP_KEEPALIVE) } YY_BREAK case 29: YY_RULE_SETUP -#line 243 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 242 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_EDNS_TCP_KEEPALIVE_TIMEOUT) } YY_BREAK case 30: YY_RULE_SETUP -#line 244 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 243 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SOCK_QUEUE_TIMEOUT) } YY_BREAK case 31: YY_RULE_SETUP -#line 245 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 244 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SSL_UPSTREAM) } YY_BREAK case 32: YY_RULE_SETUP -#line 246 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 245 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SSL_UPSTREAM) } YY_BREAK case 33: YY_RULE_SETUP -#line 247 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 246 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SSL_SERVICE_KEY) } YY_BREAK case 34: YY_RULE_SETUP -#line 248 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 247 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SSL_SERVICE_KEY) } YY_BREAK case 35: YY_RULE_SETUP -#line 249 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 248 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SSL_SERVICE_PEM) } YY_BREAK case 36: YY_RULE_SETUP -#line 250 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 249 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SSL_SERVICE_PEM) } YY_BREAK case 37: YY_RULE_SETUP -#line 251 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 250 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SSL_PORT) } YY_BREAK case 38: YY_RULE_SETUP -#line 252 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 251 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SSL_PORT) } YY_BREAK case 39: YY_RULE_SETUP -#line 253 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 252 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_CERT_BUNDLE) } YY_BREAK case 40: YY_RULE_SETUP -#line 254 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 253 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_CERT_BUNDLE) } YY_BREAK case 41: YY_RULE_SETUP -#line 255 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 254 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_WIN_CERT) } YY_BREAK case 42: YY_RULE_SETUP -#line 256 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 255 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_WIN_CERT) } YY_BREAK case 43: YY_RULE_SETUP -#line 257 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 256 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_ADDITIONAL_PORT) } YY_BREAK case 44: YY_RULE_SETUP -#line 258 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 257 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_ADDITIONAL_PORT) } YY_BREAK case 45: YY_RULE_SETUP -#line 259 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 258 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_ADDITIONAL_PORT) } YY_BREAK case 46: YY_RULE_SETUP -#line 260 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 259 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_ADDITIONAL_PORT) } YY_BREAK case 47: YY_RULE_SETUP -#line 261 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 260 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_SESSION_TICKET_KEYS) } YY_BREAK case 48: YY_RULE_SETUP -#line 262 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 261 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_CIPHERS) } YY_BREAK case 49: YY_RULE_SETUP -#line 263 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 262 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_CIPHERSUITES) } YY_BREAK case 50: YY_RULE_SETUP -#line 264 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 263 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TLS_USE_SNI) } YY_BREAK case 51: YY_RULE_SETUP +#line 264 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +{ YDVAR(1, VAR_TLS_PROTOCOLS) } + YY_BREAK +case 52: +YY_RULE_SETUP #line 265 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HTTPS_PORT) } YY_BREAK -case 52: +case 53: YY_RULE_SETUP #line 266 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HTTP_ENDPOINT) } YY_BREAK -case 53: +case 54: YY_RULE_SETUP #line 267 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HTTP_MAX_STREAMS) } YY_BREAK -case 54: +case 55: YY_RULE_SETUP #line 268 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HTTP_QUERY_BUFFER_SIZE) } YY_BREAK -case 55: +case 56: YY_RULE_SETUP #line 269 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HTTP_RESPONSE_BUFFER_SIZE) } YY_BREAK -case 56: +case 57: YY_RULE_SETUP #line 270 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HTTP_NODELAY) } YY_BREAK -case 57: +case 58: YY_RULE_SETUP #line 271 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HTTP_NOTLS_DOWNSTREAM) } YY_BREAK -case 58: +case 59: YY_RULE_SETUP #line 272 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_QUIC_PORT) } YY_BREAK -case 59: +case 60: YY_RULE_SETUP #line 273 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_QUIC_SIZE) } YY_BREAK -case 60: +case 61: YY_RULE_SETUP #line 274 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_USE_SYSTEMD) } YY_BREAK -case 61: +case 62: YY_RULE_SETUP #line 275 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DO_DAEMONIZE) } YY_BREAK -case 62: +case 63: YY_RULE_SETUP #line 276 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INTERFACE) } YY_BREAK -case 63: +case 64: YY_RULE_SETUP #line 277 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INTERFACE) } YY_BREAK -case 64: +case 65: YY_RULE_SETUP #line 278 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_OUTGOING_INTERFACE) } YY_BREAK -case 65: +case 66: YY_RULE_SETUP #line 279 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INTERFACE_AUTOMATIC) } YY_BREAK -case 66: +case 67: YY_RULE_SETUP #line 280 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INTERFACE_AUTOMATIC_PORTS) } YY_BREAK -case 67: +case 68: YY_RULE_SETUP #line 281 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SO_RCVBUF) } YY_BREAK -case 68: +case 69: YY_RULE_SETUP #line 282 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SO_SNDBUF) } YY_BREAK -case 69: +case 70: YY_RULE_SETUP #line 283 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SO_REUSEPORT) } YY_BREAK -case 70: +case 71: YY_RULE_SETUP #line 284 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IP_TRANSPARENT) } YY_BREAK -case 71: +case 72: YY_RULE_SETUP #line 285 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IP_FREEBIND) } YY_BREAK -case 72: +case 73: YY_RULE_SETUP #line 286 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IP_DSCP) } YY_BREAK -case 73: +case 74: YY_RULE_SETUP #line 287 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CHROOT) } YY_BREAK -case 74: +case 75: YY_RULE_SETUP #line 288 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_USERNAME) } YY_BREAK -case 75: +case 76: YY_RULE_SETUP #line 289 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DIRECTORY) } YY_BREAK -case 76: +case 77: YY_RULE_SETUP #line 290 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOGFILE) } YY_BREAK -case 77: +case 78: YY_RULE_SETUP #line 291 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PIDFILE) } YY_BREAK -case 78: +case 79: YY_RULE_SETUP #line 292 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ROOT_HINTS) } YY_BREAK -case 79: +case 80: YY_RULE_SETUP #line 293 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_STREAM_WAIT_SIZE) } YY_BREAK -case 80: +case 81: YY_RULE_SETUP #line 294 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_EDNS_BUFFER_SIZE) } YY_BREAK -case 81: +case 82: YY_RULE_SETUP #line 295 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MSG_BUFFER_SIZE) } YY_BREAK -case 82: +case 83: YY_RULE_SETUP #line 296 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MSG_CACHE_SIZE) } YY_BREAK -case 83: +case 84: YY_RULE_SETUP #line 297 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MSG_CACHE_SLABS) } YY_BREAK -case 84: +case 85: YY_RULE_SETUP #line 298 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_RRSET_CACHE_SIZE) } YY_BREAK -case 85: +case 86: YY_RULE_SETUP #line 299 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_RRSET_CACHE_SLABS) } YY_BREAK -case 86: +case 87: YY_RULE_SETUP #line 300 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHE_MAX_TTL) } YY_BREAK -case 87: +case 88: YY_RULE_SETUP #line 301 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHE_MAX_NEGATIVE_TTL) } YY_BREAK -case 88: +case 89: YY_RULE_SETUP #line 302 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHE_MIN_NEGATIVE_TTL) } YY_BREAK -case 89: +case 90: YY_RULE_SETUP #line 303 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHE_MIN_TTL) } YY_BREAK -case 90: +case 91: YY_RULE_SETUP #line 304 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INFRA_HOST_TTL) } YY_BREAK -case 91: +case 92: YY_RULE_SETUP #line 305 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INFRA_LAME_TTL) } YY_BREAK -case 92: +case 93: YY_RULE_SETUP #line 306 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INFRA_CACHE_SLABS) } YY_BREAK -case 93: +case 94: YY_RULE_SETUP #line 307 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INFRA_CACHE_NUMHOSTS) } YY_BREAK -case 94: +case 95: YY_RULE_SETUP #line 308 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INFRA_CACHE_LAME_SIZE) } YY_BREAK -case 95: +case 96: YY_RULE_SETUP #line 309 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INFRA_CACHE_MIN_RTT) } YY_BREAK -case 96: +case 97: YY_RULE_SETUP #line 310 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INFRA_CACHE_MAX_RTT) } YY_BREAK -case 97: +case 98: YY_RULE_SETUP #line 311 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_INFRA_KEEP_PROBING) } YY_BREAK -case 98: +case 99: YY_RULE_SETUP #line 312 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_NUM_QUERIES_PER_THREAD) } YY_BREAK -case 99: +case 100: YY_RULE_SETUP #line 313 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_JOSTLE_TIMEOUT) } YY_BREAK -case 100: +case 101: YY_RULE_SETUP #line 314 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DELAY_CLOSE) } YY_BREAK -case 101: +case 102: YY_RULE_SETUP #line 315 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_UDP_CONNECT) } YY_BREAK -case 102: +case 103: YY_RULE_SETUP #line 316 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TARGET_FETCH_POLICY) } YY_BREAK -case 103: +case 104: YY_RULE_SETUP #line 317 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HARDEN_SHORT_BUFSIZE) } YY_BREAK -case 104: +case 105: YY_RULE_SETUP #line 318 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HARDEN_LARGE_QUERIES) } YY_BREAK -case 105: +case 106: YY_RULE_SETUP #line 319 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HARDEN_GLUE) } YY_BREAK -case 106: +case 107: YY_RULE_SETUP #line 320 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HARDEN_UNVERIFIED_GLUE) } YY_BREAK -case 107: +case 108: YY_RULE_SETUP #line 321 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HARDEN_DNSSEC_STRIPPED) } YY_BREAK -case 108: +case 109: YY_RULE_SETUP #line 322 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) } YY_BREAK -case 109: +case 110: YY_RULE_SETUP #line 323 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) } YY_BREAK -case 110: +case 111: YY_RULE_SETUP #line 324 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HARDEN_ALGO_DOWNGRADE) } YY_BREAK -case 111: +case 112: YY_RULE_SETUP #line 325 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HARDEN_UNKNOWN_ADDITIONAL) } YY_BREAK -case 112: +case 113: YY_RULE_SETUP #line 326 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_USE_CAPS_FOR_ID) } YY_BREAK -case 113: +case 114: YY_RULE_SETUP #line 327 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CAPS_WHITELIST) } YY_BREAK -case 114: +case 115: YY_RULE_SETUP #line 328 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CAPS_WHITELIST) } YY_BREAK -case 115: +case 116: YY_RULE_SETUP #line 329 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) } YY_BREAK -case 116: +case 117: YY_RULE_SETUP #line 330 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PRIVATE_ADDRESS) } YY_BREAK -case 117: +case 118: YY_RULE_SETUP #line 331 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PRIVATE_DOMAIN) } YY_BREAK -case 118: +case 119: YY_RULE_SETUP #line 332 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PREFETCH_KEY) } YY_BREAK -case 119: +case 120: YY_RULE_SETUP #line 333 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PREFETCH) } YY_BREAK -case 120: +case 121: YY_RULE_SETUP #line 334 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DENY_ANY) } YY_BREAK -case 121: +case 122: YY_RULE_SETUP #line 335 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(0, VAR_STUB_ZONE) } YY_BREAK -case 122: +case 123: YY_RULE_SETUP #line 336 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_NAME) } YY_BREAK -case 123: +case 124: YY_RULE_SETUP #line 337 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_STUB_ADDR) } YY_BREAK -case 124: +case 125: YY_RULE_SETUP #line 338 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_STUB_HOST) } YY_BREAK -case 125: +case 126: YY_RULE_SETUP #line 339 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_STUB_PRIME) } YY_BREAK -case 126: +case 127: YY_RULE_SETUP #line 340 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_STUB_FIRST) } YY_BREAK -case 127: +case 128: YY_RULE_SETUP #line 341 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_STUB_NO_CACHE) } YY_BREAK -case 128: +case 129: YY_RULE_SETUP #line 342 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_STUB_SSL_UPSTREAM) } YY_BREAK -case 129: +case 130: YY_RULE_SETUP #line 343 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_STUB_SSL_UPSTREAM) } YY_BREAK -case 130: +case 131: YY_RULE_SETUP #line 344 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_STUB_TCP_UPSTREAM) } YY_BREAK -case 131: +case 132: YY_RULE_SETUP #line 345 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(0, VAR_FORWARD_ZONE) } YY_BREAK -case 132: +case 133: YY_RULE_SETUP #line 346 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FORWARD_ADDR) } YY_BREAK -case 133: +case 134: YY_RULE_SETUP #line 347 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FORWARD_HOST) } YY_BREAK -case 134: +case 135: YY_RULE_SETUP #line 348 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FORWARD_FIRST) } YY_BREAK -case 135: +case 136: YY_RULE_SETUP #line 349 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FORWARD_NO_CACHE) } YY_BREAK -case 136: +case 137: YY_RULE_SETUP #line 350 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) } YY_BREAK -case 137: +case 138: YY_RULE_SETUP #line 351 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) } YY_BREAK -case 138: +case 139: YY_RULE_SETUP #line 352 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FORWARD_TCP_UPSTREAM) } YY_BREAK -case 139: +case 140: YY_RULE_SETUP #line 353 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(0, VAR_AUTH_ZONE) } YY_BREAK -case 140: +case 141: YY_RULE_SETUP #line 354 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(0, VAR_RPZ) } YY_BREAK -case 141: +case 142: YY_RULE_SETUP #line 355 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TAGS) } YY_BREAK -case 142: +case 143: YY_RULE_SETUP #line 356 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_RPZ_ACTION_OVERRIDE) } YY_BREAK -case 143: +case 144: YY_RULE_SETUP #line 357 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_RPZ_CNAME_OVERRIDE) } YY_BREAK -case 144: +case 145: YY_RULE_SETUP #line 358 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_RPZ_LOG) } YY_BREAK -case 145: +case 146: YY_RULE_SETUP #line 359 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_RPZ_LOG_NAME) } YY_BREAK -case 146: +case 147: YY_RULE_SETUP #line 360 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_RPZ_SIGNAL_NXDOMAIN_RA) } YY_BREAK -case 147: +case 148: YY_RULE_SETUP #line 361 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ZONEFILE) } YY_BREAK -case 148: +case 149: YY_RULE_SETUP #line 362 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MASTER) } YY_BREAK -case 149: +case 150: YY_RULE_SETUP #line 363 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MASTER) } YY_BREAK -case 150: +case 151: YY_RULE_SETUP #line 364 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_URL) } YY_BREAK -case 151: +case 152: YY_RULE_SETUP #line 365 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ALLOW_NOTIFY) } YY_BREAK -case 152: +case 153: YY_RULE_SETUP #line 366 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FOR_DOWNSTREAM) } YY_BREAK -case 153: +case 154: YY_RULE_SETUP #line 367 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FOR_UPSTREAM) } YY_BREAK -case 154: +case 155: YY_RULE_SETUP #line 368 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FALLBACK_ENABLED) } YY_BREAK -case 155: +case 156: YY_RULE_SETUP #line 369 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(0, VAR_VIEW) } YY_BREAK -case 156: +case 157: YY_RULE_SETUP #line 370 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VIEW_FIRST) } YY_BREAK -case 157: +case 158: YY_RULE_SETUP #line 371 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DO_NOT_QUERY_ADDRESS) } YY_BREAK -case 158: +case 159: YY_RULE_SETUP #line 372 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DO_NOT_QUERY_LOCALHOST) } YY_BREAK -case 159: +case 160: YY_RULE_SETUP #line 373 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(2, VAR_ACCESS_CONTROL) } YY_BREAK -case 160: +case 161: YY_RULE_SETUP #line 374 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(2, VAR_INTERFACE_ACTION) } YY_BREAK -case 161: +case 162: YY_RULE_SETUP #line 375 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SEND_CLIENT_SUBNET) } YY_BREAK -case 162: +case 163: YY_RULE_SETUP #line 376 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CLIENT_SUBNET_ZONE) } YY_BREAK -case 163: +case 164: YY_RULE_SETUP #line 377 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CLIENT_SUBNET_ALWAYS_FORWARD) } YY_BREAK -case 164: +case 165: YY_RULE_SETUP #line 378 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CLIENT_SUBNET_OPCODE) } YY_BREAK -case 165: +case 166: YY_RULE_SETUP #line 379 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MAX_CLIENT_SUBNET_IPV4) } YY_BREAK -case 166: +case 167: YY_RULE_SETUP #line 380 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MAX_CLIENT_SUBNET_IPV6) } YY_BREAK -case 167: +case 168: YY_RULE_SETUP #line 381 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MIN_CLIENT_SUBNET_IPV4) } YY_BREAK -case 168: +case 169: YY_RULE_SETUP #line 382 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MIN_CLIENT_SUBNET_IPV6) } YY_BREAK -case 169: +case 170: YY_RULE_SETUP #line 383 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MAX_ECS_TREE_SIZE_IPV4) } YY_BREAK -case 170: +case 171: YY_RULE_SETUP #line 384 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MAX_ECS_TREE_SIZE_IPV6) } YY_BREAK -case 171: +case 172: YY_RULE_SETUP #line 385 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HIDE_IDENTITY) } YY_BREAK -case 172: +case 173: YY_RULE_SETUP #line 386 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HIDE_VERSION) } YY_BREAK -case 173: +case 174: YY_RULE_SETUP #line 387 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HIDE_TRUSTANCHOR) } YY_BREAK -case 174: +case 175: YY_RULE_SETUP #line 388 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HIDE_HTTP_USER_AGENT) } YY_BREAK -case 175: +case 176: YY_RULE_SETUP #line 389 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IDENTITY) } YY_BREAK -case 176: +case 177: YY_RULE_SETUP #line 390 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VERSION) } YY_BREAK -case 177: +case 178: YY_RULE_SETUP #line 391 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_HTTP_USER_AGENT) } YY_BREAK -case 178: +case 179: YY_RULE_SETUP #line 392 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MODULE_CONF) } YY_BREAK -case 179: +case 180: YY_RULE_SETUP #line 393 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DLV_ANCHOR) } YY_BREAK -case 180: +case 181: YY_RULE_SETUP #line 394 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DLV_ANCHOR_FILE) } YY_BREAK -case 181: +case 182: YY_RULE_SETUP #line 395 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TRUST_ANCHOR_FILE) } YY_BREAK -case 182: +case 183: YY_RULE_SETUP #line 396 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_AUTO_TRUST_ANCHOR_FILE) } YY_BREAK -case 183: +case 184: YY_RULE_SETUP #line 397 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TRUSTED_KEYS_FILE) } YY_BREAK -case 184: +case 185: YY_RULE_SETUP #line 398 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TRUST_ANCHOR) } YY_BREAK -case 185: +case 186: YY_RULE_SETUP #line 399 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_TRUST_ANCHOR_SIGNALING) } YY_BREAK -case 186: +case 187: YY_RULE_SETUP #line 400 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ROOT_KEY_SENTINEL) } YY_BREAK -case 187: +case 188: YY_RULE_SETUP #line 401 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VAL_OVERRIDE_DATE) } YY_BREAK -case 188: +case 189: YY_RULE_SETUP #line 402 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VAL_SIG_SKEW_MIN) } YY_BREAK -case 189: +case 190: YY_RULE_SETUP #line 403 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VAL_SIG_SKEW_MAX) } YY_BREAK -case 190: +case 191: YY_RULE_SETUP #line 404 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VAL_MAX_RESTART) } YY_BREAK -case 191: +case 192: YY_RULE_SETUP #line 405 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_BOGUS_TTL) } YY_BREAK -case 192: +case 193: YY_RULE_SETUP #line 406 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VAL_CLEAN_ADDITIONAL) } YY_BREAK -case 193: +case 194: YY_RULE_SETUP #line 407 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VAL_PERMISSIVE_MODE) } YY_BREAK -case 194: +case 195: YY_RULE_SETUP #line 408 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_AGGRESSIVE_NSEC) } YY_BREAK -case 195: +case 196: YY_RULE_SETUP #line 409 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IGNORE_CD_FLAG) } YY_BREAK -case 196: +case 197: YY_RULE_SETUP #line 410 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DISABLE_EDNS_DO) } YY_BREAK -case 197: +case 198: YY_RULE_SETUP #line 411 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SERVE_EXPIRED) } YY_BREAK -case 198: +case 199: YY_RULE_SETUP #line 412 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SERVE_EXPIRED_TTL) } YY_BREAK -case 199: +case 200: YY_RULE_SETUP #line 413 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SERVE_EXPIRED_TTL_RESET) } YY_BREAK -case 200: +case 201: YY_RULE_SETUP #line 414 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SERVE_EXPIRED_REPLY_TTL) } YY_BREAK -case 201: +case 202: YY_RULE_SETUP #line 415 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SERVE_EXPIRED_CLIENT_TIMEOUT) } YY_BREAK -case 202: +case 203: YY_RULE_SETUP #line 416 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_EDE_SERVE_EXPIRED) } YY_BREAK -case 203: +case 204: YY_RULE_SETUP #line 417 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_SERVE_ORIGINAL_TTL) } YY_BREAK -case 204: +case 205: YY_RULE_SETUP #line 418 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FAKE_DSA) } YY_BREAK -case 205: +case 206: YY_RULE_SETUP #line 419 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FAKE_SHA1) } YY_BREAK -case 206: +case 207: YY_RULE_SETUP #line 420 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VAL_LOG_LEVEL) } YY_BREAK -case 207: +case 208: YY_RULE_SETUP #line 421 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_KEY_CACHE_SIZE) } YY_BREAK -case 208: +case 209: YY_RULE_SETUP #line 422 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_KEY_CACHE_SLABS) } YY_BREAK -case 209: +case 210: YY_RULE_SETUP #line 423 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_NEG_CACHE_SIZE) } YY_BREAK -case 210: +case 211: YY_RULE_SETUP #line 424 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_VAL_NSEC3_KEYSIZE_ITERATIONS) } YY_BREAK -case 211: +case 212: YY_RULE_SETUP #line 426 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ZONEMD_PERMISSIVE_MODE) } YY_BREAK -case 212: +case 213: YY_RULE_SETUP #line 427 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ZONEMD_CHECK) } YY_BREAK -case 213: +case 214: YY_RULE_SETUP #line 428 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ZONEMD_REJECT_ABSENCE) } YY_BREAK -case 214: +case 215: YY_RULE_SETUP #line 429 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ADD_HOLDDOWN) } YY_BREAK -case 215: +case 216: YY_RULE_SETUP #line 430 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DEL_HOLDDOWN) } YY_BREAK -case 216: +case 217: YY_RULE_SETUP #line 431 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_KEEP_MISSING) } YY_BREAK -case 217: +case 218: YY_RULE_SETUP #line 432 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PERMIT_SMALL_HOLDDOWN) } YY_BREAK -case 218: +case 219: YY_RULE_SETUP #line 433 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_USE_SYSLOG) } YY_BREAK -case 219: +case 220: YY_RULE_SETUP #line 434 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOG_IDENTITY) } YY_BREAK -case 220: +case 221: YY_RULE_SETUP #line 435 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOG_TIME_ASCII) } YY_BREAK -case 221: +case 222: YY_RULE_SETUP #line 436 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOG_TIME_ISO) } YY_BREAK -case 222: +case 223: YY_RULE_SETUP #line 437 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOG_QUERIES) } YY_BREAK -case 223: +case 224: YY_RULE_SETUP #line 438 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOG_REPLIES) } YY_BREAK -case 224: +case 225: YY_RULE_SETUP #line 439 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOG_TAG_QUERYREPLY) } YY_BREAK -case 225: +case 226: YY_RULE_SETUP #line 440 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOG_LOCAL_ACTIONS) } YY_BREAK -case 226: +case 227: YY_RULE_SETUP #line 441 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOG_SERVFAIL) } YY_BREAK -case 227: +case 228: YY_RULE_SETUP #line 442 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_LOG_DESTADDR) } YY_BREAK -case 228: +case 229: YY_RULE_SETUP #line 443 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_LOCAL_ZONE) } +{ YDVAR(1, VAR_LOG_THREAD_ID) } YY_BREAK -case 229: +case 230: YY_RULE_SETUP #line 444 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_LOCAL_DATA) } +{ YDVAR(2, VAR_LOCAL_ZONE) } YY_BREAK -case 230: +case 231: YY_RULE_SETUP #line 445 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_LOCAL_DATA_PTR) } +{ YDVAR(1, VAR_LOCAL_DATA) } YY_BREAK -case 231: +case 232: YY_RULE_SETUP #line 446 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_UNBLOCK_LAN_ZONES) } +{ YDVAR(1, VAR_LOCAL_DATA_PTR) } YY_BREAK -case 232: +case 233: YY_RULE_SETUP #line 447 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_INSECURE_LAN_ZONES) } +{ YDVAR(1, VAR_UNBLOCK_LAN_ZONES) } YY_BREAK -case 233: +case 234: YY_RULE_SETUP #line 448 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_STATISTICS_INTERVAL) } +{ YDVAR(1, VAR_INSECURE_LAN_ZONES) } YY_BREAK -case 234: +case 235: YY_RULE_SETUP #line 449 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_STATISTICS_CUMULATIVE) } +{ YDVAR(1, VAR_STATISTICS_INTERVAL) } YY_BREAK -case 235: +case 236: YY_RULE_SETUP #line 450 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_EXTENDED_STATISTICS) } +{ YDVAR(1, VAR_STATISTICS_CUMULATIVE) } YY_BREAK -case 236: +case 237: YY_RULE_SETUP #line 451 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_STATISTICS_INHIBIT_ZERO) } +{ YDVAR(1, VAR_EXTENDED_STATISTICS) } YY_BREAK -case 237: +case 238: YY_RULE_SETUP #line 452 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_SHM_ENABLE) } +{ YDVAR(1, VAR_STATISTICS_INHIBIT_ZERO) } YY_BREAK -case 238: +case 239: YY_RULE_SETUP #line 453 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_SHM_KEY) } +{ YDVAR(1, VAR_SHM_ENABLE) } YY_BREAK -case 239: +case 240: YY_RULE_SETUP #line 454 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(0, VAR_REMOTE_CONTROL) } +{ YDVAR(1, VAR_SHM_KEY) } YY_BREAK -case 240: +case 241: YY_RULE_SETUP #line 455 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_ENABLE) } +{ YDVAR(0, VAR_REMOTE_CONTROL) } YY_BREAK -case 241: +case 242: YY_RULE_SETUP #line 456 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_INTERFACE) } +{ YDVAR(1, VAR_CONTROL_ENABLE) } YY_BREAK -case 242: +case 243: YY_RULE_SETUP #line 457 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_PORT) } +{ YDVAR(1, VAR_CONTROL_INTERFACE) } YY_BREAK -case 243: +case 244: YY_RULE_SETUP #line 458 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_USE_CERT) } +{ YDVAR(1, VAR_CONTROL_PORT) } YY_BREAK -case 244: +case 245: YY_RULE_SETUP #line 459 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_SERVER_KEY_FILE) } +{ YDVAR(1, VAR_CONTROL_USE_CERT) } YY_BREAK -case 245: +case 246: YY_RULE_SETUP #line 460 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_SERVER_CERT_FILE) } +{ YDVAR(1, VAR_SERVER_KEY_FILE) } YY_BREAK -case 246: +case 247: YY_RULE_SETUP #line 461 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_KEY_FILE) } +{ YDVAR(1, VAR_SERVER_CERT_FILE) } YY_BREAK -case 247: +case 248: YY_RULE_SETUP #line 462 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_CERT_FILE) } +{ YDVAR(1, VAR_CONTROL_KEY_FILE) } YY_BREAK -case 248: +case 249: YY_RULE_SETUP #line 463 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_PYTHON_SCRIPT) } +{ YDVAR(1, VAR_CONTROL_CERT_FILE) } YY_BREAK -case 249: +case 250: YY_RULE_SETUP #line 464 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(0, VAR_PYTHON) } +{ YDVAR(1, VAR_PYTHON_SCRIPT) } YY_BREAK -case 250: +case 251: YY_RULE_SETUP #line 465 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DYNLIB_FILE) } +{ YDVAR(0, VAR_PYTHON) } YY_BREAK -case 251: +case 252: YY_RULE_SETUP #line 466 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(0, VAR_DYNLIB) } +{ YDVAR(1, VAR_DYNLIB_FILE) } YY_BREAK -case 252: +case 253: YY_RULE_SETUP #line 467 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DOMAIN_INSECURE) } +{ YDVAR(0, VAR_DYNLIB) } YY_BREAK -case 253: +case 254: YY_RULE_SETUP #line 468 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_MINIMAL_RESPONSES) } +{ YDVAR(1, VAR_DOMAIN_INSECURE) } YY_BREAK -case 254: +case 255: YY_RULE_SETUP #line 469 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_RRSET_ROUNDROBIN) } +{ YDVAR(1, VAR_MINIMAL_RESPONSES) } YY_BREAK -case 255: +case 256: YY_RULE_SETUP #line 470 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_UNKNOWN_SERVER_TIME_LIMIT) } +{ YDVAR(1, VAR_RRSET_ROUNDROBIN) } YY_BREAK -case 256: +case 257: YY_RULE_SETUP #line 471 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DISCARD_TIMEOUT) } +{ YDVAR(1, VAR_UNKNOWN_SERVER_TIME_LIMIT) } YY_BREAK -case 257: +case 258: YY_RULE_SETUP #line 472 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_WAIT_LIMIT) } +{ YDVAR(1, VAR_DISCARD_TIMEOUT) } YY_BREAK -case 258: +case 259: YY_RULE_SETUP #line 473 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_WAIT_LIMIT_COOKIE) } +{ YDVAR(1, VAR_WAIT_LIMIT) } YY_BREAK -case 259: +case 260: YY_RULE_SETUP #line 474 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_WAIT_LIMIT_NETBLOCK) } +{ YDVAR(1, VAR_WAIT_LIMIT_COOKIE) } YY_BREAK -case 260: +case 261: YY_RULE_SETUP #line 475 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_WAIT_LIMIT_COOKIE_NETBLOCK) } +{ YDVAR(2, VAR_WAIT_LIMIT_NETBLOCK) } YY_BREAK -case 261: +case 262: YY_RULE_SETUP #line 476 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_MAX_UDP_SIZE) } +{ YDVAR(2, VAR_WAIT_LIMIT_COOKIE_NETBLOCK) } YY_BREAK -case 262: +case 263: YY_RULE_SETUP #line 477 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNS64_PREFIX) } +{ YDVAR(1, VAR_MAX_UDP_SIZE) } YY_BREAK -case 263: +case 264: YY_RULE_SETUP #line 478 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNS64_SYNTHALL) } +{ YDVAR(1, VAR_DNS64_PREFIX) } YY_BREAK -case 264: +case 265: YY_RULE_SETUP #line 479 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNS64_IGNORE_AAAA) } +{ YDVAR(1, VAR_DNS64_SYNTHALL) } YY_BREAK -case 265: +case 266: YY_RULE_SETUP #line 480 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_NAT64_PREFIX) } +{ YDVAR(1, VAR_DNS64_IGNORE_AAAA) } YY_BREAK -case 266: +case 267: YY_RULE_SETUP #line 481 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DEFINE_TAG) } +{ YDVAR(1, VAR_NAT64_PREFIX) } YY_BREAK -case 267: +case 268: YY_RULE_SETUP #line 482 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_LOCAL_ZONE_TAG) } +{ YDVAR(1, VAR_DEFINE_TAG) } YY_BREAK -case 268: +case 269: YY_RULE_SETUP #line 483 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_ACCESS_CONTROL_TAG) } +{ YDVAR(2, VAR_LOCAL_ZONE_TAG) } YY_BREAK -case 269: +case 270: YY_RULE_SETUP #line 484 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(3, VAR_ACCESS_CONTROL_TAG_ACTION) } +{ YDVAR(2, VAR_ACCESS_CONTROL_TAG) } YY_BREAK -case 270: +case 271: YY_RULE_SETUP #line 485 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(3, VAR_ACCESS_CONTROL_TAG_DATA) } +{ YDVAR(3, VAR_ACCESS_CONTROL_TAG_ACTION) } YY_BREAK -case 271: +case 272: YY_RULE_SETUP #line 486 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_ACCESS_CONTROL_VIEW) } +{ YDVAR(3, VAR_ACCESS_CONTROL_TAG_DATA) } YY_BREAK -case 272: +case 273: YY_RULE_SETUP #line 487 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_INTERFACE_TAG) } +{ YDVAR(2, VAR_ACCESS_CONTROL_VIEW) } YY_BREAK -case 273: +case 274: YY_RULE_SETUP #line 488 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(3, VAR_INTERFACE_TAG_ACTION) } +{ YDVAR(2, VAR_INTERFACE_TAG) } YY_BREAK -case 274: +case 275: YY_RULE_SETUP #line 489 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(3, VAR_INTERFACE_TAG_DATA) } +{ YDVAR(3, VAR_INTERFACE_TAG_ACTION) } YY_BREAK -case 275: +case 276: YY_RULE_SETUP #line 490 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_INTERFACE_VIEW) } +{ YDVAR(3, VAR_INTERFACE_TAG_DATA) } YY_BREAK -case 276: +case 277: YY_RULE_SETUP #line 491 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(3, VAR_LOCAL_ZONE_OVERRIDE) } +{ YDVAR(2, VAR_INTERFACE_VIEW) } YY_BREAK -case 277: +case 278: YY_RULE_SETUP #line 492 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(0, VAR_DNSTAP) } +{ YDVAR(3, VAR_LOCAL_ZONE_OVERRIDE) } YY_BREAK -case 278: +case 279: YY_RULE_SETUP #line 493 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_ENABLE) } +{ YDVAR(0, VAR_DNSTAP) } YY_BREAK -case 279: +case 280: YY_RULE_SETUP #line 494 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_BIDIRECTIONAL) } +{ YDVAR(1, VAR_DNSTAP_ENABLE) } YY_BREAK -case 280: +case 281: YY_RULE_SETUP #line 495 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_SOCKET_PATH) } +{ YDVAR(1, VAR_DNSTAP_BIDIRECTIONAL) } YY_BREAK -case 281: +case 282: YY_RULE_SETUP #line 496 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_IP) } +{ YDVAR(1, VAR_DNSTAP_SOCKET_PATH) } YY_BREAK -case 282: +case 283: YY_RULE_SETUP #line 497 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_TLS) } +{ YDVAR(1, VAR_DNSTAP_IP) } YY_BREAK -case 283: +case 284: YY_RULE_SETUP #line 498 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_TLS_SERVER_NAME) } +{ YDVAR(1, VAR_DNSTAP_TLS) } YY_BREAK -case 284: +case 285: YY_RULE_SETUP #line 499 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_TLS_CERT_BUNDLE) } +{ YDVAR(1, VAR_DNSTAP_TLS_SERVER_NAME) } YY_BREAK -case 285: +case 286: YY_RULE_SETUP #line 500 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +{ YDVAR(1, VAR_DNSTAP_TLS_CERT_BUNDLE) } + YY_BREAK +case 287: +YY_RULE_SETUP +#line 501 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_TLS_CLIENT_KEY_FILE) } YY_BREAK -case 286: +case 288: YY_RULE_SETUP -#line 502 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 503 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_TLS_CLIENT_CERT_FILE) } YY_BREAK -case 287: +case 289: YY_RULE_SETUP -#line 504 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 505 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_SEND_IDENTITY) } YY_BREAK -case 288: +case 290: YY_RULE_SETUP -#line 505 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 506 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_SEND_VERSION) } YY_BREAK -case 289: +case 291: YY_RULE_SETUP -#line 506 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 507 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_IDENTITY) } YY_BREAK -case 290: +case 292: YY_RULE_SETUP -#line 507 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 508 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_VERSION) } YY_BREAK -case 291: +case 293: YY_RULE_SETUP -#line 508 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 509 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES) } YY_BREAK -case 292: +case 294: YY_RULE_SETUP -#line 510 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 511 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES) } YY_BREAK -case 293: +case 295: YY_RULE_SETUP -#line 512 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 513 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES) } YY_BREAK -case 294: +case 296: YY_RULE_SETUP -#line 514 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 515 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES) } YY_BREAK -case 295: +case 297: YY_RULE_SETUP -#line 516 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 517 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) } YY_BREAK -case 296: +case 298: YY_RULE_SETUP -#line 518 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 519 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) } YY_BREAK -case 297: -YY_RULE_SETUP -#line 520 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_SAMPLE_RATE) } - YY_BREAK -case 298: +case 299: YY_RULE_SETUP #line 521 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DISABLE_DNSSEC_LAME_CHECK) } +{ YDVAR(1, VAR_DNSTAP_SAMPLE_RATE) } YY_BREAK -case 299: +case 300: YY_RULE_SETUP #line 522 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_IP_RATELIMIT) } +{ YDVAR(1, VAR_DISABLE_DNSSEC_LAME_CHECK) } YY_BREAK -case 300: +case 301: YY_RULE_SETUP #line 523 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_IP_RATELIMIT_COOKIE) } +{ YDVAR(1, VAR_IP_RATELIMIT) } YY_BREAK -case 301: +case 302: YY_RULE_SETUP #line 524 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_RATELIMIT) } +{ YDVAR(1, VAR_IP_RATELIMIT_COOKIE) } YY_BREAK -case 302: +case 303: YY_RULE_SETUP #line 525 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_IP_RATELIMIT_SLABS) } +{ YDVAR(1, VAR_RATELIMIT) } YY_BREAK -case 303: +case 304: YY_RULE_SETUP #line 526 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_RATELIMIT_SLABS) } +{ YDVAR(1, VAR_IP_RATELIMIT_SLABS) } YY_BREAK -case 304: +case 305: YY_RULE_SETUP #line 527 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_IP_RATELIMIT_SIZE) } +{ YDVAR(1, VAR_RATELIMIT_SLABS) } YY_BREAK -case 305: +case 306: YY_RULE_SETUP #line 528 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_RATELIMIT_SIZE) } +{ YDVAR(1, VAR_IP_RATELIMIT_SIZE) } YY_BREAK -case 306: +case 307: YY_RULE_SETUP #line 529 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) } +{ YDVAR(1, VAR_RATELIMIT_SIZE) } YY_BREAK -case 307: +case 308: YY_RULE_SETUP #line 530 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) } +{ YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) } YY_BREAK -case 308: +case 309: YY_RULE_SETUP #line 531 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_IP_RATELIMIT_FACTOR) } +{ YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) } YY_BREAK -case 309: +case 310: YY_RULE_SETUP #line 532 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_RATELIMIT_FACTOR) } +{ YDVAR(1, VAR_IP_RATELIMIT_FACTOR) } YY_BREAK -case 310: +case 311: YY_RULE_SETUP #line 533 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_IP_RATELIMIT_BACKOFF) } +{ YDVAR(1, VAR_RATELIMIT_FACTOR) } YY_BREAK -case 311: +case 312: YY_RULE_SETUP #line 534 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_RATELIMIT_BACKOFF) } +{ YDVAR(1, VAR_IP_RATELIMIT_BACKOFF) } YY_BREAK -case 312: +case 313: YY_RULE_SETUP #line 535 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_OUTBOUND_MSG_RETRY) } +{ YDVAR(1, VAR_RATELIMIT_BACKOFF) } YY_BREAK -case 313: +case 314: YY_RULE_SETUP #line 536 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_MAX_SENT_COUNT) } +{ YDVAR(1, VAR_OUTBOUND_MSG_RETRY) } YY_BREAK -case 314: +case 315: YY_RULE_SETUP #line 537 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_MAX_QUERY_RESTARTS) } +{ YDVAR(1, VAR_MAX_SENT_COUNT) } YY_BREAK -case 315: +case 316: YY_RULE_SETUP #line 538 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_LOW_RTT) } +{ YDVAR(1, VAR_MAX_QUERY_RESTARTS) } YY_BREAK -case 316: +case 317: YY_RULE_SETUP #line 539 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_FAST_SERVER_NUM) } +{ YDVAR(1, VAR_LOW_RTT) } YY_BREAK -case 317: +case 318: YY_RULE_SETUP #line 540 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_FAST_SERVER_PERMIL) } +{ YDVAR(1, VAR_FAST_SERVER_NUM) } YY_BREAK -case 318: +case 319: YY_RULE_SETUP #line 541 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FAST_SERVER_PERMIL) } YY_BREAK -case 319: +case 320: YY_RULE_SETUP #line 542 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_FAST_SERVER_PERMIL) } YY_BREAK -case 320: +case 321: YY_RULE_SETUP #line 543 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_RESPONSE_IP_TAG) } +{ YDVAR(1, VAR_FAST_SERVER_PERMIL) } YY_BREAK -case 321: +case 322: YY_RULE_SETUP #line 544 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_RESPONSE_IP) } +{ YDVAR(2, VAR_RESPONSE_IP_TAG) } YY_BREAK -case 322: +case 323: YY_RULE_SETUP #line 545 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(2, VAR_RESPONSE_IP_DATA) } +{ YDVAR(2, VAR_RESPONSE_IP) } YY_BREAK -case 323: +case 324: YY_RULE_SETUP #line 546 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(0, VAR_DNSCRYPT) } +{ YDVAR(2, VAR_RESPONSE_IP_DATA) } YY_BREAK -case 324: +case 325: YY_RULE_SETUP #line 547 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSCRYPT_ENABLE) } +{ YDVAR(0, VAR_DNSCRYPT) } YY_BREAK -case 325: +case 326: YY_RULE_SETUP #line 548 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSCRYPT_PORT) } +{ YDVAR(1, VAR_DNSCRYPT_ENABLE) } YY_BREAK -case 326: +case 327: YY_RULE_SETUP #line 549 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSCRYPT_PROVIDER) } +{ YDVAR(1, VAR_DNSCRYPT_PORT) } YY_BREAK -case 327: +case 328: YY_RULE_SETUP #line 550 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSCRYPT_SECRET_KEY) } +{ YDVAR(1, VAR_DNSCRYPT_PROVIDER) } YY_BREAK -case 328: +case 329: YY_RULE_SETUP #line 551 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSCRYPT_PROVIDER_CERT) } +{ YDVAR(1, VAR_DNSCRYPT_SECRET_KEY) } YY_BREAK -case 329: +case 330: YY_RULE_SETUP #line 552 "/usr/src/usr.sbin/unbound/util/configlexer.lex" -{ YDVAR(1, VAR_DNSCRYPT_PROVIDER_CERT_ROTATED) } +{ YDVAR(1, VAR_DNSCRYPT_PROVIDER_CERT) } YY_BREAK -case 330: +case 331: YY_RULE_SETUP #line 553 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +{ YDVAR(1, VAR_DNSCRYPT_PROVIDER_CERT_ROTATED) } + YY_BREAK +case 332: +YY_RULE_SETUP +#line 554 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE) } YY_BREAK -case 331: +case 333: YY_RULE_SETUP -#line 555 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 556 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS) } YY_BREAK -case 332: +case 334: YY_RULE_SETUP -#line 557 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 558 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSCRYPT_NONCE_CACHE_SIZE) } YY_BREAK -case 333: +case 335: YY_RULE_SETUP -#line 558 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 559 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNSCRYPT_NONCE_CACHE_SLABS) } YY_BREAK -case 334: +case 336: YY_RULE_SETUP -#line 559 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 560 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PAD_RESPONSES) } YY_BREAK -case 335: +case 337: YY_RULE_SETUP -#line 560 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 561 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PAD_RESPONSES_BLOCK_SIZE) } YY_BREAK -case 336: +case 338: YY_RULE_SETUP -#line 561 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 562 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PAD_QUERIES) } YY_BREAK -case 337: +case 339: YY_RULE_SETUP -#line 562 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 563 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PAD_QUERIES_BLOCK_SIZE) } YY_BREAK -case 338: +case 340: YY_RULE_SETUP -#line 563 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 564 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IPSECMOD_ENABLED) } YY_BREAK -case 339: +case 341: YY_RULE_SETUP -#line 564 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 565 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IPSECMOD_IGNORE_BOGUS) } YY_BREAK -case 340: +case 342: YY_RULE_SETUP -#line 565 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 566 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IPSECMOD_HOOK) } YY_BREAK -case 341: +case 343: YY_RULE_SETUP -#line 566 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 567 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IPSECMOD_MAX_TTL) } YY_BREAK -case 342: +case 344: YY_RULE_SETUP -#line 567 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 568 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IPSECMOD_WHITELIST) } YY_BREAK -case 343: +case 345: YY_RULE_SETUP -#line 568 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 569 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IPSECMOD_WHITELIST) } YY_BREAK -case 344: +case 346: YY_RULE_SETUP -#line 569 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 570 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IPSECMOD_STRICT) } YY_BREAK -case 345: +case 347: YY_RULE_SETUP -#line 570 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 571 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(0, VAR_CACHEDB) } YY_BREAK -case 346: +case 348: YY_RULE_SETUP -#line 571 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 572 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_BACKEND) } YY_BREAK -case 347: +case 349: YY_RULE_SETUP -#line 572 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 573 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_SECRETSEED) } YY_BREAK -case 348: +case 350: YY_RULE_SETUP -#line 573 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 574 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_NO_STORE) } YY_BREAK -case 349: +case 351: YY_RULE_SETUP -#line 574 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 575 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED) } YY_BREAK -case 350: +case 352: YY_RULE_SETUP -#line 575 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 576 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISHOST) } YY_BREAK -case 351: +case 353: YY_RULE_SETUP -#line 576 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 577 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISREPLICAHOST) } YY_BREAK -case 352: +case 354: YY_RULE_SETUP -#line 577 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 578 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISPORT) } YY_BREAK -case 353: +case 355: YY_RULE_SETUP -#line 578 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 579 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISREPLICAPORT) } YY_BREAK -case 354: +case 356: YY_RULE_SETUP -#line 579 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 580 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISPATH) } YY_BREAK -case 355: +case 357: YY_RULE_SETUP -#line 580 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 581 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISREPLICAPATH) } YY_BREAK -case 356: +case 358: YY_RULE_SETUP -#line 581 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 582 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISPASSWORD) } YY_BREAK -case 357: +case 359: YY_RULE_SETUP -#line 582 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 583 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISREPLICAPASSWORD) } YY_BREAK -case 358: +case 360: YY_RULE_SETUP -#line 583 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 584 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISTIMEOUT) } YY_BREAK -case 359: +case 361: YY_RULE_SETUP -#line 584 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 585 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISREPLICATIMEOUT) } YY_BREAK -case 360: +case 362: YY_RULE_SETUP -#line 585 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 586 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISCOMMANDTIMEOUT) } YY_BREAK -case 361: +case 363: YY_RULE_SETUP -#line 586 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 587 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISREPLICACOMMANDTIMEOUT) } YY_BREAK -case 362: +case 364: YY_RULE_SETUP -#line 587 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 588 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISCONNECTTIMEOUT) } YY_BREAK -case 363: +case 365: YY_RULE_SETUP -#line 588 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 589 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISREPLICACONNECTTIMEOUT) } YY_BREAK -case 364: +case 366: YY_RULE_SETUP -#line 589 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 590 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISEXPIRERECORDS) } YY_BREAK -case 365: +case 367: YY_RULE_SETUP -#line 590 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 591 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISLOGICALDB) } YY_BREAK -case 366: +case 368: YY_RULE_SETUP -#line 591 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 592 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_CACHEDB_REDISREPLICALOGICALDB) } YY_BREAK -case 367: +case 369: YY_RULE_SETUP -#line 592 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 593 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(0, VAR_IPSET) } YY_BREAK -case 368: +case 370: YY_RULE_SETUP -#line 593 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 594 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IPSET_NAME_V4) } YY_BREAK -case 369: +case 371: YY_RULE_SETUP -#line 594 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 595 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_IPSET_NAME_V6) } YY_BREAK -case 370: +case 372: YY_RULE_SETUP -#line 595 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 596 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM) } YY_BREAK -case 371: +case 373: YY_RULE_SETUP -#line 596 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 597 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) } YY_BREAK -case 372: +case 374: YY_RULE_SETUP -#line 597 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 598 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ANSWER_COOKIE ) } YY_BREAK -case 373: +case 375: YY_RULE_SETUP -#line 598 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 599 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_COOKIE_SECRET) } YY_BREAK -case 374: +case 376: YY_RULE_SETUP -#line 599 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 600 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_COOKIE_SECRET_FILE) } YY_BREAK -case 375: +case 377: YY_RULE_SETUP -#line 600 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 601 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(2, VAR_EDNS_CLIENT_STRING) } YY_BREAK -case 376: +case 378: YY_RULE_SETUP -#line 601 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 602 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_EDNS_CLIENT_STRING_OPCODE) } YY_BREAK -case 377: +case 379: YY_RULE_SETUP -#line 602 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 603 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_NSID ) } YY_BREAK -case 378: +case 380: YY_RULE_SETUP -#line 603 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 604 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_EDE ) } YY_BREAK -case 379: +case 381: YY_RULE_SETUP -#line 604 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 605 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_DNS_ERROR_REPORTING ) } YY_BREAK -case 380: +case 382: YY_RULE_SETUP -#line 605 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 606 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_PROXY_PROTOCOL_PORT) } YY_BREAK -case 381: +case 383: YY_RULE_SETUP -#line 606 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 607 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ITER_SCRUB_NS) } YY_BREAK -case 382: +case 384: YY_RULE_SETUP -#line 607 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 608 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ITER_SCRUB_CNAME) } YY_BREAK -case 383: +case 385: YY_RULE_SETUP -#line 608 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 609 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +{ YDVAR(1, VAR_ITER_SCRUB_RRSIG) } + YY_BREAK +case 386: +YY_RULE_SETUP +#line 610 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_MAX_GLOBAL_QUOTA) } YY_BREAK -case 384: +case 387: YY_RULE_SETUP -#line 609 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 611 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +{ YDVAR(1, VAR_VAL_VALIDATION_ATTEMPTS) } + YY_BREAK +case 388: +YY_RULE_SETUP +#line 612 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +{ YDVAR(1, VAR_VAL_HASH_ATTEMPTS) } + YY_BREAK +case 389: +YY_RULE_SETUP +#line 613 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +{ YDVAR(1, VAR_MAX_TRANSFER_SIZE) } + YY_BREAK +case 390: +YY_RULE_SETUP +#line 614 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +{ YDVAR(1, VAR_MAX_TRANSFER_TIME) } + YY_BREAK +case 391: +YY_RULE_SETUP +#line 615 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { YDVAR(1, VAR_ITER_SCRUB_PROMISCUOUS) } YY_BREAK -case 385: -/* rule 385 can match eol */ +case 392: +/* rule 392 can match eol */ YY_RULE_SETUP -#line 610 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 616 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("NL\n")); cfg_parser->line++; } YY_BREAK /* Quoted strings. Strip leading and ending quotes */ -case 386: +case 393: YY_RULE_SETUP -#line 613 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 619 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { BEGIN(quotedstring); LEXOUT(("QS ")); } YY_BREAK case YY_STATE_EOF(quotedstring): -#line 614 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 620 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("EOF inside quoted string"); if(--num_args == 0) { BEGIN(INITIAL); } else { BEGIN(val); } } YY_BREAK -case 387: +case 394: YY_RULE_SETUP -#line 619 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 625 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("STR(%s) ", yytext)); yymore(); } YY_BREAK -case 388: -/* rule 388 can match eol */ +case 395: +/* rule 395 can match eol */ YY_RULE_SETUP -#line 620 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 626 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("newline inside quoted string, no end \""); cfg_parser->line++; BEGIN(INITIAL); } YY_BREAK -case 389: +case 396: YY_RULE_SETUP -#line 622 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 628 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("QE ")); if(--num_args == 0) { BEGIN(INITIAL); } @@ -6055,34 +6148,34 @@ YY_RULE_SETUP } YY_BREAK /* Single Quoted strings. Strip leading and ending quotes */ -case 390: +case 397: YY_RULE_SETUP -#line 634 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 640 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { BEGIN(singlequotedstr); LEXOUT(("SQS ")); } YY_BREAK case YY_STATE_EOF(singlequotedstr): -#line 635 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 641 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("EOF inside quoted string"); if(--num_args == 0) { BEGIN(INITIAL); } else { BEGIN(val); } } YY_BREAK -case 391: +case 398: YY_RULE_SETUP -#line 640 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 646 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("STR(%s) ", yytext)); yymore(); } YY_BREAK -case 392: -/* rule 392 can match eol */ +case 399: +/* rule 399 can match eol */ YY_RULE_SETUP -#line 641 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 647 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("newline inside quoted string, no end '"); cfg_parser->line++; BEGIN(INITIAL); } YY_BREAK -case 393: +case 400: YY_RULE_SETUP -#line 643 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 649 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("SQE ")); if(--num_args == 0) { BEGIN(INITIAL); } @@ -6095,38 +6188,38 @@ YY_RULE_SETUP } YY_BREAK /* include: directive */ -case 394: +case 401: YY_RULE_SETUP -#line 655 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 661 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("v(%s) ", yytext)); inc_prev = YYSTATE; BEGIN(include); } YY_BREAK case YY_STATE_EOF(include): -#line 657 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 663 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("EOF inside include directive"); BEGIN(inc_prev); } YY_BREAK -case 395: +case 402: YY_RULE_SETUP -#line 661 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 667 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("ISP ")); /* ignore */ } YY_BREAK -case 396: -/* rule 396 can match eol */ +case 403: +/* rule 403 can match eol */ YY_RULE_SETUP -#line 662 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 668 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("NL\n")); cfg_parser->line++;} YY_BREAK -case 397: +case 404: YY_RULE_SETUP -#line 663 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 669 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("IQS ")); BEGIN(include_quoted); } YY_BREAK -case 398: +case 405: YY_RULE_SETUP -#line 664 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 670 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("Iunquotedstr(%s) ", yytext)); config_start_include_glob(yytext, 0); @@ -6134,27 +6227,27 @@ YY_RULE_SETUP } YY_BREAK case YY_STATE_EOF(include_quoted): -#line 669 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 675 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("EOF inside quoted string"); BEGIN(inc_prev); } YY_BREAK -case 399: +case 406: YY_RULE_SETUP -#line 673 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 679 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("ISTR(%s) ", yytext)); yymore(); } YY_BREAK -case 400: -/* rule 400 can match eol */ +case 407: +/* rule 407 can match eol */ YY_RULE_SETUP -#line 674 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 680 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("newline before \" in include name"); cfg_parser->line++; BEGIN(inc_prev); } YY_BREAK -case 401: +case 408: YY_RULE_SETUP -#line 676 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 682 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("IQE ")); yytext[yyleng - 1] = '\0'; @@ -6164,7 +6257,7 @@ YY_RULE_SETUP YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(val): -#line 682 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 688 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("LEXEOF ")); yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ @@ -6179,39 +6272,39 @@ case YY_STATE_EOF(val): } YY_BREAK /* include-toplevel: directive */ -case 402: +case 409: YY_RULE_SETUP -#line 696 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 702 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("v(%s) ", yytext)); inc_prev = YYSTATE; BEGIN(include_toplevel); } YY_BREAK case YY_STATE_EOF(include_toplevel): -#line 699 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 705 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("EOF inside include_toplevel directive"); BEGIN(inc_prev); } YY_BREAK -case 403: +case 410: YY_RULE_SETUP -#line 703 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 709 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("ITSP ")); /* ignore */ } YY_BREAK -case 404: -/* rule 404 can match eol */ +case 411: +/* rule 411 can match eol */ YY_RULE_SETUP -#line 704 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 710 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("NL\n")); cfg_parser->line++; } YY_BREAK -case 405: +case 412: YY_RULE_SETUP -#line 705 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 711 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("ITQS ")); BEGIN(include_toplevel_quoted); } YY_BREAK -case 406: +case 413: YY_RULE_SETUP -#line 706 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 712 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("ITunquotedstr(%s) ", yytext)); config_start_include_glob(yytext, 1); @@ -6220,29 +6313,29 @@ YY_RULE_SETUP } YY_BREAK case YY_STATE_EOF(include_toplevel_quoted): -#line 712 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 718 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("EOF inside quoted string"); BEGIN(inc_prev); } YY_BREAK -case 407: +case 414: YY_RULE_SETUP -#line 716 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 722 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("ITSTR(%s) ", yytext)); yymore(); } YY_BREAK -case 408: -/* rule 408 can match eol */ +case 415: +/* rule 415 can match eol */ YY_RULE_SETUP -#line 717 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 723 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { yyerror("newline before \" in include name"); cfg_parser->line++; BEGIN(inc_prev); } YY_BREAK -case 409: +case 416: YY_RULE_SETUP -#line 721 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 727 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("ITQE ")); yytext[yyleng - 1] = '\0'; @@ -6251,33 +6344,33 @@ YY_RULE_SETUP return (VAR_FORCE_TOPLEVEL); } YY_BREAK -case 410: +case 417: YY_RULE_SETUP -#line 729 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 735 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { LEXOUT(("unquotedstr(%s) ", yytext)); if(--num_args == 0) { BEGIN(INITIAL); } yylval.str = strdup(yytext); return STRING_ARG; } YY_BREAK -case 411: +case 418: YY_RULE_SETUP -#line 733 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 739 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { ub_c_error_msg("unknown keyword '%s'", yytext); } YY_BREAK -case 412: +case 419: YY_RULE_SETUP -#line 737 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 743 "/usr/src/usr.sbin/unbound/util/configlexer.lex" { ub_c_error_msg("stray '%s'", yytext); } YY_BREAK -case 413: +case 420: YY_RULE_SETUP -#line 741 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 747 "/usr/src/usr.sbin/unbound/util/configlexer.lex" ECHO; YY_BREAK -#line 6279 "" +#line 6372 "" case YY_END_OF_BUFFER: { @@ -6570,7 +6663,7 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 4130 ) + if ( yy_current_state >= 4207 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -6598,11 +6691,11 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 4130 ) + if ( yy_current_state >= 4207 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 4129); + yy_is_jam = (yy_current_state == 4206); return yy_is_jam ? 0 : yy_current_state; } @@ -7235,7 +7328,7 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" -#line 741 "/usr/src/usr.sbin/unbound/util/configlexer.lex" +#line 747 "/usr/src/usr.sbin/unbound/util/configlexer.lex" Index: sbin/unwind/libunbound/util/configlexer.lex =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/configlexer.lex,v diff -u -p -r1.21 configlexer.lex --- sbin/unwind/libunbound/util/configlexer.lex 28 Nov 2025 07:37:51 -0000 1.21 +++ sbin/unwind/libunbound/util/configlexer.lex 21 Sep 2026 16:28:00 -0000 @@ -13,7 +13,6 @@ #pragma GCC diagnostic ignored "-Wsign-compare" #endif -#include #include #ifdef HAVE_GLOB_H # include @@ -262,6 +261,7 @@ tls-session-ticket-keys{COLON} { YDVAR(1 tls-ciphers{COLON} { YDVAR(1, VAR_TLS_CIPHERS) } tls-ciphersuites{COLON} { YDVAR(1, VAR_TLS_CIPHERSUITES) } tls-use-sni{COLON} { YDVAR(1, VAR_TLS_USE_SNI) } +tls-protocols{COLON} { YDVAR(1, VAR_TLS_PROTOCOLS) } https-port{COLON} { YDVAR(1, VAR_HTTPS_PORT) } http-endpoint{COLON} { YDVAR(1, VAR_HTTP_ENDPOINT) } http-max-streams{COLON} { YDVAR(1, VAR_HTTP_MAX_STREAMS) } @@ -440,6 +440,7 @@ log-tag-queryreply{COLON} { YDVAR(1, VAR log-local-actions{COLON} { YDVAR(1, VAR_LOG_LOCAL_ACTIONS) } log-servfail{COLON} { YDVAR(1, VAR_LOG_SERVFAIL) } log-destaddr{COLON} { YDVAR(1, VAR_LOG_DESTADDR) } +log-thread-id{COLON} { YDVAR(1, VAR_LOG_THREAD_ID) } local-zone{COLON} { YDVAR(2, VAR_LOCAL_ZONE) } local-data{COLON} { YDVAR(1, VAR_LOCAL_DATA) } local-data-ptr{COLON} { YDVAR(1, VAR_LOCAL_DATA_PTR) } @@ -605,7 +606,12 @@ dns-error-reporting{COLON} { YDVAR(1, VA proxy-protocol-port{COLON} { YDVAR(1, VAR_PROXY_PROTOCOL_PORT) } iter-scrub-ns{COLON} { YDVAR(1, VAR_ITER_SCRUB_NS) } iter-scrub-cname{COLON} { YDVAR(1, VAR_ITER_SCRUB_CNAME) } +iter-scrub-rrsig{COLON} { YDVAR(1, VAR_ITER_SCRUB_RRSIG) } max-global-quota{COLON} { YDVAR(1, VAR_MAX_GLOBAL_QUOTA) } +val-validation-attempts{COLON} { YDVAR(1, VAR_VAL_VALIDATION_ATTEMPTS) } +val-hash-attempts{COLON} { YDVAR(1, VAR_VAL_HASH_ATTEMPTS) } +max-transfer-size{COLON} { YDVAR(1, VAR_MAX_TRANSFER_SIZE) } +max-transfer-time{COLON} { YDVAR(1, VAR_MAX_TRANSFER_TIME) } iter-scrub-promiscuous{COLON} { YDVAR(1, VAR_ITER_SCRUB_PROMISCUOUS) } {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; } Index: sbin/unwind/libunbound/util/configparser.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/configparser.h,v diff -u -p -r1.20 configparser.h --- sbin/unwind/libunbound/util/configparser.h 28 Nov 2025 07:37:51 -0000 1.20 +++ sbin/unwind/libunbound/util/configparser.h 21 Sep 2026 16:28:00 -0000 @@ -330,49 +330,56 @@ #define VAR_TLS_CIPHERS 586 #define VAR_TLS_CIPHERSUITES 587 #define VAR_TLS_USE_SNI 588 -#define VAR_IPSET 589 -#define VAR_IPSET_NAME_V4 590 -#define VAR_IPSET_NAME_V6 591 -#define VAR_TLS_SESSION_TICKET_KEYS 592 -#define VAR_RPZ 593 -#define VAR_TAGS 594 -#define VAR_RPZ_ACTION_OVERRIDE 595 -#define VAR_RPZ_CNAME_OVERRIDE 596 -#define VAR_RPZ_LOG 597 -#define VAR_RPZ_LOG_NAME 598 -#define VAR_DYNLIB 599 -#define VAR_DYNLIB_FILE 600 -#define VAR_EDNS_CLIENT_STRING 601 -#define VAR_EDNS_CLIENT_STRING_OPCODE 602 -#define VAR_NSID 603 -#define VAR_ZONEMD_PERMISSIVE_MODE 604 -#define VAR_ZONEMD_CHECK 605 -#define VAR_ZONEMD_REJECT_ABSENCE 606 -#define VAR_RPZ_SIGNAL_NXDOMAIN_RA 607 -#define VAR_INTERFACE_AUTOMATIC_PORTS 608 -#define VAR_EDE 609 -#define VAR_DNS_ERROR_REPORTING 610 -#define VAR_INTERFACE_ACTION 611 -#define VAR_INTERFACE_VIEW 612 -#define VAR_INTERFACE_TAG 613 -#define VAR_INTERFACE_TAG_ACTION 614 -#define VAR_INTERFACE_TAG_DATA 615 -#define VAR_QUIC_PORT 616 -#define VAR_QUIC_SIZE 617 -#define VAR_PROXY_PROTOCOL_PORT 618 -#define VAR_STATISTICS_INHIBIT_ZERO 619 -#define VAR_HARDEN_UNKNOWN_ADDITIONAL 620 -#define VAR_DISABLE_EDNS_DO 621 -#define VAR_CACHEDB_NO_STORE 622 -#define VAR_LOG_DESTADDR 623 -#define VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED 624 -#define VAR_COOKIE_SECRET_FILE 625 -#define VAR_ITER_SCRUB_NS 626 -#define VAR_ITER_SCRUB_CNAME 627 -#define VAR_MAX_GLOBAL_QUOTA 628 -#define VAR_HARDEN_UNVERIFIED_GLUE 629 -#define VAR_LOG_TIME_ISO 630 -#define VAR_ITER_SCRUB_PROMISCUOUS 631 +#define VAR_TLS_PROTOCOLS 589 +#define VAR_IPSET 590 +#define VAR_IPSET_NAME_V4 591 +#define VAR_IPSET_NAME_V6 592 +#define VAR_TLS_SESSION_TICKET_KEYS 593 +#define VAR_RPZ 594 +#define VAR_TAGS 595 +#define VAR_RPZ_ACTION_OVERRIDE 596 +#define VAR_RPZ_CNAME_OVERRIDE 597 +#define VAR_RPZ_LOG 598 +#define VAR_RPZ_LOG_NAME 599 +#define VAR_DYNLIB 600 +#define VAR_DYNLIB_FILE 601 +#define VAR_EDNS_CLIENT_STRING 602 +#define VAR_EDNS_CLIENT_STRING_OPCODE 603 +#define VAR_NSID 604 +#define VAR_ZONEMD_PERMISSIVE_MODE 605 +#define VAR_ZONEMD_CHECK 606 +#define VAR_ZONEMD_REJECT_ABSENCE 607 +#define VAR_RPZ_SIGNAL_NXDOMAIN_RA 608 +#define VAR_INTERFACE_AUTOMATIC_PORTS 609 +#define VAR_EDE 610 +#define VAR_DNS_ERROR_REPORTING 611 +#define VAR_INTERFACE_ACTION 612 +#define VAR_INTERFACE_VIEW 613 +#define VAR_INTERFACE_TAG 614 +#define VAR_INTERFACE_TAG_ACTION 615 +#define VAR_INTERFACE_TAG_DATA 616 +#define VAR_QUIC_PORT 617 +#define VAR_QUIC_SIZE 618 +#define VAR_PROXY_PROTOCOL_PORT 619 +#define VAR_STATISTICS_INHIBIT_ZERO 620 +#define VAR_HARDEN_UNKNOWN_ADDITIONAL 621 +#define VAR_DISABLE_EDNS_DO 622 +#define VAR_CACHEDB_NO_STORE 623 +#define VAR_LOG_DESTADDR 624 +#define VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED 625 +#define VAR_COOKIE_SECRET_FILE 626 +#define VAR_ITER_SCRUB_NS 627 +#define VAR_ITER_SCRUB_CNAME 628 +#define VAR_ITER_SCRUB_RRSIG 629 +#define VAR_MAX_TRANSFER_SIZE 630 +#define VAR_MAX_TRANSFER_TIME 631 +#define VAR_MAX_GLOBAL_QUOTA 632 +#define VAR_HARDEN_UNVERIFIED_GLUE 633 +#define VAR_LOG_TIME_ISO 634 +#define VAR_VAL_VALIDATION_ATTEMPTS 635 +#define VAR_VAL_HASH_ATTEMPTS 636 +#define VAR_ITER_SCRUB_PROMISCUOUS 637 +#define VAR_LOG_THREAD_ID 638 #ifndef YYSTYPE_DEFINED #define YYSTYPE_DEFINED typedef union { Index: sbin/unwind/libunbound/util/configparser.y =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/configparser.y,v diff -u -p -r1.22 configparser.y --- sbin/unwind/libunbound/util/configparser.y 28 Nov 2025 07:37:51 -0000 1.22 +++ sbin/unwind/libunbound/util/configparser.y 21 Sep 2026 16:28:00 -0000 @@ -199,6 +199,7 @@ extern struct config_parser_state* cfg_p %token VAR_DISCARD_TIMEOUT VAR_WAIT_LIMIT VAR_WAIT_LIMIT_COOKIE %token VAR_WAIT_LIMIT_NETBLOCK VAR_WAIT_LIMIT_COOKIE_NETBLOCK %token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES VAR_TLS_USE_SNI +%token VAR_TLS_PROTOCOLS %token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6 %token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE %token VAR_RPZ_CNAME_OVERRIDE VAR_RPZ_LOG VAR_RPZ_LOG_NAME @@ -214,8 +215,11 @@ extern struct config_parser_state* cfg_p %token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE %token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED %token VAR_COOKIE_SECRET_FILE VAR_ITER_SCRUB_NS VAR_ITER_SCRUB_CNAME +%token VAR_ITER_SCRUB_RRSIG +%token VAR_MAX_TRANSFER_SIZE VAR_MAX_TRANSFER_TIME %token VAR_MAX_GLOBAL_QUOTA VAR_HARDEN_UNVERIFIED_GLUE VAR_LOG_TIME_ISO -%token VAR_ITER_SCRUB_PROMISCUOUS +%token VAR_VAL_VALIDATION_ATTEMPTS VAR_VAL_HASH_ATTEMPTS +%token VAR_ITER_SCRUB_PROMISCUOUS VAR_LOG_THREAD_ID %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -287,7 +291,7 @@ content_server: server_num_threads | ser server_edns_buffer_size | server_prefetch | server_prefetch_key | server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag | server_log_queries | server_log_replies | server_tcp_upstream | server_ssl_upstream | - server_log_local_actions | + server_log_local_actions | server_log_thread_id | server_ssl_service_key | server_ssl_service_pem | server_ssl_port | server_https_port | server_http_endpoint | server_http_max_streams | server_http_query_buffer_size | server_http_response_buffer_size | @@ -346,7 +350,7 @@ content_server: server_num_threads | ser server_stream_wait_size | server_tls_ciphers | server_tls_ciphersuites | server_tls_session_ticket_keys | server_answer_cookie | server_cookie_secret | server_ip_ratelimit_cookie | - server_tls_use_sni | server_edns_client_string | + server_tls_use_sni | server_edns_client_string | server_tls_protocols | server_edns_client_string_opcode | server_nsid | server_zonemd_permissive_mode | server_max_reuse_tcp_queries | server_tcp_reuse_timeout | server_tcp_auth_query_timeout | @@ -357,6 +361,8 @@ content_server: server_num_threads | ser server_harden_unknown_additional | server_disable_edns_do | server_log_destaddr | server_cookie_secret_file | server_iter_scrub_ns | server_iter_scrub_cname | server_max_global_quota | + server_val_validation_attempts | + server_val_hash_attempts | server_iter_scrub_rrsig | server_harden_unverified_glue | server_log_time_iso | server_iter_scrub_promiscuous ; stub_clause: stubstart contents_stub @@ -456,6 +462,8 @@ authstart: VAR_AUTH_ZONE s->zonemd_check = 0; s->zonemd_reject_absence = 0; s->isrpz = 0; + s->max_transfer_size = 0; + s->max_transfer_time = 0; } else { yyerror("out of memory"); } @@ -465,7 +473,8 @@ contents_auth: contents_auth content_aut | ; content_auth: auth_name | auth_zonefile | auth_master | auth_url | auth_for_downstream | auth_for_upstream | auth_fallback_enabled | - auth_allow_notify | auth_zonemd_check | auth_zonemd_reject_absence + auth_allow_notify | auth_zonemd_check | auth_zonemd_reject_absence | + auth_max_transfer_size | auth_max_transfer_time ; rpz_tag: VAR_TAGS STRING_ARG @@ -553,6 +562,8 @@ rpzstart: VAR_RPZ s->for_upstream = 0; s->fallback_enabled = 0; s->isrpz = 1; + s->max_transfer_size = 0; + s->max_transfer_time = 0; } else { yyerror("out of memory"); } @@ -562,7 +573,8 @@ contents_rpz: contents_rpz content_rpz | ; content_rpz: auth_name | auth_zonefile | rpz_tag | auth_master | auth_url | auth_allow_notify | rpz_action_override | rpz_cname_override | - rpz_log | rpz_log_name | rpz_signal_nxdomain_ra | auth_for_downstream + rpz_log | rpz_log_name | rpz_signal_nxdomain_ra | auth_for_downstream | + auth_max_transfer_size | auth_max_transfer_time ; server_num_threads: VAR_NUM_THREADS STRING_ARG { @@ -654,7 +666,7 @@ server_send_client_subnet: VAR_SEND_CLIE #ifdef CLIENT_SUBNET OUTYY(("P(server_send_client_subnet:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->client_subnet, $2)) - fatal_exit("out of memory adding client-subnet"); + yyerror("out of memory"); #else OUTYY(("P(Compiled without edns subnet option, ignoring)\n")); free($2); @@ -667,7 +679,7 @@ server_client_subnet_zone: VAR_CLIENT_SU OUTYY(("P(server_client_subnet_zone:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->client_subnet_zone, $2)) - fatal_exit("out of memory adding client-subnet-zone"); + yyerror("out of memory"); #else OUTYY(("P(Compiled without edns subnet option, ignoring)\n")); free($2); @@ -1155,6 +1167,15 @@ server_tls_use_sni: VAR_TLS_USE_SNI STRI free($2); } ; +server_tls_protocols: VAR_TLS_PROTOCOLS STRING_ARG + { + OUTYY(("P(server_tls_protocols:%s)\n", $2)); + if(!cfg_tls_protocols_is_valid($2)) + yyerror("tls-protocols: valid values are 'TLSv1.2' and 'TLSv1.3'."); + free(cfg_parser->cfg->tls_protocols); + cfg_parser->cfg->tls_protocols = $2; + } + ; server_https_port: VAR_HTTPS_PORT STRING_ARG { OUTYY(("P(server_https_port:%s)\n", $2)); @@ -1224,14 +1245,17 @@ server_http_notls_downstream: VAR_HTTP_N server_quic_port: VAR_QUIC_PORT STRING_ARG { OUTYY(("P(server_quic_port:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2,"0")!=0) + yyerror("port number expected"); + else { + cfg_parser->cfg->quic_port = atoi($2); #ifndef HAVE_NGTCP2 - log_warn("%s:%d: Unbound is not compiled with " - "ngtcp2. This is required to use DNS " - "over QUIC.", cfg_parser->filename, cfg_parser->line); + if (cfg_parser->cfg->quic_port != 0) + log_warn("%s:%d: Unbound is not compiled with " + "ngtcp2. This is required to use DNS " + "over QUIC.", cfg_parser->filename, cfg_parser->line); #endif - if(atoi($2) == 0) - yyerror("port number expected"); - else cfg_parser->cfg->quic_port = atoi($2); + } free($2); }; server_quic_size: VAR_QUIC_SIZE STRING_ARG @@ -1336,6 +1360,15 @@ server_log_destaddr: VAR_LOG_DESTADDR ST free($2); } ; +server_log_thread_id: VAR_LOG_THREAD_ID STRING_ARG + { + OUTYY(("P(server_log_thread_id:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->log_thread_id = (strcmp($2, "yes")==0); + free($2); + } + ; server_log_local_actions: VAR_LOG_LOCAL_ACTIONS STRING_ARG { OUTYY(("P(server_log_local_actions:%s)\n", $2)); @@ -2005,7 +2038,7 @@ server_access_control: VAR_ACCESS_CONTRO OUTYY(("P(server_access_control:%s %s)\n", $2, $3)); validate_acl_action($3); if(!cfg_str2list_insert(&cfg_parser->cfg->acls, $2, $3)) - fatal_exit("out of memory adding acl"); + yyerror("out of memory"); } ; server_interface_action: VAR_INTERFACE_ACTION STRING_ARG STRING_ARG @@ -2014,7 +2047,7 @@ server_interface_action: VAR_INTERFACE_A validate_acl_action($3); if(!cfg_str2list_insert( &cfg_parser->cfg->interface_actions, $2, $3)) - fatal_exit("out of memory adding acl"); + yyerror("out of memory"); } ; server_module_conf: VAR_MODULE_CONF STRING_ARG @@ -2364,6 +2397,9 @@ server_local_zone: VAR_LOCAL_ZONE STRING && strcmp($3, "typetransparent")!=0 && strcmp($3, "always_transparent")!=0 && strcmp($3, "block_a")!=0 + && strcmp($3, "block_aaaa")!=0 + && strcmp($3, "block_a_wdata")!=0 + && strcmp($3, "block_aaaa_wdata")!=0 && strcmp($3, "always_refuse")!=0 && strcmp($3, "always_nxdomain")!=0 && strcmp($3, "always_nodata")!=0 @@ -2376,7 +2412,9 @@ server_local_zone: VAR_LOCAL_ZONE STRING yyerror("local-zone type: expected static, deny, " "refuse, redirect, transparent, " "typetransparent, inform, inform_deny, " - "inform_redirect, always_transparent, block_a," + "inform_redirect, always_transparent, " + "block_a, block_aaaa, " + "block_a_wdata, block_aaaa_wdata, " "always_refuse, always_nxdomain, " "always_nodata, always_deny, always_null, " "noview, nodefault or ipset"); @@ -2385,7 +2423,7 @@ server_local_zone: VAR_LOCAL_ZONE STRING } else if(strcmp($3, "nodefault")==0) { if(!cfg_strlist_insert(&cfg_parser->cfg-> local_zones_nodefault, $2)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); free($3); #ifdef USE_IPSET } else if(strcmp($3, "ipset")==0) { @@ -2393,21 +2431,24 @@ server_local_zone: VAR_LOCAL_ZONE STRING /* Make sure to add the trailing dot. * These are str compared to domain names. */ if($2[len-1] != '.') { + char* prev = $2; if(!($2 = realloc($2, len+2))) { - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); + free(prev); + } else { + $2[len] = '.'; + $2[len+1] = 0; } - $2[len] = '.'; - $2[len+1] = 0; } if(!cfg_strlist_insert(&cfg_parser->cfg-> local_zones_ipset, $2)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); free($3); #endif } else { if(!cfg_str2list_insert(&cfg_parser->cfg->local_zones, $2, $3)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); } } ; @@ -2415,7 +2456,7 @@ server_local_data: VAR_LOCAL_DATA STRING { OUTYY(("P(server_local_data:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->local_data, $2)) - fatal_exit("out of memory adding local-data"); + yyerror("out of memory"); } ; server_local_data_ptr: VAR_LOCAL_DATA_PTR STRING_ARG @@ -2427,7 +2468,7 @@ server_local_data_ptr: VAR_LOCAL_DATA_PT if(ptr) { if(!cfg_strlist_insert(&cfg_parser->cfg-> local_data, ptr)) - fatal_exit("out of memory adding local-data"); + yyerror("out of memory"); } else { yyerror("local-data-ptr could not be reversed"); } @@ -2491,8 +2532,7 @@ server_wait_limit_netblock: VAR_WAIT_LIM } else { if(!cfg_str2list_insert(&cfg_parser->cfg-> wait_limit_netblock, $2, $3)) - fatal_exit("out of memory adding " - "wait-limit-netblock"); + yyerror("out of memory"); } } ; @@ -2506,8 +2546,7 @@ server_wait_limit_cookie_netblock: VAR_W } else { if(!cfg_str2list_insert(&cfg_parser->cfg-> wait_limit_cookie_netblock, $2, $3)) - fatal_exit("out of memory adding " - "wait-limit-cookie-netblock"); + yyerror("out of memory"); } } ; @@ -2539,7 +2578,7 @@ server_dns64_ignore_aaaa: VAR_DNS64_IGNO OUTYY(("P(dns64_ignore_aaaa:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->dns64_ignore_aaaa, $2)) - fatal_exit("out of memory adding dns64-ignore-aaaa"); + yyerror("out of memory"); } ; server_nat64_prefix: VAR_NAT64_PREFIX STRING_ARG @@ -2804,8 +2843,7 @@ server_ratelimit_for_domain: VAR_RATELIM } else { if(!cfg_str2list_insert(&cfg_parser->cfg-> ratelimit_for_domain, $2, $3)) - fatal_exit("out of memory adding " - "ratelimit-for-domain"); + yyerror("out of memory"); } } ; @@ -2819,8 +2857,7 @@ server_ratelimit_below_domain: VAR_RATEL } else { if(!cfg_str2list_insert(&cfg_parser->cfg-> ratelimit_below_domain, $2, $3)) - fatal_exit("out of memory adding " - "ratelimit-below-domain"); + yyerror("out of memory"); } } ; @@ -3054,8 +3091,7 @@ server_edns_client_string: VAR_EDNS_CLIE OUTYY(("P(server_edns_client_string:%s %s)\n", $2, $3)); if(!cfg_str2list_insert( &cfg_parser->cfg->edns_client_strings, $2, $3)) - fatal_exit("out of memory adding " - "edns-client-string"); + yyerror("out of memory"); } ; server_edns_client_string_opcode: VAR_EDNS_CLIENT_STRING_OPCODE STRING_ARG @@ -3317,6 +3353,23 @@ auth_fallback_enabled: VAR_FALLBACK_ENAB free($2); } ; +auth_max_transfer_size: VAR_MAX_TRANSFER_SIZE STRING_ARG + { + OUTYY(("P(max-transfer-size:%s)\n", $2)); + if(!cfg_parse_memsize($2, &cfg_parser->cfg->auths->max_transfer_size)) + yyerror("memory size expected"); + free($2); + } + ; +auth_max_transfer_time: VAR_MAX_TRANSFER_TIME STRING_ARG + { + OUTYY(("P(max-transfer-time:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->auths->max_transfer_time = atoi($2); + free($2); + } + ; view_name: VAR_NAME STRING_ARG { OUTYY(("P(name:%s)\n", $2)); @@ -3356,7 +3409,7 @@ view_local_zone: VAR_LOCAL_ZONE STRING_A } else if(strcmp($3, "nodefault")==0) { if(!cfg_strlist_insert(&cfg_parser->cfg->views-> local_zones_nodefault, $2)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); free($3); #ifdef USE_IPSET } else if(strcmp($3, "ipset")==0) { @@ -3364,22 +3417,25 @@ view_local_zone: VAR_LOCAL_ZONE STRING_A /* Make sure to add the trailing dot. * These are str compared to domain names. */ if($2[len-1] != '.') { + char* prev = $2; if(!($2 = realloc($2, len+2))) { - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); + free(prev); + } else { + $2[len] = '.'; + $2[len+1] = 0; } - $2[len] = '.'; - $2[len+1] = 0; } if(!cfg_strlist_insert(&cfg_parser->cfg->views-> local_zones_ipset, $2)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); free($3); #endif } else { if(!cfg_str2list_insert( &cfg_parser->cfg->views->local_zones, $2, $3)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); } } ; @@ -3389,8 +3445,7 @@ view_response_ip: VAR_RESPONSE_IP STRING validate_respip_action($3); if(!cfg_str2list_insert( &cfg_parser->cfg->views->respip_actions, $2, $3)) - fatal_exit("out of memory adding per-view " - "response-ip action"); + yyerror("out of memory"); } ; view_response_ip_data: VAR_RESPONSE_IP_DATA STRING_ARG STRING_ARG @@ -3398,14 +3453,14 @@ view_response_ip_data: VAR_RESPONSE_IP_D OUTYY(("P(view_response_ip_data:%s)\n", $2)); if(!cfg_str2list_insert( &cfg_parser->cfg->views->respip_data, $2, $3)) - fatal_exit("out of memory adding response-ip-data"); + yyerror("out of memory"); } ; view_local_data: VAR_LOCAL_DATA STRING_ARG { OUTYY(("P(view_local_data:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->views->local_data, $2)) { - fatal_exit("out of memory adding local-data"); + yyerror("out of memory"); } } ; @@ -3418,7 +3473,7 @@ view_local_data_ptr: VAR_LOCAL_DATA_PTR if(ptr) { if(!cfg_strlist_insert(&cfg_parser->cfg->views-> local_data, ptr)) - fatal_exit("out of memory adding local-data"); + yyerror("out of memory"); } else { yyerror("local-data-ptr could not be reversed"); } @@ -3758,7 +3813,7 @@ server_response_ip: VAR_RESPONSE_IP STRI validate_respip_action($3); if(!cfg_str2list_insert(&cfg_parser->cfg->respip_actions, $2, $3)) - fatal_exit("out of memory adding response-ip"); + yyerror("out of memory"); } ; server_response_ip_data: VAR_RESPONSE_IP_DATA STRING_ARG STRING_ARG @@ -3766,7 +3821,7 @@ server_response_ip_data: VAR_RESPONSE_IP OUTYY(("P(server_response_ip_data:%s)\n", $2)); if(!cfg_str2list_insert(&cfg_parser->cfg->respip_data, $2, $3)) - fatal_exit("out of memory adding response-ip-data"); + yyerror("out of memory"); } ; dnscstart: VAR_DNSCRYPT @@ -3814,26 +3869,30 @@ dnsc_dnscrypt_provider: VAR_DNSCRYPT_PRO dnsc_dnscrypt_provider_cert: VAR_DNSCRYPT_PROVIDER_CERT STRING_ARG { OUTYY(("P(dnsc_dnscrypt_provider_cert:%s)\n", $2)); - if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_provider_cert, $2)) + if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_provider_cert, $2)) { log_warn("dnscrypt-provider-cert %s is a duplicate", $2); - if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert, $2)) - fatal_exit("out of memory adding dnscrypt-provider-cert"); + free($2); + } else if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert, $2)) { + yyerror("out of memory"); + } } ; dnsc_dnscrypt_provider_cert_rotated: VAR_DNSCRYPT_PROVIDER_CERT_ROTATED STRING_ARG { OUTYY(("P(dnsc_dnscrypt_provider_cert_rotated:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert_rotated, $2)) - fatal_exit("out of memory adding dnscrypt-provider-cert-rotated"); + yyerror("out of memory"); } ; dnsc_dnscrypt_secret_key: VAR_DNSCRYPT_SECRET_KEY STRING_ARG { OUTYY(("P(dnsc_dnscrypt_secret_key:%s)\n", $2)); - if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_secret_key, $2)) + if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_secret_key, $2)) { log_warn("dnscrypt-secret-key: %s is a duplicate", $2); - if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_secret_key, $2)) - fatal_exit("out of memory adding dnscrypt-secret-key"); + free($2); + } else if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_secret_key, $2)) { + yyerror("out of memory"); + } } ; dnsc_dnscrypt_shared_secret_cache_size: VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE STRING_ARG @@ -4178,7 +4237,7 @@ server_tcp_connection_limit: VAR_TCP_CON yyerror("positive number expected"); else { if(!cfg_str2list_insert(&cfg_parser->cfg->tcp_connection_limits, $2, $3)) - fatal_exit("out of memory adding tcp connection limit"); + yyerror("out of memory"); } } ; @@ -4217,8 +4276,8 @@ server_cookie_secret_file: VAR_COOKIE_SE server_iter_scrub_ns: VAR_ITER_SCRUB_NS STRING_ARG { OUTYY(("P(server_iter_scrub_ns:%s)\n", $2)); - if(atoi($2) == 0 && strcmp($2, "0") != 0) - yyerror("number expected"); + if(atoi($2) < 1) + yyerror("number >= 1 expected"); else cfg_parser->cfg->iter_scrub_ns = atoi($2); free($2); } @@ -4232,6 +4291,15 @@ server_iter_scrub_cname: VAR_ITER_SCRUB_ free($2); } ; +server_iter_scrub_rrsig: VAR_ITER_SCRUB_RRSIG STRING_ARG + { + OUTYY(("P(server_iter_scrub_rrsig:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->iter_scrub_rrsig = atoi($2); + free($2); + } + ; server_max_global_quota: VAR_MAX_GLOBAL_QUOTA STRING_ARG { OUTYY(("P(server_max_global_quota:%s)\n", $2)); @@ -4248,6 +4316,24 @@ server_iter_scrub_promiscuous: VAR_ITER_ yyerror("expected yes or no."); else cfg_parser->cfg->iter_scrub_promiscuous = (strcmp($2, "yes")==0); + free($2); + } + ; +server_val_validation_attempts: VAR_VAL_VALIDATION_ATTEMPTS STRING_ARG + { + OUTYY(("P(server_val_validation_attempts:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->val_validation_attempts = atoi($2); + free($2); + } + ; +server_val_hash_attempts: VAR_VAL_HASH_ATTEMPTS STRING_ARG + { + OUTYY(("P(server_val_hash_attempts:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->val_hash_attempts = atoi($2); free($2); } ; Index: sbin/unwind/libunbound/util/fptr_wlist.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/fptr_wlist.c,v diff -u -p -r1.16 fptr_wlist.c --- sbin/unwind/libunbound/util/fptr_wlist.c 14 Sep 2025 15:16:53 -0000 1.16 +++ sbin/unwind/libunbound/util/fptr_wlist.c 21 Sep 2026 16:28:00 -0000 @@ -141,6 +141,8 @@ fptr_whitelist_comm_timer(void (*fptr)(v #ifdef UB_ON_WINDOWS else if(fptr == &wsvc_cron_cb) return 1; #endif + else if(fptr == &tcp_read_again_cb) return 1; + else if(fptr == &tcp_more_read_again_cb) return 1; else if(fptr == &auth_xfer_timer) return 1; else if(fptr == &auth_xfer_probe_timer_callback) return 1; else if(fptr == &auth_xfer_transfer_timer_callback) return 1; @@ -362,7 +364,7 @@ fptr_whitelist_modenv_send_query(struct int nocaps, int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, struct module_qstate* q, - int* was_ratelimited)) + int* was_ratelimited, int* ratelimit_incremented)) { if(fptr == &worker_send_query) return 1; else if(fptr == &libworker_send_query) return 1; @@ -380,7 +382,8 @@ fptr_whitelist_modenv_detach_subs(void ( int fptr_whitelist_modenv_attach_sub(int (*fptr)( struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq)) + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq)) { if(fptr == &mesh_attach_sub) return 1; return 0; @@ -389,8 +392,8 @@ fptr_whitelist_modenv_attach_sub(int (*f int fptr_whitelist_modenv_add_sub(int (*fptr)( struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq, - struct mesh_state** sub)) + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq, struct mesh_state** sub)) { if(fptr == &mesh_add_sub) return 1; return 0; @@ -412,7 +415,7 @@ fptr_whitelist_modenv_detect_cycle(int ( return 0; } -int +int fptr_whitelist_mod_init(int (*fptr)(struct module_env* env, int id)) { if(fptr == &iter_init) return 1; @@ -440,7 +443,7 @@ fptr_whitelist_mod_init(int (*fptr)(stru return 0; } -int +int fptr_whitelist_mod_deinit(void (*fptr)(struct module_env* env, int id)) { if(fptr == &iter_deinit) return 1; @@ -609,6 +612,7 @@ int fptr_whitelist_alloc_cleanup(void (*fptr)(void*)) { if(fptr == &worker_alloc_cleanup) return 1; + else if(fptr == &libworker_alloc_cleanup) return 1; return 0; } Index: sbin/unwind/libunbound/util/fptr_wlist.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/fptr_wlist.h,v diff -u -p -r1.4 fptr_wlist.h --- sbin/unwind/libunbound/util/fptr_wlist.h 5 Sep 2024 08:22:47 -0000 1.4 +++ sbin/unwind/libunbound/util/fptr_wlist.h 21 Sep 2026 16:28:00 -0000 @@ -214,7 +214,7 @@ int fptr_whitelist_modenv_send_query(str int nocaps, int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, struct module_qstate* q, - int* was_ratelimited)); + int* was_ratelimited, int* ratelimit_incremented)); /** * Check function pointer whitelist for module_env detach_subs callback values. @@ -233,7 +233,8 @@ int fptr_whitelist_modenv_detach_subs(vo */ int fptr_whitelist_modenv_attach_sub(int (*fptr)( struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq)); + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq)); /** * Check function pointer whitelist for module_env add_sub callback values. @@ -242,8 +243,9 @@ int fptr_whitelist_modenv_attach_sub(int * @return false if not in whitelist. */ int fptr_whitelist_modenv_add_sub(int (*fptr)(struct module_qstate* qstate, - struct query_info* qinfo, uint16_t qflags, int prime, int valrec, - struct module_qstate** newq, struct mesh_state** sub)); + struct query_info* qinfo, struct respip_client_info* cinfo, + uint16_t qflags, int prime, int valrec, struct module_qstate** newq, + struct mesh_state** sub)); /** * Check function pointer whitelist for module_env kill_sub callback values. * Index: sbin/unwind/libunbound/util/iana_ports.inc =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/iana_ports.inc,v diff -u -p -r1.16 iana_ports.inc --- sbin/unwind/libunbound/util/iana_ports.inc 29 Sep 2025 14:53:38 -0000 1.16 +++ sbin/unwind/libunbound/util/iana_ports.inc 21 Sep 2026 16:28:00 -0000 @@ -649,9 +649,6 @@ 828, 829, 830, -831, -832, -833, 847, 848, 853, @@ -3869,6 +3866,7 @@ 4456, 4457, 4458, +4480, 4484, 4486, 4488, @@ -3981,6 +3979,7 @@ 4791, 4792, 4793, +4794, 4800, 4801, 4802, @@ -4173,6 +4172,7 @@ 5313, 5314, 5315, +5319, 5343, 5344, 5349, @@ -4507,6 +4507,7 @@ 6581, 6582, 6583, +6610, 6619, 6620, 6621, @@ -4609,6 +4610,7 @@ 7101, 7107, 7121, +7123, 7128, 7129, 7161, @@ -4950,6 +4952,7 @@ 9162, 9163, 9164, +9183, 9191, 9200, 9201, @@ -5343,6 +5346,7 @@ 24465, 24554, 24577, +24601, 24676, 24677, 24678, @@ -5392,6 +5396,7 @@ 30004, 30260, 30832, +30939, 30999, 31016, 31029, @@ -5433,6 +5438,8 @@ 34962, 34963, 34964, +34965, +34966, 34980, 35001, 35004, Index: sbin/unwind/libunbound/util/locks.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/locks.h,v diff -u -p -r1.2 locks.h --- sbin/unwind/libunbound/util/locks.h 23 Feb 2025 07:53:40 -0000 1.2 +++ sbin/unwind/libunbound/util/locks.h 21 Sep 2026 16:28:00 -0000 @@ -178,6 +178,30 @@ typedef pthread_key_t ub_thread_key_type #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v)) #define ub_thread_key_get(key) pthread_getspecific(key) +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#if defined(HAVE_PTHREAD_SET_NAME_NP) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_set_name_np(thread, name);\ + } while(0) +#elif defined(HAVE_PTHREAD_SETNAME_NP1) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_setname_np(name); \ + } while(0) +#elif defined(HAVE_PTHREAD_SETNAME_NP3) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_setname_np(thread, name, NULL); \ + } while(0) +#elif defined(HAVE_PTHREAD_SETNAME_NP) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_setname_np(thread, name); \ + } while(0) +#else + #define ub_thread_setname(thread, name) /* nop */ +#endif /* HAVE_PTHREAD_SET_NAME_NP */ + + #else /* we do not HAVE_PTHREAD */ #ifdef HAVE_SOLARIS_THREADS @@ -215,6 +239,7 @@ typedef thread_key_t ub_thread_key_type; #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f)) #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v)) void* ub_thread_key_get(ub_thread_key_type key); +#define ub_thread_setname(thread, name) /* nop */ #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */ @@ -253,6 +278,7 @@ typedef DWORD ub_thread_key_type; void ub_thread_key_create(ub_thread_key_type* key, void* f); void ub_thread_key_set(ub_thread_key_type key, void* v); void* ub_thread_key_get(ub_thread_key_type key); +#define ub_thread_setname(thread, name) /* nop */ #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */ @@ -294,6 +320,7 @@ typedef void* ub_thread_key_type; #define ub_thread_key_create(key, f) (*(key)) = NULL #define ub_thread_key_set(key, v) (key) = (v) #define ub_thread_key_get(key) (key) +#define ub_thread_setname(thread, name) /* nop */ #endif /* HAVE_WINDOWS_THREADS */ #endif /* HAVE_SOLARIS_THREADS */ Index: sbin/unwind/libunbound/util/log.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/log.c,v diff -u -p -r1.10 log.c --- sbin/unwind/libunbound/util/log.c 14 Sep 2025 15:16:53 -0000 1.10 +++ sbin/unwind/libunbound/util/log.c 21 Sep 2026 16:28:00 -0000 @@ -174,10 +174,10 @@ void log_thread_set(int* num) int log_thread_get(void) { - unsigned int* tid; + int* tid; if(!key_created) return 0; - tid = (unsigned int*)ub_thread_key_get(logkey); - return (int)(tid?*tid:0); + tid = ub_thread_key_get(logkey); + return (tid?*tid:0); } void log_ident_set(const char* id) @@ -229,7 +229,7 @@ log_vmsg(int pri, const char* type, const char *format, va_list args) { char message[MAXSYSLOGMSGLEN]; - unsigned int* tid = (unsigned int*)ub_thread_key_get(logkey); + int tid = log_thread_get(); time_t now; #if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R) char tmbuf[32]; @@ -241,8 +241,8 @@ log_vmsg(int pri, const char* type, vsnprintf(message, sizeof(message), format, args); #ifdef HAVE_SYSLOG_H if(logging_to_syslog) { - syslog(pri, "[%d:%x] %s: %s", - (int)getpid(), tid?*tid:0, type, message); + syslog(pri, "[%d:%d] %s: %s", + (int)getpid(), tid, type, message); return; } #elif defined(UB_ON_WINDOWS) @@ -263,8 +263,8 @@ log_vmsg(int pri, const char* type, tp=MSG_GENERIC_SUCCESS; wt=EVENTLOG_SUCCESS; } - snprintf(m, sizeof(m), "[%s:%x] %s: %s", - ident, tid?*tid:0, type, message); + snprintf(m, sizeof(m), "[%s:%d] %s: %s", + ident, tid, type, message); s = RegisterEventSource(NULL, SERVICE_NAME); if(!s) return; ReportEvent(s, wt, 0, tp, NULL, 1, 0, &str, NULL); @@ -294,9 +294,9 @@ log_vmsg(int pri, const char* type, tzbuf[3] = ':'; tzbuf[6] = 0; } - fprintf(logfile, "%s.%3.3d%s %s[%d:%x] %s: %s\n", + fprintf(logfile, "%s.%3.3d%s %s[%d:%d] %s: %s\n", tmbuf, (int)tv.tv_usec/1000, tzbuf, - ident, (int)getpid(), tid?*tid:0, type, message); + ident, (int)getpid(), tid, type, message); #ifdef UB_ON_WINDOWS /* line buffering does not work on windows */ fflush(logfile); @@ -310,19 +310,19 @@ log_vmsg(int pri, const char* type, if(log_time_asc && localtime_r(&now, &tm) && strftime(tmbuf, sizeof(tmbuf), "%b %d %H:%M:%S", &tm)%(sizeof(tmbuf)) != 0) { /* %sizeof buf!=0 because old strftime returned max on error */ - fprintf(logfile, "%s %s[%d:%x] %s: %s\n", tmbuf, - ident, (int)getpid(), tid?*tid:0, type, message); + fprintf(logfile, "%s %s[%d:%d] %s: %s\n", tmbuf, + ident, (int)getpid(), tid, type, message); } else #elif defined(UB_ON_WINDOWS) if(log_time_asc && GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, tmbuf, sizeof(tmbuf)) && GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, dtbuf, sizeof(dtbuf))) { - fprintf(logfile, "%s %s %s[%d:%x] %s: %s\n", dtbuf, tmbuf, - ident, (int)getpid(), tid?*tid:0, type, message); + fprintf(logfile, "%s %s %s[%d:%d] %s: %s\n", dtbuf, tmbuf, + ident, (int)getpid(), tid, type, message); } else #endif - fprintf(logfile, "[" ARG_LL "d] %s[%d:%x] %s: %s\n", (long long)now, - ident, (int)getpid(), tid?*tid:0, type, message); + fprintf(logfile, "[" ARG_LL "d] %s[%d:%d] %s: %s\n", (long long)now, + ident, (int)getpid(), tid, type, message); #ifdef UB_ON_WINDOWS /* line buffering does not work on windows */ fflush(logfile); Index: sbin/unwind/libunbound/util/module.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/module.h,v diff -u -p -r1.14 module.h --- sbin/unwind/libunbound/util/module.h 14 Sep 2025 15:16:53 -0000 1.14 +++ sbin/unwind/libunbound/util/module.h 21 Sep 2026 16:28:00 -0000 @@ -375,6 +375,8 @@ struct module_env { * @param q: which query state to reactivate upon return. * @param was_ratelimited: it will signal back if the query failed to pass the * ratelimit check. + * @param ratelimit_incremented: set to true if the ratelimit counter + * was increased. * @return: false on failure (memory or socket related). no query was * sent. Or returns an outbound entry with qsent and qstate set. * This outbound_entry will be used on later module invocations @@ -385,7 +387,8 @@ struct module_env { int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, - char* tls_auth_name, struct module_qstate* q, int* was_ratelimited); + char* tls_auth_name, struct module_qstate* q, int* was_ratelimited, + int* ratelimit_incremented); /** * Detach-subqueries. @@ -411,6 +414,8 @@ struct module_env { * @param qstate: the state to find mesh state, and that wants to * receive the results from the new subquery. * @param qinfo: what to query for (copied). + * @param cinfo: if non-NULL client specific info that may affect + * IP-based actions that apply to the query result. * @param qflags: what flags to use (RD, CD flag or not). * @param prime: if it is a (stub) priming query. * @param valrec: validation lookup recursion, does not need validation @@ -419,8 +424,9 @@ struct module_env { * @return: false on error, true if success (and init may be needed). */ int (*attach_sub)(struct module_qstate* qstate, - struct query_info* qinfo, uint16_t qflags, int prime, - int valrec, struct module_qstate** newq); + struct query_info* qinfo, struct respip_client_info* cinfo, + uint16_t qflags, int prime, int valrec, + struct module_qstate** newq); /** * Add detached query. @@ -440,6 +446,8 @@ struct module_env { * @param qstate: the state to find mesh state, and that wants to receive * the results from the new subquery. * @param qinfo: what to query for (copied). + * @param cinfo: if non-NULL client specific info that may affect + * IP-based actions that apply to the query result. * @param qflags: what flags to use (RD / CD flag or not). * @param prime: if it is a (stub) priming query. * @param valrec: if it is a validation recursion query (lookup of key, DS). @@ -449,9 +457,9 @@ struct module_env { * @return: false on error, true if success (and init may be needed). */ int (*add_sub)(struct module_qstate* qstate, - struct query_info* qinfo, uint16_t qflags, int prime, - int valrec, struct module_qstate** newq, - struct mesh_state** sub); + struct query_info* qinfo, struct respip_client_info* cinfo, + uint16_t qflags, int prime, int valrec, + struct module_qstate** newq, struct mesh_state** sub); /** * Kill newly attached sub. If attach_sub returns newq for @@ -693,6 +701,16 @@ struct module_qstate { time_t qstarttime; /** whether a message from cachedb will be used for the reply */ int is_cachedb_answer; + /** whether the reply is subnet specific */ + int is_subnet_answer; + /** if the response as error is from error_response_cache, and is + * suitable for caching (briefly) the error response. Set by the + * iterator when no_cache_store is enabled, and there is an error. */ + int error_response_cache; + /** if the iterator sees that the forward/stub has no_cache set. + * to signal to calling modules that their setting of no_cache for + * other reasons, has to take into account the fwd/stub no_cache. */ + int fwd_stub_no_cache; /** * Attributes of clients that share the qstate that may affect IP-based @@ -712,6 +730,12 @@ struct module_qstate { /** whether the reply should be dropped */ int is_drop; + /** the global quota that was reached, by one of the modules. + * So that continued counting can go on from that point. */ + int global_quota_reached; + /** the global quota that a query started with, it is a subquery, + * so that calling mesh states can see the increase. */ + int global_quota_started; }; /** @@ -721,7 +745,7 @@ struct module_func_block { /** text string name of module */ const char* name; - /** + /** * Set up the module for start. This is called only once at startup. * Privileged operations like opening device files may be done here. * The function ptr can be NULL, if it is not used. Index: sbin/unwind/libunbound/util/net_help.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/net_help.c,v diff -u -p -r1.23 net_help.c --- sbin/unwind/libunbound/util/net_help.c 29 Sep 2025 14:53:38 -0000 1.23 +++ sbin/unwind/libunbound/util/net_help.c 21 Sep 2026 16:28:00 -0000 @@ -242,7 +242,7 @@ int extstrtoaddr(const char* str, struct sockaddr_storage* addr, socklen_t* addrlen, int port) { - char* s; + const char* s; if((s=strchr(str, '@'))) { char buf[MAX_ADDR_STRLEN]; if(s-str >= MAX_ADDR_STRLEN) { @@ -268,7 +268,7 @@ ipstrtoaddr(const char* ip, int port, st p = (uint16_t) port; if(str_is_ip6(ip)) { char buf[MAX_ADDR_STRLEN]; - char* s; + const char* s; struct sockaddr_in6* sa = (struct sockaddr_in6*)addr; *addrlen = (socklen_t)sizeof(struct sockaddr_in6); memset(sa, 0, *addrlen); @@ -304,8 +304,9 @@ ipstrtoaddr(const char* ip, int port, st int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr, socklen_t* addrlen, int* net) { + const char* s; char buf[64]; - char* s; + char* b = NULL; *net = (str_is_ip6(str)?128:32); if((s=strchr(str, '/'))) { if(atoi(s+1) > *net) { @@ -323,15 +324,15 @@ int netblockstrtoaddr(const char* str, i return 0; } strlcpy(buf, str, sizeof(buf)); - s = strchr(buf, '/'); - if(s) *s = 0; - s = buf; + b = strchr(buf, '/'); + if(b) *b = 0; + b = buf; } - if(!ipstrtoaddr(s?s:str, port, addr, addrlen)) { + if(!ipstrtoaddr(b?b:str, port, addr, addrlen)) { log_err("cannot parse ip address: '%s'", str); return 0; } - if(s) { + if(b) { addr_mask(addr, *addrlen, *net); } return 1; @@ -783,7 +784,7 @@ sockaddr_cmp_scopeid(struct sockaddr_sto } int -addr_is_ip6(struct sockaddr_storage* addr, socklen_t len) +addr_is_ip6(const struct sockaddr_storage* addr, socklen_t len) { if(len == (socklen_t)sizeof(struct sockaddr_in6) && ((struct sockaddr_in6*)addr)->sin6_family == AF_INET6) @@ -1226,10 +1227,13 @@ setup_ticket_keys_cb(void* sslctx) #endif /* HAVE_SSL */ int -listen_sslctx_setup(void* ctxt) +listen_sslctx_setup(void* ctxt, const char* tls_protocols) { #ifdef HAVE_SSL + int allow12, allow13; SSL_CTX* ctx = (SSL_CTX*)ctxt; + cfg_tls_protocols_allowed(tls_protocols, &allow12, &allow13); + /* no SSLv2, SSLv3 because has defects */ #if SSL_OP_NO_SSLv2 != 0 if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) @@ -1259,12 +1263,24 @@ listen_sslctx_setup(void* ctxt) return 0; } #endif -#if defined(SSL_OP_NO_TLSv1_2) && defined(SSL_OP_NO_TLSv1_3) - /* if we have tls 1.3 disable 1.2 */ - if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_2) & SSL_OP_NO_TLSv1_2) - != SSL_OP_NO_TLSv1_2){ - log_crypto_err("could not set SSL_OP_NO_TLSv1_2"); - return 0; +#if defined(SSL_OP_NO_TLSv1_2) + if(!allow12) { + /* we are not allowed to use TLS1.2 */ + if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_2) & SSL_OP_NO_TLSv1_2) + != SSL_OP_NO_TLSv1_2){ + log_crypto_err("could not set SSL_OP_NO_TLSv1_2"); + return 0; + } + } +#endif +#if defined(SSL_OP_NO_TLSv1_3) + if(!allow13) { + /* we are not allowed to use TLS1.3 */ + if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_3) & SSL_OP_NO_TLSv1_3) + != SSL_OP_NO_TLSv1_3){ + log_crypto_err("could not set SSL_OP_NO_TLSv1_3"); + return 0; + } } #endif #if defined(SSL_OP_NO_RENEGOTIATION) @@ -1305,7 +1321,7 @@ listen_sslctx_setup(void* ctxt) SSL_CTX_set_security_level(ctx, 0); #endif #else - (void)ctxt; + (void)ctxt; (void)tls_protocols; #endif /* HAVE_SSL */ return 1; } @@ -1341,7 +1357,7 @@ listen_sslctx_setup_2(void* ctxt) void* listen_sslctx_create(const char* key, const char* pem, const char* verifypem, const char* tls_ciphers, const char* tls_ciphersuites, int set_ticket_keys_cb, - int is_dot, int is_doh) + int is_dot, int is_doh, const char* tls_protocols) { #ifdef HAVE_SSL SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method()); @@ -1359,7 +1375,7 @@ void* listen_sslctx_create(const char* k SSL_CTX_free(ctx); return NULL; } - if(!listen_sslctx_setup(ctx)) { + if(!listen_sslctx_setup(ctx, tls_protocols)) { SSL_CTX_free(ctx); return NULL; } @@ -1430,12 +1446,15 @@ void* listen_sslctx_create(const char* k SSL_CTX_set_alpn_select_cb(ctx, doh_alpn_select_cb, NULL); #endif } +#else /* HAVE_SSL_CTX_SET_ALPN_SELECT_CB */ + (void)is_dot; (void)is_doh; #endif /* HAVE_SSL_CTX_SET_ALPN_SELECT_CB */ return ctx; #else (void)key; (void)pem; (void)verifypem; (void)tls_ciphers; (void)tls_ciphersuites; (void)set_ticket_keys_cb; (void)is_dot; (void)is_doh; + (void)tls_protocols; return NULL; #endif /* HAVE_SSL */ } @@ -1688,6 +1707,10 @@ int check_auth_name_for_ssl(char* auth_n /** set the authname on an SSL structure, SSL* ssl */ int set_auth_name_on_ssl(void* ssl, char* auth_name, int use_sni) { +#ifdef HAVE_SSL_SET1_DNSNAME + struct sockaddr_storage tmpaddr; + socklen_t tmpaddrlen = (socklen_t)sizeof(tmpaddr); +#endif if(!auth_name) return 1; #ifdef HAVE_SSL if(use_sni) { @@ -1697,7 +1720,20 @@ int set_auth_name_on_ssl(void* ssl, char (void)ssl; (void)use_sni; #endif -#ifdef HAVE_SSL_SET1_HOST +#ifdef HAVE_SSL_SET1_DNSNAME + SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL); + if(ipstrtoaddr(auth_name, UNBOUND_DNS_PORT, &tmpaddr, &tmpaddrlen)) { + if(!SSL_set1_ipaddr(ssl, auth_name)) { + log_err("SSL_set1_ipaddr failed"); + return 0; + } + } else { + if(!SSL_set1_dnsname(ssl, auth_name)) { + log_err("SSL_set1_dnsname failed"); + return 0; + } + } +#elif defined(HAVE_SSL_SET1_HOST) SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL); /* setting the hostname makes openssl verify the * host name in the x509 certificate in the @@ -1797,7 +1833,7 @@ void ub_openssl_lock_delete(void) #endif /* OPENSSL_THREADS */ } -int listen_sslctx_setup_ticket_keys(struct config_strlist* tls_session_ticket_keys) { +int listen_sslctx_setup_ticket_keys(struct config_strlist* tls_session_ticket_keys, char* chroot) { #ifdef HAVE_SSL size_t s = 1; struct config_strlist* p; @@ -1815,14 +1851,18 @@ int listen_sslctx_setup_ticket_keys(stru size_t n; unsigned char *data; FILE *f; + char* fstr; data = (unsigned char *)malloc(80); if(!data) return 0; - f = fopen(p->str, "rb"); + fstr = p->str; + if(chroot && strncmp(fstr, chroot, strlen(chroot)) == 0) + fstr += strlen(chroot); + f = fopen(fstr, "rb"); if(!f) { - log_err("could not read tls-session-ticket-key %s: %s", p->str, strerror(errno)); + log_err("could not read tls-session-ticket-key %s: %s", fstr, strerror(errno)); free(data); return 0; } @@ -1830,11 +1870,11 @@ int listen_sslctx_setup_ticket_keys(stru fclose(f); if(n != 80) { - log_err("tls-session-ticket-key %s is %d bytes, must be 80 bytes", p->str, (int)n); + log_err("tls-session-ticket-key %s is %d bytes, must be 80 bytes", fstr, (int)n); free(data); return 0; } - verbose(VERB_OPS, "read tls-session-ticket-key: %s", p->str); + verbose(VERB_OPS, "read tls-session-ticket-key: %s", fstr); keys->key_name = data; keys->aes_key = data + 16; @@ -1845,7 +1885,7 @@ int listen_sslctx_setup_ticket_keys(stru keys->key_name = NULL; return 1; #else - (void)tls_session_ticket_keys; + (void)tls_session_ticket_keys; (void)chroot; return 0; #endif } Index: sbin/unwind/libunbound/util/net_help.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/net_help.h,v diff -u -p -r1.13 net_help.h --- sbin/unwind/libunbound/util/net_help.h 14 Sep 2025 15:16:53 -0000 1.13 +++ sbin/unwind/libunbound/util/net_help.h 21 Sep 2026 16:28:00 -0000 @@ -307,7 +307,7 @@ int sockaddr_cmp_scopeid(struct sockaddr * @param len: the length of addr. * @return: true if sockaddr is ip6. */ -int addr_is_ip6(struct sockaddr_storage* addr, socklen_t len); +int addr_is_ip6(const struct sockaddr_storage* addr, socklen_t len); /** * Make sure the sockaddr ends in zeroes. For tree insertion and subsequent @@ -478,9 +478,10 @@ void log_cert(unsigned level, const char /** * Set SSL_OP_NOxxx options on SSL context to disable bad crypto * @param ctxt: SSL_CTX* + * @param tls_protocols: configure string with allowed TLS protocols to use. * @return false on failure. */ -int listen_sslctx_setup(void* ctxt); +int listen_sslctx_setup(void* ctxt, const char* tls_protocols); /** * Further setup of listening SSL context, after keys loaded. @@ -499,12 +500,13 @@ void listen_sslctx_setup_2(void* ctxt); * to be set. * @param is_dot: if the TLS connection is for DoT to set the appropriate ALPN. * @param is_doh: if the TLS connection is for DoH to set the appropriate ALPN. + * @param tls_protocols: configure string with allowed TLS protocols to use. * return SSL_CTX* or NULL on failure (logged). */ void* listen_sslctx_create(const char* key, const char* pem, const char* verifypem, const char* tls_ciphers, const char* tls_ciphersuites, int set_ticket_keys_cb, - int is_dot, int is_doh); + int is_dot, int is_doh, const char* tls_protocols); /** * create SSL connect context @@ -563,9 +565,11 @@ void ub_openssl_lock_delete(void); /** * setup TLS session ticket * @param tls_session_ticket_keys: TLS ticket secret filenames + * @param chroot: if not NULL, the chroot that is in use. * @return false on failure (alloc failure). */ -int listen_sslctx_setup_ticket_keys(struct config_strlist* tls_session_ticket_keys); +int listen_sslctx_setup_ticket_keys( + struct config_strlist* tls_session_ticket_keys, char* chroot); /** Free memory used for TLS session ticket keys */ void listen_sslctx_delete_ticket_keys(void); Index: sbin/unwind/libunbound/util/netevent.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/netevent.c,v diff -u -p -r1.26 netevent.c --- sbin/unwind/libunbound/util/netevent.c 29 Sep 2025 14:53:38 -0000 1.26 +++ sbin/unwind/libunbound/util/netevent.c 21 Sep 2026 16:28:01 -0000 @@ -122,6 +122,10 @@ #define NUM_UDP_PER_SELECT 1 #endif +/** The number of TCP queries over a TCP connection, per read indication + * from select. */ +#define NUM_TCP_PER_SELECT 100 + /** timeout in millisec to wait for write to unblock, packets dropped after.*/ #define SEND_BLOCKED_WAIT_TIMEOUT 200 /** max number of times to wait for write to unblock, packets dropped after.*/ @@ -951,6 +955,10 @@ static int consume_pp2_header(struct sld { struct sockaddr_in* addr = (struct sockaddr_in*)&rep->client_addr; + if(ntohs(header->len) < PP2_HEADER_LEN_INET) { + verbose(VERB_OPS, "proxy_protocol: header too short for IPv4 address"); + return 0; + } addr->sin_family = AF_INET; addr->sin_addr.s_addr = header->addr.addr4.src_addr; addr->sin_port = header->addr.addr4.src_port; @@ -963,6 +971,10 @@ static int consume_pp2_header(struct sld { struct sockaddr_in6* addr = (struct sockaddr_in6*)&rep->client_addr; + if(ntohs(header->len) < PP2_HEADER_LEN_INET6) { + verbose(VERB_OPS, "proxy_protocol: header too short for IPv6 address"); + return 0; + } memset(addr, 0, sizeof(*addr)); addr->sin6_family = AF_INET6; memcpy(&addr->sin6_addr, @@ -1827,7 +1839,6 @@ doq_send_retry(struct comm_point* c, str char host[256], port[32]; struct ngtcp2_cid scid; uint8_t token[NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN]; - ngtcp2_tstamp ts; ngtcp2_ssize tokenlen, ret; if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, @@ -1841,12 +1852,10 @@ doq_send_retry(struct comm_point* c, str scid.datalen = c->doq_socket->sv_scidlen; doq_cid_randfill(&scid, scid.datalen, c->doq_socket->rnd); - ts = doq_get_timestamp_nanosec(); - tokenlen = ngtcp2_crypto_generate_retry_token(token, c->doq_socket->static_secret, c->doq_socket->static_secret_len, hd->version, (void*)&paddr->addr, paddr->addrlen, &scid, - &hd->dcid, ts); + &hd->dcid, doq_get_timestamp_nanosec()); if(tokenlen < 0) { log_err("ngtcp2_crypto_generate_retry_token failed: %s", ngtcp2_strerror(tokenlen)); @@ -1895,13 +1904,11 @@ doq_verify_retry_token(struct comm_point struct ngtcp2_cid* ocid, struct ngtcp2_pkt_hd* hd) { char host[256], port[32]; - ngtcp2_tstamp ts; if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, sizeof(host), port, sizeof(port))) { log_err("doq_verify_retry_token failed"); return 0; } - ts = doq_get_timestamp_nanosec(); verbose(VERB_ALGO, "doq: verifying retry token from %s %s", host, port); if(ngtcp2_crypto_verify_retry_token(ocid, @@ -1913,7 +1920,7 @@ doq_verify_retry_token(struct comm_point c->doq_socket->static_secret, c->doq_socket->static_secret_len, hd->version, (void*)&paddr->addr, paddr->addrlen, &hd->dcid, - 10*NGTCP2_SECONDS, ts) != 0) { + 10*NGTCP2_SECONDS, doq_get_timestamp_nanosec()) != 0) { verbose(VERB_ALGO, "doq: could not verify retry token " "from %s %s", host, port); return 0; @@ -1928,13 +1935,11 @@ doq_verify_token(struct comm_point* c, s struct ngtcp2_pkt_hd* hd) { char host[256], port[32]; - ngtcp2_tstamp ts; if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, sizeof(host), port, sizeof(port))) { log_err("doq_verify_token failed"); return 0; } - ts = doq_get_timestamp_nanosec(); verbose(VERB_ALGO, "doq: verifying token from %s %s", host, port); if(ngtcp2_crypto_verify_regular_token( #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN @@ -1944,7 +1949,7 @@ doq_verify_token(struct comm_point* c, s #endif c->doq_socket->static_secret, c->doq_socket->static_secret_len, (void*)&paddr->addr, paddr->addrlen, 3600*NGTCP2_SECONDS, - ts) != 0) { + doq_get_timestamp_nanosec()) != 0) { verbose(VERB_ALGO, "doq: could not verify token from %s %s", host, port); return 0; @@ -2171,6 +2176,7 @@ doq_pickup_timer(struct comm_point* c) { struct doq_timer* t; struct timeval tv; + ngtcp2_tstamp ts = 0; int have_time = 0; memset(&tv, 0, sizeof(tv)); @@ -2180,27 +2186,24 @@ doq_pickup_timer(struct comm_point* c) t->worker_doq_socket == c->doq_socket) { /* pick up this element */ t->worker_doq_socket = c->doq_socket; + memcpy(&tv, &t->time_real, sizeof(tv)); + ts = t->time_mono; have_time = 1; - memcpy(&tv, &t->time, sizeof(tv)); break; } } lock_rw_unlock(&c->doq_socket->table->lock); - + c->doq_socket->marked_time = ts; if(have_time) { struct timeval rel; timeval_subtract(&rel, &tv, c->doq_socket->now_tv); comm_timer_set(c->doq_socket->timer, &rel); - memcpy(&c->doq_socket->marked_time, &tv, - sizeof(c->doq_socket->marked_time)); verbose(VERB_ALGO, "doq pickup timer at %d.%6.6d in %d.%6.6d", (int)tv.tv_sec, (int)tv.tv_usec, (int)rel.tv_sec, (int)rel.tv_usec); } else { if(comm_timer_is_set(c->doq_socket->timer)) comm_timer_disable(c->doq_socket->timer); - memset(&c->doq_socket->marked_time, 0, - sizeof(c->doq_socket->marked_time)); verbose(VERB_ALGO, "doq timer disabled"); } } @@ -2213,13 +2216,14 @@ doq_done_setup_timer_and_write(struct co uint8_t cid[NGTCP2_MAX_CIDLEN]; rbnode_type* node; struct timeval new_tv; + ngtcp2_tstamp new_ts; int write_change = 0, timer_change = 0; /* No longer in callbacks, so the pointer to doq_socket is back * to NULL. */ conn->doq_socket = NULL; - if(doq_conn_check_timer(conn, &new_tv)) + if(doq_conn_check_timer(conn, &new_tv, &new_ts)) timer_change = 1; if( (conn->write_interest && !conn->on_write_list) || (!conn->write_interest && conn->on_write_list)) @@ -2265,7 +2269,7 @@ doq_done_setup_timer_and_write(struct co } if(timer_change) { doq_timer_set(c->doq_socket->table, &conn->timer, - c->doq_socket, &new_tv); + c->doq_socket, &new_tv, new_ts); } lock_rw_unlock(&c->doq_socket->table->lock); lock_basic_unlock(&conn->lock); @@ -2429,7 +2433,7 @@ doq_write_blocked_pkt(struct comm_point* return 1; } -/** doq find a timer that timeouted and return the conn, locked. */ +/** doq find a timer that timed out and return the conn, locked. */ static struct doq_conn* doq_timer_timeout_conn(struct doq_server_socket* doq_socket) { @@ -2442,7 +2446,7 @@ doq_timer_timeout_conn(struct doq_server conn = t->conn; /* If now < timer then no further timeouts in tree. */ - if(timeval_smaller(doq_socket->now_tv, &t->time)) { + if(timeval_smaller(doq_socket->now_tv, &t->time_real)) { lock_rw_unlock(&doq_socket->table->lock); return NULL; } @@ -2465,11 +2469,11 @@ doq_timer_erase_marker(struct doq_server { struct doq_timer* t; lock_rw_wrlock(&doq_socket->table->lock); - t = doq_timer_find_time(doq_socket->table, &doq_socket->marked_time); + t = doq_timer_find_time(doq_socket->table, doq_socket->marked_time); if(t && t->worker_doq_socket == doq_socket) t->worker_doq_socket = NULL; lock_rw_unlock(&doq_socket->table->lock); - memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time)); + doq_socket->marked_time = 0; } void @@ -2723,6 +2727,7 @@ doq_server_socket_create(struct doq_tabl { size_t doq_buffer_size = 4096; /* bytes buffer size, for one packet. */ struct doq_server_socket* doq_socket; + log_assert(table != NULL); doq_socket = calloc(1, sizeof(*doq_socket)); if(!doq_socket) { return NULL; @@ -2775,7 +2780,7 @@ doq_server_socket_create(struct doq_tabl free(doq_socket); return NULL; } - memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time)); + doq_socket->marked_time = 0; comm_base_timept(base, &doq_socket->now_tt, &doq_socket->now_tv); doq_socket->cfg = cfg; return doq_socket; @@ -2804,6 +2809,7 @@ doq_lookup_repinfo(struct doq_table* tab { struct doq_conn* conn; struct doq_conn_key key; + log_assert(table != NULL); doq_conn_key_from_repinfo(&key, repinfo); lock_rw_rdlock(&table->lock); conn = doq_conn_find(table, &key.paddr.addr, @@ -2938,6 +2944,8 @@ setup_tcp_handler(struct comm_point* c, c->tcp_is_reading = 1; c->tcp_byte_count = 0; c->tcp_keepalive = 0; + /* reset to configured value before applying load-based reduction */ + c->tcp_timeout_msec = c->tcp_parent->tcp_timeout_msec; /* if more than half the tcp handlers are in use, use a shorter * timeout for this TCP connection, we need to make space for * other connections to be able to get attention */ @@ -2973,6 +2981,62 @@ void comm_base_handle_slow_accept(int AT } } +/** out of resources in the accept path: pause all listening for + * NETEVENT_SLOW_ACCEPT_TIME and re-arm via comm_base_handle_slow_accept. + * + * If the routine fails, the socket is accepted and then closed, draining it + * from the waiting list of connections to be accepted. + * @param c: the comm point that is a listening socket. + * @param msec: if 0: uses the slow accept time. Otherwise, sets the time + * to wait. + */ +static void +comm_point_slow_accept(struct comm_point* c, int msec) +{ + struct comm_base* b = c->ev->base; + struct timeval tv; + struct ub_event* slowev; + if(!b->stop_accept) + return; + if(b->eb->slow_accept_enabled) + return; + /* Allocate the event */ + slowev = ub_event_new(b->eb->base, -1, UB_EV_TIMEOUT, + comm_base_handle_slow_accept, b); + if(!slowev) { + /* The slow accept was not enabled yet, to handle + * the allocation failure, instead drain the incoming + * connection. */ + int new_fd = accept(c->fd, NULL, NULL); + if(new_fd != -1) { + verbose(VERB_ALGO, "slow accept: event_new failed, " + "drop connection"); + sock_close(new_fd); + } + return; + } + ub_comm_base_now(b); + if(b->eb->last_slow_log+SLOW_LOG_TIME <= b->eb->secs) { + b->eb->last_slow_log = b->eb->secs; + verbose(VERB_OPS, "out of resources on accept, " + "slow down accept for %d msec", + NETEVENT_SLOW_ACCEPT_TIME); + } + b->eb->slow_accept_enabled = 1; + fptr_ok(fptr_whitelist_stop_accept(b->stop_accept)); + (*b->stop_accept)(b->cb_arg); + /* set timeout, no mallocs */ + if(msec == 0) + msec = NETEVENT_SLOW_ACCEPT_TIME; + tv.tv_sec = msec/1000; + tv.tv_usec = (msec%1000)*1000; + b->eb->slow_accept = slowev; + if(ub_event_add(b->eb->slow_accept, &tv) != 0) { + /* we do not want to log here, + * error: "event_add failed." */ + } +} + int comm_point_perform_accept(struct comm_point* c, struct sockaddr_storage* addr, socklen_t* addrlen) { @@ -3006,6 +3070,14 @@ int comm_point_perform_accept(struct com if(c->ev->base->stop_accept) { struct comm_base* b = c->ev->base; struct timeval tv; + struct ub_event* slowev = ub_event_new( + b->eb->base, -1, UB_EV_TIMEOUT, + comm_base_handle_slow_accept, b); + if(!slowev) { + verbose(VERB_ALGO, "slow accept: " + "event_new failed"); + return -1; + } verbose(VERB_ALGO, "out of file descriptors: " "slow accept"); ub_comm_base_now(b); @@ -3025,15 +3097,8 @@ int comm_point_perform_accept(struct com /* set timeout, no mallocs */ tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000; tv.tv_usec = (NETEVENT_SLOW_ACCEPT_TIME%1000)*1000; - b->eb->slow_accept = ub_event_new(b->eb->base, - -1, UB_EV_TIMEOUT, - comm_base_handle_slow_accept, b); - if(b->eb->slow_accept == NULL) { - /* we do not want to log here, because - * that would spam the logfiles. - * error: "event_base_set failed." */ - } - else if(ub_event_add(b->eb->slow_accept, &tv) + b->eb->slow_accept = slowev; + if(ub_event_add(b->eb->slow_accept, &tv) != 0) { /* we do not want to log here, * error: "event_add failed." */ @@ -3165,6 +3230,26 @@ static int http2_submit_settings(struct } #endif /* HAVE_NGHTTP2 */ +/** Clear http2 stream mesh states */ +static void http2_session_clear_meshstate(struct http2_session* h2_session) +{ +#ifdef HAVE_NGHTTP2 + /* Since the session gets closed, remove the mesh state references. */ + struct http2_stream* h2_stream; + for(h2_stream = h2_session->first_stream; h2_stream; + h2_stream = h2_stream->next) { + if(h2_stream->mesh_state) { + mesh_state_remove_reply(h2_stream->mesh, + h2_stream->mesh_state, h2_session->c, + h2_stream, NULL); + h2_stream->mesh_state = NULL; + } + } +#else + (void)h2_session; +#endif /* HAVE_NGHTTP2 */ +} + #ifdef HAVE_NGHTTP2 /** Delete http2 stream. After session delete or stream close callback */ static void http2_stream_delete(struct http2_session* h2_session, @@ -3172,7 +3257,7 @@ static void http2_stream_delete(struct h { if(h2_stream->mesh_state) { mesh_state_remove_reply(h2_stream->mesh, h2_stream->mesh_state, - h2_session->c); + h2_session->c, h2_stream, NULL); h2_stream->mesh_state = NULL; } http2_req_stream_clear(h2_stream); @@ -3214,6 +3299,13 @@ comm_point_tcp_accept_callback(int fd, s /* find free tcp handler. */ if(!c->tcp_free) { log_warn("accepted too many tcp, connections full"); + /* Wait for a short moment (say 50msec) so that other + * TCP connections can complete. Or timeout, at the busy + * timeout of about 200msec. That stops this routine from + * spinning endlessly, and gives time to complete the other + * requests. But it is not as slow as the 2000msec wait + * time for when the kernel is out of buffers. */ + comm_point_slow_accept(c, NETEVENT_SLOW_ACCEPT_QUEUE_TIME); return; } /* accept incoming connection. */ @@ -3235,6 +3327,7 @@ comm_point_tcp_accept_callback(int fd, s if(!c_hdl->h2_session || !http2_session_server_create(c_hdl->h2_session)) { log_warn("failed to create nghttp2"); + comm_point_slow_accept(c, 0); return; } if(!c_hdl->h2_session || @@ -3242,6 +3335,7 @@ comm_point_tcp_accept_callback(int fd, s log_warn("failed to submit http2 settings"); if(c_hdl->h2_session) http2_session_server_delete(c_hdl->h2_session); + comm_point_slow_accept(c, 0); return; } if(!c->ssl) { @@ -3258,11 +3352,12 @@ comm_point_tcp_accept_callback(int fd, s comm_point_tcp_handle_callback, c_hdl); } if(!c_hdl->ev->ev) { - log_warn("could not ub_event_new, dropped tcp"); + log_warn("could not ub_event_new, for new tcp"); #ifdef HAVE_NGHTTP2 if(c_hdl->type == comm_http && c_hdl->h2_session) http2_session_server_delete(c_hdl->h2_session); #endif + comm_point_slow_accept(c, 0); return; } log_assert(fd != -1); @@ -3276,6 +3371,10 @@ comm_point_tcp_accept_callback(int fd, s #endif return; } + /* move per-netblock TCP-connection-limit handle to the handler so that + * comm_point_close() on the handler decrements the count on close */ + c_hdl->tcl_addr = c->tcl_addr; + c->tcl_addr = NULL; /* Copy remote_address to client_address. * Simplest way/time for streams to do that. */ c_hdl->repinfo.client_addrlen = c_hdl->repinfo.remote_addrlen; @@ -4178,8 +4277,8 @@ recv_error: if(errno == EINTR || errno == EAGAIN) return 1; #ifdef ECONNRESET - if(errno == ECONNRESET && verbosity < 2) - return 0; /* silence reset by peer */ + if(errno == ECONNRESET && verbosity < 2) + return 0; /* silence reset by peer */ #endif if(recv_initial) { #ifdef ECONNREFUSED @@ -4546,6 +4645,10 @@ comm_point_tcp_handle_write(int fd, stru static int tcp_req_info_read_again(int fd, struct comm_point* c) { + /* One event-loop visit drains at most this many pipelined queries; + * the rest is re-queued, so that other file descriptors get + * serviced in between. */ + int budget = NUM_TCP_PER_SELECT; while(c->tcp_req_info->read_again) { int r; c->tcp_req_info->read_again = 0; @@ -4562,6 +4665,16 @@ tcp_req_info_read_again(int fd, struct c } return 0; } + if(--budget <= 0 && c->tcp_req_info->read_again) { + /* Defer the rest of the drain to the next loop turn. + * This uses a zero delay timer. For TLS the undrained + * remainder sits in OpenSSL's user-space buffer. */ + struct timeval tv; + memset(&tv, 0, sizeof(tv)); + verbose(VERB_ALGO, "Defer tcp_req_info read again"); + comm_timer_set(c->tcp_req_info->read_again_timer, &tv); + return 1; + } } return 1; } @@ -4575,6 +4688,7 @@ tcp_more_read_again(int fd, struct comm_ /* this continues until the read routines get EAGAIN or so, * and thus does not call the callback, and the bool is 0 */ int* moreread = c->tcp_more_read_again; + int budget = NUM_TCP_PER_SELECT; while(moreread && *moreread) { *moreread = 0; if(!comm_point_tcp_handle_read(fd, c, 0)) { @@ -4587,6 +4701,30 @@ tcp_more_read_again(int fd, struct comm_ } return; } + if(--budget <= 0 && *moreread) { + /* Defer the rest of the drain to the next loop turn. + * This uses a zero delay timer. For TLS the undrained + * remainder sits in OpenSSL's user-space buffer. */ + struct timeval tv; + memset(&tv, 0, sizeof(tv)); + if(!c->tcp_more_read_again_timer) { + c->tcp_more_read_again_timer = comm_timer_create(c->ev->base, tcp_more_read_again_cb, c); + if(!c->tcp_more_read_again_timer) { + log_err("out of memory for tcp more read again timer"); + reclaim_tcp_handler(c); + if(!c->tcp_do_close) { + fptr_ok(fptr_whitelist_comm_point( + c->callback)); + (void)(*c->callback)(c, c->cb_arg, + NETEVENT_CLOSED, NULL); + } + return; + } + } + verbose(VERB_ALGO, "Defer more read again"); + comm_timer_set(c->tcp_more_read_again_timer, &tv); + return; + } } } @@ -4615,6 +4753,23 @@ tcp_more_write_again(int fd, struct comm } void +tcp_read_again_cb(void* arg) +{ + struct tcp_req_info* req = (struct tcp_req_info*)arg; + verbose(VERB_ALGO, "tcp_read_again_cb"); + if(!tcp_req_info_read_again(req->cp->fd, req->cp)) + return; +} + +void +tcp_more_read_again_cb(void* arg) +{ + struct comm_point* c = (struct comm_point*)arg; + verbose(VERB_ALGO, "tcp_more_read_again_cb"); + tcp_more_read_again(c->fd, c); +} + +void comm_point_tcp_handle_callback(int fd, short event, void* arg) { struct comm_point* c = (struct comm_point*)arg; @@ -4868,8 +5023,17 @@ http_process_initial_header(struct comm_ return 0; } } else if(strncasecmp(line, "Content-Length: ", 16) == 0) { - if(!c->http_is_chunked) - c->tcp_byte_count = (size_t)atoi(line+16); + if(!c->http_is_chunked) { + char* end = NULL; + long long cl; + errno = 0; + cl = strtoll(line+16, &end, 10); + if(end == line+16 || errno != 0 || cl < 0) { + verbose(VERB_ALGO, "http invalid Content-Length: " ARG_LL "d", cl); + return 0; /* reject */ + } + c->tcp_byte_count = (size_t)cl; + } } else if(strncasecmp(line, "Transfer-Encoding: chunked", 19+7) == 0) { c->tcp_byte_count = 0; c->http_is_chunked = 1; @@ -4925,9 +5089,15 @@ http_process_chunk_header(struct comm_po if(c->http_in_chunk_headers == 1) { /* read chunked start line */ char* end = NULL; - c->tcp_byte_count = (size_t)strtol(line, &end, 16); - if(end == line) + long chunk_sz; + errno = 0; + chunk_sz = strtol(line, &end, 16); + if(end == line || errno != 0 || chunk_sz < 0) { + verbose(VERB_ALGO, "http invalid chunk size: %ld", + chunk_sz); return 0; + } + c->tcp_byte_count = (size_t)chunk_sz; c->http_in_chunk_headers = 0; /* remove header text from front of buffer */ http_moveover_buffer(c->buffer); @@ -5005,6 +5175,14 @@ http_chunked_segment(struct comm_point* c->http_stored = 0; sldns_buffer_skip(c->buffer, (ssize_t)c->tcp_byte_count); sldns_buffer_clear(c->http_temp); + if(sldns_buffer_remaining(c->buffer) > + sldns_buffer_capacity(c->http_temp)) { + verbose(VERB_OPS, "http chunked: surplus %d exceeds " + "temp buffer %d", (int)sldns_buffer_remaining( + c->buffer), (int)sldns_buffer_capacity( + c->http_temp)); + return 0; + } sldns_buffer_write(c->http_temp, sldns_buffer_current(c->buffer), sldns_buffer_remaining(c->buffer)); @@ -5335,6 +5513,13 @@ comm_point_http_handle_read(int fd, stru if(c->http_in_headers || c->http_in_chunk_headers) { /* if header is done, process the header */ if(!http_header_done(c->buffer)) { + if(sldns_buffer_limit(c->buffer) == + sldns_buffer_capacity(c->buffer)) { + verbose(VERB_OPS, "http header line " + "exceeds %d bytes, transfer " + "failed", (int)sldns_buffer_capacity(c->buffer)); + return 0; + } /* copy remaining data to front of buffer * and set rest for writing into it */ http_moveover_buffer(c->buffer); @@ -5883,6 +6068,7 @@ comm_point_create_doq(struct comm_base * struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); short evbits; + log_assert(table != NULL); if(!c) return NULL; c->ev = (struct internal_event*)calloc(1, @@ -6025,7 +6211,7 @@ comm_point_create_tcp_handler(struct com c->pp2_enabled = parent->pp2_enabled; c->pp2_header_state = pp2_header_none; if(spoolbuf) { - c->tcp_req_info = tcp_req_info_create(spoolbuf); + c->tcp_req_info = tcp_req_info_create(base, spoolbuf); if(!c->tcp_req_info) { log_err("could not create tcp commpoint"); sldns_buffer_free(c->buffer); @@ -6574,7 +6760,10 @@ comm_point_close(struct comm_point* c) c->event_added = 0; } } - tcl_close_connection(c->tcl_addr); + if(c->tcl_addr) { + tcl_close_connection(c->tcl_addr); + c->tcl_addr = NULL; + } if(c->tcp_req_info) tcp_req_info_clear(c->tcp_req_info); if(c->h2_session) @@ -6584,6 +6773,9 @@ comm_point_close(struct comm_point* c) *c->tcp_more_read_again = 0; if(c->tcp_more_write_again && *c->tcp_more_write_again) *c->tcp_more_write_again = 0; + if(c->tcp_more_read_again_timer && + comm_timer_is_set(c->tcp_more_read_again_timer)) + comm_timer_disable(c->tcp_more_read_again_timer); /* close fd after removing from event lists, or epoll.. is messed up */ if(c->fd != -1 && !c->do_not_close) { @@ -6623,6 +6815,7 @@ comm_point_delete(struct comm_point* c) free(c->tcp_handlers); } free(c->timeout); + comm_timer_delete(c->tcp_more_read_again_timer); if(c->type == comm_tcp || c->type == comm_local || c->type == comm_http) { sldns_buffer_free(c->buffer); #ifdef USE_DNSCRYPT @@ -6667,7 +6860,9 @@ comm_point_send_reply(struct comm_reply log_assert(repinfo && repinfo->c); #ifdef USE_DNSCRYPT buffer = repinfo->c->dnscrypt_buffer; - if(!dnsc_handle_uncurved_request(repinfo)) { + if(!dnsc_handle_uncurved_request(repinfo, + repinfo->c->tcp_req_info? + repinfo->c->tcp_req_info->spool_buffer:repinfo->c->buffer)) { return; } #else @@ -6728,7 +6923,6 @@ comm_point_send_reply(struct comm_reply tcp_req_info_send_reply(repinfo->c->tcp_req_info); } else if(repinfo->c->use_h2) { if(!http2_submit_dns_response(repinfo->c->h2_session)) { - comm_point_drop_reply(repinfo); return; } repinfo->c->h2_stream = NULL; @@ -6762,6 +6956,7 @@ comm_point_drop_reply(struct comm_reply* if(repinfo->c->type == comm_http) { if(repinfo->c->h2_session) { repinfo->c->h2_session->is_drop = 1; + http2_session_clear_meshstate(repinfo->c->h2_session); if(!repinfo->c->h2_session->postpone_drop) reclaim_http_handler(repinfo->c); return; Index: sbin/unwind/libunbound/util/netevent.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/netevent.h,v diff -u -p -r1.15 netevent.h --- sbin/unwind/libunbound/util/netevent.h 29 Sep 2025 14:53:38 -0000 1.15 +++ sbin/unwind/libunbound/util/netevent.h 21 Sep 2026 16:28:01 -0000 @@ -111,6 +111,8 @@ typedef int comm_point_callback_type(str /** timeout to slow accept calls when not possible, in msec. */ #define NETEVENT_SLOW_ACCEPT_TIME 2000 +/** timeout to slow accept calls when tcp queue is full, in msec. */ +#define NETEVENT_SLOW_ACCEPT_QUEUE_TIME 50 /** timeout to slow down log print, so it does not spam the logs, in sec */ #define SLOW_LOG_TIME 10 /** for doq, the maximum dcid length, in ngtcp2 it is 20. */ @@ -187,6 +189,8 @@ struct comm_reply { /** port number for doq */ int doq_srcport; #endif /* HAVE_NGTCP2 */ + /** The doq stream to register mesh states to. */ + struct doq_stream* doq_stream; }; /** @@ -380,6 +384,9 @@ struct comm_point { * Or leave NULL if it is not used at all. */ int* tcp_more_write_again; + /** resume timer for tcp_more_read_again */ + struct comm_timer* tcp_more_read_again_timer; + /** if set, read/write completes: read/write state of tcp is toggled. buffer reset/bytecount reset. @@ -1093,8 +1100,10 @@ struct doq_server_socket { struct doq_pkt_addr* blocked_paddr; /** timer for this worker on this comm_point to wait on. */ struct comm_timer* timer; +#ifdef HAVE_NGTCP2 /** the timer that is marked by the doq_socket as waited on. */ - struct timeval marked_time; + ngtcp2_tstamp marked_time; +#endif /** the current time for use by time functions, time_t. */ time_t* now_tt; /** the current time for use by time functions, timeval. */ @@ -1126,6 +1135,12 @@ void doq_send_pkt(struct comm_point* c, /** doq timer callback function. */ void doq_timer_cb(void* arg); + +/** tcp read again callback function. For tcp req info listen. */ +void tcp_read_again_cb(void* arg); + +/** tcp more read again callback function. For outside network. */ +void tcp_more_read_again_cb(void* arg); /** * This routine is published for checks and tests, and is only used internally. Index: sbin/unwind/libunbound/util/proxy_protocol.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/proxy_protocol.c,v diff -u -p -r1.3 proxy_protocol.c --- sbin/unwind/libunbound/util/proxy_protocol.c 5 Sep 2024 08:22:47 -0000 1.3 +++ sbin/unwind/libunbound/util/proxy_protocol.c 21 Sep 2026 16:28:01 -0000 @@ -185,14 +185,23 @@ pp2_read_header(uint8_t* buf, size_t buf (header->ver_cmd & 0xF) != PP2_CMD_PROXY) { return PP_PARSE_UNKNOWN_CMD; } - /* Check for supported family and protocol */ - if(header->fam_prot != PP2_UNSPEC_UNSPEC && - header->fam_prot != PP2_INET_STREAM && - header->fam_prot != PP2_INET_DGRAM && - header->fam_prot != PP2_INET6_STREAM && - header->fam_prot != PP2_INET6_DGRAM && - header->fam_prot != PP2_UNIX_STREAM && - header->fam_prot != PP2_UNIX_DGRAM) { + /* Check for supported family and protocol, and that len covers + * the per-family address block (proxy-protocol.txt s2.2). */ + switch(header->fam_prot) { + case PP2_UNSPEC_UNSPEC: + break; + case PP2_INET_STREAM: + case PP2_INET_DGRAM: + if(ntohs(header->len) < PP2_HEADER_LEN_INET) + return PP_PARSE_SIZE; + break; + case PP2_INET6_STREAM: + case PP2_INET6_DGRAM: + if(ntohs(header->len) < PP2_HEADER_LEN_INET6) + return PP_PARSE_SIZE; + break; + default: + /* PP2_UNIX_STREAM, PP2_UNIX_DGRAM, others. */ return PP_PARSE_UNKNOWN_FAM_PROT; } /* We have a correct header */ Index: sbin/unwind/libunbound/util/proxy_protocol.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/proxy_protocol.h,v diff -u -p -r1.2 proxy_protocol.h --- sbin/unwind/libunbound/util/proxy_protocol.h 13 Apr 2024 13:58:35 -0000 1.2 +++ sbin/unwind/libunbound/util/proxy_protocol.h 21 Sep 2026 16:28:01 -0000 @@ -54,6 +54,15 @@ /** PROXYv2 version (protocol value) */ #define PP2_VERSION 0x2 +/** PROXYv2 minimum header.len value for TCP/UDP over IPv4 */ +#define PP2_HEADER_LEN_INET 12 + +/** PROXYv2 minimum header.len value for TCP/UDP over IPv6 */ +#define PP2_HEADER_LEN_INET6 36 + +/** PROXYv2 minimum header.len value for TCP/UDP over AF_UNIX */ +#define PP2_HEADER_LEN_UNIX 216 + /** * PROXYv2 command (protocol value). */ Index: sbin/unwind/libunbound/util/timehist.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/timehist.h,v diff -u -p -r1.1 timehist.h --- sbin/unwind/libunbound/util/timehist.h 23 Jan 2019 13:05:27 -0000 1.1 +++ sbin/unwind/libunbound/util/timehist.h 21 Sep 2026 16:28:01 -0000 @@ -42,6 +42,10 @@ #ifndef UTIL_TIMEHIST_H #define UTIL_TIMEHIST_H +#ifdef __QNX__ +/* For struct timeval */ +#include +#endif /* __QNX__ */ /** Number of buckets in a histogram */ #define NUM_BUCKETS_HIST 40 Index: sbin/unwind/libunbound/util/tube.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/tube.c,v diff -u -p -r1.6 tube.c --- sbin/unwind/libunbound/util/tube.c 14 Sep 2025 15:16:53 -0000 1.6 +++ sbin/unwind/libunbound/util/tube.c 21 Sep 2026 16:28:01 -0000 @@ -145,6 +145,20 @@ void tube_remove_bg_write(struct tube* t } } +/** Drain the pipe of bytes. */ +static void +fd_drain(int fd, uint32_t len) +{ + uint8_t discard[256]; + uint32_t remaining = len; + while(remaining > 0) { + ssize_t n = read(fd, discard, + remaining < sizeof(discard) ? remaining : sizeof(discard)); + if(n <= 0) break; + remaining -= (uint32_t)n; + } +} + int tube_handle_listen(struct comm_point* c, void* arg, int error, struct comm_reply* ATTR_UNUSED(reply_info)) @@ -184,6 +198,9 @@ tube_handle_listen(struct comm_point* c, tube->cmd_msg = (uint8_t*)calloc(1, tube->cmd_len); if(!tube->cmd_msg) { log_err("malloc failure"); + /* Drain the remaining bytes, since they belong to this + * message. The next message starts after it. */ + fd_drain(c->fd, tube->cmd_len); tube->cmd_read = 0; return 0; } @@ -374,6 +391,9 @@ int tube_read_msg(struct tube* tube, uin *buf = (uint8_t*)malloc(*len); if(!*buf) { log_err("tube read out of memory"); + /* Drain the remaining bytes, since they belong to this + * message. The next message starts after it. */ + fd_drain(fd, *len); (void)fd_set_nonblock(fd); return 0; } Index: sbin/unwind/libunbound/util/data/dname.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/data/dname.c,v diff -u -p -r1.6 dname.c --- sbin/unwind/libunbound/util/data/dname.c 29 Sep 2025 14:53:38 -0000 1.6 +++ sbin/unwind/libunbound/util/data/dname.c 21 Sep 2026 16:28:01 -0000 @@ -192,34 +192,34 @@ pkt_dname_len(sldns_buffer* pkt) while(1) { /* read next label */ if(sldns_buffer_remaining(pkt) < 1) - return 0; + goto fail; labellen = sldns_buffer_read_u8(pkt); if(LABEL_IS_PTR(labellen)) { /* compression ptr */ uint16_t ptr; if(sldns_buffer_remaining(pkt) < 1) - return 0; + goto fail; ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt)); if(ptrcount++ > MAX_COMPRESS_PTRS) - return 0; /* loop! */ + goto fail; /* loop! */ if(sldns_buffer_limit(pkt) <= ptr) - return 0; /* out of bounds! */ + goto fail; /* out of bounds! */ if(!endpos) endpos = sldns_buffer_position(pkt); sldns_buffer_set_position(pkt, ptr); } else { /* label contents */ if(labellen > 0x3f) - return 0; /* label too long */ + goto fail; /* label too long */ len += 1 + labellen; if(len > LDNS_MAX_DOMAINLEN) - return 0; + goto fail; if(labellen == 0) { /* end of dname */ break; } if(sldns_buffer_remaining(pkt) < labellen) - return 0; + goto fail; sldns_buffer_skip(pkt, (ssize_t)labellen); } } @@ -227,6 +227,13 @@ pkt_dname_len(sldns_buffer* pkt) sldns_buffer_set_position(pkt, endpos); return len; +fail: + /* Restore the position on failure too: callers (rdata_copy) compute + * the consumed field length from the buffer position and must not + * see a partial walk of a name that failed to parse. */ + if(endpos) + sldns_buffer_set_position(pkt, endpos); + return 0; } int Index: sbin/unwind/libunbound/util/data/msgencode.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/data/msgencode.c,v diff -u -p -r1.10 msgencode.c --- sbin/unwind/libunbound/util/data/msgencode.c 29 Sep 2025 14:53:38 -0000 1.10 +++ sbin/unwind/libunbound/util/data/msgencode.c 21 Sep 2026 16:28:01 -0000 @@ -352,7 +352,6 @@ compress_any_dname(uint8_t* dname, sldns (p = compress_tree_lookup(tree, dname, labs, &insertpt))) { if(!write_compressed_dname(pkt, dname, labs, p)) return RETVAL_TRUNC; - (*compress_count)++; } else { if(!dname_buffer_write(pkt, dname)) return RETVAL_TRUNC; @@ -360,6 +359,7 @@ compress_any_dname(uint8_t* dname, sldns if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && !compress_tree_store(dname, labs, pos, region, p, insertpt)) return RETVAL_OUTMEM; + (*compress_count)++; return RETVAL_OK; } @@ -496,10 +496,18 @@ packed_rrset_encode(struct ub_packed_rrs return r; sldns_buffer_write(pkt, &key->rk.type, 2); sldns_buffer_write(pkt, &key->rk.rrset_class, 2); - if(data->rr_ttl[j] < adjust) + if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) { + sldns_buffer_write_u32(pkt, 0); + } else if(adjust == 0) { + sldns_buffer_write_u32(pkt, data->rr_ttl[j]); + } else if(TTL_IS_EXPIRED(data->rr_ttl[j], adjust)) { sldns_buffer_write_u32(pkt, - SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0); - else sldns_buffer_write_u32(pkt, data->rr_ttl[j]-adjust); + EXPIRED_REPLY_TTL_CALC( + data->rr_ttl[j], data->ttl_add)); + } else { + sldns_buffer_write_u32(pkt, + data->rr_ttl[j] - adjust); + } if(c) { if((r=compress_rdata(pkt, data->rr_data[j], data->rr_len[j], region, tree, c, @@ -533,10 +541,18 @@ packed_rrset_encode(struct ub_packed_rrs } sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG); sldns_buffer_write(pkt, &key->rk.rrset_class, 2); - if(data->rr_ttl[i] < adjust) + if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) { + sldns_buffer_write_u32(pkt, 0); + } else if(adjust == 0) { + sldns_buffer_write_u32(pkt, data->rr_ttl[i]); + } else if(TTL_IS_EXPIRED(data->rr_ttl[i], adjust)) { sldns_buffer_write_u32(pkt, - SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0); - else sldns_buffer_write_u32(pkt, data->rr_ttl[i]-adjust); + EXPIRED_REPLY_TTL_CALC( + data->rr_ttl[i], data->ttl_add)); + } else { + sldns_buffer_write_u32(pkt, + data->rr_ttl[i] - adjust); + } /* rrsig rdata cannot be compressed, perform 100+ byte * memcopy. */ sldns_buffer_write(pkt, data->rr_data[i], @@ -618,7 +634,7 @@ insert_query(struct query_info* qinfo, s size_t qname_len = qinfo->local_alias ? qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; if(sldns_buffer_remaining(buffer) < - qinfo->qname_len+sizeof(uint16_t)*2) + qname_len+sizeof(uint16_t)*2) return RETVAL_TRUNC; /* buffer too small */ /* the query is the first name inserted into the tree */ if(!compress_tree_store(qname, dname_count_labels(qname), @@ -804,7 +820,7 @@ reply_info_encode(struct query_info* qin return 1; } -uint16_t +size_t calc_edns_field_size(struct edns_data* edns) { size_t rdatalen = 0; @@ -840,7 +856,7 @@ calc_edns_option_size(struct edns_data* } uint16_t -calc_ede_option_size(struct edns_data* edns, uint16_t* txt_size) +calc_ede_option_size(struct edns_data* edns, size_t* txt_size) { size_t rdatalen = 0; struct edns_option* opt; @@ -942,6 +958,10 @@ attach_edns_record_max_msg_sz(sldns_buff padding_option = opt; continue; } + if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz) + break; /* no space for it */ + if(!sldns_buffer_available(pkt, 4 + opt->opt_len)) + break; sldns_buffer_write_u16(pkt, opt->opt_code); sldns_buffer_write_u16(pkt, opt->opt_len); if(opt->opt_len != 0) @@ -952,12 +972,18 @@ attach_edns_record_max_msg_sz(sldns_buff padding_option = opt; continue; } + if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz) + break; /* no space for it */ + if(!sldns_buffer_available(pkt, 4 + opt->opt_len)) + break; sldns_buffer_write_u16(pkt, opt->opt_code); sldns_buffer_write_u16(pkt, opt->opt_len); if(opt->opt_len != 0) sldns_buffer_write(pkt, opt->opt_data, opt->opt_len); } - if (padding_option && edns->padding_block_size ) { + if (padding_option && edns->padding_block_size && + sldns_buffer_position(pkt)+4 <= max_msg_sz && + sldns_buffer_available(pkt, 4) /* if there is space for it */) { size_t pad_pos = sldns_buffer_position(pkt); size_t msg_sz = ((pad_pos + 3) / edns->padding_block_size + 1) * edns->padding_block_size; @@ -993,15 +1019,15 @@ attach_edns_record(sldns_buffer* pkt, st attach_edns_record_max_msg_sz(pkt, edns, edns->udp_size); } -int -reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, +int +reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow, - int cached, struct regional* region, uint16_t udpsize, + int cached, struct regional* region, uint16_t udpsize, struct edns_data* edns, int dnssec, int secure) { uint16_t flags; unsigned int attach_edns = 0; - uint16_t edns_field_size, ede_size, ede_txt_size; + size_t edns_field_size, ede_size, ede_txt_size; if(!cached || rep->authoritative) { /* original flags, copy RD and CD bits from query. */ @@ -1028,12 +1054,12 @@ reply_info_answer_encode(struct query_in * calculate sizes once here */ edns_field_size = calc_edns_field_size(edns); ede_size = calc_ede_option_size(edns, &ede_txt_size); - if(sldns_buffer_capacity(pkt) < udpsize) + if(sldns_buffer_capacity(pkt) < (size_t)udpsize) udpsize = sldns_buffer_capacity(pkt); if(!edns || !edns->edns_present) { attach_edns = 0; /* EDEs are optional, try to fit anything else before them */ - } else if(udpsize < LDNS_HEADER_SIZE + edns_field_size - ede_size) { + } else if((size_t)udpsize < (size_t)LDNS_HEADER_SIZE + edns_field_size - ede_size) { /* packet too small to contain edns, omit it. */ attach_edns = 0; } else { @@ -1047,13 +1073,13 @@ reply_info_answer_encode(struct query_in return 0; } if(attach_edns) { - if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size) + if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size) attach_edns_record_max_msg_sz(pkt, edns, udpsize); - else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) { + else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) { ede_trim_text(&edns->opt_list_inplace_cb_out); ede_trim_text(&edns->opt_list_out); attach_edns_record_max_msg_sz(pkt, edns, udpsize); - } else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) { + } else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) { edns_opt_list_remove(&edns->opt_list_inplace_cb_out, LDNS_EDNS_EDE); edns_opt_list_remove(&edns->opt_list_out, LDNS_EDNS_EDE); attach_edns_record_max_msg_sz(pkt, edns, udpsize); @@ -1103,9 +1129,11 @@ extended_error_encode(sldns_buffer* buf, sldns_buffer_write(buf, &flags, sizeof(uint16_t)); sldns_buffer_write(buf, &flags, sizeof(uint16_t)); if(qinfo) { - const uint8_t* qname = qinfo->local_alias ? + const uint8_t* qname = + (qinfo->local_alias && qinfo->local_alias->rrset) ? qinfo->local_alias->rrset->rk.dname : qinfo->qname; - size_t qname_len = qinfo->local_alias ? + size_t qname_len = + (qinfo->local_alias && qinfo->local_alias->rrset) ? qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; if(sldns_buffer_current(buf) == qname) @@ -1115,22 +1143,30 @@ extended_error_encode(sldns_buffer* buf, sldns_buffer_write_u16(buf, qinfo->qclass); } sldns_buffer_flip(buf); - if(edns) { + if(edns && edns->edns_present) { + size_t edns_field_size, ede_size, ede_txt_size; struct edns_data es = *edns; es.edns_version = EDNS_ADVERTISED_VERSION; es.udp_size = EDNS_ADVERTISED_SIZE; es.ext_rcode = (uint8_t)(rcode >> 4); es.bits &= EDNS_DO; - if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > - edns->udp_size) { + /* EDEs are optional. If space is a concern try in order: + * - removing any EXTRA-TEXT fields from explicit EDEs, or + * - removing all EDEs, + * to see if EDNS can fit. */ + edns_field_size = calc_edns_field_size(&es); + ede_size = calc_ede_option_size(&es, &ede_txt_size); + if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size) + attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); + else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_txt_size) { + ede_trim_text(&es.opt_list_inplace_cb_out); + ede_trim_text(&es.opt_list_out); + attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); + } else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_size) { edns_opt_list_remove(&es.opt_list_inplace_cb_out, LDNS_EDNS_EDE); edns_opt_list_remove(&es.opt_list_out, LDNS_EDNS_EDE); - if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > - edns->udp_size) { - return; - } + attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); } - attach_edns_record(buf, &es); } } Index: sbin/unwind/libunbound/util/data/msgencode.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/data/msgencode.h,v diff -u -p -r1.4 msgencode.h --- sbin/unwind/libunbound/util/data/msgencode.h 29 Sep 2025 14:53:38 -0000 1.4 +++ sbin/unwind/libunbound/util/data/msgencode.h 21 Sep 2026 16:28:01 -0000 @@ -66,9 +66,9 @@ struct edns_data; * @param secure: if 1, the AD bit is set in the reply. * @return: 0 on error (server failure). */ -int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, +int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, uint16_t id, uint16_t qflags, struct sldns_buffer* dest, time_t timenow, - int cached, struct regional* region, uint16_t udpsize, + int cached, struct regional* region, uint16_t udpsize, struct edns_data* edns, int dnssec, int secure); /** @@ -106,7 +106,7 @@ void qinfo_query_encode(struct sldns_buf * @param edns: edns data or NULL. * @return octets to reserve for EDNS. */ -uint16_t calc_edns_field_size(struct edns_data* edns); +size_t calc_edns_field_size(struct edns_data* edns); /** * Calculate the size of a specific EDNS option in packet. @@ -127,7 +127,7 @@ uint16_t calc_edns_option_size(struct ed * extra text. * @return octets the option will take up. */ -uint16_t calc_ede_option_size(struct edns_data* edns, uint16_t* txt_size); +uint16_t calc_ede_option_size(struct edns_data* edns, size_t* txt_size); /** * Attach EDNS record to buffer. Buffer has complete packet. There must Index: sbin/unwind/libunbound/util/data/msgparse.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/data/msgparse.c,v diff -u -p -r1.9 msgparse.c --- sbin/unwind/libunbound/util/data/msgparse.c 5 Sep 2024 08:22:47 -0000 1.9 +++ sbin/unwind/libunbound/util/data/msgparse.c 21 Sep 2026 16:28:01 -0000 @@ -53,6 +53,8 @@ #include "sldns/parseutil.h" #include "sldns/wire2str.h" +#define MAX_PARSED_EDNS_OPTIONS 100 + /** smart comparison of (compressed, valid) dnames from packet */ static int smart_compare(sldns_buffer* pkt, uint8_t* dnow, @@ -685,6 +687,9 @@ calc_size(sldns_buffer* pkt, uint16_t ty } rdf++; } + /* rdata ended before all _dname_count names were seen */ + if(count != 0) + return 0; /* the rdata is too short. */ } /* remaining rdata */ rr->size += pkt_len; @@ -950,6 +955,7 @@ parse_edns_options_from_query(uint8_t* r struct comm_reply* repinfo, uint32_t now, struct regional* region, struct cookie_secrets* cookie_secrets) { + int i = 0, nsid_seen = 0, cookie_seen = 0, padding_seen = 0; /* To respond with a Keepalive option, the client connection must have * received one message with a TCP Keepalive EDNS option, and that * option must have 0 length data. Subsequent messages sent on that @@ -969,7 +975,7 @@ parse_edns_options_from_query(uint8_t* r /* while still more options, and have code+len to read */ /* ignores partial content (i.e. rdata len 3) */ - while(rdata_len >= 4) { + while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) { uint16_t opt_code = sldns_read_uint16(rdata_ptr); uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); uint8_t server_cookie[40]; @@ -984,8 +990,9 @@ parse_edns_options_from_query(uint8_t* r /* handle parse time edns options here */ switch(opt_code) { case LDNS_EDNS_NSID: - if (!cfg || !cfg->nsid) + if (!cfg || !cfg->nsid || nsid_seen) break; + nsid_seen = 1; if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_NSID, cfg->nsid_len, cfg->nsid, region)) { @@ -1026,9 +1033,13 @@ parse_edns_options_from_query(uint8_t* r break; case LDNS_EDNS_PADDING: - if(!cfg || !cfg->pad_responses || - !c || c->type != comm_tcp ||!c->ssl) + if(!cfg || !cfg->pad_responses || !c || padding_seen) + break; + if(!((c->type == comm_tcp && c->ssl) || + (c->type == comm_http && c->ssl) || + c->type == comm_doq)) break; + padding_seen = 1; if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_PADDING, 0, NULL, region)) { @@ -1039,8 +1050,9 @@ parse_edns_options_from_query(uint8_t* r break; case LDNS_EDNS_COOKIE: - if(!cfg || !cfg->do_answer_cookie || !repinfo) + if(!cfg || !cfg->do_answer_cookie || !repinfo || cookie_seen) break; + cookie_seen = 1; if(opt_len != 8 && (opt_len < 16 || opt_len > 40)) { verbose(VERB_ALGO, "worker request: " "badly formatted cookie"); @@ -1062,13 +1074,13 @@ parse_edns_options_from_query(uint8_t* r * purposes. It will be overwritten if (re)creation * is needed. */ - if(repinfo->remote_addr.ss_family == AF_INET) { + if(repinfo->client_addr.ss_family == AF_INET) { memcpy(server_cookie + 16, - &((struct sockaddr_in*)&repinfo->remote_addr)->sin_addr, 4); + &((struct sockaddr_in*)&repinfo->client_addr)->sin_addr, 4); } else { cookie_is_v4 = 0; memcpy(server_cookie + 16, - &((struct sockaddr_in6*)&repinfo->remote_addr)->sin6_addr, 16); + &((struct sockaddr_in6*)&repinfo->client_addr)->sin6_addr, 16); } if(cfg->cookie_secret_file && @@ -1080,10 +1092,10 @@ parse_edns_options_from_query(uint8_t* r cookie_is_v4, server_cookie, now); } else { /* Use the cookie option value to validate. */ - cookie_val_status = edns_cookie_server_validate( - rdata_ptr, opt_len, cfg->cookie_secret, - cfg->cookie_secret_len, cookie_is_v4, - server_cookie, now); + cookie_val_status = edns_cookie_server_validate( + rdata_ptr, opt_len, cfg->cookie_secret, + cfg->cookie_secret_len, cookie_is_v4, + server_cookie, now); } if(cookie_val_status == COOKIE_STATUS_VALID_RENEW) edns->cookie_valid = 1; @@ -1124,8 +1136,8 @@ parse_edns_options_from_query(uint8_t* r cookie_is_v4, now); lock_basic_unlock(&cookie_secrets->lock); } else { - edns_cookie_server_write(server_cookie, - cfg->cookie_secret, cookie_is_v4, now); + edns_cookie_server_write(server_cookie, + cfg->cookie_secret, cookie_is_v4, now); } if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_COOKIE, 24, server_cookie, @@ -1146,6 +1158,7 @@ parse_edns_options_from_query(uint8_t* r } rdata_ptr += opt_len; rdata_len -= opt_len; + i++; } return LDNS_RCODE_NOERROR; } @@ -1160,6 +1173,7 @@ parse_extract_edns_from_response_msg(str struct rrset_parse* found_prev = 0; size_t rdata_len; uint8_t* rdata_ptr; + int i = 0; /* since the class encodes the UDP size, we cannot use hash table to * find the EDNS OPT record. Scan the packet. */ while(rrset) { @@ -1219,7 +1233,7 @@ parse_extract_edns_from_response_msg(str /* while still more options, and have code+len to read */ /* ignores partial content (i.e. rdata len 3) */ - while(rdata_len >= 4) { + while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) { uint16_t opt_code = sldns_read_uint16(rdata_ptr); uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); rdata_ptr += 4; @@ -1234,6 +1248,7 @@ parse_extract_edns_from_response_msg(str } rdata_ptr += opt_len; rdata_len -= opt_len; + i++; } /* ignore rrsigs */ return LDNS_RCODE_NOERROR; @@ -1361,3 +1376,15 @@ msgparse_rrset_remove_rr(const char* str * the rr->next works fine to continue. */ return rrset->rr_count == 0; } + +#ifdef UNBOUND_DEBUG +time_t debug_expired_reply_ttl_calc(time_t ttl, time_t ttl_add) { + /* Check that we are serving expired when this is called */ + /* ttl (absolute) should be later than ttl_add */ + /* It is also called during the grace period for type DNAME, + * and then the 'SERVE_EXPIRED' boolean may not be on. */ + log_assert(ttl_add <= ttl); + return (SERVE_EXPIRED_REPLY_TTL < (ttl) - (ttl_add) ? + SERVE_EXPIRED_REPLY_TTL : (ttl) - (ttl_add)); +} +#endif Index: sbin/unwind/libunbound/util/data/msgparse.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/data/msgparse.h,v diff -u -p -r1.11 msgparse.h --- sbin/unwind/libunbound/util/data/msgparse.h 29 Sep 2025 14:53:38 -0000 1.11 +++ sbin/unwind/libunbound/util/data/msgparse.h 21 Sep 2026 16:28:01 -0000 @@ -98,6 +98,31 @@ extern time_t SERVE_EXPIRED_REPLY_TTL; /** If we serve the original TTL or decrementing TTLs */ extern int SERVE_ORIGINAL_TTL; +/** calculate the prefetch TTL as 90% of original. Calculation + * without numerical overflow (uin32_t) */ +#define PREFETCH_TTL_CALC(ttl) ((ttl) - (ttl)/10) + +/* caclulate the TTL used for expired answers to somewhat make sense wrt the + * original TTL; don't reply with higher TTL than the original */ +#ifdef UNBOUND_DEBUG +time_t debug_expired_reply_ttl_calc(time_t ttl, time_t ttl_add); +#define EXPIRED_REPLY_TTL_CALC(ttl, ttl_add) \ + debug_expired_reply_ttl_calc(ttl, ttl_add) +#else +#define EXPIRED_REPLY_TTL_CALC(ttl, ttl_add) \ + (SERVE_EXPIRED_REPLY_TTL < (ttl) - (ttl_add) ? \ + SERVE_EXPIRED_REPLY_TTL : (ttl) - (ttl_add)) +#endif + +/** Update the reply_info TTL from an RRSet's TTL, essentially keeping the TTL + * sane with all the (progressively added) rrsets to the message */ +#define UPDATE_TTL_FROM_RRSET(ttl, rrsetttl) \ + ((ttl) = ((ttl) < (rrsetttl)) ? (ttl) : (rrsetttl)) + +/** Check if TTL is expired. 0 TTL is considered expired. + * Used mainly to identify parts of the code that do this comparison. */ +#define TTL_IS_EXPIRED(ttl, now) ((ttl) <= (now)) + /** * Data stored in scratch pad memory during parsing. * Stores the data that will enter into the msgreply and packet result. Index: sbin/unwind/libunbound/util/data/msgreply.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/data/msgreply.c,v diff -u -p -r1.16 msgreply.c --- sbin/unwind/libunbound/util/data/msgreply.c 29 Sep 2025 14:53:38 -0000 1.16 +++ sbin/unwind/libunbound/util/data/msgreply.c 21 Sep 2026 16:28:02 -0000 @@ -178,9 +178,9 @@ reply_info_alloc_rrset_keys(struct reply int reply_info_can_answer_expired(struct reply_info* rep, time_t timenow) { - log_assert(rep->ttl < timenow); + log_assert(TTL_IS_EXPIRED(rep->ttl, timenow)); /* Really expired */ - if(SERVE_EXPIRED_TTL && rep->serve_expired_ttl < timenow) return 0; + if(SERVE_EXPIRED_TTL && TTL_IS_EXPIRED(rep->serve_expired_ttl, timenow)) return 0; /* Ignore expired failure answers */ if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR && FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN && @@ -188,12 +188,13 @@ reply_info_can_answer_expired(struct rep return 1; } -int reply_info_could_use_expired(struct reply_info* rep, time_t timenow) +int +reply_info_could_use_expired(struct reply_info* rep, time_t timenow) { - log_assert(rep->ttl < timenow); + log_assert(TTL_IS_EXPIRED(rep->ttl, timenow)); /* Really expired */ - if(SERVE_EXPIRED_TTL && rep->serve_expired_ttl < timenow && - !SERVE_EXPIRED_TTL_RESET) return 0; + if(SERVE_EXPIRED_TTL && TTL_IS_EXPIRED(rep->serve_expired_ttl, timenow) + && !SERVE_EXPIRED_TTL_RESET) return 0; /* Ignore expired failure answers */ if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR && FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN && @@ -229,7 +230,7 @@ make_new_reply_info(const struct reply_i } /** find the minimumttl in the rdata of SOA record */ -static time_t +static uint32_t soa_find_minttl(struct rr_parse* rr) { uint16_t rlen = sldns_read_uint16(rr->ttl_data+4); @@ -237,7 +238,7 @@ soa_find_minttl(struct rr_parse* rr) return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */ /* minimum TTL is the last 32bit value in the rdata of the record */ /* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/ - return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4); + return sldns_read_uint32(rr->ttl_data+6+rlen-4); } /** do the rdata copy */ @@ -247,37 +248,41 @@ rdata_copy(sldns_buffer* pkt, struct pac sldns_pkt_section section) { uint16_t pkt_len; + size_t tolen; + uint32_t ttl; const sldns_rr_descriptor* desc; - *rr_ttl = sldns_read_uint32(rr->ttl_data); + ttl = sldns_read_uint32(rr->ttl_data); /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */ - if((*rr_ttl & 0x80000000U)) - *rr_ttl = 0; + /* RFC 8767 Section 4. values with high-order bit as positive, not 0. ++ * As such, it will be capped by MAX_TTL below. */ if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { /* negative response. see if TTL of SOA record larger than the * minimum-ttl in the rdata of the SOA record */ - if(*rr_ttl > soa_find_minttl(rr)) *rr_ttl = soa_find_minttl(rr); + if(ttl > soa_find_minttl(rr)) ttl = soa_find_minttl(rr); if(!SERVE_ORIGINAL_TTL) { /* If MIN_NEG_TTL is configured skip setting MIN_TTL */ - if(MIN_NEG_TTL <= 0 && *rr_ttl < MIN_TTL) { - *rr_ttl = MIN_TTL; + if(MIN_NEG_TTL <= 0 && ttl < (uint32_t)MIN_TTL) { + ttl = (uint32_t)MIN_TTL; } - if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL; + if(ttl > (uint32_t)MAX_TTL) ttl = (uint32_t)MAX_TTL; } /* MAX_NEG_TTL overrides the min and max ttl of everything * else; it is for a more specific record */ - if(*rr_ttl > MAX_NEG_TTL) *rr_ttl = MAX_NEG_TTL; + if(ttl > (uint32_t)MAX_NEG_TTL) ttl = (uint32_t)MAX_NEG_TTL; /* MIN_NEG_TTL overrides the min and max ttl of everything * else if configured; it is for a more specific record */ - if(MIN_NEG_TTL > 0 && *rr_ttl < MIN_NEG_TTL) { - *rr_ttl = MIN_NEG_TTL; + if(MIN_NEG_TTL > 0 && ttl < (uint32_t)MIN_NEG_TTL) { + ttl = (uint32_t)MIN_NEG_TTL; } } else if(!SERVE_ORIGINAL_TTL) { - if(*rr_ttl < MIN_TTL) *rr_ttl = MIN_TTL; - if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL; + if(ttl < (uint32_t)MIN_TTL) ttl = (uint32_t)MIN_TTL; + if(ttl > (uint32_t)MAX_TTL) ttl = (uint32_t)MAX_TTL; } - if(*rr_ttl < data->ttl) - data->ttl = *rr_ttl; + if((time_t)ttl < data->ttl) + data->ttl = (time_t)ttl; + /* We have concluded the TTL checks */ + *rr_ttl = (time_t)ttl; if(rr->outside_packet) { /* uncompressed already, only needs copy */ @@ -289,9 +294,13 @@ rdata_copy(sldns_buffer* pkt, struct pac (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t))); /* insert decompressed size into rdata len stored in memory */ /* -2 because rdatalen bytes are not included. */ + tolen = rr->size; + if(tolen < 2) + return 0; pkt_len = htons(rr->size - 2); memmove(to, &pkt_len, sizeof(uint16_t)); to += 2; + tolen -= 2; /* read packet rdata len */ pkt_len = sldns_buffer_read_u16(pkt); if(sldns_buffer_remaining(pkt) < pkt_len) @@ -300,16 +309,29 @@ rdata_copy(sldns_buffer* pkt, struct pac if(pkt_len > 0 && desc && desc->_dname_count > 0) { int count = (int)desc->_dname_count; int rdf = 0; - size_t len; - size_t oldpos; + size_t len, dlen; + size_t oldpos, newpos; /* decompress dnames. */ while(pkt_len > 0 && count) { switch(desc->_wireformat[rdf]) { case LDNS_RDF_TYPE_DNAME: oldpos = sldns_buffer_position(pkt); - dname_pkt_copy(pkt, to, + dlen = pkt_dname_len(pkt); + if(dlen == 0) + return 0; /* malformed */ + if(dlen > tolen) + return 0; /* alloc mismatch */ + newpos = sldns_buffer_position(pkt); + if(oldpos > newpos) + return 0; /* should have moved forward*/ + sldns_buffer_set_position(pkt, oldpos); + dname_pkt_copy(pkt, to, sldns_buffer_current(pkt)); - to += pkt_dname_len(pkt); + sldns_buffer_set_position(pkt, newpos); + to += dlen; + tolen -= dlen; + if(sldns_buffer_position(pkt)-oldpos > pkt_len) + return 0; /* malformed: walks diverged */ pkt_len -= sldns_buffer_position(pkt)-oldpos; count--; len = 0; @@ -322,9 +344,12 @@ rdata_copy(sldns_buffer* pkt, struct pac break; } if(len) { + if(len > tolen) + return 0; /* alloc mismatch */ log_assert(len <= pkt_len); memmove(to, sldns_buffer_current(pkt), len); to += len; + tolen -= len; sldns_buffer_skip(pkt, (ssize_t)len); pkt_len -= len; } @@ -332,8 +357,11 @@ rdata_copy(sldns_buffer* pkt, struct pac } } /* copy remaining rdata */ - if(pkt_len > 0) + if(pkt_len > 0) { + if(pkt_len > tolen) + return 0; /* alloc mismatch */ memmove(to, sldns_buffer_current(pkt), pkt_len); + } return 1; } @@ -479,7 +507,11 @@ parse_copy_decompress_rrset(sldns_buffer } pk->entry.data = (void*)data; pk->entry.key = (void*)pk; - pk->entry.hash = pset->hash; + pk->rk.flags |= (data->ttl == 0) ? PACKED_RRSET_UPSTREAM_0TTL : 0; + if( (pk->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) != 0) + pk->entry.hash = rrset_key_hash(&pk->rk); + else + pk->entry.hash = pset->hash; data->trust = get_rrset_trust(msg, pset); return 1; } @@ -617,6 +649,29 @@ reply_info_set_ttls(struct reply_info* r } } +void +reply_info_absolute_ttls(struct reply_info* rep, time_t ttl, time_t ttl_add) +{ + size_t i, j; + rep->ttl = ttl; + rep->prefetch_ttl = PREFETCH_TTL_CALC(ttl); + rep->serve_expired_ttl = ttl + SERVE_EXPIRED_TTL; + /* Don't set rep->serve_expired_norec_ttl; this should only be set + * on cached records when encountering an error */ + log_assert(rep->serve_expired_norec_ttl == 0); + for(i=0; irrset_count; i++) { + struct packed_rrset_data* data = (struct packed_rrset_data*) + rep->ref[i].key->entry.data; + if(i>0 && rep->ref[i].key == rep->ref[i-1].key) + continue; + data->ttl = ttl; + for(j=0; jcount + data->rrsig_count; j++) { + data->rr_ttl[j] = ttl; + } + data->ttl_add = ttl_add; + } +} + void reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc) { @@ -1084,6 +1139,17 @@ reply_all_rrsets_secure(struct reply_inf return 1; } +int reply_an_ns_rrsets_secure(struct reply_info* rep) +{ + size_t i; + for(i=0; ian_numrrsets+rep->ns_numrrsets; i++) { + if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) + ->security != sec_status_secure ) + return 0; + } + return 1; +} + struct reply_info* parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region, struct query_info* qi) @@ -1475,8 +1541,12 @@ struct edns_option* edns_opt_list_find(s int local_alias_shallow_copy_qname(struct local_rrset* local_alias, uint8_t** qname, size_t* qname_len) { - struct ub_packed_rrset_key* rrset = local_alias->rrset; - struct packed_rrset_data* d = rrset->entry.data; + struct ub_packed_rrset_key* rrset; + struct packed_rrset_data* d; + rrset = local_alias->rrset; + if(!rrset) return 0; + d = rrset->entry.data; + if(!d) return 0; /* Sanity check: our current implementation only supports * a single CNAME RRset as a local alias. */ Index: sbin/unwind/libunbound/util/data/msgreply.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/data/msgreply.h,v diff -u -p -r1.11 msgreply.h --- sbin/unwind/libunbound/util/data/msgreply.h 29 Sep 2025 14:53:38 -0000 1.11 +++ sbin/unwind/libunbound/util/data/msgreply.h 21 Sep 2026 16:28:02 -0000 @@ -44,6 +44,10 @@ #include "util/storage/lruhash.h" #include "util/data/packed_rrset.h" #include "sldns/rrdef.h" +#ifdef __QNX__ +/* For struct timeval */ +#include +#endif /* __QNX__ */ struct sldns_buffer; struct comm_reply; struct alloc_cache; @@ -60,10 +64,6 @@ struct local_rrset; struct dns_msg; enum comm_point_type; -/** calculate the prefetch TTL as 90% of original. Calculation - * without numerical overflow (uin32_t) */ -#define PREFETCH_TTL_CALC(ttl) ((ttl) - (ttl)/10) - /** * Structure to store query information that makes answers to queries * different. @@ -340,6 +340,15 @@ void reply_info_sortref(struct reply_inf */ void reply_info_set_ttls(struct reply_info* rep, time_t timenow); +/** + * Set TTLs inside the replyinfo to the given absolute values. + * @param rep: reply info. rrsets must be filled in. + * Also refs must be filled in. + * @param ttl: absolute ttl value to be set. + * @param ttl_add: the current time to be used verbatim for ttl_add in the rrsets. + */ +void reply_info_absolute_ttls(struct reply_info* rep, time_t ttl, time_t ttl_add); + /** * Delete reply_info and packed_rrsets (while they are not yet added to the * hashtables.). Returns rrsets to the alloc cache. @@ -485,6 +494,9 @@ int reply_check_cname_chain(struct query */ int reply_all_rrsets_secure(struct reply_info* rep); +/** Check status of answer and authority section RRs. */ +int reply_an_ns_rrsets_secure(struct reply_info* rep); + /** * Find answer rrset in reply, the one matching qinfo. Follows CNAMEs, so the * result may have a different owner name. @@ -572,7 +584,7 @@ void log_query_info(enum verbosity_value struct query_info* qinf); /** - * Append edns option to edns option list + * Append edns option to edns option list. * @param list: the edns option list to append the edns option to. * @param code: the edns option's code. * @param len: the edns option's length. @@ -584,17 +596,20 @@ int edns_opt_list_append(struct edns_opt uint8_t* data, struct regional* region); /** - * Append edns EDE option to edns options list + * Append edns EDE option to edns options list. + * We need ATTR_NONSTRING because we are trimming the trailing \0 of static + * string (TXT) when assigning to ede.text; it silences compiler nonstring + * warnings. * @param LIST: the edns option list to append the edns option to. * @param REGION: region to allocate the new edns option. * @param CODE: the EDE code. - * @param TXT: Additional text for the option + * @param TXT: Additional text for the option. */ #define EDNS_OPT_LIST_APPEND_EDE(LIST, REGION, CODE, TXT) \ do { \ struct { \ uint16_t code; \ - char text[sizeof(TXT) - 1]; \ + char ATTR_NONSTRING(text[sizeof(TXT) - 1]) ; \ } ede = { htons(CODE), TXT }; \ verbose(VERB_ALGO, "attached EDE code: %d with" \ " message: '%s'", CODE, TXT); \ Index: sbin/unwind/libunbound/util/data/packed_rrset.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/data/packed_rrset.c,v diff -u -p -r1.4 packed_rrset.c --- sbin/unwind/libunbound/util/data/packed_rrset.c 13 Apr 2024 13:58:35 -0000 1.4 +++ sbin/unwind/libunbound/util/data/packed_rrset.c 21 Sep 2026 16:28:02 -0000 @@ -198,6 +198,7 @@ get_cname_target(struct ub_packed_rrset_ { struct packed_rrset_data* d; size_t len; + if(!rrset) return; if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME) return; @@ -296,7 +297,7 @@ int packed_rr_to_string(struct ub_packed wlen = (size_t)sldns_wire2str_rr_buf(rr, rlen, dest, dest_len); if(wlen >= dest_len) { /* the output string was truncated */ - log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest); + verbose(VERB_ALGO, "rrbuf failure %d %s", (int)d->rr_len[i], dest); dest[0] = 0; return 0; } @@ -336,10 +337,9 @@ packed_rrset_copy_region(struct ub_packe struct ub_packed_rrset_key* ck = regional_alloc(region, sizeof(struct ub_packed_rrset_key)); struct packed_rrset_data* d; - struct packed_rrset_data* data = (struct packed_rrset_data*) - key->entry.data; + struct packed_rrset_data* data = key->entry.data; size_t dsize, i; - time_t adjust = 0; + time_t now_control; if(!ck) return NULL; ck->id = key->id; @@ -352,22 +352,34 @@ packed_rrset_copy_region(struct ub_packe if(!ck->rk.dname) return NULL; dsize = packed_rrset_sizeof(data); - d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize); + d = regional_alloc_init(region, data, dsize); if(!d) return NULL; ck->entry.data = d; packed_rrset_ptr_fixup(d); - /* make TTLs relative - once per rrset */ - adjust = SERVE_ORIGINAL_TTL ? data->ttl_add : now; - for(i=0; icount + d->rrsig_count; i++) { - if(d->rr_ttl[i] < adjust) - d->rr_ttl[i] = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0; - else d->rr_ttl[i] -= adjust; + /* make TTLs relative - once per rr */ + if(now > 0) { + /* NS RRSets may be here with ttl_add higher than now because + * of the novel ghost attack mitigation i.e., using the + * qstarttime for NS RRSets. In that case make sure that the + * returned TTL is not higher than the original one. */ + /* For types other than type NS, auth zone and rpz code + * can have ttl_add values. Also time could conceivably move + * in reverse, due to operator action, and it is prudent + * to not assert on that here. + * So there is no assertion d->ttl_add <= now || type==NS */ + now_control = SERVE_ORIGINAL_TTL ? data->ttl_add + : (d->ttl_add > now ? d->ttl_add : now ); + for(i=0; icount + d->rrsig_count; i++) { + if(TTL_IS_EXPIRED(d->rr_ttl[i], now_control)) { + d->rr_ttl[i] = EXPIRED_REPLY_TTL_CALC(d->rr_ttl[i], data->ttl_add); + } else d->rr_ttl[i] -= now_control; + } + if(TTL_IS_EXPIRED(d->ttl, now_control)) { + d->ttl = EXPIRED_REPLY_TTL_CALC(d->ttl, data->ttl_add); + } else d->ttl -= now_control; + d->ttl_add = 0; /* TTLs have been made relative */ } - if(d->ttl < adjust) - d->ttl = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0; - else d->ttl -= adjust; - d->ttl_add = 0; /* TTLs have been made relative */ return ck; } Index: sbin/unwind/libunbound/util/data/packed_rrset.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/data/packed_rrset.h,v diff -u -p -r1.5 packed_rrset.h --- sbin/unwind/libunbound/util/data/packed_rrset.h 23 Feb 2025 07:53:40 -0000 1.5 +++ sbin/unwind/libunbound/util/data/packed_rrset.h 21 Sep 2026 16:28:02 -0000 @@ -70,6 +70,10 @@ typedef uint64_t rrset_id_type; #define PACKED_RRSET_RPZ 0x8 /** this rrset is A/AAAA and is an unverified glue record */ #define PACKED_RRSET_UNVERIFIED_GLUE 0x10 +/** this rrset has a 0TTL from upstream */ +#define PACKED_RRSET_UPSTREAM_0TTL 0x20 +/** this rrset has 0TTL from upstream and also has had grace TTL applied */ +#define PACKED_RRSET_0TTL_GRACE 0x40 /** number of rrs and rrsets for integer overflow protection. More than * this is not really possible (64K packet has much less RRs and RRsets) in @@ -99,6 +103,7 @@ struct packed_rrset_key { * o PACKED_RRSET_FIXEDTTL (not supposed to be cached) * o PACKED_RRSET_RPZ * o PACKED_RRSET_UNVERIFIED_GLUE + * o PACKED_RRSET_UPSTREAM_0TTL (not supposed to be cached) */ uint32_t flags; /** the rrset type in network format */ Index: sbin/unwind/libunbound/util/storage/lookup3.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/util/storage/lookup3.c,v diff -u -p -r1.5 lookup3.c --- sbin/unwind/libunbound/util/storage/lookup3.c 5 Sep 2024 08:22:48 -0000 1.5 +++ sbin/unwind/libunbound/util/storage/lookup3.c 21 Sep 2026 16:28:02 -0000 @@ -255,10 +255,10 @@ uint32_t initval) /* the { case 3 : c+=k[2]; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 2 : b+=k[1]; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 1 : a+=k[0]; final(a,b,c); ATTR_FALLTHROUGH @@ -531,37 +531,37 @@ uint32_t hashlittle( const void *key, si { case 12: c+=((uint32_t)k[11])<<24; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 11: c+=((uint32_t)k[10])<<16; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 10: c+=((uint32_t)k[9])<<8; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 9 : c+=k[8]; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 8 : b+=((uint32_t)k[7])<<24; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 7 : b+=((uint32_t)k[6])<<16; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 6 : b+=((uint32_t)k[5])<<8; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 5 : b+=k[4]; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 4 : a+=((uint32_t)k[3])<<24; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 3 : a+=((uint32_t)k[2])<<16; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 2 : a+=((uint32_t)k[1])<<8; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 1 : a+=k[0]; break; case 0 : return c; Index: sbin/unwind/libunbound/validator/autotrust.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/autotrust.c,v diff -u -p -r1.12 autotrust.c --- sbin/unwind/libunbound/validator/autotrust.c 14 Sep 2025 15:16:53 -0000 1.12 +++ sbin/unwind/libunbound/validator/autotrust.c 21 Sep 2026 16:28:02 -0000 @@ -160,10 +160,12 @@ verbose_key(struct autr_ta* ta, enum ver * Parse comments * @param str: to parse * @param ta: trust key autotrust metadata + * @param header_seen: if an autotrust file header was seen. + * Without such a header it is a list of resource records. * @return false on failure. */ static int -parse_comments(char* str, struct autr_ta* ta) +parse_comments(char* str, struct autr_ta* ta, int header_seen) { int len = (int)strlen(str), pos = 0, timestamp = 0; char* comment = (char*) malloc(sizeof(char)*len+1); @@ -196,10 +198,18 @@ parse_comments(char* str, struct autr_ta free(comment); return 0; } - if (pos <= 0) - ta->s = AUTR_STATE_VALID; - else - { + if (pos <= 0) { + if(header_seen) { + /* There was an autotrust trust anchor file header, + * with a ;; id=.. line, so the entries + * have to have ;;state= annotations. */ + log_err("trust anchor in state file has no ;;state= " + "annotation, ignoring"); + free(comment); + return 0; + } + ta->s = AUTR_STATE_VALID; + } else { int s = (int) comments[pos] - '0'; switch(s) { @@ -391,6 +401,15 @@ autr_rrset_delete(struct ub_packed_rrset } } +/** delete autotrust key data */ +static void +autr_ta_delete(struct autr_ta* ta) +{ + if(!ta) return; + free(ta->rr); + free(ta); +} + void autr_point_delete(struct trust_anchor* tp) { if(!tp) @@ -404,8 +423,7 @@ void autr_point_delete(struct trust_anch struct autr_ta* p = tp->autr->keys, *np; while(p) { np = p->next; - free(p->rr); - free(p); + autr_ta_delete(p); p = np; } free(tp->autr->file); @@ -449,8 +467,7 @@ add_trustanchor_frm_rr(struct val_anchor return NULL; *tp = find_add_tp(anchors, rr, rr_len, dname_len); if(!*tp) { - free(ta->rr); - free(ta); + autr_ta_delete(ta); return NULL; } /* add ta to tp */ @@ -523,12 +540,14 @@ add_trustanchor_frm_str(struct val_ancho * @param prev: passed to ldns. * @param prev_len: length of prev * @param skip: if true, the result is NULL, but not an error, skip it. + * @param header_seen: if an autotrust file header was seen. + * Without such a header it is a list of resource records. * @return false on failure, otherwise the tp read. */ static struct trust_anchor* load_trustanchor(struct val_anchors* anchors, char* str, const char* fname, uint8_t* origin, size_t origin_len, uint8_t** prev, size_t* prev_len, - int* skip) + int* skip, int header_seen) { struct autr_ta* ta = NULL; struct trust_anchor* tp = NULL; @@ -538,7 +557,11 @@ load_trustanchor(struct val_anchors* anc if(!ta) return NULL; lock_basic_lock(&tp->lock); - if(!parse_comments(str, ta)) { + if(!parse_comments(str, ta, header_seen)) { + /* ta was already linked into the list of keys, unlink it */ + log_assert(tp->autr->keys == ta); + tp->autr->keys = ta->next; + autr_ta_delete(ta); lock_basic_unlock(&tp->lock); return NULL; } @@ -846,19 +869,32 @@ parse_id(struct val_anchors* anchors, ch * @param anchors: the anchor is added to this, if "id:" is seen. * @param anchor: the anchor as result value or previously returned anchor * value to read the variable lines into. + * @param header_seen: if a header ';;id: example.com.' was seen. + * @param nm: file name. * @return: 0 no match, -1 failed syntax error, +1 success line read. * +2 revoked trust anchor file. */ static int parse_var_line(char* line, struct val_anchors* anchors, - struct trust_anchor** anchor) + struct trust_anchor** anchor, int* header_seen, const char* nm) { struct trust_anchor* tp = *anchor; int r = 0; if(strncmp(line, ";;id: ", 6) == 0) { + *header_seen = 1; *anchor = parse_id(anchors, line+6); if(!*anchor) return -1; - else return 1; + lock_basic_lock(&(*anchor)->lock); + if(*anchor && !(*anchor)->autr->file) { + (*anchor)->autr->file = strdup(nm); + if(!(*anchor)->autr->file) { + lock_basic_unlock(&(*anchor)->lock); + log_err("malloc failure"); + return -1; + } + } + lock_basic_unlock(&(*anchor)->lock); + if(*anchor) return 1; } else if(strncmp(line, ";;REVOKED", 9) == 0) { if(tp) { log_err("REVOKED statement must be at start of file"); @@ -992,14 +1028,15 @@ int autr_read_file(struct val_anchors* a FILE* fd; /* keep track of line numbers */ int line_nr = 0; - /* single line */ - char line[10240]; + /* single line, enough space for large DNSKEY, 64K, in hex and dname */ + char line[10240+65536*2]; /* trust point being read */ struct trust_anchor *tp = NULL, *tp2; int r; /* for $ORIGIN parsing */ uint8_t *origin=NULL, *prev=NULL; size_t origin_len=0, prev_len=0; + int header_seen = 0; if (!(fd = fopen(nm, "r"))) { log_err("unable to open %s for reading: %s", @@ -1008,7 +1045,7 @@ int autr_read_file(struct val_anchors* a } verbose(VERB_ALGO, "reading autotrust anchor file %s", nm); while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) { - if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) { + if(r == -1 || (r = parse_var_line(line, anchors, &tp, &header_seen, nm)) == -1) { log_err("could not parse auto-trust-anchor-file " "%s line %d", nm, line_nr); fclose(fd); @@ -1030,7 +1067,7 @@ int autr_read_file(struct val_anchors* a continue; r = 0; if(!(tp2=load_trustanchor(anchors, line, nm, origin, - origin_len, &prev, &prev_len, &r))) { + origin_len, &prev, &prev_len, &r, header_seen))) { if(!r) log_err("failed to load trust anchor from %s " "at line %i, skipping", nm, line_nr); /* try to do the rest */ @@ -1198,6 +1235,11 @@ void autr_write_file(struct module_env* #endif char tempf[2048]; log_assert(tp->autr); + if(!fname) { + log_err("autotrust: trust point has no backing file, " + "skipping write"); + return; + } if(!env) { log_err("autr_write_file: Module environment is NULL."); return; @@ -1259,12 +1301,13 @@ void autr_write_file(struct module_env* * @param tp: trust point to verify with * @param rrset: DNSKEY rrset to verify. * @param qstate: qstate with region. + * @param vq: validator query state. * @return false on failure, true if verification successful. */ static int verify_dnskey(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* rrset, - struct module_qstate* qstate) + struct module_qstate* qstate, struct val_qstate* vq) { char reasonbuf[256]; char* reason = NULL; @@ -1272,7 +1315,7 @@ verify_dnskey(struct module_env* env, st int downprot = env->cfg->harden_algo_downgrade; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason, - NULL, qstate, reasonbuf, sizeof(reasonbuf)); + NULL, qstate, vq, reasonbuf, sizeof(reasonbuf)); /* sigalg is ignored, it returns algorithms signalled to exist, but * in 5011 there are no other rrsets to check. if downprot is * enabled, then it checks that the DNSKEY is signed with all @@ -1312,16 +1355,18 @@ min_expiry(struct module_env* env, struc static int rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, size_t i, - struct module_qstate* qstate) + struct module_qstate* qstate, struct val_qstate* vq) { enum sec_status sec; char* reason = NULL; + size_t num_tagmatches = 0; verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d", (int)i); /* no algorithm downgrade protection necessary, if it is selfsigned * revoked it can be removed. */ sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i, - &reason, NULL, LDNS_SECTION_ANSWER, qstate); + &reason, NULL, LDNS_SECTION_ANSWER, qstate, vq, + &num_tagmatches); return (sec == sec_status_secure); } @@ -1537,7 +1582,7 @@ init_events(struct trust_anchor* tp) static void check_contains_revoked(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, - int* changed, struct module_qstate* qstate) + int* changed, struct module_qstate* qstate, struct val_qstate* vq) { struct packed_rrset_data* dd = (struct packed_rrset_data*) dnskey_rrset->entry.data; @@ -1557,7 +1602,8 @@ check_contains_revoked(struct module_env } if(!ta) continue; /* key not found */ - if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) { + if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate, + vq)) { /* checked if there is an rrsig signed by this key. */ /* same keytag, but stored can be revoked already, so * compare keytags, with +0 or +128(REVOKE flag) */ @@ -1996,8 +2042,7 @@ autr_cleanup_keys(struct trust_anchor* t != LDNS_RR_TYPE_DNSKEY) { struct autr_ta* np = p->next; /* remove */ - free(p->rr); - free(p); + autr_ta_delete(p); /* snip and go to next item */ *prevp = np; p = np; @@ -2172,7 +2217,7 @@ autr_tp_remove(struct module_env* env, s int autr_process_prime(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, - struct module_qstate* qstate) + struct module_qstate* qstate, struct val_qstate* vq) { int changed = 0; log_assert(tp && tp->autr); @@ -2213,7 +2258,7 @@ int autr_process_prime(struct module_env return 1; /* trust point exists */ } /* check for revoked keys to remove immediately */ - check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate); + check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate, vq); if(changed) { verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble"); if(!autr_assemble(tp)) { @@ -2229,7 +2274,7 @@ int autr_process_prime(struct module_env } } /* verify the dnskey rrset and see if it is valid. */ - if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) { + if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate, vq)) { verbose(VERB_ALGO, "autotrust: dnskey did not verify."); /* only increase failure count if this is not the first prime, * this means there was a previous successful probe */ @@ -2322,7 +2367,7 @@ autr_debug_print_tp(struct trust_anchor* if(tp->dnskey_rrset) { log_packed_rrset(NO_VERBOSE, "DNSKEY:", tp->dnskey_rrset); } - log_info("file %s", tp->autr->file); + log_info("file %s", (tp->autr->file?tp->autr->file:"null")); (void)autr_ctime_r(&tp->autr->last_queried, buf); if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf); @@ -2420,7 +2465,7 @@ probe_anchor(struct module_env* env, str qinfo.qclass); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, - &probe_answer_cb, env, 0)) { + &probe_answer_cb, env, 0, NULL)) { log_err("out of memory making 5011 probe"); } } Index: sbin/unwind/libunbound/validator/autotrust.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/autotrust.h,v diff -u -p -r1.1 autotrust.h --- sbin/unwind/libunbound/validator/autotrust.h 23 Jan 2019 13:05:27 -0000 1.1 +++ sbin/unwind/libunbound/validator/autotrust.h 21 Sep 2026 16:28:02 -0000 @@ -50,6 +50,7 @@ struct module_env; struct module_qstate; struct val_env; struct sldns_buffer; +struct val_qstate; /** Autotrust anchor states */ typedef enum { @@ -190,13 +191,14 @@ void autr_point_delete(struct trust_anch * @param dnskey_rrset: DNSKEY rrset probed (can be NULL if bad prime result). * allocated in a region. Has not been validated yet. * @param qstate: qstate with region. + * @param vq: validator query state. * @return false if trust anchor was revoked completely. * Otherwise logs errors to log, does not change return value. * On errors, likely the trust point has been unchanged. */ int autr_process_prime(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, - struct module_qstate* qstate); + struct module_qstate* qstate, struct val_qstate* vq); /** * Debug printout of rfc5011 tracked anchors Index: sbin/unwind/libunbound/validator/val_anchor.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_anchor.c,v diff -u -p -r1.6 val_anchor.c --- sbin/unwind/libunbound/validator/val_anchor.c 14 Sep 2025 15:16:53 -0000 1.6 +++ sbin/unwind/libunbound/validator/val_anchor.c 21 Sep 2026 16:28:02 -0000 @@ -534,7 +534,10 @@ readkeyword_bindfile(FILE* in, sldns_buf while((c = getc(in)) != EOF ) { if(comments && c == '#') { /* # blabla */ skip_to_eol(in, &c); - if(c == EOF) return 0; + if(c == EOF) { + log_err("trusted-keys, %d, got EOF", *line); + return 0; + } (*line)++; continue; } else if(comments && c=='/' && numdone>0 && /* /_/ bla*/ @@ -543,7 +546,10 @@ readkeyword_bindfile(FILE* in, sldns_buf sldns_buffer_skip(buf, -1); numdone--; skip_to_eol(in, &c); - if(c == EOF) return 0; + if(c == EOF) { + log_err("trusted-keys, %d, got EOF", *line); + return 0; + } (*line)++; continue; } else if(comments && c=='*' && numdone>0 && /* /_* bla *_/ */ @@ -560,7 +566,10 @@ readkeyword_bindfile(FILE* in, sldns_buf if(c == '\n') (*line)++; } - if(c == EOF) return 0; + if(c == EOF) { + log_err("trusted-keys, %d, got EOF", *line); + return 0; + } continue; } /* not a comment, complete the keyword */ @@ -581,7 +590,8 @@ readkeyword_bindfile(FILE* in, sldns_buf } /* space for 1 char + 0 string terminator */ if(sldns_buffer_remaining(buf) < 2) { - fatal_exit("trusted-keys, %d, string too long", *line); + log_err("trusted-keys, %d, string too long", *line); + return 0; } sldns_buffer_write_u8(buf, (uint8_t)c); numdone++; @@ -595,7 +605,10 @@ readkeyword_bindfile(FILE* in, sldns_buf break; } } - if(c == EOF) return 0; + if(c == EOF) { + log_err("trusted-keys, %d, got EOF", *line); + return 0; + } return numdone; } if(is_bind_special(c)) @@ -623,7 +636,7 @@ skip_to_special(FILE* in, sldns_buffer* } return 1; } - log_err("trusted-keys, line %d, expected %c got EOF", *line, spec); + log_err("trusted-keys, line %d, expected %c, read failed", *line, spec); return 0; } Index: sbin/unwind/libunbound/validator/val_neg.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_neg.c,v diff -u -p -r1.6 val_neg.c --- sbin/unwind/libunbound/validator/val_neg.c 14 Sep 2025 15:16:53 -0000 1.6 +++ sbin/unwind/libunbound/validator/val_neg.c 21 Sep 2026 16:28:02 -0000 @@ -62,6 +62,13 @@ #include "sldns/rrdef.h" #include "sldns/sbuffer.h" +/** + * The maximum salt length that the negative cache is willing to use. + * Larger salt increases the computation time, while recommendations are + * for zero salt length for zones. + */ +#define MAX_SALT_LENGTH 64 + int val_neg_data_compare(const void* a, const void* b) { struct val_neg_data* x = (struct val_neg_data*)a; @@ -826,7 +833,11 @@ void neg_insert_data(struct val_neg_cach (slen != 0 && zone->nsec3_salt && s && memcmp(zone->nsec3_salt, s, slen) != 0))) { - if(slen > 0) { + if(slen > MAX_SALT_LENGTH) { + /* RFC 9276 s3.1: operators SHOULD NOT use a salt; large + * salts inflate per-hash block count. Decline to cache. */ + return; + } else if(slen > 0) { uint8_t* sa = memdup(s, slen); if(sa) { free(zone->nsec3_salt); @@ -927,6 +938,10 @@ void val_neg_addreply(struct val_neg_cac continue; if(!dname_subdomain_c(rep->rrsets[i]->rk.dname, zone->name)) continue; + if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC && + !nsec_nextowner_subdomain(rep->rrsets[i], zone->name)) { + continue; /* nextowner not in zone */ + } /* insert NSEC into this zone's tree */ neg_insert_data(neg, zone, rep->rrsets[i]); } @@ -1011,6 +1026,10 @@ void val_neg_addreferral(struct val_neg_ continue; if(!dname_subdomain_c(rep->rrsets[i]->rk.dname, zone->name)) continue; + if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC && + !nsec_nextowner_subdomain(rep->rrsets[i], zone->name)) { + continue; /* nextowner not in zone */ + } /* insert NSEC into this zone's tree */ neg_insert_data(neg, zone, rep->rrsets[i]); } @@ -1066,11 +1085,7 @@ grab_nsec(struct rrset_cache* rrset_cach qname, qname_len, qtype, qclass, flags, now, 0); struct packed_rrset_data* d; if(!k) return NULL; - d = (struct packed_rrset_data*)k->entry.data; - if(d->ttl < now) { - lock_rw_unlock(&k->entry.lock); - return NULL; - } + d = k->entry.data; /* only secure or unchecked records that have signatures. */ if( ! ( d->security == sec_status_secure || (d->security == sec_status_unchecked && @@ -1103,12 +1118,14 @@ grab_nsec(struct rrset_cache* rrset_cach * @param rrset_cache: rrset cache * @param now: to check ttl against * @param region: where to alloc result + * @param topname: do not look higher than this name, so that the + * result cannot be taken from a zone above the current trust anchor. * @return rrset or NULL */ static struct ub_packed_rrset_key* neg_find_nsec(struct val_neg_cache* neg_cache, uint8_t* qname, size_t qname_len, uint16_t qclass, struct rrset_cache* rrset_cache, time_t now, - struct regional* region) + struct regional* region, uint8_t* topname) { int labs; uint32_t flags; @@ -1126,6 +1143,11 @@ neg_find_nsec(struct val_neg_cache* neg_ lock_basic_unlock(&neg_cache->lock); return NULL; } + if(topname && !dname_subdomain_c(zone->name, topname)) { + /* Reject NSEC not within trust anchor's bailiwick */ + lock_basic_unlock(&neg_cache->lock); + return NULL; + } /* NSEC only for now */ if(zone->nsec3_hash) { @@ -1169,6 +1191,15 @@ neg_find_nsec3_ce(struct val_neg_zone* z uint8_t hashce[NSEC3_SHA_LEN]; uint8_t b32[257]; size_t celen, b32len; + int hashmax = MAX_NSEC3_CALCULATIONS; + if(qlabs > hashmax) { + /* strip leading labels so the walk costs at most + * MAX_NSEC3_CALCULATIONS hashes, mirroring val_nsec3.c */ + while(qlabs > hashmax) { + dname_remove_label(&qname, &qname_len); + qlabs--; + } + } *nclen = 0; while(qlabs > 0) { @@ -1207,8 +1238,8 @@ neg_params_ok(struct val_neg_zone* zone, return 0; return (h == zone->nsec3_hash && it == zone->nsec3_iter && slen == zone->nsec3_saltlen && - (slen != 0 && zone->nsec3_salt && s - && memcmp(zone->nsec3_salt, s, slen) == 0)); + (slen == 0 || (slen != 0 && zone->nsec3_salt && s + && memcmp(zone->nsec3_salt, s, slen) == 0))); } /** get next closer for nsec3 proof */ @@ -1269,6 +1300,12 @@ neg_nsec3_proof_ds(struct val_neg_zone* if(!zone->nsec3_hash) return NULL; /* not nsec3 zone */ + if(!topname && qlabs > zone->labs + 1) + return NULL; /* iterator caller; opt-out proof would be discarded + * at the !topname check below anyway. + * The qlabs check allows the exact-match for + * the one-label-below-zone case. */ + if(!(data=neg_find_nsec3_ce(zone, qname, qname_len, qlabs, buf, hashnc, &nclen))) { return NULL; @@ -1291,8 +1328,10 @@ neg_nsec3_proof_ds(struct val_neg_zone* !nsec3_has_type(ce_rrset, 0, LDNS_RR_TYPE_NS)) return NULL; if(!(msg = dns_msg_create(qname, qname_len, - LDNS_RR_TYPE_DS, zone->dclass, region, 1))) + LDNS_RR_TYPE_DS, zone->dclass, region, 2))) /* ce + soa */ return NULL; + /* The cache response means recursion is available. */ + msg->rep->flags |= BIT_RA; /* TTL reduced in grab_nsec */ if(!dns_msg_authadd(msg, region, ce_rrset, 0)) return NULL; @@ -1327,6 +1366,8 @@ neg_nsec3_proof_ds(struct val_neg_zone* if(!(msg = dns_msg_create(qname, qname_len, LDNS_RR_TYPE_DS, zone->dclass, region, 3))) return NULL; + /* The cache response means recursion is available. */ + msg->rep->flags |= BIT_RA; /* now=0 because TTL was reduced in grab_nsec */ if(!dns_msg_authadd(msg, region, ce_rrset, 0)) return NULL; @@ -1404,7 +1445,7 @@ val_neg_getmsg(struct val_neg_cache* neg /* Get best available NSEC for qname */ nsec = neg_find_nsec(neg, qinfo->qname, qinfo->qname_len, qinfo->qclass, - rrset_cache, now, region); + rrset_cache, now, region, topname); /* Matching NSEC, use to generate No Data answer. Not creating answers * yet for No Data proven using wildcard. */ @@ -1417,6 +1458,8 @@ val_neg_getmsg(struct val_neg_cache* neg if(!(msg = dns_msg_create(qinfo->qname, qinfo->qname_len, qinfo->qtype, qinfo->qclass, region, 2))) return NULL; + /* The cache response means recursion is available. */ + msg->rep->flags |= BIT_RA; if(!dns_msg_authadd(msg, region, nsec, 0)) return NULL; if(addsoa && !add_soa(rrset_cache, now, region, msg, NULL)) @@ -1430,6 +1473,8 @@ val_neg_getmsg(struct val_neg_cache* neg if(!(msg = dns_msg_create(qinfo->qname, qinfo->qname_len, qinfo->qtype, qinfo->qclass, region, 3))) return NULL; + /* The cache response means recursion is available. */ + msg->rep->flags |= BIT_RA; if(!(ce = nsec_closest_encloser(qinfo->qname, nsec))) return NULL; dname_count_size_labels(ce, &ce_len); @@ -1480,7 +1525,7 @@ val_neg_getmsg(struct val_neg_cache* neg * proof */ if(!(wcrr = neg_find_nsec(neg, wc_qinfo.qname, wc_qinfo.qname_len, qinfo->qclass, - rrset_cache, now, region))) + rrset_cache, now, region, topname))) return NULL; nodata_wc = NULL; Index: sbin/unwind/libunbound/validator/val_nsec.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_nsec.c,v diff -u -p -r1.7 val_nsec.c --- sbin/unwind/libunbound/validator/val_nsec.c 5 Sep 2024 08:22:48 -0000 1.7 +++ sbin/unwind/libunbound/validator/val_nsec.c 21 Sep 2026 16:28:02 -0000 @@ -177,7 +177,8 @@ static int nsec_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen) { struct packed_rrset_data* d = (struct packed_rrset_data*) nsec->entry.data; @@ -189,7 +190,7 @@ nsec_verify_rrset(struct module_env* env if(d->security == sec_status_secure) return 1; d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason, - reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified, + reason_bogus, LDNS_SECTION_AUTHORITY, qstate, vq, &verified, reasonbuf, reasonlen); if(d->security == sec_status_secure) { rrset_update_sec_status(env->rrset_cache, nsec, *env->now); @@ -203,7 +204,7 @@ val_nsec_prove_nodata_dsreply(struct mod struct query_info* qinfo, struct reply_info* rep, struct key_entry_key* kkey, time_t* proof_ttl, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns( rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC, @@ -221,26 +222,32 @@ val_nsec_prove_nodata_dsreply(struct mod * 2) this is not a delegation point */ if(nsec) { if(!nsec_verify_rrset(env, ve, nsec, kkey, reason, - reason_bogus, qstate, reasonbuf, reasonlen)) { + reason_bogus, qstate, vq, reasonbuf, reasonlen)) { verbose(VERB_ALGO, "NSEC RRset for the " "referral did not verify."); return sec_status_bogus; } - sec = val_nsec_proves_no_ds(nsec, qinfo); - if(sec == sec_status_bogus) { - /* something was wrong. */ - *reason = "NSEC does not prove absence of DS"; - *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; - return sec; - } else if(sec == sec_status_insecure) { - /* this wasn't a delegation point. */ - return sec; - } else if(sec == sec_status_secure) { - /* this proved no DS. */ - *proof_ttl = ub_packed_rrset_ttl(nsec); - return sec; + /* If the NSEC was a wildcard, the verify rewrites the + * owner to '*.zone'. Check the NSEC owner matches. */ + if(query_dname_compare(nsec->rk.dname, qinfo->qname) == 0) { + sec = val_nsec_proves_no_ds(nsec, qinfo); + if(sec == sec_status_bogus) { + /* something was wrong. */ + *reason = "NSEC does not prove absence of DS"; + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec; + } else if(sec == sec_status_insecure) { + /* this wasn't a delegation point. */ + return sec; + } else if(sec == sec_status_secure) { + /* this proved no DS. */ + *proof_ttl = ub_packed_rrset_ttl(nsec); + return sec; + } } /* if unchecked, fall through to next proof */ + /* For *.closest-encloser NSEC, there is a closer-match + * check for the wildcard below. */ } /* Otherwise, there is no NSEC at qname. This could be an ENT. @@ -252,7 +259,7 @@ val_nsec_prove_nodata_dsreply(struct mod if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC)) continue; if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason, - reason_bogus, qstate, reasonbuf, reasonlen)) { + reason_bogus, qstate, vq, reasonbuf, reasonlen)) { verbose(VERB_ALGO, "NSEC for empty non-terminal " "did not verify."); *reason = "NSEC for empty non-terminal " Index: sbin/unwind/libunbound/validator/val_nsec.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_nsec.h,v diff -u -p -r1.4 val_nsec.h --- sbin/unwind/libunbound/validator/val_nsec.h 5 Sep 2024 08:22:48 -0000 1.4 +++ sbin/unwind/libunbound/validator/val_nsec.h 21 Sep 2026 16:28:02 -0000 @@ -52,6 +52,7 @@ struct ub_packed_rrset_key; struct reply_info; struct query_info; struct key_entry_key; +struct val_qstate; /** * Check DS absence. @@ -68,6 +69,7 @@ struct key_entry_key; * @param reason: string explaining why bogus. * @param reason_bogus: relevant EDE code for validation failure. * @param qstate: qstate with region. + * @param vq: validator qstate. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return security status. @@ -80,7 +82,8 @@ enum sec_status val_nsec_prove_nodata_ds struct val_env* ve, struct query_info* qinfo, struct reply_info* rep, struct key_entry_key* kkey, time_t* proof_ttl, char** reason, sldns_ede_code* reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen); + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen); /** * nsec typemap check, takes an NSEC-type bitmap as argument, checks for type. Index: sbin/unwind/libunbound/validator/val_nsec3.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_nsec3.c,v diff -u -p -r1.5 val_nsec3.c --- sbin/unwind/libunbound/validator/val_nsec3.c 23 Feb 2025 07:53:40 -0000 1.5 +++ sbin/unwind/libunbound/validator/val_nsec3.c 21 Sep 2026 16:28:02 -0000 @@ -60,11 +60,6 @@ #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. @@ -456,6 +451,67 @@ filter_init(struct nsec3_filter* filter, } } +/** Check if the NSEC3s have the same parameter set. */ +static int +param_set_same(struct nsec3_filter* flt, char** reason) +{ + size_t rrsetnum; + int rrnum; + struct ub_packed_rrset_key* rrset; + int have_params = 0; + int first_algo = 0; + size_t first_iter = 0; + uint8_t* first_salt = NULL; + size_t first_saltlen = 0; + + /* If the NSEC3 parameter sets have distinct values, then they are + * from different NSEC3 chains, and we do not want that. */ + for(rrset=filter_first(flt, &rrsetnum, &rrnum); rrset; + rrset=filter_next(flt, &rrsetnum, &rrnum)) { + if(!have_params) { + first_algo = nsec3_get_algo(rrset, rrnum); + first_iter = nsec3_get_iter(rrset, rrnum); + if(!nsec3_get_salt(rrset, rrnum, &first_salt, + &first_saltlen)) { + verbose(VERB_ALGO, "NSEC3 salt malformed"); + if(reason) + *reason = "NSEC3 salt malformed"; + return 0; + } + have_params = 1; + } else { + uint8_t* salt = NULL; + size_t saltlen = 0; + if(nsec3_get_algo(rrset, rrnum) != first_algo) { + verbose(VERB_ALGO, "NSEC3 algorithm mismatch"); + if(reason) + *reason = "NSEC3 algorithm mismatch"; + return 0; + } + if(nsec3_get_iter(rrset, rrnum) != first_iter) { + verbose(VERB_ALGO, "NSEC3 iterations mismatch"); + if(reason) + *reason = "NSEC3 iterations mismatch"; + return 0; + } + if(!nsec3_get_salt(rrset, rrnum, &salt, &saltlen)) { + verbose(VERB_ALGO, "NSEC3 salt malformed"); + if(reason) + *reason = "NSEC3 salt malformed"; + return 0; + } + if(saltlen != first_saltlen || + memcmp(salt, first_salt, saltlen) != 0) { + verbose(VERB_ALGO, "NSEC3 salt mismatch"); + if(reason) + *reason = "NSEC3 salt mismatch"; + return 0; + } + } + } + return 1; +} + /** * Find max iteration count using config settings and key size * @param ve: validator environment with iteration count config settings. @@ -1192,6 +1248,12 @@ nsec3_prove_nameerror(struct module_env* filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone", @@ -1378,6 +1440,12 @@ nsec3_prove_nodata(struct module_env* en filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ 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, calc); @@ -1401,6 +1469,12 @@ nsec3_prove_wildcard(struct module_env* filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ @@ -1447,7 +1521,8 @@ static int list_is_secure(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen) { struct packed_rrset_data* d; size_t i; @@ -1463,7 +1538,7 @@ list_is_secure(struct module_env* env, s continue; d->security = val_verify_rrset_entry(env, ve, list[i], kkey, reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate, - &verified, reasonbuf, reasonlen); + vq, &verified, reasonbuf, reasonlen); if(d->security != sec_status_secure) { verbose(VERB_ALGO, "NSEC3 did not verify"); return 0; @@ -1478,7 +1553,8 @@ nsec3_prove_nods(struct module_env* env, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, struct nsec3_cache_table* ct, char* reasonbuf, + size_t reasonlen) { struct nsec3_filter flt; struct ce_response ce; @@ -1494,7 +1570,7 @@ nsec3_prove_nods(struct module_env* env, return sec_status_bogus; /* no valid NSEC3s, bogus */ } if(!list_is_secure(env, ve, list, num, kkey, reason, reason_bogus, - qstate, reasonbuf, reasonlen)) { + qstate, vq, reasonbuf, reasonlen)) { *reason = "not all NSEC3 records secure"; return sec_status_bogus; /* not all NSEC3 records secure */ } @@ -1503,6 +1579,13 @@ nsec3_prove_nods(struct module_env* env, *reason = "no NSEC3 records"; return sec_status_bogus; /* no RRs */ } + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + *reason = "NSEC3 name is not b32.signer name"; + return sec_status_bogus; + } + if(!param_set_same(&flt, reason)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ @@ -1596,6 +1679,12 @@ nsec3_prove_nxornodata(struct module_env filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ Index: sbin/unwind/libunbound/validator/val_nsec3.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_nsec3.h,v diff -u -p -r1.4 val_nsec3.h --- sbin/unwind/libunbound/validator/val_nsec3.h 5 Sep 2024 08:22:48 -0000 1.4 +++ sbin/unwind/libunbound/validator/val_nsec3.h 21 Sep 2026 16:28:02 -0000 @@ -78,6 +78,7 @@ struct reply_info; struct query_info; struct key_entry_key; struct sldns_buffer; +struct val_qstate; /** * 0 1 2 3 4 5 6 7 @@ -99,6 +100,12 @@ struct sldns_buffer; #define NSEC3_HASH_SHA1 0x01 /** + * 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 + +/** * Cache table for NSEC3 hashes. * It keeps a *pointer* to the region its items are allocated. */ @@ -209,6 +216,7 @@ nsec3_prove_wildcard(struct module_env* * @param reason: string for bogus result. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate. * @param ct: cached hashes table. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. @@ -224,7 +232,8 @@ nsec3_prove_nods(struct module_env* env, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, struct nsec3_cache_table* ct, char* reasonbuf, + size_t reasonlen); /** * Prove NXDOMAIN or NODATA. Index: sbin/unwind/libunbound/validator/val_secalgo.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_secalgo.c,v diff -u -p -r1.8 val_secalgo.c --- sbin/unwind/libunbound/validator/val_secalgo.c 5 Sep 2024 08:22:48 -0000 1.8 +++ sbin/unwind/libunbound/validator/val_secalgo.c 21 Sep 2026 16:28:02 -0000 @@ -745,11 +745,9 @@ verify_canonrrset(sldns_buffer* buf, int if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) &&(fake_dsa||fake_sha1)) return sec_status_secure; #endif -#ifndef USE_SHA1 if(fake_sha1 && (algo == LDNS_DSA || algo == LDNS_DSA_NSEC3 || algo == LDNS_RSASHA1 || algo == LDNS_RSASHA1_NSEC3)) return sec_status_secure; -#endif - + if(!setup_key_digest(algo, &evp_key, &digest_type, key, keylen)) { verbose(VERB_QUERY, "verify: failed to setup key"); *reason = "use of key for crypto failed"; @@ -1874,9 +1872,9 @@ _verify_nettle_rsa(sldns_buffer* buf, un } mod_offset = exp_offset + exp_len; nettle_rsa_public_key_init(&pubkey); - pubkey.size = keylen - mod_offset; nettle_mpz_set_str_256_u(pubkey.e, exp_len, &key[exp_offset]); - nettle_mpz_set_str_256_u(pubkey.n, pubkey.size, &key[mod_offset]); + nettle_mpz_set_str_256_u(pubkey.n, keylen - mod_offset, &key[mod_offset]); + pubkey.size = nettle_mpz_sizeinbase_256_u(pubkey.n); /* Digest content of "buf" and verify its RSA signature in "sigblock"*/ nettle_mpz_init_set_str_256_u(signature, sigblock_len, (uint8_t*)sigblock); Index: sbin/unwind/libunbound/validator/val_sigcrypt.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_sigcrypt.c,v diff -u -p -r1.11 val_sigcrypt.c --- sbin/unwind/libunbound/validator/val_sigcrypt.c 29 Sep 2025 14:53:38 -0000 1.11 +++ sbin/unwind/libunbound/validator/val_sigcrypt.c 21 Sep 2026 16:28:02 -0000 @@ -82,6 +82,8 @@ /** Maximum number of RRSIG validations for an RRset. */ #define MAX_VALIDATE_RRSIGS 8 +/** Maximum number of NSEC validations for a message. */ +#define MAX_VALIDATE_NSECS 8 /** return number of rrs in an rrset */ static size_t @@ -305,6 +307,8 @@ ds_create_dnskey_digest(struct module_en * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA); * DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */ sldns_buffer_clear(b); + if(!sldns_buffer_available(b, dnskey_rrset->rk.dname_len + dnskey_len-2)) + return 0; /* buffer too small */ sldns_buffer_write(b, dnskey_rrset->rk.dname, dnskey_rrset->rk.dname_len); query_dname_tolower(sldns_buffer_begin(b)); @@ -546,8 +550,10 @@ int algo_needs_missing(struct algo_needs * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param numverified: incremented when the number of RRSIG validations * increases. + * @param num_tagmatches: incremented for tag matches. * @return secure if any key signs *this* signature. bogus if no key signs it, * unchecked on error, or indeterminate if all keys are not supported by * the crypto library (openssl3+ only). @@ -559,7 +565,7 @@ dnskeyset_verify_rrset_sig(struct module struct rbtree_type** sortree, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* numverified) + struct val_qstate* vq, int* numverified, size_t* num_tagmatches) { /* find matching keys and check them */ enum sec_status sec = sec_status_bogus; @@ -578,6 +584,14 @@ dnskeyset_verify_rrset_sig(struct module } for(i=0; i MAX_TAG_MATCHES) { + *reason = "too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "verify sig: too many tag matches, " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } /* see if key matches keytag and algo */ if(algo != dnskey_get_algo(dnskey, i) || tag != dnskey_calc_keytag(dnskey, i)) @@ -585,6 +599,26 @@ dnskeyset_verify_rrset_sig(struct module numchecked ++; (*numverified)++; + if(vq && vq->num_validation_attempts++ > env->cfg->val_validation_attempts) { + *reason = "too many validation attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "verify sig: too many validation attempts, " + "val-validation-attempts (%d); bogus", env->cfg->val_validation_attempts); + return sec_status_bogus; + } + if(vq && (ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC || + ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC3) && + vq->num_nsec_attempts++ > MAX_VALIDATE_NSECS) { + *reason = "too many NSEC or NSEC3 validation attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "verify sig: too many NSEC or NSEC3 validation attempts, " + "(%d); bogus", MAX_VALIDATE_NSECS); + vq->num_nsec_attempts_exceeded = 1; + return sec_status_bogus; + } + /* see if key verifies */ sec = dnskey_verify_rrset_sig(env->scratch, env->scratch_buffer, ve, now, rrset, dnskey, i, @@ -624,11 +658,12 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate, int* verified, - char* reasonbuf, size_t reasonlen) + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen) { enum sec_status sec; - size_t i, num; + size_t i, num, num_tagmatches = 0; rbtree_type* sortree = NULL; /* make sure that for all DNSKEY algorithms there are valid sigs */ struct algo_needs needs; @@ -656,9 +691,19 @@ dnskeyset_verify_rrset(struct module_env } } for(i=0; i MAX_TAG_MATCHES) { + *reason = "too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many tag matches, " + "MAX_TAG_MATCHES (%d)", MAX_TAG_MATCHES); + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset, dnskey, i, &sortree, reason, reason_bogus, - section, qstate, verified); + section, qstate, vq, verified, &num_tagmatches); /* see which algorithm has been fixed up */ if(sec == sec_status_secure) { if(!sigalg) @@ -707,7 +752,8 @@ enum sec_status dnskey_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate) + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, size_t* num_tagmatches) { enum sec_status sec; size_t i, num, numchecked = 0, numindeterminate = 0; @@ -728,9 +774,26 @@ dnskey_verify_rrset(struct module_env* e } for(i=0; i MAX_TAG_MATCHES) { + *reason = "too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many tag matches, " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } if(algo != rrset_get_sig_algo(rrset, i) || tag != rrset_get_sig_keytag(rrset, i)) continue; + if(vq && vq->num_validation_attempts++ > env->cfg->val_validation_attempts) { + *reason = "too many validation attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many validation attempts, " + "val-validation-attempts (%d); bogus", env->cfg->val_validation_attempts); + return sec_status_bogus; + } + buf_canon = 0; sec = dnskey_verify_rrset_sig(env->scratch, env->scratch_buffer, ve, *env->now, rrset, @@ -1083,6 +1146,18 @@ insert_can_owner(sldns_buffer* buf, stru } } +/** lowercase a wire dname but never step past end */ +static void +canon_dname_tolower(uint8_t* d, uint8_t* end) +{ + uint8_t lab; + while(d < end && (lab = *d) != 0) { + if((size_t)lab+1 > (size_t)(end-d)) return; /* malformed */ + for(d++; lab; lab--, d++) + *d = (uint8_t)tolower((unsigned char)*d); + } +} + /** * Canonicalize Rdata in buffer. * @param buf: buffer at position just after the rdata. @@ -1094,6 +1169,8 @@ canonicalize_rdata(sldns_buffer* buf, st size_t len) { uint8_t* datstart = sldns_buffer_current(buf)-len+2; + uint8_t* datend = sldns_buffer_current(buf); + size_t firstlen; switch(ntohs(rrset->rk.type)) { case LDNS_RR_TYPE_NXT: case LDNS_RR_TYPE_NS: @@ -1106,15 +1183,16 @@ canonicalize_rdata(sldns_buffer* buf, st case LDNS_RR_TYPE_PTR: case LDNS_RR_TYPE_DNAME: /* type only has a single argument, the name */ - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; case LDNS_RR_TYPE_MINFO: case LDNS_RR_TYPE_RP: case LDNS_RR_TYPE_SOA: /* two names after another */ - query_dname_tolower(datstart); - query_dname_tolower(datstart + - dname_valid(datstart, len-2)); + canon_dname_tolower(datstart, datend); + firstlen = dname_valid(datstart, len-2); + if(firstlen && firstlen < len-2) + canon_dname_tolower(datstart + firstlen, datend); return; case LDNS_RR_TYPE_RT: case LDNS_RR_TYPE_AFSDB: @@ -1124,7 +1202,7 @@ canonicalize_rdata(sldns_buffer* buf, st if(len < 2+2+1) /* rdlen, skiplen, 1byteroot */ return; datstart += 2; - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; case LDNS_RR_TYPE_SIG: /* downcase the RRSIG, compat with BIND (kept it from SIG) */ @@ -1133,16 +1211,17 @@ canonicalize_rdata(sldns_buffer* buf, st if(len < 2+18+1) return; datstart += 18; - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; case LDNS_RR_TYPE_PX: /* skip, then two names after another */ if(len < 2+2+1) return; datstart += 2; - query_dname_tolower(datstart); - query_dname_tolower(datstart + - dname_valid(datstart, len-2-2)); + canon_dname_tolower(datstart, datend); + firstlen = dname_valid(datstart, len-2-2); + if(firstlen && firstlen < len-2-2) + canon_dname_tolower(datstart + firstlen, datend); return; case LDNS_RR_TYPE_NAPTR: if(len < 2+4) @@ -1163,14 +1242,14 @@ canonicalize_rdata(sldns_buffer* buf, st datstart += (size_t)datstart[0]+1; if(len < 1) /* check name is at least 1 byte*/ return; - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; case LDNS_RR_TYPE_SRV: /* skip fixed part */ if(len < 2+6+1) return; datstart += 6; - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; /* do not canonicalize NSEC rdata name, compat with @@ -1292,14 +1371,32 @@ rrset_canonical(struct regional* region, } sldns_buffer_clear(buf); + if(sldns_buffer_remaining(buf) < siglen || siglen < 18+1) { + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } sldns_buffer_write(buf, sig, siglen); /* canonicalize signer name */ - query_dname_tolower(sldns_buffer_begin(buf)+18); + canon_dname_tolower(sldns_buffer_begin(buf)+18, + sldns_buffer_current(buf)); + + if(sldns_buffer_remaining(buf) < k->rk.dname_len+2) { + /* Check if the first can_owner name can fit in the buffer. + * The length is k->rk.dname_len or k->rk.dname_len+2 + * if it has '*.' in prefixed. Checks the upper bound, + * also realistically the rest of the rrtype, rrclass, origttl, + * rdata and so on has to be inserted, so that extra space has + * to be there. */ + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } RBTREE_FOR(walk, struct canon_rr*, (*sortree)) { /* see if there is enough space left in the buffer */ if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + d->rr_len[walk->rr_idx]) { - log_err("verify: failed to canonicalize, " + verbose(VERB_ALGO, "verify: failed to canonicalize, " "rrset too big"); return 0; } @@ -1308,6 +1405,13 @@ rrset_canonical(struct regional* region, sldns_buffer_write(buf, can_owner, can_owner_len); else insert_can_owner(buf, k, sig, &can_owner, &can_owner_len); + /* Check again, if the rdata can fit in the buffer */ + if(sldns_buffer_remaining(buf) < 2 + 2 + 4 + + d->rr_len[walk->rr_idx]) { + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } sldns_buffer_write(buf, &k->rk.type, 2); sldns_buffer_write(buf, &k->rk.rrset_class, 2); sldns_buffer_write(buf, sig+4, 4); @@ -1322,10 +1426,11 @@ rrset_canonical(struct regional* region, * the non-existence proves. */ if(ntohs(k->rk.type) == LDNS_RR_TYPE_NSEC && section == LDNS_SECTION_AUTHORITY && qstate) { - k->rk.dname = regional_alloc_init(qstate->region, can_owner, + uint8_t* new_dname = regional_alloc_init(qstate->region, can_owner, can_owner_len); - if(!k->rk.dname) + if(!new_dname) return 0; + k->rk.dname = new_dname; k->rk.dname_len = can_owner_len; } @@ -1358,11 +1463,17 @@ rrset_canonicalize_to_buffer(struct regi canonical_sort(k, d, sortree, rrs); sldns_buffer_clear(buf); + if(sldns_buffer_remaining(buf) < k->rk.dname_len) { + /* Check if the first can_owner name can fit in the buffer. */ + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } RBTREE_FOR(walk, struct canon_rr*, sortree) { /* see if there is enough space left in the buffer */ if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + d->rr_len[walk->rr_idx]) { - log_err("verify: failed to canonicalize, " + verbose(VERB_ALGO, "verify: failed to canonicalize, " "rrset too big"); return 0; } @@ -1375,6 +1486,13 @@ rrset_canonicalize_to_buffer(struct regi query_dname_tolower(can_owner); can_owner_len = k->rk.dname_len; } + /* Check again, if the rdata can fit in the buffer */ + if(sldns_buffer_remaining(buf) < 2 + 2 + 4 + + d->rr_len[walk->rr_idx]) { + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } sldns_buffer_write(buf, &k->rk.type, 2); sldns_buffer_write(buf, &k->rk.rrset_class, 2); sldns_buffer_write_u32(buf, d->rr_ttl[walk->rr_idx]); @@ -1570,6 +1688,18 @@ dnskey_verify_rrset_sig(struct regional* *reason_bogus = LDNS_EDE_NO_ZONE_KEY_BIT_SET; return sec_status_bogus; } + if((dnskey_get_flags(dnskey, dnskey_idx) & LDNS_KEY_REVOKE_KEY) && + /* The REVOKE key is allowed to check sigs on itself. */ + !(ntohs(rrset->rk.type) == LDNS_RR_TYPE_DNSKEY && + query_dname_compare(rrset->rk.dname, dnskey->rk.dname)==0) + ) { + verbose(VERB_QUERY, "verify: dnskey has REVOKE bit set, " + "not usable for data validation per RFC 5011 s2.1"); + *reason = "dnskey revoked"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSKEY_MISSING; + return sec_status_bogus; + } if(dnskey_get_protocol(dnskey, dnskey_idx) != LDNS_DNSSEC_KEYPROTO) { /* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */ @@ -1597,6 +1727,30 @@ dnskey_verify_rrset_sig(struct regional* *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; return sec_status_bogus; /* signer name offtree */ } + /* NSEC3, the owner name must be the .signername */ + if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC3 && + rrset->rk.dname_len > 0) { + uint8_t* dnameless = rrset->rk.dname; + size_t dnamelesslen = rrset->rk.dname_len; + dname_remove_label(&dnameless, &dnamelesslen); + if(query_dname_compare(dnameless, signer) != 0) { + verbose(VERB_QUERY, "verify: NSEC3 owner name is not b32.signer name"); + *reason = "NSEC3 owner name is not b32.signer name"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; /* NSEC3 owner not b32.signer */ + } + } + /* NSEC, a next owner that is not under the signer is not allowed.*/ + if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC && + !nsec_nextowner_subdomain(rrset, signer)) { + verbose(VERB_QUERY, "verify: NSEC next owner overreaches signer name"); + *reason = "NSEC next owner overreaches signer name"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; /* nextowner overreaching */ + } + sigblock = (unsigned char*)signer+signer_len; if(siglen < 2+18+signer_len+1) { verbose(VERB_QUERY, "verify: too short, no signature data"); @@ -1650,6 +1804,13 @@ dnskey_verify_rrset_sig(struct regional* if((int)sig[2+3] > dname_signame_label_count(rrset->rk.dname)) { verbose(VERB_QUERY, "verify: labelcount out of range"); *reason = "signature labelcount out of range"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } + if((int)sig[2+3] < dname_signame_label_count(signer)) { + verbose(VERB_QUERY, "verify: RRSIG label count too low for signer"); + *reason = "signature labelcount lower than signature signer"; if(reason_bogus) *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; return sec_status_bogus; Index: sbin/unwind/libunbound/validator/val_sigcrypt.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_sigcrypt.h,v diff -u -p -r1.5 val_sigcrypt.h --- sbin/unwind/libunbound/validator/val_sigcrypt.h 5 Sep 2024 08:22:48 -0000 1.5 +++ sbin/unwind/libunbound/validator/val_sigcrypt.h 21 Sep 2026 16:28:02 -0000 @@ -53,6 +53,7 @@ struct ub_packed_rrset_key; struct rbtree_type; struct regional; struct sldns_buffer; +struct val_qstate; /** number of entries in algorithm needs array */ #define ALGO_NEEDS_MAX 256 @@ -262,6 +263,7 @@ uint16_t dnskey_get_flags(struct ub_pack * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param verified: if not NULL the number of RRSIG validations is returned. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. @@ -273,8 +275,9 @@ enum sec_status dnskeyset_verify_rrset(s struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate, int* verified, - char* reasonbuf, size_t reasonlen); + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen); /** * verify rrset against one specific dnskey (from rrset) @@ -287,13 +290,16 @@ enum sec_status dnskeyset_verify_rrset(s * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. + * @param num_tagmatches: incremented to keep track of tag matches. * @return secure if *this* key signs any of the signatures on rrset. * unchecked on error or and bogus on bad signature. */ enum sec_status dnskey_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate); + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, size_t* num_tagmatches); /** * verify rrset, with specific dnskey(from set), for a specific rrsig @@ -311,7 +317,7 @@ enum sec_status dnskey_verify_rrset(stru * pass false at start. pass old value only for same rrset and same * signature (but perhaps different key) for reuse. * @param reason: if bogus, a string returned, fixed or alloced in scratch. - * @param reason_bogus: EDE (8914) code paired with the reason of failure. + * @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. * @return secure if this key signs this signature. unchecked on error or Index: sbin/unwind/libunbound/validator/val_utils.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_utils.c,v diff -u -p -r1.10 val_utils.c --- sbin/unwind/libunbound/validator/val_utils.c 5 Sep 2024 08:22:48 -0000 1.10 +++ sbin/unwind/libunbound/validator/val_utils.c 21 Sep 2026 16:28:02 -0000 @@ -157,7 +157,7 @@ val_classify_response(uint16_t query_fla } /** Get signer name from RRSIG */ -static void +void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen) { /* RRSIG rdata is not allowed to be compressed, it is stored @@ -406,7 +406,8 @@ val_verify_rrset(struct module_env* env, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int *verified, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, int *verified, char* reasonbuf, + size_t reasonlen) { enum sec_status sec; struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> @@ -431,7 +432,8 @@ val_verify_rrset(struct module_env* env, log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname, ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class)); sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason, - reason_bogus, section, qstate, verified, reasonbuf, reasonlen); + reason_bogus, section, qstate, vq, verified, reasonbuf, + reasonlen); verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec)); regional_free_all(env->scratch); @@ -439,10 +441,15 @@ val_verify_rrset(struct module_env* env, * only improves security status * and bogus is set only once, even if we rechecked the status */ if(sec > d->security) { + int wc_expanded = 0; d->security = sec; - if(sec == sec_status_secure) + if(sec == sec_status_secure) { + uint8_t* wc = NULL; + size_t wclen = 0; d->trust = rrset_trust_validated; - else if(sec == sec_status_bogus) { + if(val_rrset_wildcard(rrset, &wc, &wclen) && wc) + wc_expanded = 1; + } else if(sec == sec_status_bogus) { size_t i; /* update ttl for rrset to fixed value. */ d->ttl = ve->bogus_ttl; @@ -455,7 +462,11 @@ val_verify_rrset(struct module_env* env, lock_basic_unlock(&ve->bogus_lock); } /* if status updated - store in cache for reuse */ - rrset_update_sec_status(env->rrset_cache, rrset, *env->now); + /* For a wildcard rrset, that is secure, do not store this + * into the cache, because it changes proofs around the + * item. */ + if(!wc_expanded) + rrset_update_sec_status(env->rrset_cache, rrset, *env->now); } return sec; @@ -466,7 +477,8 @@ val_verify_rrset_entry(struct module_env struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* verified, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen) { /* temporary dnskey rrset-key */ struct ub_packed_rrset_key dnskey; @@ -480,7 +492,8 @@ val_verify_rrset_entry(struct module_env dnskey.entry.key = &dnskey; dnskey.entry.data = kd->rrset_data; sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason, - reason_bogus, section, qstate, verified, reasonbuf, reasonlen); + reason_bogus, section, qstate, vq, verified, reasonbuf, + reasonlen); return sec; } @@ -490,13 +503,20 @@ verify_dnskeys_with_ds_rr(struct module_ struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - int *nonechecked, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, int *nonechecked, char* reasonbuf, + size_t reasonlen, size_t* num_tagmatches, + size_t* num_tagmatches_dnskeysig) { enum sec_status sec = sec_status_bogus; size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0; num = rrset_get_count(dnskey_rrset); *nonechecked = 0; for(i=0; i MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS match attempt reached " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } /* Skip DNSKEYs that don't match the basic criteria. */ if(ds_get_key_algo(ds_rrset, ds_idx) != dnskey_get_algo(dnskey_rrset, i) @@ -509,6 +529,15 @@ verify_dnskeys_with_ds_rr(struct module_ ds_get_key_algo(ds_rrset, ds_idx), ds_get_keytag(ds_rrset, ds_idx)); + if(vq && vq->num_hash_attempts++ > env->cfg->val_hash_attempts) { + *reason = "too many hash attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many hash attempts, " + "val-hash-attempts (%d); bogus", env->cfg->val_hash_attempts); + return sec_status_bogus; + } + /* Convert the candidate DNSKEY into a hash using the * same DS hash algorithm. */ if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset, @@ -532,8 +561,14 @@ verify_dnskeys_with_ds_rr(struct module_ /* Otherwise, we have a match! Make sure that the DNSKEY * verifies *with this key* */ + if(*num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS that matched has too many DNSKEY to RRSIG tag matches " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, - i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate); + i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate, + vq, num_tagmatches_dnskeysig); if(sec == sec_status_secure) { return sec; } @@ -577,14 +612,14 @@ val_verify_DNSKEY_with_DS(struct module_ struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { /* as long as this is false, we can consider this DS rrset to be * equivalent to no DS rrset. */ int has_useful_ds = 0, digest_algo, alg, has_algo_refusal = 0, nonechecked, has_checked_ds = 0; struct algo_needs needs; - size_t i, num; + size_t i, num, num_tagmatches = 0, num_tagmatches_dnskeysig = 0; enum sec_status sec; if(dnskey_rrset->rk.dname_len != ds_rrset->rk.dname_len || @@ -606,6 +641,13 @@ val_verify_DNSKEY_with_DS(struct module_ } num = rrset_get_count(ds_rrset); for(i=0; i MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS verify attempt reached " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "DS verify has too many tag matches"; + return sec_status_bogus; + } + /* Check to see if we can understand this DS. * And check it is the strongest digest */ if(!ds_digest_algo_is_supported(ds_rrset, i) || @@ -614,9 +656,16 @@ val_verify_DNSKEY_with_DS(struct module_ continue; } + if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS verify attempt reached " + "DNSKEY to RRSIG MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "DS verify has too many DNSKEY to RRSIG tag matches"; + return sec_status_bogus; + } sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, - ds_rrset, i, reason, reason_bogus, qstate, - &nonechecked, reasonbuf, reasonlen); + ds_rrset, i, reason, reason_bogus, qstate, vq, + &nonechecked, reasonbuf, reasonlen, &num_tagmatches, + &num_tagmatches_dnskeysig); if(sec == sec_status_insecure) { /* DNSKEY too large unsupported or algo refused by * crypto lib. */ @@ -678,12 +727,12 @@ val_verify_new_DNSKEYs(struct regional* struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { uint8_t sigalg[ALGO_NEEDS_MAX+1]; enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve, dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason, - reason_bogus, qstate, reasonbuf, reasonlen); + reason_bogus, qstate, vq, reasonbuf, reasonlen); if(sec == sec_status_secure) { return key_entry_create_rrset(region, @@ -709,14 +758,14 @@ val_verify_DNSKEY_with_TA(struct module_ struct ub_packed_rrset_key* ta_ds, struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { /* as long as this is false, we can consider this anchor to be * equivalent to no anchor. */ int has_useful_ta = 0, digest_algo = 0, alg, has_algo_refusal = 0, nonechecked, has_checked_ds = 0; struct algo_needs needs; - size_t i, num; + size_t i, num, num_tagmatches = 0, num_tagmatches_dnskeysig = 0; enum sec_status sec; if(ta_ds && (dnskey_rrset->rk.dname_len != ta_ds->rk.dname_len || @@ -752,6 +801,15 @@ val_verify_DNSKEY_with_TA(struct module_ if(ta_ds) { num = rrset_get_count(ta_ds); for(i=0; i MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "anchor DS verify attempt reached " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "anchor DS verify has too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } + /* Check to see if we can understand this DS. * And check it is the strongest digest */ if(!ds_digest_algo_is_supported(ta_ds, i) || @@ -759,9 +817,18 @@ val_verify_DNSKEY_with_TA(struct module_ ds_get_digest_algo(ta_ds, i) != digest_algo) continue; + if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "anchor DS verify has too many DNSKEY to RRSIG tag matches " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "anchor DS verify has too many DNSKEY to RRSIG tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, - ta_ds, i, reason, reason_bogus, qstate, &nonechecked, - reasonbuf, reasonlen); + ta_ds, i, reason, reason_bogus, qstate, vq, + &nonechecked, reasonbuf, reasonlen, &num_tagmatches, + &num_tagmatches_dnskeysig); if(sec == sec_status_insecure) { has_algo_refusal = 1; continue; @@ -804,8 +871,16 @@ val_verify_DNSKEY_with_TA(struct module_ /* we saw a useful TA */ has_useful_ta = 1; + if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "anchor DS that matched has too many DNSKEY to RRSIG tag matches " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "anchor DS that matched has too many DNSKEY to RRSIG tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } sec = dnskey_verify_rrset(env, ve, dnskey_rrset, - ta_dnskey, i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate); + ta_dnskey, i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate, vq, &num_tagmatches_dnskeysig); if(sec == sec_status_secure) { if(!sigalg || algo_needs_set_secure(&needs, (uint8_t)dnskey_get_algo(ta_dnskey, i))) { @@ -853,12 +928,13 @@ val_verify_new_DNSKEYs_with_ta(struct re struct ub_packed_rrset_key* ta_ds_rrset, struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen) { uint8_t sigalg[ALGO_NEEDS_MAX+1]; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset, - downprot?sigalg:NULL, reason, reason_bogus, qstate, + downprot?sigalg:NULL, reason, reason_bogus, qstate, vq, reasonbuf, reasonlen); if(sec == sec_status_secure) { @@ -1043,7 +1119,7 @@ val_fill_reply(struct reply_info* chase, chase->rrsets[chase->an_numrrsets++] = orig->rrsets[j]; chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i]; } - } + } /* AUTHORITY section */ for(i = (skip > orig->an_numrrsets)?skip:orig->an_numrrsets; ian_numrrsets+orig->ns_numrrsets; @@ -1066,10 +1142,10 @@ val_fill_reply(struct reply_info* chase, if(query_dname_compare(name, orig->rrsets[i]->rk.dname) == 0) chase->rrsets[chase->an_numrrsets - +orig->ns_numrrsets+chase->ar_numrrsets++] + +chase->ns_numrrsets+chase->ar_numrrsets++] = orig->rrsets[i]; } else if(rrset_has_signer(orig->rrsets[i], name, len)) { - chase->rrsets[chase->an_numrrsets+orig->ns_numrrsets+ + chase->rrsets[chase->an_numrrsets+chase->ns_numrrsets+ chase->ar_numrrsets++] = orig->rrsets[i]; } } @@ -1077,6 +1153,23 @@ val_fill_reply(struct reply_info* chase, chase->ar_numrrsets; } +void val_reply_remove_answers(struct reply_info* rep, size_t index, + size_t count) +{ + log_assert(index < rep->rrset_count); + log_assert(index < rep->an_numrrsets); + if(count == 0) + return; /* nothing to do */ + log_assert(index+(count-1) < rep->rrset_count); + log_assert(index+(count-1) < rep->an_numrrsets); + if(rep->rrset_count - (count-1) - index - 1 > 0) + memmove(rep->rrsets+index, rep->rrsets+index+(count-1)+1, + sizeof(struct ub_packed_rrset_key*)* + (rep->rrset_count - (count-1) - index - 1)); + rep->an_numrrsets -= count; + rep->rrset_count -= count; +} + void val_reply_remove_auth(struct reply_info* rep, size_t index) { log_assert(index < rep->rrset_count); @@ -1310,15 +1403,18 @@ val_find_DS(struct module_env* env, uint /* DS rrset exists. Return it to the validator immediately*/ struct ub_packed_rrset_key* copy = packed_rrset_copy_region( rrset, region, *env->now); + struct packed_rrset_data* d; lock_rw_unlock(&rrset->entry.lock); if(!copy) return NULL; + d = (struct packed_rrset_data*)copy->entry.data; msg = dns_msg_create(nm, nmlen, LDNS_RR_TYPE_DS, c, region, 1); if(!msg) return NULL; msg->rep->rrsets[0] = copy; msg->rep->rrset_count++; msg->rep->an_numrrsets++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); return msg; } /* lookup in rrset and negative cache for NSEC/NSEC3 */ @@ -1331,4 +1427,44 @@ val_find_DS(struct module_env* env, uint msg = val_neg_getmsg(env->neg_cache, &qinfo, region, env->rrset_cache, env->scratch_buffer, *env->now, 0, topname, env->cfg); return msg; +} + +int derive_cname_from_dname(struct ub_packed_rrset_key* cname, + struct ub_packed_rrset_key* dname, uint8_t* out, size_t outlen) +{ + size_t prefix_len; + uint8_t* dname_target = NULL; + size_t dname_target_len = 0; + if(!dname_strict_subdomain_c(cname->rk.dname, dname->rk.dname)) + return 0; /* Invalid: CNAME owner must be subdomain */ + get_cname_target(dname, &dname_target, &dname_target_len); + if(!dname_target || !dname_target_len) + return 0; /* DNAME malformed */ + if(cname->rk.dname_len < dname->rk.dname_len) + return 0; /* Not possible, due to subdomain, but check */ + if(cname->rk.dname_len == 0) + return 0; /* Not possible, but check */ + prefix_len = cname->rk.dname_len - dname->rk.dname_len; + if(prefix_len + dname_target_len > outlen) + return 0; /* Buffer too small */ + memmove(out, cname->rk.dname, prefix_len); + memmove(out+prefix_len, dname_target, dname_target_len); + return 1; +} + +int nsec_nextowner_subdomain(struct ub_packed_rrset_key* rrset, uint8_t* name) +{ + struct packed_rrset_data* d; + uint8_t* next; + size_t nextlen; + if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_NSEC) + return 0; + d = (struct packed_rrset_data*)rrset->entry.data; + if(!d || d->count == 0) + return 0; + next = d->rr_data[0]+2; + nextlen = dname_valid(next, d->rr_len[0]-2); + if(nextlen == 0) + return 0; /* malformed */ + return dname_subdomain_c(next, name); } Index: sbin/unwind/libunbound/validator/val_utils.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/val_utils.h,v diff -u -p -r1.4 val_utils.h --- sbin/unwind/libunbound/validator/val_utils.h 5 Sep 2024 08:22:48 -0000 1.4 +++ sbin/unwind/libunbound/validator/val_utils.h 21 Sep 2026 16:28:02 -0000 @@ -55,6 +55,11 @@ struct regional; struct val_anchors; struct rrset_cache; struct sock_list; +struct val_qstate; + +/** Maximum number of matches with key tag and algorithm, for DNSKEY to + * RRSIG and DS to DNSKEY. Since the number is O(N*N), there is a limit. */ +#define MAX_TAG_MATCHES 256 /** * Response classifications for the validator. The different types of proofs. @@ -124,6 +129,7 @@ void val_find_signer(enum val_classifica * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param verified: if not NULL, the number of RRSIG validations is returned. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. @@ -133,7 +139,8 @@ enum sec_status val_verify_rrset_entry(s struct val_env* ve, struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* verified, char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen); /** * Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but @@ -148,6 +155,7 @@ enum sec_status val_verify_rrset_entry(s * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return: sec_status_secure if a DS matches. @@ -158,7 +166,7 @@ enum sec_status val_verify_DNSKEY_with_D struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS @@ -172,8 +180,9 @@ enum sec_status val_verify_DNSKEY_with_D * algorithm is enough. The list of signalled algorithms is returned, * must have enough space for ALGO_NEEDS_MAX+1. * @param reason: reason of failure. Fixed string or alloced in scratch. -* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. + * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return: sec_status_secure if a DS matches. @@ -185,7 +194,7 @@ enum sec_status val_verify_DNSKEY_with_T struct ub_packed_rrset_key* ta_ds, struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Verify new DNSKEYs with DS rrset. The DS contains hash values that should @@ -202,6 +211,7 @@ enum sec_status val_verify_DNSKEY_with_T * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return a KeyEntry. This will either contain the now trusted @@ -219,7 +229,7 @@ struct key_entry_key* val_verify_new_DNS struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Verify rrset with trust anchor: DS and DNSKEY rrset. @@ -235,6 +245,7 @@ struct key_entry_key* val_verify_new_DNS * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return a KeyEntry. This will either contain the now trusted @@ -253,7 +264,7 @@ struct key_entry_key* val_verify_new_DNS struct ub_packed_rrset_key* ta_ds_rrset, struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Determine if DS rrset is usable for validator or not. @@ -315,6 +326,16 @@ void val_fill_reply(struct reply_info* c size_t cname_skip, uint8_t* name, size_t len, uint8_t* signer); /** + * Remove rrsets with index .. index+count from reply, from the answer section. + * @param rep: reply to remove it from. + * @param index: rrset to remove, must be in the answer section. + * @param count: number of rrsets to remove, starting from the index. + * with count=1, it removes only the index rrset. + */ +void val_reply_remove_answers(struct reply_info* rep, size_t index, + size_t count); + +/** * Remove rrset with index from reply, from the authority section. * @param rep: reply to remove it from. * @param index: rrset to remove, must be in the authority section. @@ -426,5 +447,23 @@ int val_favorite_ds_algo(struct ub_packe */ struct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t c, struct regional* region, uint8_t* topname); + +/** + * Derive expected CNAME target from DNAME substitution per RFC 6672 s3.1 + * @param cname: CNAME RRset, (e.g., b.d.a005.test CNAME 'some cname target') + * @param dname: DNAME RRset, (e.g., d.a005.test DNAME tgt.a005.test) + * @param out: Output buffer for expected CNAME target + * @param outlen: Output buffer size + * @return: 1 on success, 0 on error + */ +int derive_cname_from_dname(struct ub_packed_rrset_key* cname, + struct ub_packed_rrset_key* dname, uint8_t* out, size_t outlen); + +/** Get signer name from RRSIG, sname is NULL if malformed. */ +void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, + size_t* slen); + +/** See if the NSEC nextowner name is a subdomain of the name. */ +int nsec_nextowner_subdomain(struct ub_packed_rrset_key* rrset, uint8_t* name); #endif /* VALIDATOR_VAL_UTILS_H */ Index: sbin/unwind/libunbound/validator/validator.c =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/validator.c,v diff -u -p -r1.17 validator.c --- sbin/unwind/libunbound/validator/validator.c 29 Sep 2025 14:53:38 -0000 1.17 +++ sbin/unwind/libunbound/validator/validator.c 21 Sep 2026 16:28:02 -0000 @@ -68,6 +68,9 @@ #define MAX_VALIDATE_AT_ONCE 8 /** Max number of validation suspends allowed, error out otherwise. */ #define MAX_VALIDATION_SUSPENDS 16 +/** Max answer RRsets for qtype ANY that are validated. The lists is + * shortened to fit this limit. */ +#define MAX_RRSETS_ANY_VALIDATED 24 /* forward decl for cache response and normal super inform calls of a DS */ static void process_ds_response(struct module_qstate* qstate, @@ -347,13 +350,17 @@ static void val_restart(struct val_qstate* vq) { struct comm_timer* temp_timer; - int restart_count; + int restart_count, num_validation_attempts, num_hash_attempts; if(!vq) return; temp_timer = vq->suspend_timer; restart_count = vq->restart_count+1; + num_validation_attempts = vq->num_validation_attempts; + num_hash_attempts = vq->num_hash_attempts; memset(vq, 0, sizeof(*vq)); vq->suspend_timer = temp_timer; vq->restart_count = restart_count; + vq->num_validation_attempts = num_validation_attempts; + vq->num_hash_attempts = num_hash_attempts; vq->state = VAL_INIT_STATE; } @@ -452,6 +459,24 @@ already_validated(struct dns_msg* ret_ms return 0; } +/** If it is possible to restart the validation state */ +static int +val_can_restart(struct module_qstate* qstate, struct val_qstate* vq, + struct val_env* ve) +{ + /* For validation failures that are limits exceeded on the amount + * of work that the DNSSEC validator is willing to do, the restart + * is not allowed. A restart would increase the amount of effort + * spent even further. */ + if(vq->restart_count < ve->max_restart && + vq->num_validation_attempts <= qstate->env->cfg->val_validation_attempts && + vq->num_hash_attempts <= qstate->env->cfg->val_hash_attempts && + !vq->num_nsec_attempts_exceeded) + return 1; + (void)qstate; + return 0; +} + /** * Generate a request for DNS data. * @@ -496,7 +521,7 @@ generate_request(struct module_qstate* q struct mesh_state* sub = NULL; fptr_ok(fptr_whitelist_modenv_add_sub( qstate->env->add_sub)); - if(!(*qstate->env->add_sub)(qstate, &ask, + if(!(*qstate->env->add_sub)(qstate, &ask, NULL, (uint16_t)(BIT_RD|flags), 0, valrec, newq, &sub)){ log_err("Could not generate request: out of memory"); return 0; @@ -505,7 +530,7 @@ generate_request(struct module_qstate* q else { fptr_ok(fptr_whitelist_modenv_attach_sub( qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &ask, + if(!(*qstate->env->attach_sub)(qstate, &ask, NULL, (uint16_t)(BIT_RD|flags), 0, valrec, newq)){ log_err("Could not generate request: out of memory"); return 0; @@ -517,6 +542,14 @@ generate_request(struct module_qstate* q /* add our blacklist to the query blacklist */ sock_list_merge(&(*newq)->blacklist, (*newq)->region, vq->chain_blacklist); + /* start its global quota counter where this one is. */ + if(qstate->global_quota_reached > + (*newq)->global_quota_reached) { + (*newq)->global_quota_started = + qstate->global_quota_reached; + (*newq)->global_quota_reached = + qstate->global_quota_reached; + } } qstate->ext_state[id] = module_wait_subquery; return 1; @@ -710,6 +743,37 @@ validate_msg_signatures(struct module_qs ((struct packed_rrset_data*)chase_reply->rrsets[i-1]->entry.data)->security == sec_status_secure && dname_strict_subdomain_c(s->rk.dname, chase_reply->rrsets[i-1]->rk.dname) ) { + /* Check that the CNAME target matches the DNAME + * derivation. Zone changes during the redirection + * lookups or looped DNAMEs can have such a CNAME. */ + uint8_t expected_target[LDNS_MAX_DOMAINLEN]; + uint8_t* cname_target = NULL; + size_t cname_target_len = 0; + get_cname_target(s, &cname_target, &cname_target_len); + if(!cname_target || + !derive_cname_from_dname(s, /* CNAME RRset */ + chase_reply->rrsets[i-1], /* DNAME RRset */ + expected_target, /* Output buffer */ + sizeof(expected_target))) { + verbose(VERB_ALGO, "DNAME CNAME derivation failed"); + errinf_ede(qstate, "DNAME CNAME derivation failed", reason_bogus); + errinf_origin(qstate, qstate->reply_origin); + chase_reply->security = sec_status_bogus; + update_reason_bogus(chase_reply, reason_bogus); + return 0; + } + if(query_dname_compare(cname_target, expected_target) != 0) { + verbose(VERB_ALGO, "CNAME target mismatch: not synthesized from DNAME"); + errinf_ede(qstate, "CNAME target mismatch: not synthesized from DNAME", reason_bogus); + errinf_dname(qstate, ", for", s->rk.dname); + errinf_dname(qstate, "CNAME", cname_target); + errinf(qstate, ","); + errinf_origin(qstate, qstate->reply_origin); + chase_reply->security = sec_status_bogus; + update_reason_bogus(chase_reply, reason_bogus); + return 0; + } + /* CNAME was synthesized by our own iterator */ /* since the DNAME verified, mark the CNAME as secure */ ((struct packed_rrset_data*)s->entry.data)->security = @@ -721,8 +785,8 @@ validate_msg_signatures(struct module_qs /* Verify the answer rrset */ sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, - &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified, - reasonbuf, sizeof(reasonbuf)); + &reason_bogus, LDNS_SECTION_ANSWER, qstate, vq, + &verified, reasonbuf, sizeof(reasonbuf)); /* If the (answer) rrset failed to validate, then this * message is BAD. */ if(sec != sec_status_secure) { @@ -766,7 +830,7 @@ validate_msg_signatures(struct module_qs continue; s = chase_reply->rrsets[i]; sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, - &reason_bogus, LDNS_SECTION_AUTHORITY, qstate, + &reason_bogus, LDNS_SECTION_AUTHORITY, qstate, vq, &verified, reasonbuf, sizeof(reasonbuf)); /* If anything in the authority section fails to be secure, * we have a bad message. */ @@ -813,7 +877,7 @@ validate_msg_signatures(struct module_qs if(sname && query_dname_compare(sname, key_entry->name)==0) (void)val_verify_rrset_entry(env, ve, s, key_entry, &reason, NULL, LDNS_SECTION_ADDITIONAL, qstate, - &verified, reasonbuf, sizeof(reasonbuf)); + vq, &verified, reasonbuf, sizeof(reasonbuf)); /* the additional section can fail to be secure, * it is optional, check signature in case we need * to clean the additional section later. */ @@ -882,10 +946,10 @@ validate_suspend_setup_timer(struct modu 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; + /* One step of back-off after the first suspend so a single bad + * message still yields, but does not grow exponentially on its own. */ + if(vq->suspend_count > 0) + slack += 1; if(slack != 0 && slack <= 12 /* No numeric overflow. */) { usec = usec << slack; } @@ -986,6 +1050,29 @@ remove_spurious_authority(struct reply_i } /** + * Cap the number of answer RRsets for validation of type ANY. + * This limits the number of RRSIG validations performed. + * It is allowed to return a subset of available RRsets when processing + * ANY query. + * @param chase_reply: the chased reply, shorten if if too long. + * @param orig_reply: original reply, remove the records here as well, + * so it can be marked as DNSSEC valid. + * @param skip: the number of rrsets skipped in the answer section due to + * CNAME chain that is followed. + * @param max_rrsets: the number allowed. + */ +static void +shorten_answer_any(struct reply_info* chase_reply, + struct reply_info* orig_reply, size_t skip, size_t max_rrsets) +{ + if(chase_reply->an_numrrsets > max_rrsets) { + size_t to_rem = chase_reply->an_numrrsets - max_rrsets; + val_reply_remove_answers(chase_reply, max_rrsets, to_rem); + val_reply_remove_answers(orig_reply, skip+max_rrsets, to_rem); + } +} + +/** * Given a "positive" response -- a response that contains an answer to the * question, and no CNAME chain, validate this response. * @@ -1012,7 +1099,14 @@ validate_positive_response(struct module uint8_t* wc = NULL; size_t wl; int wc_cached = 0; + int wc_to_cache = 0; + uint8_t* cache_wc = NULL; + size_t cache_wl = 0; + struct ub_packed_rrset_key* cache_s = NULL; int wc_NSEC_ok = 0; + /* This is used to update the RRset cache, with the combination + * of the dname expansion and this wildcard, for security status. */ + struct ub_packed_rrset_key* wc_rrset = NULL; int nsec3s_seen = 0; size_t i; struct ub_packed_rrset_key* s; @@ -1031,14 +1125,20 @@ validate_positive_response(struct module ntohs(s->rk.type), ntohs(s->rk.rrset_class)); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } if(wc && !wc_cached && env->cfg->aggressive_nsec) { - rrset_cache_update_wildcard(env->rrset_cache, s, wc, wl, - env->alloc, *env->now); + /* Postpone cache adjust until proof has succeeded. */ + wc_to_cache = 1; + cache_wc = wc; + cache_wl = wl; + cache_s = s; wc_cached = 1; } - + if(wc) wc_rrset = s; } /* validate the AUTHORITY section as well - this will generally be @@ -1095,8 +1195,15 @@ validate_positive_response(struct module "did not exist"); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } + if(wc_to_cache) { + rrset_cache_update_wildcard(env->rrset_cache, cache_s, + cache_wc, cache_wl, env->alloc, *env->now); + } verbose(VERB_ALGO, "Successfully validated positive response"); chase_reply->security = sec_status_secure; @@ -1348,16 +1455,20 @@ validate_nameerror_response(struct modul * trusted DNSKEY rrset that signs this response must already have been * completed. * + * @param env: module env. * @param chase_reply: answer to validate. */ static void -validate_referral_response(struct reply_info* chase_reply) +validate_referral_response(struct module_env* env, struct reply_info* chase_reply) { - size_t i; + size_t i, count; enum sec_status s; /* message security equals lowest rrset security */ chase_reply->security = sec_status_secure; - for(i=0; irrset_count; i++) { + if(env->cfg->val_clean_additional) + count = chase_reply->rrset_count; + else count = chase_reply->an_numrrsets+chase_reply->ns_numrrsets; + for(i=0; irrsets[i] ->entry.data)->security; if(s < chase_reply->security) @@ -1496,6 +1607,16 @@ validate_any_response(struct module_env* "did not exist"); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + /* Make the expanded name and wildcard RRSIG rrsets bogus */ + for(i=0; ian_numrrsets; i++) { + uint8_t* cwc = NULL; + size_t cwl = 0; + s = chase_reply->rrsets[i]; + if(val_rrset_wildcard(s, &cwc, &cwl) && cwc) { + ((struct packed_rrset_data*)s-> + entry.data)->security = sec_status_bogus; + } + } return; } @@ -1533,6 +1654,9 @@ validate_cname_response(struct module_en uint8_t* wc = NULL; size_t wl; int wc_NSEC_ok = 0; + /* This is used to update the RRset cache, with the combination + * of the dname expansion and this wildcard, for security status. */ + struct ub_packed_rrset_key* wc_rrset = NULL; int nsec3s_seen = 0; size_t i; struct ub_packed_rrset_key* s; @@ -1553,6 +1677,7 @@ validate_cname_response(struct module_en update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); return; } + if(wc) wc_rrset = s; /* Refuse wildcarded DNAMEs rfc 4597. * Do not follow a wildcarded DNAME because @@ -1564,6 +1689,9 @@ validate_cname_response(struct module_en ntohs(s->rk.type), ntohs(s->rk.rrset_class)); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } @@ -1628,6 +1756,9 @@ validate_cname_response(struct module_en "did not exist"); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } @@ -2204,7 +2335,7 @@ processValidate(struct module_qstate* qs key_entry_get_reason_bogus(vq->key_entry)); errinf_ede(qstate, "while building chain of trust", key_entry_get_reason_bogus(vq->key_entry)); - if(vq->restart_count >= ve->max_restart) + if(!val_can_restart(qstate, vq, ve)) key_cache_insert(ve->kcache, vq->key_entry, qstate->env->cfg->val_log_level >= 2); return 1; @@ -2227,6 +2358,9 @@ processValidate(struct module_qstate* qs &vq->qchase, vq->orig_msg->rep, vq->rrset_skip); if(subtype != VAL_CLASS_REFERRAL) remove_spurious_authority(vq->chase_reply, vq->orig_msg->rep); + if(subtype == VAL_CLASS_ANY) + shorten_answer_any(vq->chase_reply, vq->orig_msg->rep, + vq->rrset_skip, MAX_RRSETS_ANY_VALIDATED); /* check signatures in the message; * answer and authority must be valid, additional is only checked. */ @@ -2349,7 +2483,7 @@ processValidate(struct module_qstate* qs case VAL_CLASS_REFERRAL: verbose(VERB_ALGO, "Validating a referral response"); - validate_referral_response(vq->chase_reply); + validate_referral_response(qstate->env, vq->chase_reply); verbose(VERB_DETAIL, "validate(referral): %s", sec_status_to_string( vq->chase_reply->security)); @@ -2423,15 +2557,17 @@ processFinished(struct module_qstate* qs } if(subtype == VAL_CLASS_REFERRAL) { - /* for a referral, move to next unchecked rrset and check it*/ - vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep, - vq->rrset_skip); - if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) { - /* and restart for this rrset */ - verbose(VERB_ALGO, "validator: go to next rrset"); - vq->chase_reply->security = sec_status_unchecked; - vq->state = VAL_INIT_STATE; - return 1; + if(qstate->env->cfg->val_clean_additional) { + /* for a referral, move to next unchecked rrset and check it*/ + vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep, + vq->rrset_skip); + if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) { + /* and restart for this rrset */ + verbose(VERB_ALGO, "validator: go to next rrset"); + vq->chase_reply->security = sec_status_unchecked; + vq->state = VAL_INIT_STATE; + return 1; + } } /* referral chase is done */ } @@ -2476,7 +2612,7 @@ processFinished(struct module_qstate* qs struct msgreply_entry* e; /* see if we can try again to fetch data */ - if(vq->restart_count < ve->max_restart) { + if(val_can_restart(qstate, vq, ve)) { verbose(VERB_ALGO, "validation failed, " "blacklist and retry to fetch data"); val_blacklist(&qstate->blacklist, qstate->region, @@ -2699,7 +2835,9 @@ val_operate(struct module_qstate* qstate if(!needs_validation(qstate, qstate->return_rcode, qstate->return_msg)) { /* no need to validate this */ - if(qstate->return_msg) + /* For valrec responses, leave at sec_status_unchecked, + * no security status has been requested for it. */ + if(qstate->return_msg && !qstate->is_valrec) qstate->return_msg->rep->security = sec_status_indeterminate; qstate->ext_state[id] = module_finished; @@ -2766,6 +2904,7 @@ val_operate(struct module_qstate* qstate * (this rrset is allocated in the wrong region, not the qstate). * @param ta: trust anchor. * @param qstate: qstate that needs key. + * @param vq: validator qstate. * @param id: module id. * @param sub_qstate: the sub query state, that is the lookup that fetched * the trust anchor data, it contains error information for the answer. @@ -2776,8 +2915,8 @@ val_operate(struct module_qstate* qstate */ static struct key_entry_key* primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, - struct trust_anchor* ta, struct module_qstate* qstate, int id, - struct module_qstate* sub_qstate) + struct trust_anchor* ta, struct module_qstate* qstate, + struct val_qstate* vq, int id, struct module_qstate* sub_qstate) { struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; struct key_entry_key* kkey = NULL; @@ -2817,7 +2956,8 @@ primeResponseToKE(struct ub_packed_rrset /* attempt to verify with trust anchor DS and DNSKEY */ kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve, dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot, - &reason, &reason_bogus, qstate, reasonbuf, sizeof(reasonbuf)); + &reason, &reason_bogus, qstate, vq, reasonbuf, + sizeof(reasonbuf)); if(!kkey) { log_err("out of memory: verifying prime TA"); return NULL; @@ -2930,7 +3070,7 @@ ds_response_to_ke(struct module_qstate* * bogus, then we are done. */ sec = val_verify_rrset_entry(qstate->env, ve, ds, vq->key_entry, &reason, &reason_bogus, - LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf, + LDNS_SECTION_ANSWER, qstate, vq, &verified, reasonbuf, sizeof(reasonbuf)); if(sec != sec_status_secure) { verbose(VERB_DETAIL, "DS rrset in DS response did " @@ -2981,7 +3121,7 @@ ds_response_to_ke(struct module_qstate* /* Try to prove absence of the DS with NSEC */ sec = val_nsec_prove_nodata_dsreply( qstate->env, ve, qinfo, msg->rep, vq->key_entry, - &proof_ttl, &reason, &reason_bogus, qstate, + &proof_ttl, &reason, &reason_bogus, qstate, vq, reasonbuf, sizeof(reasonbuf)); switch(sec) { case sec_status_secure: @@ -3019,7 +3159,7 @@ ds_response_to_ke(struct module_qstate* sec = nsec3_prove_nods(qstate->env, ve, msg->rep->rrsets + msg->rep->an_numrrsets, msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason, - &reason_bogus, qstate, &vq->nsec3_cache_table, + &reason_bogus, qstate, vq, &vq->nsec3_cache_table, reasonbuf, sizeof(reasonbuf)); switch(sec) { case sec_status_insecure: @@ -3087,9 +3227,65 @@ ds_response_to_ke(struct module_qstate* } sec = val_verify_rrset_entry(qstate->env, ve, cname, vq->key_entry, &reason, &reason_bogus, - LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf, + LDNS_SECTION_ANSWER, qstate, vq, &verified, reasonbuf, sizeof(reasonbuf)); if(sec == sec_status_secure) { + /* Check for wildcard expansion */ + uint8_t* wc = NULL; + size_t wl = 0; + + if(!val_rrset_wildcard(cname, &wc, &wl)) { + verbose(VERB_ALGO, "CNAME has inconsistent wildcard signatures"); + reason = "wildcard CNAME inconsistent signatures"; + errinf_ede(qstate, reason, reason_bogus); + goto return_bogus; + } + + if(wc != NULL) { + /* Wildcard expansion detected - require NSEC proof */ + /* So this is a wildcard CNAME response to DS. + * If the wildcard is bogus then we have bogus. + * If the wildcard is true, then there is + * not a referral point here or lower, + * that can be insecure, + * and also no DS records, here or lower. */ + /* For a valid chain, to DS, but this + * wildcard CNAME happens in a middle label, + * then that can not happen, because there is + * data under that label, and thus the wildcard + * should not expand. + * If we are going to the wildcard, that also + * does not expand the wildcard, when above it. + * So for valids lookup chains to DS, no + * wildcard CNAME is expected on middle labels. + * For lookups to an insecure point, the + * delegation is information under the label, + * and thus the wildcard does not expand. + * So, no insecure point is possible. + * Can not get a valid chain of trust, or + * to a delegation point for insecure. + * Or the wildcard, its nxdomain for the qname + * proof, is invalid, in which case this is + * a bogus reply. + * If this was a lookup where a wildcard + * expansion is genuinely expected, eg, + * a dnssec valid wildcard query, then the + * lookup should go to the right point, and + * not into the wildcard under the zone name. + * For insecure, or wildcard missing + * signatures, it would have to have found + * the DS or insecure point earlier, in the + * downwards search. + * So for missing signatures, it turns the + * missing signatures into a failure to the + * wildcard CNAME, as the reported log. + */ + verbose(VERB_ALGO, "wildcard CNAME in chain of trust means no DS can be found and it is also not a delegation point that can be insecure"); + reason = "wildcard CNAME in chain of trust means no DS found and it is also not a delegation point that can be insecure"; + errinf_ede(qstate, reason, reason_bogus); + goto return_bogus; + } + verbose(VERB_ALGO, "CNAME validated, " "proof that DS does not exist"); /* and that it is not a referral point */ @@ -3152,6 +3348,7 @@ process_ds_response(struct module_qstate uint8_t* olds = vq->empty_DS_name; int ret; *suspend = 0; + vq->num_nsec_attempts = 0; vq->empty_DS_name = NULL; if(sub_qstate && sub_qstate->rpz_applied) { verbose(VERB_ALGO, "rpz was applied to the DS lookup, " @@ -3163,6 +3360,8 @@ process_ds_response(struct module_qstate } ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske, sub_qstate); + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; if(ret != 0) { switch(ret) { case 1: @@ -3204,7 +3403,7 @@ process_ds_response(struct module_qstate vq->chain_blacklist = NULL; /* fresh blacklist for next part*/ /* Keep the forState.state on FINDKEY. */ } else if(key_entry_isbad(dske) - && vq->restart_count < ve->max_restart) { + && val_can_restart(qstate, vq, ve)) { vq->empty_DS_name = olds; val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3254,6 +3453,7 @@ process_dnskey_response(struct module_qs char* reason = NULL; sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + vq->num_nsec_attempts = 0; if(sub_qstate && sub_qstate->rpz_applied) { verbose(VERB_ALGO, "rpz was applied to the DNSKEY lookup, " "make it insecure"); @@ -3273,7 +3473,7 @@ process_dnskey_response(struct module_qs verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to " "DNSKEY query."); - if(vq->restart_count < ve->max_restart) { + if(val_can_restart(qstate, vq, ve)) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3310,7 +3510,9 @@ process_dnskey_response(struct module_qs downprot = qstate->env->cfg->harden_algo_downgrade; vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env, ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, - qstate, reasonbuf, sizeof(reasonbuf)); + qstate, vq, reasonbuf, sizeof(reasonbuf)); + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; if(!vq->key_entry) { log_err("out of memory in verify new DNSKEYs"); @@ -3321,7 +3523,7 @@ process_dnskey_response(struct module_qs * state. */ if(!key_entry_isgood(vq->key_entry)) { if(key_entry_isbad(vq->key_entry)) { - if(vq->restart_count < ve->max_restart) { + if(val_can_restart(qstate, vq, ve)) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3373,6 +3575,7 @@ process_prime_response(struct module_qst struct trust_anchor* ta = anchor_find(qstate->env->anchors, vq->trust_anchor_name, vq->trust_anchor_labs, vq->trust_anchor_len, vq->qchase.qclass); + vq->num_nsec_attempts = 0; if(!ta) { /* trust anchor revoked, restart with less anchors */ vq->state = VAL_INIT_STATE; @@ -3391,19 +3594,23 @@ process_prime_response(struct module_qst if(ta->autr) { if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset, - qstate)) { + qstate, vq)) { + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; /* trust anchor revoked, restart with less anchors */ vq->state = VAL_INIT_STATE; vq->trust_anchor_name = NULL; return; } } - vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id, + vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, vq, id, sub_qstate); lock_basic_unlock(&ta->lock); + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; if(vq->key_entry) { if(key_entry_isbad(vq->key_entry) - && vq->restart_count < ve->max_restart) { + && val_can_restart(qstate, vq, ve)) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3446,6 +3653,11 @@ val_inform_super(struct module_qstate* q if(!vq) { verbose(VERB_ALGO, "super: has no validator state"); return; + } + /* Pick up the global quota limit from the subquery. */ + if(qstate->global_quota_reached > qstate->global_quota_started) { + super->global_quota_reached += qstate->global_quota_reached - + qstate->global_quota_started; } if(vq->wait_prime_ta) { vq->wait_prime_ta = 0; Index: sbin/unwind/libunbound/validator/validator.h =================================================================== RCS file: /cvs/src/sbin/unwind/libunbound/validator/validator.h,v diff -u -p -r1.8 validator.h --- sbin/unwind/libunbound/validator/validator.h 14 Sep 2025 15:16:53 -0000 1.8 +++ sbin/unwind/libunbound/validator/validator.h 21 Sep 2026 16:28:02 -0000 @@ -231,6 +231,19 @@ struct val_qstate { struct comm_timer* suspend_timer; /** Number of suspends */ int suspend_count; + + /** Number of DNSKEY RRSIG validation attempts. This is the number of + * cryptographic operations done for the mesh state. */ + int num_validation_attempts; + /** Number of DS hash verification attempts. This is the number of + * hash operations done for the mesh state. + * It does not count NSEC3 hashes. */ + int num_hash_attempts; + /** Number of NSEC validations. And NSEC3 too. This is reset per + * answer. */ + int num_nsec_attempts; + /** The nsec attempts have been exceeded. */ + int num_nsec_attempts_exceeded; }; /** Index: usr.sbin/unbound/README.md =================================================================== RCS file: /cvs/src/usr.sbin/unbound/README.md,v diff -u -p -r1.9 README.md --- usr.sbin/unbound/README.md 12 Apr 2024 15:45:24 -0000 1.9 +++ usr.sbin/unbound/README.md 21 Sep 2026 16:28:02 -0000 @@ -4,13 +4,13 @@ [![Packaging status](https://repology.org/badge/tiny-repos/unbound.svg)](https://repology.org/project/unbound/versions) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/unbound.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:unbound) [![Documentation Status](https://readthedocs.org/projects/unbound/badge/?version=latest)](https://unbound.readthedocs.io/en/latest/?badge=latest) -[![Mastodon Follow](https://img.shields.io/mastodon/follow/109262826617293067?domain=https%3A%2F%2Ffosstodon.org&style=social)](https://fosstodon.org/@nlnetlabs) +[![Mastodon Follow](https://img.shields.io/mastodon/follow/114692612288811644?domain=social.nlnetlabs.nl&style=social)](https://social.nlnetlabs.nl/@nlnetlabs) Unbound is a validating, recursive, caching DNS resolver. It is designed to be fast and lean and incorporates modern features based on open standards. If you have any feedback, we would love to hear from you. Don’t hesitate to [create an issue on Github](https://github.com/NLnetLabs/unbound/issues/new) -or post a message on the [Unbound mailing list](https://lists.nlnetlabs.nl/mailman/listinfo/unbound-users). +or post a message on our [community forum](https://community.nlnetlabs.nl/). You can learn more about Unbound by reading our [documentation](https://unbound.docs.nlnetlabs.nl/). @@ -25,18 +25,21 @@ Unbound can be compiled and installed us ./configure && make && make install ``` -You can use libevent if you want. libevent is useful when using many (10000) -outgoing ports. By default max 256 ports are opened at the same time and the -builtin alternative is equally capable and a little faster. - +You can use libevent if you want. libevent is useful when using many (e.g., +10000) outgoing ports. Use the `--with-libevent` configure option to compile Unbound with libevent support. +If not, the default builtin alternative opens max 256 ports at the same time +and is equally capable and a little faster. + + ## Unbound configuration -All of Unbound's configuration options are described in the man pages, which -will be installed and are available on the Unbound -[documentation page](https://unbound.docs.nlnetlabs.nl/). +All of Unbound's configuration options are described in the `unbound.conf(5)` +man page, which will be installed and is also available on the Unbound +[documentation page](https://unbound.docs.nlnetlabs.nl/en/latest/manpages/unbound.conf.html) +for the latest version. -An example configuration file is located in +An example configuration file, with minimal documentation, is located in [doc/example.conf](https://github.com/NLnetLabs/unbound/blob/master/doc/example.conf.in). Index: usr.sbin/unbound/aclocal.m4 =================================================================== RCS file: /cvs/src/usr.sbin/unbound/aclocal.m4,v diff -u -p -r1.12 aclocal.m4 --- usr.sbin/unbound/aclocal.m4 23 Oct 2025 12:50:29 -0000 1.12 +++ usr.sbin/unbound/aclocal.m4 21 Sep 2026 16:28:02 -0000 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.17 -*- Autoconf -*- +# generated automatically by aclocal 1.18.1 -*- Autoconf -*- -# Copyright (C) 1996-2024 Free Software Foundation, Inc. +# Copyright (C) 1996-2025 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -9551,7 +9551,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2024 Free Software Foundation, Inc. +# Copyright (C) 1997-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -9582,7 +9582,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 2006-2024 Free Software Foundation, Inc. +# Copyright (C) 2006-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, Index: usr.sbin/unbound/acx_nlnetlabs.m4 =================================================================== RCS file: /cvs/src/usr.sbin/unbound/acx_nlnetlabs.m4,v diff -u -p -r1.13 acx_nlnetlabs.m4 --- usr.sbin/unbound/acx_nlnetlabs.m4 13 Apr 2024 12:24:57 -0000 1.13 +++ usr.sbin/unbound/acx_nlnetlabs.m4 21 Sep 2026 16:28:02 -0000 @@ -2,7 +2,12 @@ # Copyright 2009, Wouter Wijngaards, NLnet Labs. # BSD licensed. # -# Version 48 +# Version 51 +# 2025-11-06 Fix ACX_CHECK_NONSTRING_ATTRIBUTE to reject clang, that prints +# a warning for 'unknown attribute' when nonstring is used. +# 2025-09-29 add ac_cv_func_malloc_0_nonnull as a cache value for the malloc(0) +# check by ACX_FUNC_MALLOC. +# 2025-09-29 add ACX_CHECK_NONSTRING_ATTRIBUTE, AHX_CONFIG_NONSTRING_ATTRIBUTE. # 2024-01-16 fix to add -l:libssp.a to -lcrypto link check. # and check for getaddrinfo with only header. # 2024-01-15 fix to add crypt32 to -lcrypto link check when checking for gdi32. @@ -71,6 +76,7 @@ # ACX_DEPFLAG - find cc dependency flags. # ACX_DETERMINE_EXT_FLAGS_UNBOUND - find out which flags enable BSD and POSIX. # ACX_CHECK_FORMAT_ATTRIBUTE - find cc printf format syntax. +# ACX_CHECK_NONSTRING_ATTRIBUTE - find cc nonstring attribute syntax. # ACX_CHECK_UNUSED_ATTRIBUTE - find cc variable unused syntax. # ACX_CHECK_FLTO - see if cc supports -flto and use it if so. # ACX_LIBTOOL_C_ONLY - create libtool for C only, improved. @@ -92,6 +98,7 @@ # ACX_FUNC_IOCTLSOCKET - find ioctlsocket, portably. # ACX_FUNC_MALLOC - check malloc, define replacement . # AHX_CONFIG_FORMAT_ATTRIBUTE - config.h text for format. +# AHX_CONFIG_NONSTRING_ATTRIBUTE - config.h text for nonstring. # AHX_CONFIG_UNUSED_ATTRIBUTE - config.h text for unused. # AHX_CONFIG_FSEEKO - define fseeko, ftello fallback. # AHX_CONFIG_RAND_MAX - define RAND_MAX if needed. @@ -490,7 +497,7 @@ AC_DEFUN([AHX_CONFIG_FORMAT_ATTRIBUTE], ]) dnl Check how to mark function arguments as unused. -dnl result in HAVE_ATTR_UNUSED. +dnl result in HAVE_ATTR_UNUSED. dnl Make sure you include AHX_CONFIG_UNUSED_ATTRIBUTE also. AC_DEFUN([ACX_CHECK_UNUSED_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) @@ -525,6 +532,49 @@ if test $ac_cv_c_unused_attribute = yes; fi ])dnl +dnl Check how to mark function arguments as nonstring. +dnl result in HAVE_ATTR_NONSTRING. +dnl Make sure you include AHX_CONFIG_NONSTRING_ATTRIBUTE also. +AC_DEFUN([ACX_CHECK_NONSTRING_ATTRIBUTE], +[AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([ACX_CHECK_ERROR_FLAGS]) +BAKCFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $ERRFLAG" +AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "nonstring" attribute) +AC_CACHE_VAL(ac_cv_c_nonstring_attribute, +[ac_cv_c_nonstring_attribute=no +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +struct test { + char __attribute__((nonstring)) s[1]; +}; +]], [[ + struct test t = { "1" }; + (void) t; +]])],[ac_cv_c_nonstring_attribute="yes"],[ac_cv_c_nonstring_attribute="no"]) +CFLAGS="$BAKCFLAGS" +]) + +dnl Setup ATTR_NONSTRING config.h parts. +dnl make sure you call ACX_CHECK_NONSTRING_ATTRIBUTE also. +AC_DEFUN([AHX_CONFIG_NONSTRING_ATTRIBUTE], +[ +#if defined(DOXYGEN) +# define ATTR_NONSTRING(x) x +#elif defined(__cplusplus) +# define ATTR_NONSTRING(x) __attribute__((nonstring)) x +#elif defined(HAVE_ATTR_NONSTRING) +# define ATTR_NONSTRING(x) __attribute__((nonstring)) x +#else /* !HAVE_ATTR_NONSTRING */ +# define ATTR_NONSTRING(x) x +#endif /* !HAVE_ATTR_NONSTRING */ +]) + +AC_MSG_RESULT($ac_cv_c_nonstring_attribute) +if test $ac_cv_c_nonstring_attribute = yes; then + AC_DEFINE(HAVE_ATTR_NONSTRING, 1, [Whether the C compiler accepts the "nonstring" attribute]) +fi +])dnl + dnl Pre-fun for ACX_LIBTOOL_C_ONLY AC_DEFUN([ACX_LIBTOOL_C_PRE], [ # skip these tests, we do not need them. @@ -1190,8 +1240,9 @@ dnl detect malloc and provide malloc com dnl $1: unique name for compat code AC_DEFUN([ACX_FUNC_MALLOC], [ - AC_MSG_CHECKING([for GNU libc compatible malloc]) - AC_RUN_IFELSE([AC_LANG_PROGRAM( + AC_CACHE_CHECK([for GNU libc compatible malloc],[ac_cv_func_malloc_0_nonnull], + [ + AC_RUN_IFELSE([AC_LANG_PROGRAM( [[#if defined STDC_HEADERS || defined HAVE_STDLIB_H #include #else @@ -1199,14 +1250,16 @@ char *malloc (); #endif ]], [ if(malloc(0) != 0) return 1;]) ], - [AC_MSG_RESULT([no]) - AC_LIBOBJ(malloc) - AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] , - [AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_MALLOC], 1, [If have GNU libc compatible malloc])], - [AC_MSG_RESULT([no (crosscompile)]) - AC_LIBOBJ(malloc) - AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] ) + [ac_cv_func_malloc_0_nonnull=no], + [ac_cv_func_malloc_0_nonnull=yes], + [ac_cv_func_malloc_0_nonnull="no (crosscompile)"]) + ]) + AS_IF([test "$ac_cv_func_malloc_0_nonnull" = yes], + [AC_DEFINE([HAVE_MALLOC], 1, [If have GNU libc compatible malloc])], + [ + AC_LIBOBJ(malloc) + AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.]) + ]) ]) dnl Define fallback for fseeko and ftello if needed. Index: usr.sbin/unbound/ax_pthread.m4 =================================================================== RCS file: /cvs/src/usr.sbin/unbound/ax_pthread.m4,v diff -u -p -r1.3 ax_pthread.m4 --- usr.sbin/unbound/ax_pthread.m4 13 Jun 2024 14:30:28 -0000 1.3 +++ usr.sbin/unbound/ax_pthread.m4 21 Sep 2026 16:28:02 -0000 @@ -87,7 +87,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 31 +#serial 32 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ @@ -249,7 +249,22 @@ AS_IF([test "x$ax_pthread_clang" = "xyes # correctly enabled case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) + solaris*) + # Solaris 11.4 introduced XPG7 support and did away with the need for + # _REENTRANT. + + AC_EGREP_CPP([AX_PTHREAD_SOLARIS__REENTRANT], + [ +# undef _XOPEN_SOURCE +# include +# if _XOPEN_VERSION < 700 + AX_PTHREAD_SOLARIS__REENTRANT +# endif + ], + [ax_pthread_check_macro="_REENTRANT"], + [ax_pthread_check_macro="--"]) + ;; + darwin* | hpux* | linux* | osf*) ax_pthread_check_macro="_REENTRANT" ;; Index: usr.sbin/unbound/config.guess =================================================================== RCS file: /cvs/src/usr.sbin/unbound/config.guess,v diff -u -p -r1.18 config.guess --- usr.sbin/unbound/config.guess 31 Aug 2025 21:41:09 -0000 1.18 +++ usr.sbin/unbound/config.guess 21 Sep 2026 16:28:02 -0000 @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2025 Free Software Foundation, Inc. +# Copyright 1992-2026 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2025-07-10' +timestamp='2026-05-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2025 Free Software Foundation, Inc. +Copyright 1992-2026 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -150,7 +150,7 @@ UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in -Linux|GNU|GNU/*) +Ironclad|Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build @@ -167,6 +167,8 @@ Linux|GNU|GNU/*) LIBC=gnu #elif defined(__LLVM_LIBC__) LIBC=llvm + #elif defined(__mlibc__) + LIBC=mlibc #else #include /* First heuristic to detect musl libc. */ @@ -1186,6 +1188,9 @@ EOF sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; + sw_64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; @@ -1598,10 +1603,10 @@ EOF GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; x86_64:[Ii]ronclad:*:*|i?86:[Ii]ronclad:*:*) - GUESS=$UNAME_MACHINE-pc-ironclad-mlibc + GUESS=$UNAME_MACHINE-pc-ironclad-$LIBC ;; *:[Ii]ronclad:*:*) - GUESS=$UNAME_MACHINE-unknown-ironclad-mlibc + GUESS=$UNAME_MACHINE-unknown-ironclad-$LIBC ;; esac Index: usr.sbin/unbound/config.h.in =================================================================== RCS file: /cvs/src/usr.sbin/unbound/config.h.in,v diff -u -p -r1.36 config.h.in --- usr.sbin/unbound/config.h.in 15 Dec 2025 16:07:12 -0000 1.36 +++ usr.sbin/unbound/config.h.in 21 Sep 2026 16:28:03 -0000 @@ -31,6 +31,9 @@ /* Whether daemon is deprecated */ #undef DEPRECATED_DAEMON +/* Whether X509_NAME_get_text_by_NID is deprecated */ +#undef DEPRECATED_X509_NAME_GET_TEXT_BY_NID + /* Deprecate RSA 1024 bit length, makes that an unsupported key */ #undef DEPRECATE_RSA_1024 @@ -48,24 +51,30 @@ internal symbols */ #undef EXPORT_ALL_SYMBOLS -/* Define to 1 if you have the 'accept4' function. */ +/* Define to 1 if you have the `accept4' function. */ #undef HAVE_ACCEPT4 -/* Define to 1 if you have the 'arc4random' function. */ +/* Define to 1 if you have the `arc4random' function. */ #undef HAVE_ARC4RANDOM -/* Define to 1 if you have the 'arc4random_uniform' function. */ +/* Define to 1 if you have the `arc4random_uniform' function. */ #undef HAVE_ARC4RANDOM_UNIFORM /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H +/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */ +#undef HAVE_ASN1_STRING_GET0_DATA + /* Whether the C compiler accepts the "fallthrough" attribute */ #undef HAVE_ATTR_FALLTHROUGH /* Whether the C compiler accepts the "format" attribute */ #undef HAVE_ATTR_FORMAT +/* Whether the C compiler accepts the "nonstring" attribute */ +#undef HAVE_ATTR_NONSTRING + /* Whether the C compiler accepts the "noreturn" attribute */ #undef HAVE_ATTR_NORETURN @@ -78,7 +87,7 @@ /* If we have be64toh */ #undef HAVE_BE64TOH -/* Define to 1 if you have the 'BIO_set_callback_ex' function. */ +/* Define to 1 if you have the `BIO_set_callback_ex' function. */ #undef HAVE_BIO_SET_CALLBACK_EX /* Define to 1 if you have the header file. */ @@ -87,245 +96,255 @@ /* Define to 1 if you have the header file. */ #undef HAVE_BSD_STRING_H -/* Define to 1 if you have the 'chown' function. */ +/* Define to 1 if you have the `chown' function. */ #undef HAVE_CHOWN -/* Define to 1 if you have the 'chroot' function. */ +/* Define to 1 if you have the `chroot' function. */ #undef HAVE_CHROOT -/* Define to 1 if you have the 'CRYPTO_cleanup_all_ex_data' function. */ +/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA -/* Define to 1 if you have the 'CRYPTO_THREADID_set_callback' function. */ +/* Define to 1 if you have the `CRYPTO_THREADID_set_callback' function. */ #undef HAVE_CRYPTO_THREADID_SET_CALLBACK -/* Define to 1 if you have the 'ctime_r' function. */ +/* Define to 1 if you have the `ctime_r' function. */ #undef HAVE_CTIME_R -/* Define to 1 if you have the 'daemon' function. */ +/* Define to 1 if you have the `daemon' function. */ #undef HAVE_DAEMON -/* Define to 1 if you have the declaration of 'arc4random', and to 0 if you +/* Define to 1 if you have the declaration of `arc4random', and to 0 if you don't. */ #undef HAVE_DECL_ARC4RANDOM -/* Define to 1 if you have the declaration of 'arc4random_uniform', and to 0 +/* Define to 1 if you have the declaration of `arc4random_uniform', and to 0 if you don't. */ #undef HAVE_DECL_ARC4RANDOM_UNIFORM -/* Define to 1 if you have the declaration of 'evsignal_assign', and to 0 if +/* Define to 1 if you have the declaration of `evsignal_assign', and to 0 if you don't. */ #undef HAVE_DECL_EVSIGNAL_ASSIGN -/* Define to 1 if you have the declaration of 'inet_ntop', and to 0 if you +/* Define to 1 if you have the declaration of `inet_ntop', and to 0 if you don't. */ #undef HAVE_DECL_INET_NTOP -/* Define to 1 if you have the declaration of 'inet_pton', and to 0 if you +/* Define to 1 if you have the declaration of `inet_pton', and to 0 if you don't. */ #undef HAVE_DECL_INET_PTON -/* Define to 1 if you have the declaration of 'nghttp2_session_server_new', +/* Define to 1 if you have the declaration of `nghttp2_session_server_new', and to 0 if you don't. */ #undef HAVE_DECL_NGHTTP2_SESSION_SERVER_NEW -/* Define to 1 if you have the declaration of 'ngtcp2_conn_server_new', and to +/* Define to 1 if you have the declaration of `ngtcp2_conn_server_new', and to 0 if you don't. */ #undef HAVE_DECL_NGTCP2_CONN_SERVER_NEW -/* Define to 1 if you have the declaration of 'ngtcp2_crypto_encrypt_cb', and +/* Define to 1 if you have the declaration of `ngtcp2_crypto_encrypt_cb', and to 0 if you don't. */ #undef HAVE_DECL_NGTCP2_CRYPTO_ENCRYPT_CB -/* Define to 1 if you have the declaration of 'NID_ED25519', and to 0 if you +/* Define to 1 if you have the declaration of `ngtcp2_crypto_ossl_ctx_new', + and to 0 if you don't. */ +#undef HAVE_DECL_NGTCP2_CRYPTO_OSSL_CTX_NEW + +/* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you don't. */ #undef HAVE_DECL_NID_ED25519 -/* Define to 1 if you have the declaration of 'NID_ED448', and to 0 if you +/* Define to 1 if you have the declaration of `NID_ED448', and to 0 if you don't. */ #undef HAVE_DECL_NID_ED448 -/* Define to 1 if you have the declaration of 'NID_secp384r1', and to 0 if you +/* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you don't. */ #undef HAVE_DECL_NID_SECP384R1 -/* Define to 1 if you have the declaration of 'NID_X9_62_prime256v1', and to 0 +/* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0 if you don't. */ #undef HAVE_DECL_NID_X9_62_PRIME256V1 -/* Define to 1 if you have the declaration of 'reallocarray', and to 0 if you +/* Define to 1 if you have the declaration of `reallocarray', and to 0 if you don't. */ #undef HAVE_DECL_REALLOCARRAY -/* Define to 1 if you have the declaration of 'redisConnect', and to 0 if you +/* Define to 1 if you have the declaration of `redisConnect', and to 0 if you don't. */ #undef HAVE_DECL_REDISCONNECT -/* Define to 1 if you have the declaration of 'sk_SSL_COMP_pop_free', and to 0 +/* Define to 1 if you have the declaration of `sk_SSL_COMP_pop_free', and to 0 if you don't. */ #undef HAVE_DECL_SK_SSL_COMP_POP_FREE /* Define to 1 if you have the declaration of - 'SSL_COMP_get_compression_methods', and to 0 if you don't. */ + `SSL_COMP_get_compression_methods', and to 0 if you don't. */ #undef HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS -/* Define to 1 if you have the declaration of 'SSL_CTX_set_ecdh_auto', and to +/* Define to 1 if you have the declaration of `SSL_CTX_set_ecdh_auto', and to 0 if you don't. */ #undef HAVE_DECL_SSL_CTX_SET_ECDH_AUTO -/* Define to 1 if you have the declaration of 'SSL_CTX_set_tmp_ecdh', and to 0 +/* Define to 1 if you have the declaration of `SSL_CTX_set_tmp_ecdh', and to 0 if you don't. */ #undef HAVE_DECL_SSL_CTX_SET_TMP_ECDH -/* Define to 1 if you have the declaration of 'strlcat', and to 0 if you +/* Define to 1 if you have the declaration of `strlcat', and to 0 if you don't. */ #undef HAVE_DECL_STRLCAT -/* Define to 1 if you have the declaration of 'strlcpy', and to 0 if you +/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you don't. */ #undef HAVE_DECL_STRLCPY -/* Define to 1 if you have the declaration of 'XML_StopParser', and to 0 if +/* Define to 1 if you have the declaration of `XML_StopParser', and to 0 if you don't. */ #undef HAVE_DECL_XML_STOPPARSER /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H -/* Define to 1 if you have the 'DSA_SIG_set0' function. */ +/* Define to 1 if you have the `DSA_SIG_set0' function. */ #undef HAVE_DSA_SIG_SET0 /* Define to 1 if you have the header file. */ #undef HAVE_ENDIAN_H -/* Define to 1 if you have the 'endprotoent' function. */ +/* Define to 1 if you have the `endprotoent' function. */ #undef HAVE_ENDPROTOENT -/* Define to 1 if you have the 'endpwent' function. */ +/* Define to 1 if you have the `endpwent' function. */ #undef HAVE_ENDPWENT -/* Define to 1 if you have the 'endservent' function. */ +/* Define to 1 if you have the `endservent' function. */ #undef HAVE_ENDSERVENT -/* Define to 1 if you have the 'ENGINE_cleanup' function. */ +/* Define to 1 if you have the `ENGINE_cleanup' function. */ #undef HAVE_ENGINE_CLEANUP -/* Define to 1 if you have the 'ERR_free_strings' function. */ +/* Define to 1 if you have the `ERR_free_strings' function. */ #undef HAVE_ERR_FREE_STRINGS -/* Define to 1 if you have the 'ERR_load_crypto_strings' function. */ +/* Define to 1 if you have the `ERR_load_crypto_strings' function. */ #undef HAVE_ERR_LOAD_CRYPTO_STRINGS -/* Define to 1 if you have the 'event_assign' function. */ +/* Define to 1 if you have the `event_assign' function. */ #undef HAVE_EVENT_ASSIGN -/* Define to 1 if you have the 'event_base_free' function. */ +/* Define to 1 if you have the `event_base_free' function. */ #undef HAVE_EVENT_BASE_FREE -/* Define to 1 if you have the 'event_base_get_method' function. */ +/* Define to 1 if you have the `event_base_get_method' function. */ #undef HAVE_EVENT_BASE_GET_METHOD -/* Define to 1 if you have the 'event_base_new' function. */ +/* Define to 1 if you have the `event_base_new' function. */ #undef HAVE_EVENT_BASE_NEW -/* Define to 1 if you have the 'event_base_once' function. */ +/* Define to 1 if you have the `event_base_once' function. */ #undef HAVE_EVENT_BASE_ONCE /* Define to 1 if you have the header file. */ #undef HAVE_EVENT_H -/* Define to 1 if you have the 'EVP_aes_256_cbc' function. */ +/* Define to 1 if you have the `EVP_aes_256_cbc' function. */ #undef HAVE_EVP_AES_256_CBC -/* Define to 1 if you have the 'EVP_cleanup' function. */ +/* Define to 1 if you have the `EVP_cleanup' function. */ #undef HAVE_EVP_CLEANUP -/* Define to 1 if you have the 'EVP_default_properties_is_fips_enabled' +/* Define to 1 if you have the `EVP_default_properties_is_fips_enabled' function. */ #undef HAVE_EVP_DEFAULT_PROPERTIES_IS_FIPS_ENABLED -/* Define to 1 if you have the 'EVP_DigestVerify' function. */ +/* Define to 1 if you have the `EVP_DigestVerify' function. */ #undef HAVE_EVP_DIGESTVERIFY -/* Define to 1 if you have the 'EVP_dss1' function. */ +/* Define to 1 if you have the `EVP_dss1' function. */ #undef HAVE_EVP_DSS1 -/* Define to 1 if you have the 'EVP_EncryptInit_ex' function. */ +/* Define to 1 if you have the `EVP_EncryptInit_ex' function. */ #undef HAVE_EVP_ENCRYPTINIT_EX -/* Define to 1 if you have the 'EVP_MAC_CTX_set_params' function. */ +/* Define to 1 if you have the `EVP_MAC_CTX_set_params' function. */ #undef HAVE_EVP_MAC_CTX_SET_PARAMS -/* Define to 1 if you have the 'EVP_MD_CTX_new' function. */ +/* Define to 1 if you have the `EVP_MD_CTX_new' function. */ #undef HAVE_EVP_MD_CTX_NEW -/* Define to 1 if you have the 'EVP_sha1' function. */ +/* Define to 1 if you have the `EVP_sha1' function. */ #undef HAVE_EVP_SHA1 -/* Define to 1 if you have the 'EVP_sha256' function. */ +/* Define to 1 if you have the `EVP_sha256' function. */ #undef HAVE_EVP_SHA256 -/* Define to 1 if you have the 'EVP_sha512' function. */ +/* Define to 1 if you have the `EVP_sha512' function. */ #undef HAVE_EVP_SHA512 -/* Define to 1 if you have the 'ev_default_loop' function. */ +/* Define to 1 if you have the `ev_default_loop' function. */ #undef HAVE_EV_DEFAULT_LOOP -/* Define to 1 if you have the 'ev_loop' function. */ +/* Define to 1 if you have the `ev_loop' function. */ #undef HAVE_EV_LOOP /* Define to 1 if you have the header file. */ #undef HAVE_EXPAT_H -/* Define to 1 if you have the 'explicit_bzero' function. */ +/* Define to 1 if you have the `explicit_bzero' function. */ #undef HAVE_EXPLICIT_BZERO -/* Define to 1 if you have the 'fcntl' function. */ +/* Define to 1 if you have the `fcntl' function. */ #undef HAVE_FCNTL -/* Define to 1 if you have the 'FIPS_mode' function. */ +/* Define to 1 if you have the `FIPS_mode' function. */ #undef HAVE_FIPS_MODE -/* Define to 1 if you have the 'fork' function. */ +/* Define to 1 if you have the `fnmatch' function. */ +#undef HAVE_FNMATCH + +/* Define to 1 if you have the header file. */ +#undef HAVE_FNMATCH_H + +/* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK -/* Define to 1 if fseeko (and ftello) are declared in stdio.h. */ +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #undef HAVE_FSEEKO -/* Define to 1 if you have the 'fsync' function. */ +/* Define to 1 if you have the `fsync' function. */ #undef HAVE_FSYNC /* Whether getaddrinfo is available */ #undef HAVE_GETADDRINFO -/* Define to 1 if you have the 'getauxval' function. */ +/* Define to 1 if you have the `getauxval' function. */ #undef HAVE_GETAUXVAL -/* Define to 1 if you have the 'getentropy' function. */ +/* Define to 1 if you have the `getentropy' function. */ #undef HAVE_GETENTROPY -/* Define to 1 if you have the 'getifaddrs' function. */ +/* Define to 1 if you have the `getifaddrs' function. */ #undef HAVE_GETIFADDRS /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H -/* Define to 1 if you have the 'getpwnam' function. */ +/* Define to 1 if you have the `getpwnam' function. */ #undef HAVE_GETPWNAM -/* Define to 1 if you have the 'getrlimit' function. */ +/* Define to 1 if you have the `getrlimit' function. */ #undef HAVE_GETRLIMIT -/* Define to 1 if you have the 'gettid' function. */ +/* Define to 1 if you have the `gettid' function. */ #undef HAVE_GETTID -/* Define to 1 if you have the 'glob' function. */ +/* Define to 1 if you have the `glob' function. */ #undef HAVE_GLOB /* Define to 1 if you have the header file. */ #undef HAVE_GLOB_H -/* Define to 1 if you have the 'gmtime_r' function. */ +/* Define to 1 if you have the `gmtime_r' function. */ #undef HAVE_GMTIME_R /* Define to 1 if you have the header file. */ @@ -334,7 +353,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_HIREDIS_HIREDIS_H -/* Define to 1 if you have the 'HMAC_Init_ex' function. */ +/* Define to 1 if you have the `HMAC_Init_ex' function. */ #undef HAVE_HMAC_INIT_EX /* If we have htobe64 */ @@ -343,19 +362,19 @@ /* Define to 1 if you have the header file. */ #undef HAVE_IFADDRS_H -/* Define to 1 if you have the 'if_nametoindex' function. */ +/* Define to 1 if you have the `if_nametoindex' function. */ #undef HAVE_IF_NAMETOINDEX -/* Define to 1 if you have the 'inet_aton' function. */ +/* Define to 1 if you have the `inet_aton' function. */ #undef HAVE_INET_ATON -/* Define to 1 if you have the 'inet_ntop' function. */ +/* Define to 1 if you have the `inet_ntop' function. */ #undef HAVE_INET_NTOP -/* Define to 1 if you have the 'inet_pton' function. */ +/* Define to 1 if you have the `inet_pton' function. */ #undef HAVE_INET_PTON -/* Define to 1 if you have the 'initgroups' function. */ +/* Define to 1 if you have the `initgroups' function. */ #undef HAVE_INITGROUPS /* Define to 1 if you have the header file. */ @@ -367,10 +386,10 @@ /* Define to 1 if you have the header file. */ #undef HAVE_IPHLPAPI_H -/* Define to 1 if you have the 'isblank' function. */ +/* Define to 1 if you have the `isblank' function. */ #undef HAVE_ISBLANK -/* Define to 1 if you have the 'kill' function. */ +/* Define to 1 if you have the `kill' function. */ #undef HAVE_KILL /* Use portable libbsd functions */ @@ -388,7 +407,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NET_TSTAMP_H -/* Define to 1 if you have the 'localtime_r' function. */ +/* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if you have the header file. */ @@ -397,7 +416,7 @@ /* If have GNU libc compatible malloc */ #undef HAVE_MALLOC -/* Define to 1 if you have the 'memmove' function. */ +/* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ @@ -439,52 +458,52 @@ /* Define this to use ngtcp2. */ #undef HAVE_NGTCP2 -/* Define to 1 if you have the 'ngtcp2_ccerr_default' function. */ +/* Define to 1 if you have the `ngtcp2_ccerr_default' function. */ #undef HAVE_NGTCP2_CCERR_DEFAULT -/* Define to 1 if you have the 'ngtcp2_conn_encode_0rtt_transport_params' +/* Define to 1 if you have the `ngtcp2_conn_encode_0rtt_transport_params' function. */ #undef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS -/* Define to 1 if you have the 'ngtcp2_conn_get_max_local_streams_uni' +/* Define to 1 if you have the `ngtcp2_conn_get_max_local_streams_uni' function. */ #undef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI -/* Define to 1 if you have the 'ngtcp2_conn_get_num_scid' function. */ +/* Define to 1 if you have the `ngtcp2_conn_get_num_scid' function. */ #undef HAVE_NGTCP2_CONN_GET_NUM_SCID -/* Define to 1 if you have the 'ngtcp2_conn_in_closing_period' function. */ +/* Define to 1 if you have the `ngtcp2_conn_in_closing_period' function. */ #undef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD -/* Define to 1 if you have the 'ngtcp2_conn_in_draining_period' function. */ +/* Define to 1 if you have the `ngtcp2_conn_in_draining_period' function. */ #undef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD /* Define if ngtcp2_conn_shutdown_stream has 4 arguments. */ #undef HAVE_NGTCP2_CONN_SHUTDOWN_STREAM4 -/* Define to 1 if you have the 'ngtcp2_conn_tls_early_data_rejected' function. +/* Define to 1 if you have the `ngtcp2_conn_tls_early_data_rejected' function. */ #undef HAVE_NGTCP2_CONN_TLS_EARLY_DATA_REJECTED -/* Define to 1 if you have the 'ngtcp2_crypto_encrypt_cb' function. */ +/* Define to 1 if you have the `ngtcp2_crypto_encrypt_cb' function. */ #undef HAVE_NGTCP2_CRYPTO_ENCRYPT_CB /* Define to 1 if you have the - 'ngtcp2_crypto_quictls_configure_client_context' function. */ + `ngtcp2_crypto_quictls_configure_client_context' function. */ #undef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT /* Define to 1 if you have the - 'ngtcp2_crypto_quictls_configure_server_context' function. */ + `ngtcp2_crypto_quictls_configure_server_context' function. */ #undef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT /* Define to 1 if you have the - 'ngtcp2_crypto_quictls_from_ossl_encryption_level' function. */ + `ngtcp2_crypto_quictls_from_ossl_encryption_level' function. */ #undef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL -/* Define to 1 if you have the 'ngtcp2_crypto_quictls_init' function. */ +/* Define to 1 if you have the `ngtcp2_crypto_quictls_init' function. */ #undef HAVE_NGTCP2_CRYPTO_QUICTLS_INIT -/* Define to 1 if the system has the type 'ngtcp2_encryption_level'. */ +/* Define to 1 if the system has the type `ngtcp2_encryption_level'. */ #undef HAVE_NGTCP2_ENCRYPTION_LEVEL /* Define to 1 if you have the header file. @@ -504,13 +523,16 @@ /* Use libnss for crypto */ #undef HAVE_NSS -/* Define to 1 if you have the 'OpenSSL_add_all_digests' function. */ +/* Define to 1 if you have the `OpenSSL_add_all_digests' function. */ #undef HAVE_OPENSSL_ADD_ALL_DIGESTS /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_BN_H -/* Define to 1 if you have the 'OPENSSL_config' function. */ +/* Define to 1 if you have the `OPENSSL_cleanup' function. */ +#undef HAVE_OPENSSL_CLEANUP + +/* Define to 1 if you have the `OPENSSL_config' function. */ #undef HAVE_OPENSSL_CONFIG /* Define to 1 if you have the header file. */ @@ -531,10 +553,10 @@ /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_ERR_H -/* Define to 1 if you have the 'OPENSSL_init_crypto' function. */ +/* Define to 1 if you have the `OPENSSL_init_crypto' function. */ #undef HAVE_OPENSSL_INIT_CRYPTO -/* Define to 1 if you have the 'OPENSSL_init_ssl' function. */ +/* Define to 1 if you have the `OPENSSL_init_ssl' function. */ #undef HAVE_OPENSSL_INIT_SSL /* Define to 1 if you have the header file. */ @@ -549,10 +571,10 @@ /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_SSL_H -/* Define to 1 if you have the 'OSSL_PARAM_BLD_new' function. */ +/* Define to 1 if you have the `OSSL_PARAM_BLD_new' function. */ #undef HAVE_OSSL_PARAM_BLD_NEW -/* Define to 1 if you have the 'poll' function. */ +/* Define to 1 if you have the `poll' function. */ #undef HAVE_POLL /* Define to 1 if you have the header file. */ @@ -561,13 +583,28 @@ /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_NP_H + /* Have PTHREAD_PRIO_INHERIT. */ #undef HAVE_PTHREAD_PRIO_INHERIT -/* Define to 1 if the system has the type 'pthread_rwlock_t'. */ +/* Define to 1 if the system has the type `pthread_rwlock_t'. */ #undef HAVE_PTHREAD_RWLOCK_T -/* Define to 1 if the system has the type 'pthread_spinlock_t'. */ +/* Define if pthread_setname_np has the common 2 arguments. */ +#undef HAVE_PTHREAD_SETNAME_NP + +/* Define if pthread_setname_np has only 1 argument. */ +#undef HAVE_PTHREAD_SETNAME_NP1 + +/* Define if pthread_setname_np has 3 arguments. */ +#undef HAVE_PTHREAD_SETNAME_NP3 + +/* Define if pthread_setname_np exists as pthread_set_name_np instead. */ +#undef HAVE_PTHREAD_SET_NAME_NP + +/* Define to 1 if the system has the type `pthread_spinlock_t'. */ #undef HAVE_PTHREAD_SPINLOCK_T /* Define to 1 if you have the header file. */ @@ -576,100 +613,107 @@ /* Define if you have Python libraries and header files. */ #undef HAVE_PYTHON -/* Define to 1 if you have the 'random' function. */ +/* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM -/* Define to 1 if you have the 'RAND_cleanup' function. */ +/* Define to 1 if you have the `RAND_cleanup' function. */ #undef HAVE_RAND_CLEANUP /* If we have reallocarray(3) */ #undef HAVE_REALLOCARRAY -/* Define to 1 if you have the 'recvmsg' function. */ +/* Define to 1 if you have the `recvmsg' function. */ #undef HAVE_RECVMSG -/* Define to 1 if you have the 'sendmsg' function. */ +/* Define to 1 if you have the `sendmsg' function. */ #undef HAVE_SENDMSG -/* Define to 1 if you have the 'setregid' function. */ +/* Define to 1 if you have the `setregid' function. */ #undef HAVE_SETREGID -/* Define to 1 if you have the 'setresgid' function. */ +/* Define to 1 if you have the `setresgid' function. */ #undef HAVE_SETRESGID -/* Define to 1 if you have the 'setresuid' function. */ +/* Define to 1 if you have the `setresuid' function. */ #undef HAVE_SETRESUID -/* Define to 1 if you have the 'setreuid' function. */ +/* Define to 1 if you have the `setreuid' function. */ #undef HAVE_SETREUID -/* Define to 1 if you have the 'setrlimit' function. */ +/* Define to 1 if you have the `setrlimit' function. */ #undef HAVE_SETRLIMIT -/* Define to 1 if you have the 'setsid' function. */ +/* Define to 1 if you have the `setsid' function. */ #undef HAVE_SETSID -/* Define to 1 if you have the 'setusercontext' function. */ +/* Define to 1 if you have the `setusercontext' function. */ #undef HAVE_SETUSERCONTEXT -/* Define to 1 if you have the 'SHA512_Update' function. */ +/* Define to 1 if you have the `SHA512_Update' function. */ #undef HAVE_SHA512_UPDATE -/* Define to 1 if you have the 'shmget' function. */ +/* Define to 1 if you have the `shmget' function. */ #undef HAVE_SHMGET -/* Define to 1 if you have the 'sigprocmask' function. */ +/* Define to 1 if you have the `sigprocmask' function. */ #undef HAVE_SIGPROCMASK -/* Define to 1 if you have the 'sleep' function. */ +/* Define to 1 if you have the `sleep' function. */ #undef HAVE_SLEEP -/* Define to 1 if you have the 'snprintf' function. */ +/* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF -/* Define to 1 if you have the 'socketpair' function. */ +/* Define to 1 if you have the `socketpair' function. */ #undef HAVE_SOCKETPAIR /* Using Solaris threads */ #undef HAVE_SOLARIS_THREADS -/* Define to 1 if you have the 'srandom' function. */ +/* Define to 1 if you have the `srandom' function. */ #undef HAVE_SRANDOM /* Define if you have the SSL libraries installed. */ #undef HAVE_SSL -/* Define to 1 if you have the 'SSL_CTX_set_alpn_protos' function. */ +/* Define to 1 if you have the `SSL_CTX_set_alpn_protos' function. */ #undef HAVE_SSL_CTX_SET_ALPN_PROTOS -/* Define to 1 if you have the 'SSL_CTX_set_alpn_select_cb' function. */ +/* Define to 1 if you have the `SSL_CTX_set_alpn_select_cb' function. */ #undef HAVE_SSL_CTX_SET_ALPN_SELECT_CB -/* Define to 1 if you have the 'SSL_CTX_set_ciphersuites' function. */ +/* Define to 1 if you have the `SSL_CTX_set_ciphersuites' function. */ #undef HAVE_SSL_CTX_SET_CIPHERSUITES -/* Define to 1 if you have the 'SSL_CTX_set_security_level' function. */ +/* Define to 1 if you have the `SSL_CTX_set_security_level' function. */ #undef HAVE_SSL_CTX_SET_SECURITY_LEVEL -/* Define to 1 if you have the 'SSL_CTX_set_tlsext_ticket_key_evp_cb' +/* Define to 1 if you have the `SSL_CTX_set_tlsext_ticket_key_evp_cb' function. */ #undef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB -/* Define to 1 if you have the 'SSL_get0_alpn_selected' function. */ +/* Define to 1 if you have the `SSL_get0_alpn_selected' function. */ #undef HAVE_SSL_GET0_ALPN_SELECTED -/* Define to 1 if you have the 'SSL_get0_peername' function. */ +/* Define to 1 if you have the `SSL_get0_peername' function. */ #undef HAVE_SSL_GET0_PEERNAME -/* Define to 1 if you have the 'SSL_get1_peer_certificate' function. */ +/* Define to 1 if you have the `SSL_get1_peer_certificate' function. */ #undef HAVE_SSL_GET1_PEER_CERTIFICATE -/* Define to 1 if you have the 'SSL_is_quic' function. */ +/* Define to 1 if you have the `SSL_is_quic' function. */ #undef HAVE_SSL_IS_QUIC -/* Define to 1 if you have the 'SSL_set1_host' function. */ +/* Define to 1 if you have the `SSL_set1_dnsname' function. */ +#undef HAVE_SSL_SET1_DNSNAME + +/* Define to 1 if you have the `SSL_set1_host' function. */ #undef HAVE_SSL_SET1_HOST +/* Define to 1 if you have the `SSL_set_quic_tls_early_data_enabled' function. + */ +#undef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED + /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H @@ -688,7 +732,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H -/* Define to 1 if you have the 'strftime' function. */ +/* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME /* Define to 1 if you have the header file. */ @@ -697,41 +741,47 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H -/* Define to 1 if you have the 'strlcat' function. */ +/* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT -/* Define to 1 if you have the 'strlcpy' function. */ +/* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY -/* Define to 1 if you have the 'strptime' function. */ +/* Define to 1 if you have the `strptime' function. */ #undef HAVE_STRPTIME -/* Define to 1 if you have the 'strsep' function. */ +/* Define to 1 if you have the `strsep' function. */ #undef HAVE_STRSEP -/* Define to 1 if 'ipi_spec_dst' is a member of 'struct in_pktinfo'. */ +/* Define to 1 if `ipi_spec_dst' is a member of `struct in_pktinfo'. */ #undef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST -/* Define to 1 if 'tokenlen' is a member of 'struct ngtcp2_pkt_hd'. */ +/* Define to 1 if `tokenlen' is a member of `struct ngtcp2_pkt_hd'. */ #undef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN -/* Define to 1 if 'max_tx_udp_payload_size' is a member of 'struct +/* Define to 1 if `max_tx_udp_payload_size' is a member of `struct ngtcp2_settings'. */ #undef HAVE_STRUCT_NGTCP2_SETTINGS_MAX_TX_UDP_PAYLOAD_SIZE -/* Define to 1 if 'tokenlen' is a member of 'struct ngtcp2_settings'. */ +/* Define to 1 if `tokenlen' is a member of `struct ngtcp2_settings'. */ #undef HAVE_STRUCT_NGTCP2_SETTINGS_TOKENLEN -/* Define to 1 if 'original_dcid_present' is a member of 'struct +/* Define to 1 if `original_dcid_present' is a member of `struct ngtcp2_transport_params'. */ #undef HAVE_STRUCT_NGTCP2_TRANSPORT_PARAMS_ORIGINAL_DCID_PRESENT -/* Define to 1 if the system has the type 'struct ngtcp2_version_cid'. */ +/* Define to 1 if the system has the type `struct ngtcp2_version_cid'. */ #undef HAVE_STRUCT_NGTCP2_VERSION_CID -/* Define to 1 if 'sun_len' is a member of 'struct sockaddr_un'. */ +/* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */ #undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN +/* Define to 1 if `st_mtimensec' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_MTIMENSEC + +/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + /* Define if you have Swig libraries and header files. */ #undef HAVE_SWIG @@ -789,16 +839,16 @@ /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H -/* Define to 1 if you have the 'tzset' function. */ +/* Define to 1 if you have the `tzset' function. */ #undef HAVE_TZSET /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H -/* Define to 1 if you have the 'usleep' function. */ +/* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP -/* Define to 1 if you have the 'vfork' function. */ +/* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ @@ -816,22 +866,28 @@ /* Define to 1 if you have the header file. */ #undef HAVE_WINSOCK2_H -/* Define to 1 if 'fork' works. */ +/* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK -/* Define to 1 if 'vfork' works. */ +/* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK -/* Define to 1 if you have the 'writev' function. */ +/* Define to 1 if you have the `writev' function. */ #undef HAVE_WRITEV /* Define to 1 if you have the header file. */ #undef HAVE_WS2TCPIP_H -/* Define to 1 if you have the 'X509_VERIFY_PARAM_set1_host' function. */ +/* Define to 1 if you have the `X509_get_key_usage' function. */ +#undef HAVE_X509_GET_KEY_USAGE + +/* Define to 1 if you have the `X509_NAME_get_text_by_NID' function. */ +#undef HAVE_X509_NAME_GET_TEXT_BY_NID + +/* Define to 1 if you have the `X509_VERIFY_PARAM_set1_host' function. */ #undef HAVE_X509_VERIFY_PARAM_SET1_HOST -/* Define to 1 if you have the '_beginthreadex' function. */ +/* Define to 1 if you have the `_beginthreadex' function. */ #undef HAVE__BEGINTHREADEX /* If HMAC_Init_ex() returns void */ @@ -930,16 +986,16 @@ /* Shared data */ #undef SHARE_DIR -/* The size of 'pthread_t', as computed by sizeof. */ +/* The size of `pthread_t', as computed by sizeof. */ #undef SIZEOF_PTHREAD_T -/* The size of 'size_t', as computed by sizeof. */ +/* The size of `size_t', as computed by sizeof. */ #undef SIZEOF_SIZE_T -/* The size of 'time_t', as computed by sizeof. */ +/* The size of `time_t', as computed by sizeof. */ #undef SIZEOF_TIME_T -/* The size of 'unsigned long', as computed by sizeof. */ +/* The size of `unsigned long', as computed by sizeof. */ #undef SIZEOF_UNSIGNED_LONG /* define if (v)snprintf does not return length needed, (but length used) */ @@ -948,7 +1004,7 @@ /* Define to 1 if libsodium supports sodium_set_misuse_handler */ #undef SODIUM_MISUSE_HANDLER -/* Define to 1 if all of the C89 standard headers exist (not just the ones +/* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS @@ -1045,7 +1101,7 @@ /* Define this to enable SHA256 and SHA512 support. */ #undef USE_SHA2 -/* Enable extensions on AIX, Interix, z/OS. */ +/* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif @@ -1106,15 +1162,11 @@ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif -/* Enable extensions specified by C23 Annex F. */ -#ifndef __STDC_WANT_IEC_60559_EXT__ -# undef __STDC_WANT_IEC_60559_EXT__ -#endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif -/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ +/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif @@ -1155,36 +1207,30 @@ /* Define if you want PyUnbound. */ #undef WITH_PYUNBOUND -/* Define to 1 if 'lex' declares 'yytext' as a 'char *' by default, not a - 'char[]'. */ +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ #undef YYTEXT_POINTER /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS -/* Define to 1 if necessary to make fseeko visible. */ +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ #undef _LARGEFILE_SOURCE -/* Define to 1 on platforms where this makes off_t a 64-bit type. */ +/* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Enable for compile on Minix */ #undef _NETBSD_SOURCE -/* Number of bits in time_t, on hosts where this is settable. */ -#undef _TIME_BITS - -/* Define to 1 on platforms where this makes time_t a 64-bit type. */ -#undef __MINGW_USE_VC2005_COMPAT - /* defined to use gcc ansi snprintf and sscanf that understands %lld when compiled for windows. */ #undef __USE_MINGW_ANSI_STDIO -/* Define to empty if 'const' does not conform to ANSI C. */ +/* Define to empty if `const' does not conform to ANSI C. */ #undef const -/* Define as 'int' if doesn't define. */ +/* Define to `int' if doesn't define. */ #undef gid_t /* in_addr_t */ @@ -1193,28 +1239,28 @@ /* in_port_t */ #undef in_port_t -/* Define to '__inline__' or '__inline' if that's what the C compiler +/* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif -/* Define to 'short' if does not define. */ +/* Define to `short' if does not define. */ #undef int16_t -/* Define to 'int' if does not define. */ +/* Define to `int' if does not define. */ #undef int32_t -/* Define to 'long long' if does not define. */ +/* Define to `long long' if does not define. */ #undef int64_t -/* Define to 'signed char' if does not define. */ +/* Define to `signed char' if does not define. */ #undef int8_t /* Define if replacement function should be used. */ #undef malloc -/* Define to 'long int' if does not define. */ +/* Define to `long int' if does not define. */ #undef off_t /* Define as a signed integer type capable of holding a process identifier. */ @@ -1223,34 +1269,34 @@ /* Define to 'int' if not defined */ #undef rlim_t -/* Define as 'unsigned int' if doesn't define. */ +/* Define to `unsigned int' if does not define. */ #undef size_t /* Define to 'int' if not defined */ #undef socklen_t -/* Define to 'int' if does not define. */ +/* Define to `int' if does not define. */ #undef ssize_t /* Define to 'unsigned char if not defined */ #undef u_char -/* Define as 'int' if doesn't define. */ +/* Define to `int' if doesn't define. */ #undef uid_t -/* Define to 'unsigned short' if does not define. */ +/* Define to `unsigned short' if does not define. */ #undef uint16_t -/* Define to 'unsigned int' if does not define. */ +/* Define to `unsigned int' if does not define. */ #undef uint32_t -/* Define to 'unsigned long long' if does not define. */ +/* Define to `unsigned long long' if does not define. */ #undef uint64_t -/* Define to 'unsigned char' if does not define. */ +/* Define to `unsigned char' if does not define. */ #undef uint8_t -/* Define as 'fork' if 'vfork' does not work. */ +/* Define as `fork' if `vfork' does not work. */ #undef vfork #if defined(OMITTED__D_GNU_SOURCE) && !defined(_GNU_SOURCE) @@ -1389,6 +1435,17 @@ #else /* !HAVE_ATTR_UNUSED */ # define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ + + +#if defined(DOXYGEN) +# define ATTR_NONSTRING(x) x +#elif defined(__cplusplus) +# define ATTR_NONSTRING(x) __attribute__((nonstring)) x +#elif defined(HAVE_ATTR_NONSTRING) +# define ATTR_NONSTRING(x) __attribute__((nonstring)) x +#else /* !HAVE_ATTR_NONSTRING */ +# define ATTR_NONSTRING(x) x +#endif /* !HAVE_ATTR_NONSTRING */ #ifndef HAVE_FSEEKO Index: usr.sbin/unbound/config.sub =================================================================== RCS file: /cvs/src/usr.sbin/unbound/config.sub,v diff -u -p -r1.17 config.sub --- usr.sbin/unbound/config.sub 31 Aug 2025 21:41:09 -0000 1.17 +++ usr.sbin/unbound/config.sub 21 Sep 2026 16:28:03 -0000 @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2025 Free Software Foundation, Inc. +# Copyright 1992-2026 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale -timestamp='2025-07-10' +timestamp='2026-05-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -76,7 +76,7 @@ Report bugs and patches to . # # -# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # @@ -17,6 +17,7 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh +as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -25,13 +26,12 @@ then : # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else case e in #( - e) case `(set -o) 2>/dev/null` in #( +else $as_nop + case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; -esac ;; esac fi @@ -103,7 +103,7 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' +# We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -133,14 +133,15 @@ case $- in # (((( esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. +# out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: @@ -148,13 +149,12 @@ then : # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else case e in #( - e) case \`(set -o) 2>/dev/null\` in #( +else \$as_nop + case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; -esac ;; esac fi " @@ -172,9 +172,8 @@ as_fn_ret_failure && { exitcode=1; echo if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : -else case e in #( - e) exitcode=1; echo positional parameters were not saved. ;; -esac +else \$as_nop + exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) @@ -196,15 +195,14 @@ test \$(( 1 + 1 )) = 2 || exit 1 if (eval "$as_required") 2>/dev/null then : as_have_required=yes -else case e in #( - e) as_have_required=no ;; -esac +else $as_nop + as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : -else case e in #( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else $as_nop + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do @@ -237,13 +235,12 @@ IFS=$as_save_IFS if $as_found then : -else case e in #( - e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes -fi ;; -esac +fi fi @@ -265,7 +262,7 @@ case $- in # (((( esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. +# out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi @@ -286,8 +283,7 @@ $0: message. Then install a modern shell $0: the script under such a shell if you do have one." fi exit 1 -fi ;; -esac +fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} @@ -326,6 +322,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -394,12 +398,11 @@ then : { eval $1+=\$2 }' -else case e in #( - e) as_fn_append () +else $as_nop + as_fn_append () { eval $1=\$$1\$2 - } ;; -esac + } fi # as_fn_append # as_fn_arith ARG... @@ -413,14 +416,21 @@ then : { as_val=$(( $* )) }' -else case e in #( - e) as_fn_arith () +else $as_nop + as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } ;; -esac + } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -494,8 +504,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits /[$]LINENO/= ' <$as_myself | sed ' - t clear - :clear s/[$]LINENO.*/&-/ t lineno b @@ -544,6 +552,7 @@ esac as_echo='printf %s\n' as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -555,9 +564,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -582,12 +591,10 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} @@ -615,8 +622,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.24.2' -PACKAGE_STRING='unbound 1.24.2' +PACKAGE_VERSION='1.26.1' +PACKAGE_STRING='unbound 1.26.1' PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues' PACKAGE_URL='' @@ -653,7 +660,6 @@ ac_includes_default="\ ac_header_c_list= ac_func_c_list= -enable_year2038=no ac_subst_vars='LTLIBOBJS date version @@ -742,7 +748,6 @@ PTHREAD_LIBS PTHREAD_CXX PTHREAD_CC ax_pthread_config -CPP ASYNCLOOK_ALLOCCHECK_EXTRA_OBJ SLDNS_ALLOCCHECK_EXTRA_OBJ USE_SYSTEMD_FALSE @@ -753,6 +758,7 @@ SYSTEMD_LIBS SYSTEMD_CFLAGS RUNTIME_PATH LIBOBJS +CPP PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG @@ -938,7 +944,6 @@ with_libmnl enable_explicit_port_randomisation enable_linux_ip_local_port_range with_libunbound_only -enable_year2038 ' ac_precious_vars='build_alias host_alias @@ -954,11 +959,11 @@ LT_SYS_LIBRARY_PATH PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR +CPP SYSTEMD_CFLAGS SYSTEMD_LIBS SYSTEMD_DAEMON_CFLAGS SYSTEMD_DAEMON_LIBS -CPP PYTHON_VERSION SOURCE_DATE_EPOCH PROTOBUFC_CFLAGS @@ -1071,7 +1076,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1097,7 +1102,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1310,7 +1315,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1326,7 +1331,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1356,8 +1361,8 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) as_fn_error $? "unrecognized option: '$ac_option' -Try '$0 --help' for more information" + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" ;; *=*) @@ -1365,7 +1370,7 @@ Try '$0 --help' for more information" # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: '$ac_envvar'" ;; + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1415,7 +1420,7 @@ do as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done -# There might be people who depend on the old broken behavior: '$host' +# There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias @@ -1483,7 +1488,7 @@ if test ! -r "$srcdir/$ac_unique_file"; test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi -ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` @@ -1511,7 +1516,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures unbound 1.24.2 to adapt to many kinds of systems. +\`configure' configures unbound 1.26.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1525,11 +1530,11 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print 'checking ...' messages + -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for '--cache-file=config.cache' + -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or '..'] + --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX @@ -1537,10 +1542,10 @@ Installation directories: --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] -By default, 'make install' will install all the files in -'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify -an installation prefix other than '$ac_default_prefix' using '--prefix', -for instance '--prefix=\$HOME'. +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. For better control, use the options below. @@ -1577,7 +1582,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of unbound 1.24.2:";; + short | recursive ) echo "Configuration of unbound 1.26.1:";; esac cat <<\_ACEOF @@ -1658,7 +1663,6 @@ Optional Features: randomness. Define this only when the target system restricts (e.g. some of SELinux enabled distributions) the use of non-ephemeral ports. - --enable-year2038 support timestamps after 2038 Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1729,12 +1733,12 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory - YACC The 'Yet Another Compiler Compiler' implementation to use. - Defaults to the first program found out of: 'bison -y', 'byacc', - 'yacc'. + YACC The `Yet Another Compiler Compiler' implementation to use. + Defaults to the first program found out of: `bison -y', `byacc', + `yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a - default value of '-d' given by some make applications. + default value of `-d' given by some make applications. LT_SYS_LIBRARY_PATH User-defined run-time library search path. PKG_CONFIG path to pkg-config utility @@ -1742,6 +1746,7 @@ Some influential environment variables: directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path + CPP C preprocessor SYSTEMD_CFLAGS C compiler flags for SYSTEMD, overriding pkg-config SYSTEMD_LIBS @@ -1750,7 +1755,6 @@ Some influential environment variables: C compiler flags for SYSTEMD_DAEMON, overriding pkg-config SYSTEMD_DAEMON_LIBS linker flags for SYSTEMD_DAEMON, overriding pkg-config - CPP C preprocessor PYTHON_VERSION The installed Python version to use, for example '2.3'. This string will be appended to the Python interpreter canonical @@ -1764,7 +1768,7 @@ Some influential environment variables: PROTOBUFC_LIBS linker flags for PROTOBUFC, overriding pkg-config -Use these variables to override the choices made by 'configure' or to help +Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . @@ -1831,10 +1835,10 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -unbound configure 1.24.2 -generated by GNU Autoconf 2.72 +unbound configure 1.26.1 +generated by GNU Autoconf 2.71 -Copyright (C) 2023 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1873,12 +1877,11 @@ printf "%s\n" "$ac_try_echo"; } >&5 } && test -s conftest.$ac_objext then : ac_retval=0 -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 ;; -esac + ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -1897,8 +1900,8 @@ printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> @@ -1906,12 +1909,10 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" -else case e in #( - e) eval "$3=no" ;; -esac +else $as_nop + eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -1951,12 +1952,11 @@ printf "%s\n" "$ac_try_echo"; } >&5 } then : ac_retval=0 -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 ;; -esac + ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would @@ -1979,15 +1979,15 @@ printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (void); below. */ + which can conflict with char $2 (); below. */ #include #undef $2 @@ -1998,7 +1998,7 @@ else case e in #( #ifdef __cplusplus extern "C" #endif -char $2 (void); +char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ @@ -2017,13 +2017,11 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" -else case e in #( - e) eval "$3=no" ;; -esac +else $as_nop + eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac + conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -2044,8 +2042,8 @@ printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else case e in #( - e) eval "$3=no" +else $as_nop + eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 @@ -2075,14 +2073,12 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else case e in #( - e) eval "$3=yes" ;; -esac +else $as_nop + eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -2091,6 +2087,44 @@ printf "%s\n" "$ac_res" >&6; } } # ac_fn_c_check_type +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that @@ -2121,13 +2155,12 @@ printf "%s\n" "$ac_try_echo"; } >&5 test $ac_status = 0; }; } then : ac_retval=0 -else case e in #( - e) printf "%s\n" "$as_me: program exited with status $ac_status" >&5 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=$ac_status ;; -esac + ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -2180,19 +2213,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid; break -else case e in #( - e) as_fn_arith $ac_mid + 1 && ac_lo=$as_val +else $as_nop + as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi - as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val ;; -esac + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int @@ -2227,23 +2259,20 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_lo=$ac_mid; break -else case e in #( - e) as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val +else $as_nop + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi - as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val ;; -esac + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else case e in #( - e) ac_lo= ac_hi= ;; -esac +else $as_nop + ac_lo= ac_hi= fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. @@ -2266,9 +2295,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid -else case e in #( - e) as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val ;; -esac +else $as_nop + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done @@ -2316,9 +2344,8 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : echo >>conftest.val; read $3 &5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - } -then : - ac_retval=0 -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - # ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR # ------------------------------------------------------------------ # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR @@ -2382,8 +2370,8 @@ printf %s "checking whether $as_decl_nam if eval test \${$3+y} then : printf %s "(cached) " >&6 -else case e in #( - e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` +else $as_nop + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` eval ac_save_FLAGS=\$$6 as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2407,14 +2395,12 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" -else case e in #( - e) eval "$3=no" ;; -esac +else $as_nop + eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval $6=\$ac_save_FLAGS - ;; -esac + fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -2435,8 +2421,8 @@ printf %s "checking for $2.$3... " >&6; if eval test \${$4+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int @@ -2452,8 +2438,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int @@ -2469,15 +2455,12 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" -else case e in #( - e) eval "$4=no" ;; -esac +else $as_nop + eval "$4=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$4 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -2509,8 +2492,8 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by unbound $as_me 1.24.2, which was -generated by GNU Autoconf 2.72. Invocation command line was +It was created by unbound $as_me 1.26.1, which was +generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -2756,10 +2739,10 @@ esac printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See 'config.log' for more details" "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } fi done @@ -2796,7 +2779,9 @@ struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (char **p, int i) +static char *e (p, i) + char **p; + int i; { return p[i]; } @@ -2810,21 +2795,6 @@ static char *f (char * (*g) (char **, in return s; } -/* C89 style stringification. */ -#define noexpand_stringify(a) #a -const char *stringified = noexpand_stringify(arbitrary+token=sequence); - -/* C89 style token pasting. Exercises some of the corner cases that - e.g. old MSVC gets wrong, but not very hard. */ -#define noexpand_concat(a,b) a##b -#define expand_concat(a,b) noexpand_concat(a,b) -extern int vA; -extern int vbee; -#define aye A -#define bee B -int *pvA = &expand_concat(v,aye); -int *pvbee = &noexpand_concat(v,bee); - /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated @@ -2852,19 +2822,16 @@ ok |= (argc == 0 || f (e, argv, 0) != ar # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' -/* Does the compiler advertise C99 conformance? */ +// Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif -// See if C++-style comments work. - #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); -extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare @@ -2914,6 +2881,7 @@ typedef const char *ccp; static inline int test_restrict (ccp restrict text) { + // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) @@ -2979,8 +2947,6 @@ ac_c_conftest_c99_main=' ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; - // Work around memory leak warnings. - free (ia); // Check named initializers. struct named_init ni = { @@ -3002,7 +2968,7 @@ ac_c_conftest_c99_main=' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' -/* Does the compiler advertise C11 conformance? */ +// Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif @@ -3198,9 +3164,8 @@ IFS=$as_save_IFS if $as_found then : -else case e in #( - e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi @@ -3228,12 +3193,12 @@ for ac_var in $ac_precious_vars; do eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 -printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 -printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) @@ -3242,18 +3207,18 @@ printf "%s\n" "$as_me: error: '$ac_var' ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 -printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 -printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 -printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 -printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. @@ -3269,11 +3234,11 @@ printf "%s\n" "$as_me: current value: fi done if $ac_cache_corrupted; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## @@ -3289,13 +3254,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu UNBOUND_VERSION_MAJOR=1 -UNBOUND_VERSION_MINOR=24 +UNBOUND_VERSION_MINOR=26 -UNBOUND_VERSION_MICRO=2 +UNBOUND_VERSION_MICRO=1 LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=34 +LIBUNBOUND_REVISION=40 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -3398,6 +3363,11 @@ LIBUNBOUND_AGE=1 # 1.24.0 had 9:33:1 # 1.24.1 had 9:34:1 # 1.24.2 had 9:35:1 +# 1.25.0 had 9:36:1 +# 1.25.1 had 9:37:1 +# 1.25.2 had 9:38:1 +# 1.26.0 had 9:39:1 +# 1.26.1 had 9:40:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -3450,8 +3420,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3473,8 +3443,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3496,8 +3465,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then +else $as_nop + if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3519,8 +3488,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -3555,8 +3523,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3578,8 +3546,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3601,8 +3568,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no @@ -3641,8 +3608,7 @@ if test $ac_prog_rejected = yes; then ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3666,8 +3632,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3689,8 +3655,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3716,8 +3681,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then +else $as_nop + if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3739,8 +3704,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -3778,8 +3742,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3801,8 +3765,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -3824,8 +3787,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then +else $as_nop + if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3847,8 +3810,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -3877,10 +3839,10 @@ fi fi -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See 'config.log' for more details" "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -3952,8 +3914,8 @@ printf "%s\n" "$ac_try_echo"; } >&5 printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. -# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. @@ -3973,7 +3935,7 @@ do ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an '-o' + # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. @@ -3984,9 +3946,8 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else case e in #( - e) ac_file='' ;; -esac +else $as_nop + ac_file='' fi if test -z "$ac_file" then : @@ -3995,14 +3956,13 @@ printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables -See 'config.log' for more details" "$LINENO" 5; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } ;; -esac +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } @@ -4026,10 +3986,10 @@ printf "%s\n" "$ac_try_echo"; } >&5 printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) -# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will -# work properly (i.e., refer to 'conftest.exe'), while it won't with -# 'rm'. + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in @@ -4039,12 +3999,11 @@ for ac_file in conftest.exe conftest con * ) break;; esac done -else case e in #( - e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See 'config.log' for more details" "$LINENO" 5; } ;; -esac +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -4060,8 +4019,6 @@ int main (void) { FILE *f = fopen ("conftest.out", "w"); - if (!f) - return 1; return ferror (f) || fclose (f) != 0; ; @@ -4101,27 +4058,26 @@ printf "%s\n" "$ac_try_echo"; } >&5 if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use '--host'. -See 'config.log' for more details" "$LINENO" 5; } +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } -rm -f conftest.$ac_ext conftest$ac_cv_exeext \ - conftest.o conftest.obj conftest.out +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -4153,18 +4109,16 @@ then : break;; esac done -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See 'config.log' for more details" "$LINENO" 5; } ;; -esac +See \`config.log' for more details" "$LINENO" 5; } fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; -esac +rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } @@ -4175,8 +4129,8 @@ printf %s "checking whether the compiler if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -4193,14 +4147,12 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes -else case e in #( - e) ac_compiler_gnu=no ;; -esac +else $as_nop + ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } @@ -4218,8 +4170,8 @@ printf %s "checking whether $CC accepts if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_save_c_werror_flag=$ac_c_werror_flag +else $as_nop + ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" @@ -4237,8 +4189,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes -else case e in #( - e) CFLAGS="" +else $as_nop + CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4253,8 +4205,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else case e in #( - e) ac_c_werror_flag=$ac_save_c_werror_flag +else $as_nop + ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4271,15 +4223,12 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag ;; -esac + ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } @@ -4306,8 +4255,8 @@ printf %s "checking for $CC option to en if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c11=no +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4324,28 +4273,25 @@ rm -f core conftest.err conftest.$ac_obj test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac +CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c11" = x +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" ;; -esac + CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 ;; -esac + ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno @@ -4355,8 +4301,8 @@ printf %s "checking for $CC option to en if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c99=no +else $as_nop + ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4373,28 +4319,25 @@ rm -f core conftest.err conftest.$ac_obj test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac +CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c99" = x +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" ;; -esac + CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 ;; -esac + ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno @@ -4404,8 +4347,8 @@ printf %s "checking for $CC option to en if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c89=no +else $as_nop + ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4422,28 +4365,25 @@ rm -f core conftest.err conftest.$ac_obj test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac +CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c89" = x +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" ;; -esac + CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 ;; -esac + ac_prog_cc_stdc=c89 fi fi @@ -4494,8 +4434,8 @@ printf %s "checking whether it is safe t if test ${ac_cv_safe_to_define___extensions__+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 @@ -4511,12 +4451,10 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_safe_to_define___extensions__=yes -else case e in #( - e) ac_cv_safe_to_define___extensions__=no ;; -esac +else $as_nop + ac_cv_safe_to_define___extensions__=no fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } @@ -4526,8 +4464,8 @@ printf %s "checking whether _XOPEN_SOURC if test ${ac_cv_should_define__xopen_source+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_should_define__xopen_source=no +else $as_nop + ac_cv_should_define__xopen_source=no if test $ac_cv_header_wchar_h = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4546,8 +4484,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 500 @@ -4565,12 +4503,10 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_should_define__xopen_source=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi ;; -esac +fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } @@ -4595,8 +4531,6 @@ printf "%s\n" "$ac_cv_should_define__xop printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h - printf "%s\n" "#define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h - printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h @@ -4616,9 +4550,8 @@ then : printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h -else case e in #( - e) MINIX= ;; -esac +else $as_nop + MINIX= fi if test $ac_cv_safe_to_define___extensions__ = yes then : @@ -4713,14 +4646,13 @@ printf "%s\n" X"$ub_conf_file" | if test ${with_run_dir+y} then : withval=$with_run_dir; UNBOUND_RUN_DIR="$withval" -else case e in #( - e) if test $on_mingw = no; then +else $as_nop + if test $on_mingw = no; then UNBOUND_RUN_DIR=`dirname "$ub_conf_file"` else UNBOUND_RUN_DIR="" fi - ;; -esac + fi @@ -4735,14 +4667,13 @@ printf "%s\n" "#define RUN_DIR \"$hdr_ru if test ${with_chroot_dir+y} then : withval=$with_chroot_dir; UNBOUND_CHROOT_DIR="$withval" -else case e in #( - e) if test $on_mingw = no; then +else $as_nop + if test $on_mingw = no; then UNBOUND_CHROOT_DIR="$UNBOUND_RUN_DIR" else UNBOUND_CHROOT_DIR="" fi - ;; -esac + fi @@ -4757,9 +4688,8 @@ printf "%s\n" "#define CHROOT_DIR \"$hdr if test ${with_share_dir+y} then : withval=$with_share_dir; UNBOUND_SHARE_DIR="$withval" -else case e in #( - e) UNBOUND_SHARE_DIR="$UNBOUND_RUN_DIR" ;; -esac +else $as_nop + UNBOUND_SHARE_DIR="$UNBOUND_RUN_DIR" fi @@ -4772,14 +4702,13 @@ printf "%s\n" "#define SHARE_DIR \"$UNBO if test ${with_pidfile+y} then : withval=$with_pidfile; UNBOUND_PIDFILE="$withval" -else case e in #( - e) if test $on_mingw = no; then +else $as_nop + if test $on_mingw = no; then UNBOUND_PIDFILE="$UNBOUND_RUN_DIR/unbound.pid" else UNBOUND_PIDFILE="" fi - ;; -esac + fi @@ -4794,14 +4723,13 @@ printf "%s\n" "#define PIDFILE \"$hdr_pi if test ${with_rootkey_file+y} then : withval=$with_rootkey_file; UNBOUND_ROOTKEY_FILE="$withval" -else case e in #( - e) if test $on_mingw = no; then +else $as_nop + if test $on_mingw = no; then UNBOUND_ROOTKEY_FILE="$UNBOUND_RUN_DIR/root.key" else UNBOUND_ROOTKEY_FILE="C:\\Program Files\\Unbound\\root.key" fi - ;; -esac + fi @@ -4816,14 +4744,13 @@ printf "%s\n" "#define ROOT_ANCHOR_FILE if test ${with_rootcert_file+y} then : withval=$with_rootcert_file; UNBOUND_ROOTCERT_FILE="$withval" -else case e in #( - e) if test $on_mingw = no; then +else $as_nop + if test $on_mingw = no; then UNBOUND_ROOTCERT_FILE="$UNBOUND_RUN_DIR/icannbundle.pem" else UNBOUND_ROOTCERT_FILE="C:\\Program Files\\Unbound\\icannbundle.pem" fi - ;; -esac + fi @@ -4838,9 +4765,8 @@ printf "%s\n" "#define ROOT_CERT_FILE \" if test ${with_username+y} then : withval=$with_username; UNBOUND_USERNAME="$withval" -else case e in #( - e) UNBOUND_USERNAME="unbound" ;; -esac +else $as_nop + UNBOUND_USERNAME="unbound" fi @@ -4863,8 +4789,8 @@ printf %s "checking for grep that handle if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -z "$GREP"; then +else $as_nop + if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4883,10 +4809,9 @@ do as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in #( +case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -4921,8 +4846,7 @@ IFS=$as_save_IFS else ac_cv_path_GREP=$GREP fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } @@ -4936,8 +4860,8 @@ printf %s "checking for an ANSI C-confor if test ${ac_cv_c_const+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -5001,12 +4925,10 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_const=yes -else case e in #( - e) ac_cv_c_const=no ;; -esac +else $as_nop + ac_cv_c_const=no fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 printf "%s\n" "$ac_cv_c_const" >&6; } @@ -5033,8 +4955,8 @@ cache=`echo g | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -g -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -5042,8 +4964,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -5066,8 +4987,8 @@ cache=`echo O2 | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -O2 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -5075,8 +4996,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -5106,8 +5026,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5129,8 +5049,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5152,8 +5071,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then +else $as_nop + if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5175,8 +5094,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -5211,8 +5129,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5234,8 +5152,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5257,8 +5174,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no @@ -5297,8 +5214,7 @@ if test $ac_prog_rejected = yes; then ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5322,8 +5238,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5345,8 +5261,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5372,8 +5287,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then +else $as_nop + if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5395,8 +5310,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -5434,8 +5348,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then +else $as_nop + if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5457,8 +5371,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5480,8 +5393,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then +else $as_nop + if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5503,8 +5416,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -5533,10 +5445,10 @@ fi fi -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See 'config.log' for more details" "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -5568,8 +5480,8 @@ printf %s "checking whether the compiler if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -5586,14 +5498,12 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes -else case e in #( - e) ac_compiler_gnu=no ;; -esac +else $as_nop + ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } @@ -5611,8 +5521,8 @@ printf %s "checking whether $CC accepts if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_save_c_werror_flag=$ac_c_werror_flag +else $as_nop + ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" @@ -5630,8 +5540,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes -else case e in #( - e) CFLAGS="" +else $as_nop + CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5646,8 +5556,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else case e in #( - e) ac_c_werror_flag=$ac_save_c_werror_flag +else $as_nop + ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5664,15 +5574,12 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag ;; -esac + ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } @@ -5699,8 +5606,8 @@ printf %s "checking for $CC option to en if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c11=no +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5717,28 +5624,25 @@ rm -f core conftest.err conftest.$ac_obj test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac +CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c11" = x +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" ;; -esac + CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 ;; -esac + ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno @@ -5748,8 +5652,8 @@ printf %s "checking for $CC option to en if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c99=no +else $as_nop + ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5766,28 +5670,25 @@ rm -f core conftest.err conftest.$ac_obj test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac +CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c99" = x +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" ;; -esac + CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 ;; -esac + ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno @@ -5797,8 +5698,8 @@ printf %s "checking for $CC option to en if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c89=no +else $as_nop + ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5815,28 +5716,25 @@ rm -f core conftest.err conftest.$ac_obj test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac +CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c89" = x +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" ;; -esac + CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 ;; -esac + ac_prog_cc_stdc=c89 fi fi @@ -5873,8 +5771,8 @@ cache=`echo Werror | sed 'y%.=/+-%___p_% if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -Werror -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -5882,8 +5780,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -5906,8 +5803,8 @@ cache=`echo Wall | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -Wall -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -5915,8 +5812,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -5941,8 +5837,8 @@ cache=`echo std=c99 | sed 'y%.=/+-%___p_ if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -std=c99 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -5950,8 +5846,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -5974,8 +5869,8 @@ cache=`echo xc99 | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -xc99 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -5983,8 +5878,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -6021,12 +5915,12 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE as a flag for $CC" >&5 printf %s "checking whether we need $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE as a flag for $CC... " >&6; } -cache=`printf "%s\n" "$C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE" | sed "$as_sed_sh"` +cache=`printf "%s\n" "$C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE" | $as_tr_sh` if eval test \${cv_prog_cc_flag_needed_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include "confdefs.h" #include @@ -6080,8 +5974,7 @@ fi fi rm -f conftest conftest.c conftest.o - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then @@ -6114,12 +6007,12 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE as a flag for $CC" >&5 printf %s "checking whether we need $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE as a flag for $CC... " >&6; } -cache=`printf "%s\n" "$C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE" | sed "$as_sed_sh"` +cache=`printf "%s\n" "$C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE" | $as_tr_sh` if eval test \${cv_prog_cc_flag_needed_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include "confdefs.h" #include @@ -6173,8 +6066,7 @@ fi fi rm -f conftest conftest.c conftest.o - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then @@ -6207,12 +6099,12 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need $C99FLAG as a flag for $CC" >&5 printf %s "checking whether we need $C99FLAG as a flag for $CC... " >&6; } -cache=`printf "%s\n" "$C99FLAG" | sed "$as_sed_sh"` +cache=`printf "%s\n" "$C99FLAG" | $as_tr_sh` if eval test \${cv_prog_cc_flag_needed_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include #include @@ -6239,8 +6131,7 @@ fi fi rm -f conftest conftest.c conftest.o - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then @@ -6277,8 +6168,8 @@ cache=_D_BSD_SOURCE__D_DEFAULT_SOURCE if eval test \${cv_prog_cc_flag_needed_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include @@ -6306,8 +6197,7 @@ fi fi rm -f conftest conftest.c conftest.o - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then @@ -6344,8 +6234,8 @@ cache=_D_GNU_SOURCE if eval test \${cv_prog_cc_flag_needed_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include @@ -6373,8 +6263,7 @@ fi fi rm -f conftest conftest.c conftest.o - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then @@ -6414,8 +6303,8 @@ cache=_D_GNU_SOURCE__D_FRSRESGID if eval test \${cv_prog_cc_flag_needed_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include @@ -6443,8 +6332,7 @@ fi fi rm -f conftest conftest.c conftest.o - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then @@ -6481,8 +6369,8 @@ cache=_D_POSIX_C_SOURCE_200112 if eval test \${cv_prog_cc_flag_needed_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include "confdefs.h" #ifdef HAVE_TIME_H @@ -6521,8 +6409,7 @@ fi fi rm -f conftest conftest.c conftest.o - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then @@ -6559,8 +6446,8 @@ cache=_D__EXTENSIONS__ if eval test \${cv_prog_cc_flag_needed_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include "confdefs.h" #include @@ -6605,8 +6492,7 @@ fi fi rm -f conftest conftest.c conftest.o - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then @@ -6662,8 +6548,8 @@ cache=`echo W | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -W -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -6671,8 +6557,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -6695,8 +6580,8 @@ cache=`echo Wall | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -Wall -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -6704,8 +6589,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -6728,8 +6612,8 @@ cache=`echo Wextra | sed 'y%.=/+-%___p_% if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -Wextra -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -6737,8 +6621,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -6761,8 +6644,8 @@ cache=`echo Wdeclaration-after-statement if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -Wdeclaration-after-statement -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -6770,8 +6653,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -6836,10 +6718,9 @@ printf "%s\n" "yes" >&6; } fi rm -f conftest conftest.c conftest.o -else case e in #( - e) CFLAGS="$BAKCFLAGS" ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } ;; -esac +else $as_nop + CFLAGS="$BAKCFLAGS" ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -6886,10 +6767,9 @@ printf "%s\n" "yes" >&6; } fi rm -f conftest conftest.c conftest.o -else case e in #( - e) LDFLAGS="$BAKLDFLAGS" ; CFLAGS="$BAKCFLAGS" ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } ;; -esac +else $as_nop + LDFLAGS="$BAKLDFLAGS" ; CFLAGS="$BAKCFLAGS" ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -6934,10 +6814,9 @@ printf "%s\n" "yes" >&6; } fi rm -f conftest conftest.c conftest.o -else case e in #( - e) LDFLAGS="$BAKLDFLAGS" ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } ;; -esac +else $as_nop + LDFLAGS="$BAKLDFLAGS" ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -6951,8 +6830,8 @@ printf %s "checking for inline... " >&6; if test ${ac_cv_c_inline+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_c_inline=no +else $as_nop + ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6970,8 +6849,7 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_inline" != no && break done - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 printf "%s\n" "$ac_cv_c_inline" >&6; } @@ -6997,8 +6875,8 @@ printf %s "checking whether the C compil if test ${ac_cv_c_format_attribute+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_c_format_attribute=no +else $as_nop + ac_cv_c_format_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -7018,13 +6896,11 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_format_attribute="yes" -else case e in #( - e) ac_cv_c_format_attribute="no" ;; -esac +else $as_nop + ac_cv_c_format_attribute="no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac + fi @@ -7042,8 +6918,8 @@ printf %s "checking whether the C compil if test ${ac_cv_c_unused_attribute+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_c_unused_attribute=no +else $as_nop + ac_cv_c_unused_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -7062,13 +6938,11 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_unused_attribute="yes" -else case e in #( - e) ac_cv_c_unused_attribute="no" ;; -esac +else $as_nop + ac_cv_c_unused_attribute="no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac + fi @@ -7084,14 +6958,65 @@ fi +BAKCFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $ERRFLAG" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"nonstring\" attribute" >&5 +printf %s "checking whether the C compiler (${CC-cc}) accepts the \"nonstring\" attribute... " >&6; } +if test ${ac_cv_c_nonstring_attribute+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_c_nonstring_attribute=no +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +struct test { + char __attribute__((nonstring)) s[1]; +}; + +int +main (void) +{ + + struct test t = { "1" }; + (void) t; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_c_nonstring_attribute="yes" +else $as_nop + ac_cv_c_nonstring_attribute="no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +CFLAGS="$BAKCFLAGS" + +fi + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_nonstring_attribute" >&5 +printf "%s\n" "$ac_cv_c_nonstring_attribute" >&6; } +if test $ac_cv_c_nonstring_attribute = yes; then + +printf "%s\n" "#define HAVE_ATTR_NONSTRING 1" >>confdefs.h + +fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"weak\" attribute" >&5 printf %s "checking whether the C compiler (${CC-cc}) accepts the \"weak\" attribute... " >&6; } if test ${ac_cv_c_weak_attribute+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_c_weak_attribute=no +else $as_nop + ac_cv_c_weak_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -7110,13 +7035,11 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_weak_attribute="yes" -else case e in #( - e) ac_cv_c_weak_attribute="no" ;; -esac +else $as_nop + ac_cv_c_weak_attribute="no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac + fi @@ -7143,12 +7066,19 @@ printf %s "checking whether the C compil if test ${ac_cv_c_noreturn_attribute+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_c_noreturn_attribute=no +else $as_nop + ac_cv_c_noreturn_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include -__attribute__((noreturn)) void f(int x) { printf("%d", x); } +#ifdef STDC_HEADERS +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +__attribute__((noreturn)) void f(int x) { printf("%d", x); exit(1); } int main (void) @@ -7163,13 +7093,11 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_noreturn_attribute="yes" -else case e in #( - e) ac_cv_c_noreturn_attribute="no" ;; -esac +else $as_nop + ac_cv_c_noreturn_attribute="no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac + fi @@ -7198,8 +7126,8 @@ CFLAGS="$CFLAGS -Werror" if test ${ac_cv_c_fallthrough_attribute+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_c_fallthrough_attribute=no +else $as_nop + ac_cv_c_fallthrough_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -7233,13 +7161,11 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_fallthrough_attribute="yes" -else case e in #( - e) ac_cv_c_fallthrough_attribute="no" ;; -esac +else $as_nop + ac_cv_c_fallthrough_attribute="no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac + fi CFLAGS="$BAKCFLAGS" @@ -7277,8 +7203,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_LEX+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$LEX"; then +else $as_nop + if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -7300,8 +7226,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then @@ -7359,8 +7284,8 @@ printf %s "checking for lex output file if test ${ac_cv_prog_lex_root+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + ac_cv_prog_lex_root=unknown { { ac_try="$LEX conftest.l" case "(($ac_try" in @@ -7377,8 +7302,7 @@ if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy -fi ;; -esac +fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 printf "%s\n" "$ac_cv_prog_lex_root" >&6; } @@ -7393,15 +7317,15 @@ LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test ${LEXLIB+y} then : -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lex library" >&5 printf %s "checking for lex library... " >&6; } if test ${ac_cv_lib_lex+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + ac_save_LIBS="$LIBS" ac_found=false for ac_cv_lib_lex in 'none needed' -lfl -ll 'not found'; do @@ -7431,8 +7355,7 @@ rm -f core conftest.err conftest.$ac_obj fi done LIBS="$ac_save_LIBS" - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 printf "%s\n" "$ac_cv_lib_lex" >&6; } @@ -7444,12 +7367,10 @@ printf "%s\n" "$as_me: WARNING: required elif test "$ac_cv_lib_lex" = 'none needed' then : LEXLIB='' -else case e in #( - e) LEXLIB=$ac_cv_lib_lex ;; -esac +else $as_nop + LEXLIB=$ac_cv_lib_lex fi - ;; -esac + fi @@ -7461,8 +7382,8 @@ printf %s "checking whether yytext is a if test ${ac_cv_prog_lex_yytext_pointer+y} then : printf %s "(cached) " >&6 -else case e in #( - e) # POSIX says lex can declare yytext either as a pointer or an array; the +else $as_nop + # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no @@ -7477,8 +7398,7 @@ then : ac_cv_prog_lex_yytext_pointer=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 printf "%s\n" "$ac_cv_prog_lex_yytext_pointer" >&6; } @@ -7538,8 +7458,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_YACC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$YACC"; then +else $as_nop + if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -7561,8 +7481,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then @@ -7590,8 +7509,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_doxygen+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$doxygen"; then +else $as_nop + if test -n "$doxygen"; then ac_cv_prog_doxygen="$doxygen" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -7613,8 +7532,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi doxygen=$ac_cv_prog_doxygen if test -n "$doxygen"; then @@ -7634,8 +7552,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$STRIP"; then +else $as_nop + if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -7657,8 +7575,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then @@ -7680,8 +7597,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_STRIP"; then +else $as_nop + if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -7703,8 +7620,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then @@ -7742,16 +7658,15 @@ printf %s "checking build system type... if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_build_alias=$build_alias +else $as_nop + ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } @@ -7778,15 +7693,14 @@ printf %s "checking host system type... if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test "x$host_alias" = x; then +else $as_nop + if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } @@ -7836,8 +7750,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_AR+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $AR in +else $as_nop + case $AR in [\\/]* | ?:[\\/]*) ac_cv_path_AR="$AR" # Let the user override the test with a path. ;; @@ -7862,7 +7776,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi AR=$ac_cv_path_AR @@ -7885,8 +7798,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_ac_pt_AR+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $ac_pt_AR in +else $as_nop + case $ac_pt_AR in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_AR="$ac_pt_AR" # Let the user override the test with a path. ;; @@ -7911,7 +7824,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi ac_pt_AR=$ac_cv_path_ac_pt_AR @@ -8043,8 +7955,8 @@ printf %s "checking for a sed that does if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ +else $as_nop + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done @@ -8069,10 +7981,9 @@ do as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in #( +case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -8107,8 +8018,7 @@ IFS=$as_save_IFS else ac_cv_path_SED=$SED fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } @@ -8133,8 +8043,8 @@ printf %s "checking for egrep... " >&6; if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 +else $as_nop + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then @@ -8156,10 +8066,9 @@ do as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in #( +case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -8195,23 +8104,20 @@ else ac_cv_path_EGREP=$EGREP fi - fi ;; -esac + fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" - EGREP_TRADITIONAL=$EGREP - ac_cv_path_EGREP_TRADITIONAL=$EGREP { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 printf %s "checking for fgrep... " >&6; } if test ${ac_cv_path_FGREP+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 +else $as_nop + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then @@ -8233,10 +8139,9 @@ do as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in #( +case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; -#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -8272,8 +8177,7 @@ else ac_cv_path_FGREP=$FGREP fi - fi ;; -esac + fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 printf "%s\n" "$ac_cv_path_FGREP" >&6; } @@ -8304,9 +8208,8 @@ test -z "$GREP" && GREP=grep if test ${with_gnu_ld+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes -else case e in #( - e) with_gnu_ld=no ;; -esac +else $as_nop + with_gnu_ld=no fi ac_prog=ld @@ -8351,8 +8254,8 @@ fi if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -z "$LD"; then +else $as_nop + if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs @@ -8375,8 +8278,7 @@ else case e in #( IFS=$lt_save_ifs else lt_cv_path_LD=$LD # Let the user override the test with a path. -fi ;; -esac +fi fi LD=$lt_cv_path_LD @@ -8393,8 +8295,8 @@ printf %s "checking if the linker ($LD) if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 -else case e in #( - e) # I'd rather use --version here, but apparently some GNU lds only accept -v. +else $as_nop + # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &1 &5 @@ -8422,8 +8323,8 @@ printf %s "checking for BSD- or MS-compa if test ${lt_cv_path_NM+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$NM"; then +else $as_nop + if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else @@ -8470,8 +8371,7 @@ else IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} -fi ;; -esac +fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 printf "%s\n" "$lt_cv_path_NM" >&6; } @@ -8492,8 +8392,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_DUMPBIN+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$DUMPBIN"; then +else $as_nop + if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -8515,8 +8415,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then @@ -8542,8 +8441,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_DUMPBIN+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_DUMPBIN"; then +else $as_nop + if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -8565,8 +8464,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then @@ -8620,8 +8518,8 @@ printf %s "checking the name lister ($NM if test ${lt_cv_nm_interface+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_nm_interface="BSD nm" +else $as_nop + lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) @@ -8634,8 +8532,7 @@ else case e in #( if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi - rm -f conftest* ;; -esac + rm -f conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 printf "%s\n" "$lt_cv_nm_interface" >&6; } @@ -8657,8 +8554,8 @@ printf %s "checking the maximum length o if test ${lt_cv_sys_max_cmd_len+y} then : printf %s "(cached) " >&6 -else case e in #( - e) i=0 +else $as_nop + i=0 teststring=ABCD case $build_os in @@ -8780,8 +8677,7 @@ else case e in #( fi ;; esac - ;; -esac + fi if test -n "$lt_cv_sys_max_cmd_len"; then @@ -8838,8 +8734,8 @@ printf %s "checking how to convert $buil if test ${lt_cv_to_host_file_cmd+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $host in +else $as_nop + case $host in *-*-mingw* ) case $build in *-*-mingw* | *-*-windows* ) # actually msys @@ -8870,8 +8766,7 @@ else case e in #( lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac - ;; -esac + fi to_host_file_cmd=$lt_cv_to_host_file_cmd @@ -8887,8 +8782,8 @@ printf %s "checking how to convert $buil if test ${lt_cv_to_tool_file_cmd+y} then : printf %s "(cached) " >&6 -else case e in #( - e) #assume ordinary cross tools, or native build. +else $as_nop + #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* | *-*-windows* ) @@ -8899,8 +8794,7 @@ case $host in esac ;; esac - ;; -esac + fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd @@ -8916,9 +8810,8 @@ printf %s "checking for $LD option to re if test ${lt_cv_ld_reload_flag+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_ld_reload_flag='-r' ;; -esac +else $as_nop + lt_cv_ld_reload_flag='-r' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 printf "%s\n" "$lt_cv_ld_reload_flag" >&6; } @@ -8958,8 +8851,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_FILECMD+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$FILECMD"; then +else $as_nop + if test -n "$FILECMD"; then ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -8982,8 +8875,7 @@ done IFS=$as_save_IFS test -z "$ac_cv_prog_FILECMD" && ac_cv_prog_FILECMD=":" -fi ;; -esac +fi fi FILECMD=$ac_cv_prog_FILECMD if test -n "$FILECMD"; then @@ -9009,8 +8901,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_OBJDUMP+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$OBJDUMP"; then +else $as_nop + if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9032,8 +8924,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then @@ -9055,8 +8946,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_OBJDUMP+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_OBJDUMP"; then +else $as_nop + if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9078,8 +8969,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then @@ -9120,8 +9010,8 @@ printf %s "checking how to recognize dep if test ${lt_cv_deplibs_check_method+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_file_magic_cmd='$MAGIC_CMD' +else $as_nop + lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support @@ -9321,8 +9211,7 @@ os2*) lt_cv_deplibs_check_method=pass_all ;; esac - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 printf "%s\n" "$lt_cv_deplibs_check_method" >&6; } @@ -9374,8 +9263,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_DLLTOOL+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$DLLTOOL"; then +else $as_nop + if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9397,8 +9286,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then @@ -9420,8 +9308,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_DLLTOOL+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_DLLTOOL"; then +else $as_nop + if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9443,8 +9331,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then @@ -9486,8 +9373,8 @@ printf %s "checking how to associate run if test ${lt_cv_sharedlib_from_linklib_cmd+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_sharedlib_from_linklib_cmd='unknown' +else $as_nop + lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | windows* | pw32* | cegcc*) @@ -9507,8 +9394,7 @@ cygwin* | mingw* | windows* | pw32* | ce lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 printf "%s\n" "$lt_cv_sharedlib_from_linklib_cmd" >&6; } @@ -9529,8 +9415,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$RANLIB"; then +else $as_nop + if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9552,8 +9438,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then @@ -9575,8 +9460,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_RANLIB"; then +else $as_nop + if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9598,8 +9483,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then @@ -9635,8 +9519,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$AR"; then +else $as_nop + if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9658,8 +9542,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then @@ -9685,8 +9568,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_AR"; then +else $as_nop + if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9708,8 +9591,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then @@ -9771,8 +9653,8 @@ printf %s "checking for archiver @FILE s if test ${lt_cv_ar_at_file+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_ar_at_file=no +else $as_nop + lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9809,8 +9691,7 @@ then : fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 printf "%s\n" "$lt_cv_ar_at_file" >&6; } @@ -9835,8 +9716,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$STRIP"; then +else $as_nop + if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9858,8 +9739,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then @@ -9881,8 +9761,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_STRIP"; then +else $as_nop + if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9904,8 +9784,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then @@ -9992,8 +9871,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$AWK"; then +else $as_nop + if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10015,8 +9894,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then @@ -10065,8 +9943,8 @@ printf %s "checking command to parse $NM if test ${lt_cv_sys_global_symbol_pipe+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] @@ -10318,8 +10196,7 @@ _LT_EOF lt_cv_sys_global_symbol_pipe= fi done - ;; -esac + fi if test -z "$lt_cv_sys_global_symbol_pipe"; then @@ -10383,9 +10260,8 @@ printf %s "checking for sysroot... " >&6 if test ${with_sysroot+y} then : withval=$with_sysroot; -else case e in #( - e) with_sysroot=no ;; -esac +else $as_nop + with_sysroot=no fi @@ -10422,8 +10298,8 @@ printf %s "checking for a working dd... if test ${ac_cv_path_lt_DD+y} then : printf %s "(cached) " >&6 -else case e in #( - e) printf 0123456789abcdef0123456789abcdef >conftest.i +else $as_nop + printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then @@ -10459,8 +10335,7 @@ else ac_cv_path_lt_DD=$lt_DD fi -rm -f conftest.i conftest2.i conftest.out ;; -esac +rm -f conftest.i conftest2.i conftest.out fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 printf "%s\n" "$ac_cv_path_lt_DD" >&6; } @@ -10471,8 +10346,8 @@ printf %s "checking how to truncate bina if test ${lt_cv_truncate_bin+y} then : printf %s "(cached) " >&6 -else case e in #( - e) printf 0123456789abcdef0123456789abcdef >conftest.i +else $as_nop + printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then @@ -10480,8 +10355,7 @@ if "$ac_cv_path_lt_DD" bs=32 count=1 &5 printf "%s\n" "$lt_cv_truncate_bin" >&6; } @@ -10691,8 +10565,8 @@ printf %s "checking whether the C compil if test ${lt_cv_cc_needs_belf+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_ext=c +else $as_nop + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -10712,9 +10586,8 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_cc_needs_belf=yes -else case e in #( - e) lt_cv_cc_needs_belf=no ;; -esac +else $as_nop + lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -10723,8 +10596,7 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } @@ -10782,8 +10654,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$MANIFEST_TOOL"; then +else $as_nop + if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10805,8 +10677,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then @@ -10828,8 +10699,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_MANIFEST_TOOL"; then +else $as_nop + if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10851,8 +10722,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then @@ -10884,16 +10754,15 @@ printf %s "checking if $MANIFEST_TOOL is if test ${lt_cv_path_manifest_tool+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_path_manifest_tool=no +else $as_nop + lt_cv_path_manifest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_manifest_tool=yes fi - rm -f conftest* ;; -esac + rm -f conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_manifest_tool" >&5 printf "%s\n" "$lt_cv_path_manifest_tool" >&6; } @@ -10916,8 +10785,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_DSYMUTIL+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$DSYMUTIL"; then +else $as_nop + if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10939,8 +10808,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then @@ -10962,8 +10830,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_DSYMUTIL"; then +else $as_nop + if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10985,8 +10853,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then @@ -11020,8 +10887,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_NMEDIT+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$NMEDIT"; then +else $as_nop + if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11043,8 +10910,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then @@ -11066,8 +10932,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_NMEDIT+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_NMEDIT"; then +else $as_nop + if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11089,8 +10955,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then @@ -11124,8 +10989,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_LIPO+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$LIPO"; then +else $as_nop + if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11147,8 +11012,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then @@ -11170,8 +11034,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_LIPO+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_LIPO"; then +else $as_nop + if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11193,8 +11057,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then @@ -11228,8 +11091,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_OTOOL+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$OTOOL"; then +else $as_nop + if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11251,8 +11114,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then @@ -11274,8 +11136,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_OTOOL+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_OTOOL"; then +else $as_nop + if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11297,8 +11159,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then @@ -11332,8 +11193,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_OTOOL64+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$OTOOL64"; then +else $as_nop + if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11355,8 +11216,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then @@ -11378,8 +11238,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_OTOOL64+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_OTOOL64"; then +else $as_nop + if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11401,8 +11261,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then @@ -11459,8 +11318,8 @@ printf %s "checking for -single_module l if test ${lt_cv_apple_cc_single_mod+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_apple_cc_single_mod=no +else $as_nop + lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE @@ -11486,8 +11345,7 @@ else case e in #( fi rm -rf libconftest.dylib* rm -f conftest.* - fi ;; -esac + fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } @@ -11499,8 +11357,8 @@ printf %s "checking for -no_fixup_chains if test ${lt_cv_support_no_fixup_chains+y} then : printf %s "(cached) " >&6 -else case e in #( - e) save_LDFLAGS=$LDFLAGS +else $as_nop + save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-no_fixup_chains" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -11516,17 +11374,15 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_support_no_fixup_chains=yes -else case e in #( - e) lt_cv_support_no_fixup_chains=no - ;; -esac +else $as_nop + lt_cv_support_no_fixup_chains=no + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_support_no_fixup_chains" >&5 printf "%s\n" "$lt_cv_support_no_fixup_chains" >&6; } @@ -11536,8 +11392,8 @@ printf %s "checking for -exported_symbol if test ${lt_cv_ld_exported_symbols_list+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_ld_exported_symbols_list=no +else $as_nop + lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" @@ -11555,15 +11411,13 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_ld_exported_symbols_list=yes -else case e in #( - e) lt_cv_ld_exported_symbols_list=no ;; -esac +else $as_nop + lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } @@ -11573,8 +11427,8 @@ printf %s "checking for -force_load link if test ${lt_cv_ld_force_load+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_ld_force_load=no +else $as_nop + lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF @@ -11599,8 +11453,7 @@ _LT_EOF fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 printf "%s\n" "$lt_cv_ld_force_load" >&6; } @@ -11732,9 +11585,8 @@ then : IFS=$lt_save_ifs ;; esac -else case e in #( - e) enable_shared=yes ;; -esac +else $as_nop + enable_shared=yes fi @@ -11765,9 +11617,8 @@ then : IFS=$lt_save_ifs ;; esac -else case e in #( - e) enable_static=yes ;; -esac +else $as_nop + enable_static=yes fi @@ -11797,8 +11648,8 @@ then : IFS=$lt_save_ifs ;; esac -else case e in #( - e) # Check whether --with-pic was given. +else $as_nop + # Check whether --with-pic was given. if test ${with_pic+y} then : withval=$with_pic; lt_p=${PACKAGE-default} @@ -11817,13 +11668,11 @@ then : IFS=$lt_save_ifs ;; esac -else case e in #( - e) pic_mode=default ;; -esac +else $as_nop + pic_mode=default fi - ;; -esac + fi @@ -11853,9 +11702,8 @@ then : IFS=$lt_save_ifs ;; esac -else case e in #( - e) enable_fast_install=yes ;; -esac +else $as_nop + enable_fast_install=yes fi @@ -11881,8 +11729,8 @@ then : ;; esac lt_cv_with_aix_soname=$enable_aix_soname -else case e in #( - e) # Check whether --with-aix-soname was given. +else $as_nop + # Check whether --with-aix-soname was given. if test ${with_aix_soname+y} then : withval=$with_aix_soname; case $withval in @@ -11893,20 +11741,17 @@ then : ;; esac lt_cv_with_aix_soname=$with_aix_soname -else case e in #( - e) if test ${lt_cv_with_aix_soname+y} +else $as_nop + if test ${lt_cv_with_aix_soname+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_with_aix_soname=aix ;; -esac +else $as_nop + lt_cv_with_aix_soname=aix fi - ;; -esac + fi - enable_aix_soname=$lt_cv_with_aix_soname ;; -esac + enable_aix_soname=$lt_cv_with_aix_soname fi with_aix_soname=$enable_aix_soname @@ -11998,8 +11843,8 @@ printf %s "checking for objdir... " >&6; if test ${lt_cv_objdir+y} then : printf %s "(cached) " >&6 -else case e in #( - e) rm -f .libs 2>/dev/null +else $as_nop + rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs @@ -12007,8 +11852,7 @@ else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi -rmdir .libs 2>/dev/null ;; -esac +rmdir .libs 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 printf "%s\n" "$lt_cv_objdir" >&6; } @@ -12069,8 +11913,8 @@ printf %s "checking for ${ac_tool_prefix if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $MAGIC_CMD in +else $as_nop + case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; @@ -12113,7 +11957,6 @@ _LT_EOF IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; -esac ;; esac fi @@ -12137,8 +11980,8 @@ printf %s "checking for file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $MAGIC_CMD in +else $as_nop + case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; @@ -12181,7 +12024,6 @@ _LT_EOF IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; -esac ;; esac fi @@ -12277,8 +12119,8 @@ printf %s "checking if $compiler support if test ${lt_cv_prog_compiler_rtti_exceptions+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_rtti_exceptions=no +else $as_nop + lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment @@ -12306,8 +12148,7 @@ else case e in #( fi fi $RM conftest* - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } @@ -12687,9 +12528,8 @@ printf %s "checking for $compiler option if test ${lt_cv_prog_compiler_pic+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac +else $as_nop + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; } @@ -12704,8 +12544,8 @@ printf %s "checking if $compiler PIC fla if test ${lt_cv_prog_compiler_pic_works+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_pic_works=no +else $as_nop + lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment @@ -12733,8 +12573,7 @@ else case e in #( fi fi $RM conftest* - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } @@ -12770,8 +12609,8 @@ printf %s "checking if $compiler static if test ${lt_cv_prog_compiler_static_works+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_static_works=no +else $as_nop + lt_cv_prog_compiler_static_works=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext @@ -12792,8 +12631,7 @@ else case e in #( fi $RM -r conftest* LDFLAGS=$save_LDFLAGS - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } @@ -12815,8 +12653,8 @@ printf %s "checking if $compiler support if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_c_o=no +else $as_nop + lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest @@ -12856,8 +12694,7 @@ else case e in #( cd .. $RM -r conftest $RM conftest* - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } @@ -12872,8 +12709,8 @@ printf %s "checking if $compiler support if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_c_o=no +else $as_nop + lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest @@ -12913,8 +12750,7 @@ else case e in #( cd .. $RM -r conftest $RM conftest* - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } @@ -13513,8 +13349,8 @@ else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -13546,8 +13382,7 @@ rm -f core conftest.err conftest.$ac_obj if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi - ;; -esac + fi aix_libpath=$lt_cv_aix_libpath_ @@ -13569,8 +13404,8 @@ else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -13602,8 +13437,7 @@ rm -f core conftest.err conftest.$ac_obj if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi - ;; -esac + fi aix_libpath=$lt_cv_aix_libpath_ @@ -13854,8 +13688,8 @@ printf %s "checking if $CC understands - if test ${lt_cv_prog_compiler__b+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler__b=no +else $as_nop + lt_cv_prog_compiler__b=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext @@ -13876,8 +13710,7 @@ else case e in #( fi $RM -r conftest* LDFLAGS=$save_LDFLAGS - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } @@ -13925,8 +13758,8 @@ printf %s "checking whether the $host_os if test ${lt_cv_irix_exported_symbol+y} then : printf %s "(cached) " >&6 -else case e in #( - e) save_LDFLAGS=$LDFLAGS +else $as_nop + save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -13935,14 +13768,12 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_irix_exported_symbol=yes -else case e in #( - e) lt_cv_irix_exported_symbol=no ;; -esac +else $as_nop + lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS ;; -esac + LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } @@ -14275,8 +14106,8 @@ printf %s "checking whether -lc should b if test ${lt_cv_archive_cmds_need_lc+y} then : printf %s "(cached) " >&6 -else case e in #( - e) $RM conftest* +else $as_nop + $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 @@ -14312,8 +14143,7 @@ else case e in #( cat conftest.err 1>&5 fi $RM conftest* - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } @@ -14894,9 +14724,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : shlibpath_var=LD_LIBRARY_PATH -else case e in #( - e) shlibpath_var=LD_32_LIBRARY_PATH ;; -esac +else $as_nop + shlibpath_var=LD_32_LIBRARY_PATH fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -15077,8 +14906,8 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu if test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_shlibpath_overrides_runpath=no +else $as_nop + lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ @@ -15105,8 +14934,7 @@ rm -f core conftest.err conftest.$ac_obj conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir - ;; -esac + fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath @@ -15738,9 +15566,8 @@ printf %s "checking for $compiler option if test ${lt_cv_prog_compiler_pic+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; -esac +else $as_nop + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; } @@ -15755,8 +15582,8 @@ printf %s "checking if $compiler PIC fla if test ${lt_cv_prog_compiler_pic_works+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_pic_works=no +else $as_nop + lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment @@ -15784,8 +15611,7 @@ else case e in #( fi fi $RM conftest* - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } @@ -15815,8 +15641,8 @@ printf %s "checking if $compiler static if test ${lt_cv_prog_compiler_static_works+y} then : printf %s "(cached) " >&6 -else case e in #( - e) lt_cv_prog_compiler_static_works=no +else $as_nop + lt_cv_prog_compiler_static_works=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext @@ -15837,8 +15663,7 @@ else case e in #( fi $RM -r conftest* LDFLAGS=$save_LDFLAGS - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } @@ -16059,22 +15884,16 @@ printf %s "checking for dlopen in -ldl.. if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); + builtin and then its argument prototype would still apply. */ +char dlopen (); int main (void) { @@ -16086,27 +15905,24 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes -else case e in #( - e) ac_cv_lib_dl_dlopen=no ;; -esac +else $as_nop + ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in #( - e) +else $as_nop + lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes - ;; -esac + fi ;; @@ -16124,28 +15940,22 @@ fi if test "x$ac_cv_func_shl_load" = xyes then : lt_cv_dlopen=shl_load -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (void); + builtin and then its argument prototype would still apply. */ +char shl_load (); int main (void) { @@ -16157,47 +15967,39 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes -else case e in #( - e) ac_cv_lib_dld_shl_load=no ;; -esac +else $as_nop + ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes then : lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld -else case e in #( - e) ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +else $as_nop + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes then : lt_cv_dlopen=dlopen -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); + builtin and then its argument prototype would still apply. */ +char dlopen (); int main (void) { @@ -16209,42 +16011,34 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes -else case e in #( - e) ac_cv_lib_dl_dlopen=no ;; -esac +else $as_nop + ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 printf %s "checking for dlopen in -lsvld... " >&6; } if test ${ac_cv_lib_svld_dlopen+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); + builtin and then its argument prototype would still apply. */ +char dlopen (); int main (void) { @@ -16256,42 +16050,34 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_svld_dlopen=yes -else case e in #( - e) ac_cv_lib_svld_dlopen=no ;; -esac +else $as_nop + ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 printf "%s\n" "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 printf %s "checking for dld_link in -ldld... " >&6; } if test ${ac_cv_lib_dld_dld_link+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (void); + builtin and then its argument prototype would still apply. */ +char dld_link (); int main (void) { @@ -16303,14 +16089,12 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_dld_link=yes -else case e in #( - e) ac_cv_lib_dld_dld_link=no ;; -esac +else $as_nop + ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 printf "%s\n" "$ac_cv_lib_dld_dld_link" >&6; } @@ -16319,24 +16103,19 @@ then : lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld fi - ;; -esac + fi - ;; -esac + fi - ;; -esac + fi - ;; -esac + fi - ;; -esac + fi ;; @@ -16364,8 +16143,8 @@ printf %s "checking whether a program ca if test ${lt_cv_dlopen_self+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test yes = "$cross_compiling"; then : +else $as_nop + if test yes = "$cross_compiling"; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 @@ -16459,8 +16238,7 @@ _LT_EOF fi rm -fr conftest* - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 printf "%s\n" "$lt_cv_dlopen_self" >&6; } @@ -16472,8 +16250,8 @@ printf %s "checking whether a statically if test ${lt_cv_dlopen_self_static+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test yes = "$cross_compiling"; then : +else $as_nop + if test yes = "$cross_compiling"; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 @@ -16567,8 +16345,7 @@ _LT_EOF fi rm -fr conftest* - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 printf "%s\n" "$lt_cv_dlopen_self_static" >&6; } @@ -16754,8 +16531,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_PKG_CONFIG+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $PKG_CONFIG in +else $as_nop + case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; @@ -16780,7 +16557,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG @@ -16803,8 +16579,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $ac_pt_PKG_CONFIG in +else $as_nop + case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; @@ -16829,7 +16605,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG @@ -16988,6 +16763,13 @@ then : printf "%s\n" "#define HAVE_GLOB_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "fnmatch.h" "ac_cv_header_fnmatch_h" "$ac_includes_default +" +if test "x$ac_cv_header_fnmatch_h" = xyes +then : + printf "%s\n" "#define HAVE_FNMATCH_H 1" >>confdefs.h + +fi ac_fn_c_check_header_compile "$LINENO" "grp.h" "ac_cv_header_grp_h" "$ac_includes_default " if test "x$ac_cv_header_grp_h" = xyes @@ -17164,182 +16946,312 @@ ac_fn_c_check_type "$LINENO" "int8_t" "a if test "x$ac_cv_type_int8_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define int8_t signed char" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "int16_t" "ac_cv_type_int16_t" "$ac_includes_default" if test "x$ac_cv_type_int16_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define int16_t short" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "int32_t" "ac_cv_type_int32_t" "$ac_includes_default" if test "x$ac_cv_type_int32_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define int32_t int" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "int64_t" "ac_cv_type_int64_t" "$ac_includes_default" if test "x$ac_cv_type_int64_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define int64_t long long" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "uint8_t" "ac_cv_type_uint8_t" "$ac_includes_default" if test "x$ac_cv_type_uint8_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define uint8_t unsigned char" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "uint16_t" "ac_cv_type_uint16_t" "$ac_includes_default" if test "x$ac_cv_type_uint16_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define uint16_t unsigned short" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "$ac_includes_default" if test "x$ac_cv_type_uint32_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define uint32_t unsigned int" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "$ac_includes_default" if test "x$ac_cv_type_uint64_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define uint64_t unsigned long long" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define size_t unsigned int" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = xyes then : -else case e in #( - e) -printf "%s\n" "#define ssize_t int" >>confdefs.h - ;; -esac -fi +else $as_nop -ac_fn_c_check_type "$LINENO" "uid_t" "ac_cv_type_uid_t" "$ac_includes_default" -if test "x$ac_cv_type_uid_t" = xyes -then : +printf "%s\n" "#define ssize_t int" >>confdefs.h -else case e in #( - e) -printf "%s\n" "#define uid_t int" >>confdefs.h - ;; -esac fi -ac_fn_c_check_type "$LINENO" "gid_t" "ac_cv_type_gid_t" "$ac_includes_default" -if test "x$ac_cv_type_gid_t" = xyes -then : - -else case e in #( - e) -printf "%s\n" "#define gid_t int" >>confdefs.h - ;; -esac +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +printf %s "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= fi - - - ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default -" -if test "x$ac_cv_type_pid_t" = xyes +if test -z "$CPP"; then + if test ${ac_cv_prog_CPP+y} then : - -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + printf %s "(cached) " >&6 +else $as_nop + # Double quotes because $CC needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ +#include + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : - #if defined _WIN64 && !defined __CYGWIN__ - LLP64 - #endif - -int -main (void) -{ - - ; - return 0; -} +else $as_nop + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_cpp "$LINENO" then : - ac_pid_type='int' -else case e in #( - e) ac_pid_type='__int64' ;; -esac + # Broken: success on invalid input. +continue +else $as_nop + # Passes both tests. +ac_preproc_ok=: +break fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - -printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h +rm -f conftest.err conftest.i conftest.$ac_ext - ;; -esac +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok +then : + break fi + done + ac_cv_prog_CPP=$CPP -ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +printf "%s\n" "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + +else $as_nop + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + # Broken: success on invalid input. +continue +else $as_nop + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok +then : + +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 +printf %s "checking for uid_t in sys/types.h... " >&6; } +if test ${ac_cv_type_uid_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "uid_t" >/dev/null 2>&1 +then : + ac_cv_type_uid_t=yes +else $as_nop + ac_cv_type_uid_t=no +fi +rm -rf conftest* + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 +printf "%s\n" "$ac_cv_type_uid_t" >&6; } +if test $ac_cv_type_uid_t = no; then + +printf "%s\n" "#define uid_t int" >>confdefs.h + + +printf "%s\n" "#define gid_t int" >>confdefs.h + +fi + + + ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default +" +if test "x$ac_cv_type_pid_t" = xyes +then : + +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #if defined _WIN64 && !defined __CYGWIN__ + LLP64 + #endif + +int +main (void) +{ + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_pid_type='int' +else $as_nop + ac_pid_type='__int64' +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h + + +fi + + +ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define off_t long int" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "u_char" "ac_cv_type_u_char" " @@ -17352,11 +17264,10 @@ $ac_includes_default if test "x$ac_cv_type_u_char" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define u_char unsigned char" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "rlim_t" "ac_cv_type_rlim_t" " @@ -17369,11 +17280,10 @@ $ac_includes_default if test "x$ac_cv_type_rlim_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define rlim_t unsigned long" >>confdefs.h - ;; -esac + fi @@ -17390,11 +17300,10 @@ $ac_includes_default if test "x$ac_cv_type_socklen_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define socklen_t int" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "in_addr_t" "ac_cv_type_in_addr_t" " @@ -17410,11 +17319,10 @@ $ac_includes_default if test "x$ac_cv_type_in_addr_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define in_addr_t uint32_t" >>confdefs.h - ;; -esac + fi ac_fn_c_check_type "$LINENO" "in_port_t" "ac_cv_type_in_port_t" " @@ -17430,11 +17338,10 @@ $ac_includes_default if test "x$ac_cv_type_in_port_t" = xyes then : -else case e in #( - e) +else $as_nop + printf "%s\n" "#define in_port_t uint16_t" >>confdefs.h - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if memcmp compares unsigned" >&5 @@ -17453,8 +17360,8 @@ printf "%s\n" "#define MEMCMP_IS_BROKEN esac -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -17473,8 +17380,8 @@ if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "#define MEMCMP_IS_BROKEN 1" >>confdefs.h @@ -17485,26 +17392,24 @@ printf "%s\n" "#define MEMCMP_IS_BROKEN ;; esac - ;; -esac + fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac + conftest.$ac_objext conftest.beam conftest.$ac_ext fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 printf %s "checking size of time_t... " >&6; } if test ${ac_cv_sizeof_time_t+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " $ac_includes_default #ifdef TIME_WITH_SYS_TIME # include @@ -17520,19 +17425,17 @@ $ac_includes_default " then : -else case e in #( - e) if test "$ac_cv_type_time_t" = yes; then - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +else $as_nop + if test "$ac_cv_type_time_t" = yes; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (time_t) -See 'config.log' for more details" "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_time_t=0 - fi ;; -esac + fi fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 printf "%s\n" "$ac_cv_sizeof_time_t" >&6; } @@ -17544,30 +17447,28 @@ printf "%s\n" "#define SIZEOF_TIME_T $ac # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 printf %s "checking size of size_t... " >&6; } if test ${ac_cv_sizeof_size_t+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default" +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default" then : -else case e in #( - e) if test "$ac_cv_type_size_t" = yes; then - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +else $as_nop + if test "$ac_cv_type_size_t" = yes; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (size_t) -See 'config.log' for more details" "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_size_t=0 - fi ;; -esac + fi fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 printf "%s\n" "$ac_cv_sizeof_size_t" >&6; } @@ -17584,9 +17485,8 @@ printf "%s\n" "#define SIZEOF_SIZE_T $ac if test ${enable_rpath+y} then : enableval=$enable_rpath; enable_rpath=$enableval -else case e in #( - e) enable_rpath=yes ;; -esac +else $as_nop + enable_rpath=yes fi if test "x$enable_rpath" = xno; then @@ -17602,21 +17502,15 @@ printf %s "checking for library containi if test ${ac_cv_search_inet_pton+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char inet_pton (void); + builtin and then its argument prototype would still apply. */ +char inet_pton (); int main (void) { @@ -17647,13 +17541,11 @@ done if test ${ac_cv_search_inet_pton+y} then : -else case e in #( - e) ac_cv_search_inet_pton=no ;; -esac +else $as_nop + ac_cv_search_inet_pton=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_pton" >&5 printf "%s\n" "$ac_cv_search_inet_pton" >&6; } @@ -17669,21 +17561,15 @@ printf %s "checking for library containi if test ${ac_cv_search_socket+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char socket (void); + builtin and then its argument prototype would still apply. */ +char socket (); int main (void) { @@ -17714,13 +17600,11 @@ done if test ${ac_cv_search_socket+y} then : -else case e in #( - e) ac_cv_search_socket=no ;; -esac +else $as_nop + ac_cv_search_socket=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 printf "%s\n" "$ac_cv_search_socket" >&6; } @@ -17740,8 +17624,8 @@ printf %s "checking for working chown... if test ${ac_cv_func_chown_works+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test "$cross_compiling" = yes +else $as_nop + if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on glibc systems. @@ -17749,8 +17633,8 @@ then : # If we don't know, assume the worst. *) ac_cv_func_chown_works=no ;; esac -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include @@ -17778,18 +17662,15 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_chown_works=yes -else case e in #( - e) ac_cv_func_chown_works=no ;; -esac +else $as_nop + ac_cv_func_chown_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac + conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f conftest.chown - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5 printf "%s\n" "$ac_cv_func_chown_works" >&6; } @@ -17822,19 +17703,19 @@ printf %s "checking for working fork... if test ${ac_cv_func_fork_works+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test "$cross_compiling" = yes +else $as_nop + if test "$cross_compiling" = yes then : ac_cv_func_fork_works=cross -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { - /* By R. Kuhlmann. */ + /* By Ruediger Kuhlmann. */ return fork () < 0; ; @@ -17844,16 +17725,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_fork_works=yes -else case e in #( - e) ac_cv_func_fork_works=no ;; -esac +else $as_nop + ac_cv_func_fork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac + conftest.$ac_objext conftest.beam conftest.$ac_ext fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 printf "%s\n" "$ac_cv_func_fork_works" >&6; } @@ -17881,12 +17759,12 @@ printf %s "checking for working vfork... if test ${ac_cv_func_vfork_works+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test "$cross_compiling" = yes +else $as_nop + if test "$cross_compiling" = yes then : ac_cv_func_vfork_works=cross -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default @@ -17997,16 +17875,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_vfork_works=yes -else case e in #( - e) ac_cv_func_vfork_works=no ;; -esac +else $as_nop + ac_cv_func_vfork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac + conftest.$ac_objext conftest.beam conftest.$ac_ext fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 printf "%s\n" "$ac_cv_func_vfork_works" >&6; } @@ -18036,97 +17911,72 @@ fi printf "%s\n" "#define RETSIGTYPE void" >>confdefs.h -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for declarations of fseeko and ftello" >&5 -printf %s "checking for declarations of fseeko and ftello... " >&6; } -if test ${ac_cv_func_fseeko_ftello+y} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 +printf %s "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } +if test ${ac_cv_sys_largefile_source+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - -#if defined __hpux && !defined _LARGEFILE_SOURCE -# include -# if LONG_MAX >> 31 == 0 -# error "32-bit HP-UX 11/ia64 needs _LARGEFILE_SOURCE for fseeko in C++" -# endif -#endif #include /* for off_t */ -#include - + #include int main (void) { - - int (*fp1) (FILE *, off_t, int) = fseeko; - off_t (*fp2) (FILE *) = ftello; - return fseeko (stdin, 0, 0) - && fp1 (stdin, 0, 0) - && ftello (stdin) >= 0 - && fp2 (stdin) >= 0; - +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : - ac_cv_func_fseeko_ftello=yes -else case e in #( - e) ac_save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS -D_LARGEFILE_SOURCE=1" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + ac_cv_sys_largefile_source=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - -#if defined __hpux && !defined _LARGEFILE_SOURCE -# include -# if LONG_MAX >> 31 == 0 -# error "32-bit HP-UX 11/ia64 needs _LARGEFILE_SOURCE for fseeko in C++" -# endif -#endif +#define _LARGEFILE_SOURCE 1 #include /* for off_t */ -#include - + #include int main (void) { - - int (*fp1) (FILE *, off_t, int) = fseeko; - off_t (*fp2) (FILE *) = ftello; - return fseeko (stdin, 0, 0) - && fp1 (stdin, 0, 0) - && ftello (stdin) >= 0 - && fp2 (stdin) >= 0; - +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : - ac_cv_func_fseeko_ftello="need _LARGEFILE_SOURCE" -else case e in #( - e) ac_cv_func_fseeko_ftello=no ;; -esac + ac_cv_sys_largefile_source=1; break fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + ac_cv_sys_largefile_source=unknown + break +done fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 +printf "%s\n" "$ac_cv_sys_largefile_source" >&6; } +case $ac_cv_sys_largefile_source in #( + no | unknown) ;; + *) +printf "%s\n" "#define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source" >>confdefs.h +;; esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fseeko_ftello" >&5 -printf "%s\n" "$ac_cv_func_fseeko_ftello" >&6; } -if test "$ac_cv_func_fseeko_ftello" != no -then : - -printf "%s\n" "#define HAVE_FSEEKO 1" >>confdefs.h +rm -rf conftest* -fi -if test "$ac_cv_func_fseeko_ftello" = "need _LARGEFILE_SOURCE" -then : +# We used to try defining _XOPEN_SOURCE=500 too, to work around a bug +# in glibc 2.1.3, but that breaks too many other things. +# If you want fseeko and ftello with glibc, upgrade to a fixed glibc. +if test $ac_cv_sys_largefile_source != unknown; then -printf "%s\n" "#define _LARGEFILE_SOURCE 1" >>confdefs.h +printf "%s\n" "#define HAVE_FSEEKO 1" >>confdefs.h fi @@ -18136,34 +17986,31 @@ if test ${enable_largefile+y} then : enableval=$enable_largefile; fi -if test "$enable_largefile,$enable_year2038" != no,no -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable large file support" >&5 -printf %s "checking for $CC option to enable large file support... " >&6; } -if test ${ac_cv_sys_largefile_opts+y} + +if test "$enable_largefile" != no; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +printf %s "checking for special C compiler options needed for large files... " >&6; } +if test ${ac_cv_sys_largefile_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_save_CC="$CC" - ac_opt_found=no - for ac_opt in "none needed" "-D_FILE_OFFSET_BITS=64" "-D_LARGE_FILES=1" "-n32"; do - if test x"$ac_opt" != x"none needed" -then : - CC="$ac_save_CC $ac_opt" -fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include -#ifndef FTYPE -# define FTYPE off_t -#endif - /* Check that FTYPE can represent 2**63 - 1 correctly. - We can't simply define LARGE_FTYPE to be 9223372036854775807, + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_FTYPE (((FTYPE) 1 << 31 << 31) - 1 + ((FTYPE) 1 << 31 << 31)) - int FTYPE_is_large[(LARGE_FTYPE % 2147483629 == 721 - && LARGE_FTYPE % 2147483647 == 1) +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) @@ -18173,88 +18020,72 @@ main (void) return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - if test x"$ac_opt" = x"none needed" -then : - # GNU/Linux s390x and alpha need _FILE_OFFSET_BITS=64 for wide ino_t. - CC="$CC -DFTYPE=ino_t" if ac_fn_c_try_compile "$LINENO" then : - -else case e in #( - e) CC="$CC -D_FILE_OFFSET_BITS=64" - if ac_fn_c_try_compile "$LINENO" -then : - ac_opt='-D_FILE_OFFSET_BITS=64' -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam ;; -esac + break fi rm -f core conftest.err conftest.$ac_objext conftest.beam + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_largefile_CC=' -n32'; break fi - ac_cv_sys_largefile_opts=$ac_opt - ac_opt_found=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - test $ac_opt_found = no || break - done - CC="$ac_save_CC" - - test $ac_opt_found = yes || ac_cv_sys_largefile_opts="support not detected" ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_opts" >&5 -printf "%s\n" "$ac_cv_sys_largefile_opts" >&6; } - -ac_have_largefile=yes -case $ac_cv_sys_largefile_opts in #( - "none needed") : - ;; #( - "supported through gnulib") : - ;; #( - "support not detected") : - ac_have_largefile=no ;; #( - "-D_FILE_OFFSET_BITS=64") : - -printf "%s\n" "#define _FILE_OFFSET_BITS 64" >>confdefs.h - ;; #( - "-D_LARGE_FILES=1") : - -printf "%s\n" "#define _LARGE_FILES 1" >>confdefs.h - ;; #( - "-n32") : - CC="$CC -n32" ;; #( - *) : - as_fn_error $? "internal error: bad value for \$ac_cv_sys_largefile_opts" "$LINENO" 5 ;; -esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi -if test "$enable_year2038" != no -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option for timestamps after 2038" >&5 -printf %s "checking for $CC option for timestamps after 2038... " >&6; } -if test ${ac_cv_sys_year2038_opts+y} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if test ${ac_cv_sys_file_offset_bits+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_save_CPPFLAGS="$CPPFLAGS" - ac_opt_found=no - for ac_opt in "none needed" "-D_TIME_BITS=64" "-D__MINGW_USE_VC2005_COMPAT" "-U_USE_32_BIT_TIME_T -D__MINGW_USE_VC2005_COMPAT"; do - if test x"$ac_opt" != x"none needed" +else $as_nop + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" then : - CPPFLAGS="$ac_save_CPPFLAGS $ac_opt" + ac_cv_sys_file_offset_bits=no; break fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - - #include - /* Check that time_t can represent 2**32 - 1 correctly. */ - #define LARGE_TIME_T \\ - ((time_t) (((time_t) 1 << 30) - 1 + 3 * ((time_t) 1 << 30))) - int verify_time_t_range[(LARGE_TIME_T / 65537 == 65535 - && LARGE_TIME_T % 65537 == 0) - ? 1 : -1]; - +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; int main (void) { @@ -18265,47 +18096,95 @@ main (void) _ACEOF if ac_fn_c_try_compile "$LINENO" then : - ac_cv_sys_year2038_opts="$ac_opt" - ac_opt_found=yes + ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - test $ac_opt_found = no || break - done - CPPFLAGS="$ac_save_CPPFLAGS" - test $ac_opt_found = yes || ac_cv_sys_year2038_opts="support not detected" ;; -esac + ac_cv_sys_file_offset_bits=unknown + break +done fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_year2038_opts" >&5 -printf "%s\n" "$ac_cv_sys_year2038_opts" >&6; } - -ac_have_year2038=yes -case $ac_cv_sys_year2038_opts in #( - "none needed") : - ;; #( - "support not detected") : - ac_have_year2038=no ;; #( - "-D_TIME_BITS=64") : - -printf "%s\n" "#define _TIME_BITS 64" >>confdefs.h - ;; #( - "-D__MINGW_USE_VC2005_COMPAT") : - -printf "%s\n" "#define __MINGW_USE_VC2005_COMPAT 1" >>confdefs.h - ;; #( - "-U_USE_32_BIT_TIME_T"*) : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "the 'time_t' type is currently forced to be 32-bit. It -will stop working after mid-January 2038. Remove -_USE_32BIT_TIME_T from the compiler flags. -See 'config.log' for more details" "$LINENO" 5; } ;; #( - *) : - as_fn_error $? "internal error: bad value for \$ac_cv_sys_year2038_opts" "$LINENO" 5 ;; +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h +;; esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +printf %s "checking for _LARGE_FILES value needed for large files... " >&6; } +if test ${ac_cv_sys_large_files+y} +then : + printf %s "(cached) " >&6 +else $as_nop + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main (void) +{ + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_large_files=no; break fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main (void) +{ + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_large_files=1; break fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +printf "%s\n" "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h +;; +esac +rm -rf conftest* + fi +fi + @@ -18315,8 +18194,8 @@ cache=_D_LARGEFILE_SOURCE_1 if eval test \${cv_prog_cc_flag_needed_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include int test(void) { @@ -18342,8 +18221,7 @@ fi fi rm -f conftest conftest.c conftest.o - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then @@ -18387,8 +18265,8 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: crosscompile(yes)" >&5 printf "%s\n" "crosscompile(yes)" >&6; } -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18523,19 +18401,17 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "#define NONBLOCKING_IS_BROKEN 1" >>confdefs.h - ;; -esac + fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac + conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi @@ -18573,11 +18449,10 @@ printf "%s\n" "yes" >&6; } printf "%s\n" "#define MKDIR_HAS_ONE_ARG 1" >>confdefs.h -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext @@ -18595,8 +18470,8 @@ if test c${cross_compiling} = cno; then if test "$cross_compiling" = yes then : eval "ac_cv_c_strptime_works=maybe" -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 600 @@ -18611,13 +18486,11 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : eval "ac_cv_c_strptime_works=yes" -else case e in #( - e) eval "ac_cv_c_strptime_works=no" ;; -esac +else $as_nop + eval "ac_cv_c_strptime_works=no" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac + conftest.$ac_objext conftest.beam conftest.$ac_ext fi else @@ -18638,14 +18511,13 @@ printf "%s\n" "#define STRPTIME_WORKS 1" fi -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" strptime.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strptime.$ac_objext" ;; esac - ;; -esac + fi done @@ -18672,9 +18544,8 @@ fi if test ${enable_systemd+y} then : enableval=$enable_systemd; -else case e in #( - e) enable_systemd=no ;; -esac +else $as_nop + enable_systemd=no fi have_systemd=no @@ -18755,8 +18626,8 @@ See the pkg-config man page for more det elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. @@ -18766,7 +18637,7 @@ and SYSTEMD_LIBS to avoid the need to ca See the pkg-config man page for more details. To get pkg-config, see . -See 'config.log' for more details" "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } else SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS @@ -18850,8 +18721,8 @@ See the pkg-config man page for more det elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. @@ -18861,7 +18732,7 @@ and SYSTEMD_DAEMON_LIBS to avoid the nee See the pkg-config man page for more details. To get pkg-config, see . -See 'config.log' for more details" "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } else SYSTEMD_DAEMON_CFLAGS=$pkg_cv_SYSTEMD_DAEMON_CFLAGS SYSTEMD_DAEMON_LIBS=$pkg_cv_SYSTEMD_DAEMON_LIBS @@ -18928,7 +18799,9 @@ if test x_$enable_alloc_nonregional = x_ printf "%s\n" "#define UNBOUND_ALLOC_NONREGIONAL 1" >>confdefs.h fi -if test x_$enable_alloc_checks = x_yes; then +if test x_$enable_alloc_checks = x_yes +then : + printf "%s\n" "#define UNBOUND_ALLOC_STATS 1" >>confdefs.h @@ -18936,30 +18809,31 @@ printf "%s\n" "#define UNBOUND_ALLOC_STA ASYNCLOOK_ALLOCCHECK_EXTRA_OBJ="alloc.lo" -else - if test x_$enable_alloc_lite = x_yes; then + +else $as_nop + + if test x_$enable_alloc_lite = x_yes +then : + printf "%s\n" "#define UNBOUND_ALLOC_LITE 1" >>confdefs.h - else + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 printf %s "checking for GNU libc compatible malloc... " >&6; } - if test "$cross_compiling" = yes +if test ${ac_cv_func_malloc_0_nonnull+y} then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (crosscompile)" >&5 -printf "%s\n" "no (crosscompile)" >&6; } - case " $LIBOBJS " in - *" malloc.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS malloc.$ac_objext" - ;; -esac - - -printf "%s\n" "#define malloc rpl_malloc_unbound" >>confdefs.h + printf %s "(cached) " >&6 +else $as_nop -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + if test "$cross_compiling" = yes +then : + ac_cv_func_malloc_0_nonnull="no (crosscompile)" +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H #include @@ -18978,9 +18852,26 @@ main (void) _ACEOF if ac_fn_c_try_run "$LINENO" then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - case " $LIBOBJS " in + ac_cv_func_malloc_0_nonnull=no +else $as_nop + ac_cv_func_malloc_0_nonnull=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +printf "%s\n" "$ac_cv_func_malloc_0_nonnull" >&6; } + if test "$ac_cv_func_malloc_0_nonnull" = yes +then : + +printf "%s\n" "#define HAVE_MALLOC 1" >>confdefs.h + +else $as_nop + + case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; @@ -18989,21 +18880,12 @@ esac printf "%s\n" "#define malloc rpl_malloc_unbound" >>confdefs.h -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } -printf "%s\n" "#define HAVE_MALLOC 1" >>confdefs.h - ;; -esac -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac fi - fi +fi + fi # check windows threads (we use them, not pthreads, on windows). @@ -19026,324 +18908,49 @@ printf %s "checking for CreateThread... #include #endif -int -main (void) -{ - - HANDLE t = CreateThread(NULL, 0, NULL, NULL, 0, NULL); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - -printf "%s\n" "#define HAVE_WINDOWS_THREADS 1" >>confdefs.h - - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - -else -# not on mingw, check thread libraries. - -# check for thread library. -# check this first, so that the pthread lib does not get linked in via -# libssl or libpython, and thus distorts the tests, and we end up using -# the non-threadsafe C libraries. - -# Check whether --with-pthreads was given. -if test ${with_pthreads+y} -then : - withval=$with_pthreads; -else case e in #( - e) withval="yes" ;; -esac -fi - -ub_have_pthreads=no -if test x_$withval != x_no; then - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -printf %s "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if test ${ac_cv_prog_CPP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) # Double quotes because $CC needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - -else case e in #( - e) # Broken: fails on valid input. -continue ;; -esac -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - # Broken: success on invalid input. -continue -else case e in #( - e) # Passes both tests. -ac_preproc_ok=: -break ;; -esac -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok -then : - break -fi - - done - ac_cv_prog_CPP=$CPP - ;; -esac -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -printf "%s\n" "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - -else case e in #( - e) # Broken: fails on valid input. -continue ;; -esac -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - # Broken: success on invalid input. -continue -else case e in #( - e) # Passes both tests. -ac_preproc_ok=: -break ;; -esac -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok -then : - -else case e in #( - e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep -e" >&5 -printf %s "checking for egrep -e... " >&6; } -if test ${ac_cv_path_EGREP_TRADITIONAL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -z "$EGREP_TRADITIONAL"; then - ac_path_EGREP_TRADITIONAL_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in grep ggrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue -# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found. - # Check for GNU $ac_path_EGREP_TRADITIONAL -case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #( -*GNU*) - ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;; -#( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf "%s\n" 'EGREP_TRADITIONAL' >> "conftest.nl" - "$ac_path_EGREP_TRADITIONAL" -E 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" - ac_path_EGREP_TRADITIONAL_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac +int +main (void) +{ - $ac_path_EGREP_TRADITIONAL_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then - : - fi -else - ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL -fi + HANDLE t = CreateThread(NULL, 0, NULL, NULL, 0, NULL); - if test "$ac_cv_path_EGREP_TRADITIONAL" + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" then : - ac_cv_path_EGREP_TRADITIONAL="$ac_cv_path_EGREP_TRADITIONAL -E" -else case e in #( - e) if test -z "$EGREP_TRADITIONAL"; then - ac_path_EGREP_TRADITIONAL_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in egrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue -# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found. - # Check for GNU $ac_path_EGREP_TRADITIONAL -case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #( -*GNU*) - ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;; -#( -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf "%s\n" 'EGREP_TRADITIONAL' >> "conftest.nl" - "$ac_path_EGREP_TRADITIONAL" 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" - ac_path_EGREP_TRADITIONAL_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_WINDOWS_THREADS 1" >>confdefs.h + + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } - $ac_path_EGREP_TRADITIONAL_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL fi - ;; -esac -fi ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +else +# not on mingw, check thread libraries. + +# check for thread library. +# check this first, so that the pthread lib does not get linked in via +# libssl or libpython, and thus distorts the tests, and we end up using +# the non-threadsafe C libraries. + +# Check whether --with-pthreads was given. +if test ${with_pthreads+y} +then : + withval=$with_pthreads; +else $as_nop + withval="yes" fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP_TRADITIONAL" >&5 -printf "%s\n" "$ac_cv_path_EGREP_TRADITIONAL" >&6; } - EGREP_TRADITIONAL=$ac_cv_path_EGREP_TRADITIONAL +ub_have_pthreads=no +if test x_$withval != x_no; then @@ -19384,14 +18991,8 @@ printf %s "checking for pthread_join usi /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char pthread_join (void); + builtin and then its argument prototype would still apply. */ +char pthread_join (); int main (void) { @@ -19485,7 +19086,7 @@ case $host_os in _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP_TRADITIONAL "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1 + $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1 then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5 printf "%s\n" "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;} @@ -19515,8 +19116,8 @@ printf %s "checking whether $CC is Clang if test ${ax_cv_PTHREAD_CLANG+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ax_cv_PTHREAD_CLANG=no +else $as_nop + ax_cv_PTHREAD_CLANG=no # Note that Autoconf sets GCC=yes for Clang as well as GCC if test "x$GCC" = "xyes"; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19528,15 +19129,14 @@ else case e in #( _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP_TRADITIONAL "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1 + $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1 then : ax_cv_PTHREAD_CLANG=yes fi rm -rf conftest* fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5 printf "%s\n" "$ax_cv_PTHREAD_CLANG" >&6; } @@ -19571,7 +19171,31 @@ fi # correctly enabled case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) + solaris*) + # Solaris 11.4 introduced XPG7 support and did away with the need for + # _REENTRANT. + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# undef _XOPEN_SOURCE +# include +# if _XOPEN_VERSION < 700 + AX_PTHREAD_SOLARIS__REENTRANT +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_SOLARIS__REENTRANT" >/dev/null 2>&1 +then : + ax_pthread_check_macro="_REENTRANT" +else $as_nop + ax_pthread_check_macro="--" +fi +rm -rf conftest* + + ;; + darwin* | hpux* | linux* | osf*) ax_pthread_check_macro="_REENTRANT" ;; @@ -19586,9 +19210,8 @@ esac if test "x$ax_pthread_check_macro" = "x--" then : ax_pthread_check_cond=0 -else case e in #( - e) ax_pthread_check_cond="!defined($ax_pthread_check_macro)" ;; -esac +else $as_nop + ax_pthread_check_cond="!defined($ax_pthread_check_macro)" fi @@ -19622,8 +19245,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ax_pthread_config+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ax_pthread_config"; then +else $as_nop + if test -n "$ax_pthread_config"; then ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -19646,8 +19269,7 @@ done IFS=$as_save_IFS test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no" -fi ;; -esac +fi fi ax_pthread_config=$ac_cv_prog_ax_pthread_config if test -n "$ax_pthread_config"; then @@ -19780,8 +19402,8 @@ printf %s "checking whether Clang needs if test ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown +else $as_nop + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown # Create an alternate version of $ac_link that compiles and # links in two steps (.c -> .o, .o -> exe) instead of one # (.c -> exe), because the warning occurs only in the second @@ -19827,8 +19449,7 @@ then : ax_pthread_try=no fi ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5 printf "%s\n" "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; } @@ -19855,8 +19476,8 @@ printf %s "checking for joinable pthread if test ${ax_cv_PTHREAD_JOINABLE_ATTR+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ax_cv_PTHREAD_JOINABLE_ATTR=unknown +else $as_nop + ax_cv_PTHREAD_JOINABLE_ATTR=unknown for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19876,8 +19497,7 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext done - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5 printf "%s\n" "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; } @@ -19897,15 +19517,14 @@ printf %s "checking whether more special if test ${ax_cv_PTHREAD_SPECIAL_FLAGS+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ax_cv_PTHREAD_SPECIAL_FLAGS=no +else $as_nop + ax_cv_PTHREAD_SPECIAL_FLAGS=no case $host_os in solaris*) ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" ;; esac - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5 printf "%s\n" "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; } @@ -19921,8 +19540,8 @@ printf %s "checking for PTHREAD_PRIO_INH if test ${ax_cv_PTHREAD_PRIO_INHERIT+y} then : printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -19937,14 +19556,12 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ax_cv_PTHREAD_PRIO_INHERIT=yes -else case e in #( - e) ax_cv_PTHREAD_PRIO_INHERIT=no ;; -esac +else $as_nop + ax_cv_PTHREAD_PRIO_INHERIT=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 printf "%s\n" "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } @@ -19994,8 +19611,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_PTHREAD_CC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$PTHREAD_CC"; then +else $as_nop + if test -n "$PTHREAD_CC"; then ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -20017,8 +19634,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi PTHREAD_CC=$ac_cv_prog_PTHREAD_CC if test -n "$PTHREAD_CC"; then @@ -20045,8 +19661,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_PTHREAD_CXX+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$PTHREAD_CXX"; then +else $as_nop + if test -n "$PTHREAD_CXX"; then ac_cv_prog_PTHREAD_CXX="$PTHREAD_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -20068,8 +19684,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi PTHREAD_CXX=$ac_cv_prog_PTHREAD_CXX if test -n "$PTHREAD_CXX"; then @@ -20139,30 +19754,28 @@ fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5 printf %s "checking size of unsigned long... " >&6; } if test ${ac_cv_sizeof_unsigned_long+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default" +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default" then : -else case e in #( - e) if test "$ac_cv_type_unsigned_long" = yes; then - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +else $as_nop + if test "$ac_cv_type_unsigned_long" = yes; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (unsigned long) -See 'config.log' for more details" "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_unsigned_long=0 - fi ;; -esac + fi fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5 printf "%s\n" "$ac_cv_sizeof_unsigned_long" >&6; } @@ -20174,30 +19787,28 @@ printf "%s\n" "#define SIZEOF_UNSIGNED_L # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 printf %s "checking size of pthread_t... " >&6; } if test ${ac_cv_sizeof_pthread_t+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" "$ac_includes_default" +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" "$ac_includes_default" then : -else case e in #( - e) if test "$ac_cv_type_pthread_t" = yes; then - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +else $as_nop + if test "$ac_cv_type_pthread_t" = yes; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (pthread_t) -See 'config.log' for more details" "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_pthread_t=0 - fi ;; -esac + fi fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_t" >&5 printf "%s\n" "$ac_cv_sizeof_pthread_t" >&6; } @@ -20233,30 +19844,195 @@ printf "%s\n" "yes" >&6; } CFLAGS=`echo "$CFLAGS" | sed -e 's/-pthread//'` PTHREAD_CFLAGS_ONLY="-pthread" - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - fi - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - fi # endif cc successful - rm -f conftest conftest.c conftest.o - fi # endif -pthread in CFLAGS + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi # endif cc successful + rm -f conftest conftest.c conftest.o + fi # endif -pthread in CFLAGS + + + : +else + ax_pthread_ok=no + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi + +if test x_$ub_have_pthreads != x_no; then + # Long checks to support pthread_setname_np(). + # Some OSes have the extra non-portable functions in a specific + # header file. + ac_fn_c_check_header_compile "$LINENO" "pthread_np.h" "ac_cv_header_pthread_np_h" "$ac_includes_default +" +if test "x$ac_cv_header_pthread_np_h" = xyes +then : + printf "%s\n" "#define HAVE_PTHREAD_NP_H 1" >>confdefs.h + +fi + + BAKCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror" + # MacOS only has 1 argument, the name. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np has only 1 argument" >&5 +printf %s "checking whether pthread_setname_np has only 1 argument... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + +int +main (void) +{ + + (void)pthread_setname_np(""); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP1 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + # NetBSD has 3 arguments to allow for formatting of the name. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np has 3 arguments" >&5 +printf %s "checking whether pthread_setname_np has 3 arguments... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + +int +main (void) +{ + + (void)pthread_setname_np(0, "", NULL); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP3 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + # Most OSes have the common 2 arguments, thread and name. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np has the common 2 arguments" >&5 +printf %s "checking whether pthread_setname_np has the common 2 arguments... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + +int +main (void) +{ + + (void)pthread_setname_np(0, ""); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + # FreeBSD/OpenBSD use a slightly different function name. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np exists as pthread_set_name_np instead" >&5 +printf %s "checking whether pthread_setname_np exists as pthread_set_name_np instead... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + +int +main (void) +{ + + (void)pthread_set_name_np(0, ""); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } - : -else - ax_pthread_ok=no +printf "%s\n" "#define HAVE_PTHREAD_SET_NAME_NP 1" >>confdefs.h -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS="$BAKCFLAGS" fi # check solaris thread library @@ -20265,9 +20041,8 @@ fi if test ${with_solaris_threads+y} then : withval=$with_solaris_threads; -else case e in #( - e) withval="no" ;; -esac +else $as_nop + withval="no" fi ub_have_sol_threads=no @@ -20281,21 +20056,15 @@ printf %s "checking for library containi if test ${ac_cv_search_thr_create+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char thr_create (void); + builtin and then its argument prototype would still apply. */ +char thr_create (); int main (void) { @@ -20326,13 +20095,11 @@ done if test ${ac_cv_search_thr_create+y} then : -else case e in #( - e) ac_cv_search_thr_create=no ;; -esac +else $as_nop + ac_cv_search_thr_create=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_thr_create" >&5 printf "%s\n" "$ac_cv_search_thr_create" >&6; } @@ -20353,8 +20120,8 @@ cache=`echo mt | sed 'y%.=/+-%___p_%'` if eval test \${cv_prog_cc_flag_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -mt -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" @@ -20362,8 +20129,7 @@ else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then @@ -20380,11 +20146,10 @@ fi ub_have_sol_threads=yes -else case e in #( - e) +else $as_nop + as_fn_error $? "no solaris threads found." "$LINENO" 5 - ;; -esac + fi fi @@ -20417,9 +20182,8 @@ printf "%s\n" "#define UB_SYSLOG_FACILIT if test ${with_dynlibmodule+y} then : withval=$with_dynlibmodule; -else case e in #( - e) withval="no" ;; -esac +else $as_nop + withval="no" fi @@ -20442,21 +20206,15 @@ printf %s "checking for library containi if test ${ac_cv_search_dlopen+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); + builtin and then its argument prototype would still apply. */ +char dlopen (); int main (void) { @@ -20487,13 +20245,11 @@ done if test ${ac_cv_search_dlopen+y} then : -else case e in #( - e) ac_cv_search_dlopen=no ;; -esac +else $as_nop + ac_cv_search_dlopen=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 printf "%s\n" "$ac_cv_search_dlopen" >&6; } @@ -20517,9 +20273,8 @@ fi if test ${with_pyunbound+y} then : withval=$with_pyunbound; -else case e in #( - e) withval="no" ;; -esac +else $as_nop + withval="no" fi @@ -20536,9 +20291,8 @@ fi if test ${with_pythonmodule+y} then : withval=$with_pythonmodule; -else case e in #( - e) withval="no" ;; -esac +else $as_nop + withval="no" fi @@ -20566,8 +20320,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_PYTHON+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $PYTHON in +else $as_nop + case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; @@ -20592,7 +20346,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi PYTHON=$ac_cv_path_PYTHON @@ -20770,9 +20523,8 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : pythonexists=yes -else case e in #( - e) pythonexists=no ;; -esac +else $as_nop + pythonexists=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -20882,8 +20634,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_SWIG+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $SWIG in +else $as_nop + case $SWIG in [\\/]* | ?:[\\/]*) ac_cv_path_SWIG="$SWIG" # Let the user override the test with a path. ;; @@ -20908,7 +20660,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi SWIG=$ac_cv_path_SWIG @@ -21009,8 +20760,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_SWIG+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $SWIG in +else $as_nop + case $SWIG in [\\/]* | ?:[\\/]*) ac_cv_path_SWIG="$SWIG" # Let the user override the test with a path. ;; @@ -21035,7 +20786,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi SWIG=$ac_cv_path_SWIG @@ -21197,17 +20947,15 @@ ax_date_fmt="%Y%m%d" if test x"$SOURCE_DATE_EPOCH" = x then : CONFIG_DATE=`date "+$ax_date_fmt"` -else case e in #( - e) ax_build_date=`date -u -d "@$SOURCE_DATE_EPOCH" "+$ax_date_fmt" 2>/dev/null \ +else $as_nop + ax_build_date=`date -u -d "@$SOURCE_DATE_EPOCH" "+$ax_date_fmt" 2>/dev/null \ || date -u -r "$SOURCE_DATE_EPOCH" "+$ax_date_fmt" 2>/dev/null` if test x"$ax_build_date" = x then : as_fn_error $? "malformed SOURCE_DATE_EPOCH" "$LINENO" 5 -else case e in #( - e) CONFIG_DATE=$ax_build_date ;; -esac -fi ;; -esac +else $as_nop + CONFIG_DATE=$ax_build_date +fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CONFIG_DATE" >&5 printf "%s\n" "$CONFIG_DATE" >&6; } @@ -21302,11 +21050,10 @@ if test ${with_ssl+y} then : withval=$with_ssl; -else case e in #( - e) +else $as_nop + withval="yes" - ;; -esac + fi if test x_$withval = x_no; then @@ -21402,8 +21149,8 @@ printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_EVP_SHA256 1" >>confdefs.h -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } # check if -lwsock32 or -lgdi32 are needed. @@ -21436,8 +21183,8 @@ printf "%s\n" "#define HAVE_EVP_SHA256 1 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } LIBS="$BAKLIBS" @@ -21470,8 +21217,8 @@ printf "%s\n" "#define HAVE_EVP_SHA256 1 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } LIBS="$BAKLIBS" @@ -21504,8 +21251,8 @@ printf "%s\n" "#define HAVE_EVP_SHA256 1 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } LIBS="$BAKLIBS" @@ -21538,8 +21285,8 @@ printf "%s\n" "#define HAVE_EVP_SHA256 1 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } LIBS="$BAKLIBS" @@ -21571,38 +21318,32 @@ printf "%s\n" "#define HAVE_EVP_SHA256 1 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "OpenSSL found in $ssldir, but version 0.9.7 or higher is required" "$LINENO" 5 - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -21647,14 +21388,8 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char SSL_CTX_new (void); + builtin and then its argument prototype would still apply. */ +char SSL_CTX_new (); int main (void) { @@ -21670,8 +21405,8 @@ then : printf "%s\n" "no" >&6; } LIBS="$BAKLIBS" -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } LIBS="$BAKLIBS" @@ -21680,21 +21415,15 @@ printf %s "checking for library containi if test ${ac_cv_search_dlopen+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); + builtin and then its argument prototype would still apply. */ +char dlopen (); int main (void) { @@ -21725,13 +21454,11 @@ done if test ${ac_cv_search_dlopen+y} then : -else case e in #( - e) ac_cv_search_dlopen=no ;; -esac +else $as_nop + ac_cv_search_dlopen=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 printf "%s\n" "$ac_cv_search_dlopen" >&6; } @@ -21742,8 +21469,7 @@ then : fi - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -21778,14 +21504,13 @@ then : printf "%s\n" "no" >&6; } LIBS="$BAKLIBS" -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } LIBS="$BAKLIBS" LIBS="$LIBS -lcrypt32" - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -21805,8 +21530,8 @@ printf %s "checking for $CC options need if test ${ac_cv_c_undeclared_builtin_options+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_save_CFLAGS=$CFLAGS +else $as_nop + ac_save_CFLAGS=$CFLAGS ac_cv_c_undeclared_builtin_options='cannot detect' for ac_arg in '' -fno-builtin; do CFLAGS="$ac_save_CFLAGS $ac_arg" @@ -21825,8 +21550,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else case e in #( - e) # This test program should compile successfully. +else $as_nop + # This test program should compile successfully. # No library function is consistently available on # freestanding implementations, so test against a dummy # declaration. Include always-available headers on the @@ -21854,29 +21579,26 @@ then : if test x"$ac_arg" = x then : ac_cv_c_undeclared_builtin_options='none needed' -else case e in #( - e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; -esac +else $as_nop + ac_cv_c_undeclared_builtin_options=$ac_arg fi break fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done CFLAGS=$ac_save_CFLAGS - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } case $ac_cv_c_undeclared_builtin_options in #( 'cannot detect') : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot make $CC report undeclared builtins -See 'config.log' for more details" "$LINENO" 5; } ;; #( +See \`config.log' for more details" "$LINENO" 5; } ;; #( 'none needed') : ac_c_undeclared_builtin_options='' ;; #( *) : @@ -21887,36 +21609,32 @@ ac_fn_check_decl "$LINENO" "strlcpy" "ac if test "x$ac_cv_have_decl_strlcpy" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_STRLCPY $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "strlcat" "ac_cv_have_decl_strlcat" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_strlcat" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_STRLCAT $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "arc4random" "ac_cv_have_decl_arc4random" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_arc4random" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_ARC4RANDOM $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "arc4random_uniform" "ac_cv_have_decl_arc4random_uniform" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_arc4random_uniform" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_ARC4RANDOM_UNIFORM $ac_have_decl" >>confdefs.h @@ -22131,6 +21849,12 @@ then : printf "%s\n" "#define HAVE_BIO_SET_CALLBACK_EX 1" >>confdefs.h fi +ac_fn_c_check_func "$LINENO" "OPENSSL_cleanup" "ac_cv_func_OPENSSL_cleanup" +if test "x$ac_cv_func_OPENSSL_cleanup" = xyes +then : + printf "%s\n" "#define HAVE_OPENSSL_CLEANUP 1" >>confdefs.h + +fi # these check_funcs need -lssl @@ -22160,6 +21884,24 @@ then : printf "%s\n" "#define HAVE_SSL_GET0_PEERNAME 1" >>confdefs.h fi +ac_fn_c_check_func "$LINENO" "SSL_set1_dnsname" "ac_cv_func_SSL_set1_dnsname" +if test "x$ac_cv_func_SSL_set1_dnsname" = xyes +then : + printf "%s\n" "#define HAVE_SSL_SET1_DNSNAME 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "X509_get_key_usage" "ac_cv_func_X509_get_key_usage" +if test "x$ac_cv_func_X509_get_key_usage" = xyes +then : + printf "%s\n" "#define HAVE_X509_GET_KEY_USAGE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "ASN1_STRING_get0_data" "ac_cv_func_ASN1_STRING_get0_data" +if test "x$ac_cv_func_ASN1_STRING_get0_data" = xyes +then : + printf "%s\n" "#define HAVE_ASN1_STRING_GET0_DATA 1" >>confdefs.h + +fi ac_fn_c_check_func "$LINENO" "X509_VERIFY_PARAM_set1_host" "ac_cv_func_X509_VERIFY_PARAM_set1_host" if test "x$ac_cv_func_X509_VERIFY_PARAM_set1_host" = xyes then : @@ -22203,6 +21945,54 @@ then : fi +ac_fn_c_check_func "$LINENO" "X509_NAME_get_text_by_NID" "ac_cv_func_X509_NAME_get_text_by_NID" +if test "x$ac_cv_func_X509_NAME_get_text_by_NID" = xyes +then : + printf "%s\n" "#define HAVE_X509_NAME_GET_TEXT_BY_NID 1" >>confdefs.h + +fi + +if test $ac_cv_func_X509_NAME_get_text_by_NID = yes; then + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if X509_NAME_get_text_by_NID is deprecated" >&5 +printf %s "checking if X509_NAME_get_text_by_NID is deprecated... " >&6; } +cache=`echo X509_NAME_get_text_by_NID | sed 'y%.=/+-%___p_%'` +if eval test \${cv_cc_deprecated_$cache+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +echo ' +#include "openssl/x509.h" +' >conftest.c +echo 'void f(void){ + (void)X509_NAME_get_text_by_NID(NULL, 0, NULL, 0); }' >>conftest.c +if test -z "`$CC $CPPFLAGS $CFLAGS -c conftest.c 2>&1 | grep -e deprecated -e unavailable`"; then +eval "cv_cc_deprecated_$cache=no" +else +eval "cv_cc_deprecated_$cache=yes" +fi +rm -f conftest conftest.o conftest.c + +fi + +if eval "test \"`echo '$cv_cc_deprecated_'$cache`\" = yes"; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define DEPRECATED_X509_NAME_GET_TEXT_BY_NID 1" >>confdefs.h + +: + +else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +: + +fi + +fi LIBS="$BAKLIBS" ac_fn_check_decl "$LINENO" "SSL_COMP_get_compression_methods" "ac_cv_have_decl_SSL_COMP_get_compression_methods" " @@ -22229,9 +22019,8 @@ $ac_includes_default if test "x$ac_cv_have_decl_SSL_COMP_get_compression_methods" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "sk_SSL_COMP_pop_free" "ac_cv_have_decl_sk_SSL_COMP_pop_free" " @@ -22258,9 +22047,8 @@ $ac_includes_default if test "x$ac_cv_have_decl_sk_SSL_COMP_pop_free" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_SK_SSL_COMP_POP_FREE $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "SSL_CTX_set_ecdh_auto" "ac_cv_have_decl_SSL_CTX_set_ecdh_auto" " @@ -22287,9 +22075,8 @@ $ac_includes_default if test "x$ac_cv_have_decl_SSL_CTX_set_ecdh_auto" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_SSL_CTX_SET_ECDH_AUTO $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "SSL_CTX_set_tmp_ecdh" "ac_cv_have_decl_SSL_CTX_set_tmp_ecdh" " @@ -22316,9 +22103,8 @@ $ac_includes_default if test "x$ac_cv_have_decl_SSL_CTX_set_tmp_ecdh" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_SSL_CTX_SET_TMP_ECDH $ac_have_decl" >>confdefs.h @@ -22368,15 +22154,14 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: int" >&5 printf "%s\n" "int" >&6; } -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: void" >&5 printf "%s\n" "void" >&6; } printf "%s\n" "#define HMAC_INIT_EX_RETURNS_VOID 1" >>confdefs.h - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi @@ -22407,27 +22192,21 @@ fi if test "x$ac_cv_header_bsd_string_h" = xyes -a "x$ac_cv_header_bsd_stdlib_h" = xyes; then for func in strlcpy strlcat arc4random arc4random_uniform reallocarray; do - as_ac_Search=`printf "%s\n" "ac_cv_search_$func" | sed "$as_sed_sh"` + as_ac_Search=`printf "%s\n" "ac_cv_search_$func" | $as_tr_sh` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing $func" >&5 printf %s "checking for library containing $func... " >&6; } if eval test \${$as_ac_Search+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char $func (void); + builtin and then its argument prototype would still apply. */ +char $func (); int main (void) { @@ -22458,13 +22237,11 @@ done if eval test \${$as_ac_Search+y} then : -else case e in #( - e) eval "$as_ac_Search=no" ;; -esac +else $as_nop + eval "$as_ac_Search=no" fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi eval ac_res=\$$as_ac_Search { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -22559,18 +22336,16 @@ case "$enable_gost" in if test "x$ac_cv_func_EVP_PKEY_set_type_str" = xyes then : : -else case e in #( - e) as_fn_error $? "OpenSSL 1.0.0 is needed for GOST support" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "OpenSSL 1.0.0 is needed for GOST support" "$LINENO" 5 fi ac_fn_c_check_func "$LINENO" "EC_KEY_new" "ac_cv_func_EC_KEY_new" if test "x$ac_cv_func_EC_KEY_new" = xyes then : -else case e in #( - e) as_fn_error $? "OpenSSL does not support ECC, needed for GOST support" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "OpenSSL does not support ECC, needed for GOST support" "$LINENO" 5 fi @@ -22584,8 +22359,8 @@ fi if test "$cross_compiling" = yes then : eval "ac_cv_c_gost_works=maybe" -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -22673,13 +22448,11 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : eval "ac_cv_c_gost_works=yes" -else case e in #( - e) eval "ac_cv_c_gost_works=no" ;; -esac +else $as_nop + eval "ac_cv_c_gost_works=no" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac + conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS="$BAKCFLAGS" @@ -22725,29 +22498,26 @@ then : fi -else case e in #( - e) +else $as_nop + # without EVP_PKEY_fromdata, older openssl, check for support ac_fn_c_check_func "$LINENO" "ECDSA_sign" "ac_cv_func_ECDSA_sign" if test "x$ac_cv_func_ECDSA_sign" = xyes then : -else case e in #( - e) as_fn_error $? "OpenSSL does not support ECDSA: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "OpenSSL does not support ECDSA: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5 fi ac_fn_c_check_func "$LINENO" "SHA384_Init" "ac_cv_func_SHA384_Init" if test "x$ac_cv_func_SHA384_Init" = xyes then : -else case e in #( - e) as_fn_error $? "OpenSSL does not support SHA384: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "OpenSSL does not support SHA384: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5 fi - ;; -esac + fi ac_fn_check_decl "$LINENO" "NID_X9_62_prime256v1" "ac_cv_have_decl_NID_X9_62_prime256v1" "$ac_includes_default @@ -22757,17 +22527,15 @@ fi if test "x$ac_cv_have_decl_NID_X9_62_prime256v1" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_NID_X9_62_PRIME256V1 $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 then : -else case e in #( - e) as_fn_error $? "OpenSSL does not support the ECDSA curves: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "OpenSSL does not support the ECDSA curves: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5 fi ac_fn_check_decl "$LINENO" "NID_secp384r1" "ac_cv_have_decl_NID_secp384r1" "$ac_includes_default #include @@ -22776,24 +22544,22 @@ ac_fn_check_decl "$LINENO" "NID_secp384r if test "x$ac_cv_have_decl_NID_secp384r1" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_NID_SECP384R1 $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 then : -else case e in #( - e) as_fn_error $? "OpenSSL does not support the ECDSA curves: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "OpenSSL does not support the ECDSA curves: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5 fi # see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if openssl supports SHA2 and ECDSA with EVP" >&5 printf %s "checking if openssl supports SHA2 and ECDSA with EVP... " >&6; } if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then - if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then + if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL 0\." >/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } @@ -22832,7 +22598,7 @@ case "$enable_dsa" in if test "x$ac_cv_func_DSA_SIG_new" = xyes then : - as_ac_Type=`printf "%s\n" "ac_cv_type_DSA_SIG*" | sed "$as_sed_sh"` + as_ac_Type=`printf "%s\n" "ac_cv_type_DSA_SIG*" | $as_tr_sh` ac_fn_c_check_type "$LINENO" "DSA_SIG*" "$as_ac_Type" " $ac_includes_default #ifdef HAVE_OPENSSL_ERR_H @@ -22859,17 +22625,15 @@ then : printf "%s\n" "#define USE_DSA 1" >>confdefs.h -else case e in #( - e) if test "x$enable_dsa" = "xyes"; then as_fn_error $? "OpenSSL does not support DSA and you used --enable-dsa." "$LINENO" 5 - fi ;; -esac +else $as_nop + if test "x$enable_dsa" = "xyes"; then as_fn_error $? "OpenSSL does not support DSA and you used --enable-dsa." "$LINENO" 5 + fi fi -else case e in #( - e) if test "x$enable_dsa" = "xyes"; then as_fn_error $? "OpenSSL does not support DSA and you used --enable-dsa." "$LINENO" 5 - fi ;; -esac +else $as_nop + if test "x$enable_dsa" = "xyes"; then as_fn_error $? "OpenSSL does not support DSA and you used --enable-dsa." "$LINENO" 5 + fi fi else @@ -22916,9 +22680,8 @@ case "$enable_ed25519" in if test "x$ac_cv_have_decl_NID_ED25519" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_NID_ED25519 $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 @@ -22926,10 +22689,9 @@ then : use_ed25519="yes" -else case e in #( - e) if test "x$enable_ed25519" = "xyes"; then as_fn_error $? "OpenSSL does not support ED25519 and you used --enable-ed25519." "$LINENO" 5 - fi ;; -esac +else $as_nop + if test "x$enable_ed25519" = "xyes"; then as_fn_error $? "OpenSSL does not support ED25519 and you used --enable-ed25519." "$LINENO" 5 + fi fi fi @@ -22973,9 +22735,8 @@ case "$enable_ed448" in if test "x$ac_cv_have_decl_NID_ED448" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_NID_ED448 $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 @@ -22983,10 +22744,9 @@ then : use_ed448="yes" -else case e in #( - e) if test "x$enable_ed448" = "xyes"; then as_fn_error $? "OpenSSL does not support ED448 and you used --enable-ed448." "$LINENO" 5 - fi ;; -esac +else $as_nop + if test "x$enable_ed448" = "xyes"; then as_fn_error $? "OpenSSL does not support ED448 and you used --enable-ed448." "$LINENO" 5 + fi fi fi @@ -23032,9 +22792,8 @@ if test "x$ac_cv_have_decl_MSG_FASTOPEN" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO" >&5 printf "%s\n" "$as_me: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO" >&2;} -else case e in #( - e) as_fn_error $? "TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client" "$LINENO" 5 fi printf "%s\n" "#define USE_MSG_FASTOPEN 1" >>confdefs.h @@ -23048,9 +22807,8 @@ if test "x$ac_cv_have_decl_CONNECT_RESUM then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO" >&5 printf "%s\n" "$as_me: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO" >&2;} -else case e in #( - e) as_fn_error $? "TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client" "$LINENO" 5 fi printf "%s\n" "#define USE_OSX_MSG_FASTOPEN 1" >>confdefs.h @@ -23078,9 +22836,8 @@ if test "x$ac_cv_have_decl_TCP_FASTOPEN" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support server mode TFO" >&5 printf "%s\n" "$as_me: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support server mode TFO" >&2;} -else case e in #( - e) as_fn_error $? "TCP Fast Open is not available for server mode: please rerun without --enable-tfo-server" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "TCP Fast Open is not available for server mode: please rerun without --enable-tfo-server" "$LINENO" 5 fi printf "%s\n" "#define USE_TCP_FASTOPEN 1" >>confdefs.h @@ -23096,9 +22853,8 @@ esac if test ${with_libevent+y} then : withval=$with_libevent; -else case e in #( - e) with_libevent="no" ;; -esac +else $as_nop + with_libevent="no" fi if test "x_$with_libevent" != x_no; then @@ -23177,21 +22933,15 @@ printf %s "checking for library containi if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char clock_gettime (void); + builtin and then its argument prototype would still apply. */ +char clock_gettime (); int main (void) { @@ -23222,13 +22972,11 @@ done if test ${ac_cv_search_clock_gettime+y} then : -else case e in #( - e) ac_cv_search_clock_gettime=no ;; -esac +else $as_nop + ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } @@ -23261,21 +23009,15 @@ printf %s "checking for library containi if test ${ac_cv_search_event_set+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char event_set (void); + builtin and then its argument prototype would still apply. */ +char event_set (); int main (void) { @@ -23306,13 +23048,11 @@ done if test ${ac_cv_search_event_set+y} then : -else case e in #( - e) ac_cv_search_event_set=no ;; -esac +else $as_nop + ac_cv_search_event_set=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_set" >&5 printf "%s\n" "$ac_cv_search_event_set" >&6; } @@ -23324,28 +23064,22 @@ then : fi -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing event_set" >&5 printf %s "checking for library containing event_set... " >&6; } if test ${ac_cv_search_event_set+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char event_set (void); + builtin and then its argument prototype would still apply. */ +char event_set (); int main (void) { @@ -23376,13 +23110,11 @@ done if test ${ac_cv_search_event_set+y} then : -else case e in #( - e) ac_cv_search_event_set=no ;; -esac +else $as_nop + ac_cv_search_event_set=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_set" >&5 printf "%s\n" "$ac_cv_search_event_set" >&6; } @@ -23393,8 +23125,7 @@ then : fi - ;; -esac + fi ac_fn_c_check_func "$LINENO" "event_base_free" "ac_cv_func_event_base_free" if test "x$ac_cv_func_event_base_free" = xyes @@ -23456,9 +23187,8 @@ fi if test "x$ac_cv_have_decl_evsignal_assign" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_EVSIGNAL_ASSIGN $ac_have_decl" >>confdefs.h @@ -23479,9 +23209,8 @@ fi if test ${with_libexpat+y} then : withval=$with_libexpat; -else case e in #( - e) withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr" ;; -esac +else $as_nop + withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libexpat" >&5 @@ -23517,9 +23246,8 @@ ac_fn_check_decl "$LINENO" "XML_StopPars if test "x$ac_cv_have_decl_XML_StopParser" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_XML_STOPPARSER $ac_have_decl" >>confdefs.h @@ -23530,9 +23258,8 @@ printf "%s\n" "#define HAVE_DECL_XML_STO if test ${with_libhiredis+y} then : withval=$with_libhiredis; -else case e in #( - e) withval="no" ;; -esac +else $as_nop + withval="no" fi found_libhiredis="no" @@ -23576,9 +23303,8 @@ fi if test "x$ac_cv_have_decl_redisConnect" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_REDISCONNECT $ac_have_decl" >>confdefs.h @@ -23590,9 +23316,8 @@ fi if test ${with_libnghttp2+y} then : withval=$with_libnghttp2; -else case e in #( - e) withval="no" ;; -esac +else $as_nop + withval="no" fi found_libnghttp2="no" @@ -23636,9 +23361,8 @@ fi if test "x$ac_cv_have_decl_nghttp2_session_server_new" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_NGHTTP2_SESSION_SERVER_NEW $ac_have_decl" >>confdefs.h @@ -23650,9 +23374,8 @@ fi if test ${with_libngtcp2+y} then : withval=$with_libngtcp2; -else case e in #( - e) withval="no" ;; -esac +else $as_nop + withval="no" fi found_libngtcp2="no" @@ -23717,9 +23440,8 @@ fi if test "x$ac_cv_have_decl_ngtcp2_conn_server_new" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_NGTCP2_CONN_SERVER_NEW $ac_have_decl" >>confdefs.h @@ -23730,9 +23452,8 @@ printf "%s\n" "#define HAVE_DECL_NGTCP2_ if test "x$ac_cv_have_decl_ngtcp2_crypto_encrypt_cb" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_NGTCP2_CRYPTO_ENCRYPT_CB $ac_have_decl" >>confdefs.h @@ -23741,22 +23462,16 @@ printf %s "checking for ngtcp2_crypto_en if test ${ac_cv_lib_ngtcp2_crypto_ossl_ngtcp2_crypto_encrypt_cb+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-lngtcp2_crypto_ossl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char ngtcp2_crypto_encrypt_cb (void); + builtin and then its argument prototype would still apply. */ +char ngtcp2_crypto_encrypt_cb (); int main (void) { @@ -23768,14 +23483,12 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_ngtcp2_crypto_ossl_ngtcp2_crypto_encrypt_cb=yes -else case e in #( - e) ac_cv_lib_ngtcp2_crypto_ossl_ngtcp2_crypto_encrypt_cb=no ;; -esac +else $as_nop + ac_cv_lib_ngtcp2_crypto_ossl_ngtcp2_crypto_encrypt_cb=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_crypto_ossl_ngtcp2_crypto_encrypt_cb" >&5 printf "%s\n" "$ac_cv_lib_ngtcp2_crypto_ossl_ngtcp2_crypto_encrypt_cb" >&6; } @@ -23786,30 +23499,42 @@ then : printf "%s\n" "#define USE_NGTCP2_CRYPTO_OSSL 1" >>confdefs.h + ac_fn_check_decl "$LINENO" "ngtcp2_crypto_ossl_ctx_new" "ac_cv_have_decl_ngtcp2_crypto_ossl_ctx_new" "$ac_includes_default + #include + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_ngtcp2_crypto_ossl_ctx_new" = xyes +then : + ac_have_decl=1 +else $as_nop + ac_have_decl=0 +fi +printf "%s\n" "#define HAVE_DECL_NGTCP2_CRYPTO_OSSL_CTX_NEW $ac_have_decl" >>confdefs.h +if test $ac_have_decl = 1 +then : + +else $as_nop + as_fn_error $? "No declaration of ngtcp2_crypto_ossl_ctx_new in the ngtcp2_crypto_ossl header file. Perhaps the ngtcp2_crypto_ossl devel header files need to be installed." "$LINENO" 5 +fi + + +else $as_nop -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ngtcp2_crypto_encrypt_cb in -lngtcp2_crypto_openssl" >&5 printf %s "checking for ngtcp2_crypto_encrypt_cb in -lngtcp2_crypto_openssl... " >&6; } if test ${ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-lngtcp2_crypto_openssl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char ngtcp2_crypto_encrypt_cb (void); + builtin and then its argument prototype would still apply. */ +char ngtcp2_crypto_encrypt_cb (); int main (void) { @@ -23821,43 +23546,35 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb=yes -else case e in #( - e) ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb=no ;; -esac +else $as_nop + ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb" >&5 printf "%s\n" "$ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb" >&6; } if test "x$ac_cv_lib_ngtcp2_crypto_openssl_ngtcp2_crypto_encrypt_cb" = xyes then : LIBS="$LIBS -lngtcp2_crypto_openssl" -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ngtcp2_crypto_encrypt_cb in -lngtcp2_crypto_quictls" >&5 printf %s "checking for ngtcp2_crypto_encrypt_cb in -lngtcp2_crypto_quictls... " >&6; } if test ${ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-lngtcp2_crypto_quictls $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char ngtcp2_crypto_encrypt_cb (void); + builtin and then its argument prototype would still apply. */ +char ngtcp2_crypto_encrypt_cb (); int main (void) { @@ -23869,14 +23586,12 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb=yes -else case e in #( - e) ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb=no ;; -esac +else $as_nop + ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb" >&5 printf "%s\n" "$ac_cv_lib_ngtcp2_crypto_quictls_ngtcp2_crypto_encrypt_cb" >&6; } @@ -23885,12 +23600,10 @@ then : LIBS="$LIBS -lngtcp2_crypto_quictls" fi - ;; -esac + fi - ;; -esac + fi ac_fn_c_check_func "$LINENO" "ngtcp2_crypto_encrypt_cb" "ac_cv_func_ngtcp2_crypto_encrypt_cb" @@ -23978,12 +23691,18 @@ if test "x$ac_cv_func_SSL_is_quic" = xye then : printf "%s\n" "#define HAVE_SSL_IS_QUIC 1" >>confdefs.h -else case e in #( - e) as_fn_error $? "No QUIC support detected in OpenSSL. Need OpenSSL version with QUIC support to enable DNS over QUIC with libngtcp2." "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "No QUIC support detected in OpenSSL. Need OpenSSL version with QUIC support to enable DNS over QUIC with libngtcp2." "$LINENO" 5 fi done + ac_fn_c_check_func "$LINENO" "SSL_set_quic_tls_early_data_enabled" "ac_cv_func_SSL_set_quic_tls_early_data_enabled" +if test "x$ac_cv_func_SSL_set_quic_tls_early_data_enabled" = xyes +then : + printf "%s\n" "#define HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED 1" >>confdefs.h + +fi + LIBS="$BAKLIBS" ac_fn_c_check_type "$LINENO" "struct ngtcp2_version_cid" "ac_cv_type_struct_ngtcp2_version_cid" "$ac_includes_default @@ -24081,15 +23800,37 @@ printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_NGTCP2_CONN_SHUTDOWN_STREAM4 1" >>confdefs.h -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_fn_check_decl "$LINENO" "CLOCK_MONOTONIC + " "ac_cv_have_decl_CLOCK_MONOTONIC_________" "$ac_includes_default +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_CLOCK_MONOTONIC_________" = xyes +then : + + +else $as_nop + as_fn_error $? "ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system" "$LINENO" 5 + +fi + fi # set static linking for uninstalled libraries if requested @@ -24116,22 +23857,16 @@ printf %s "checking for compress in -lz. if test ${ac_cv_lib_z_compress+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char compress (void); + builtin and then its argument prototype would still apply. */ +char compress (); int main (void) { @@ -24143,14 +23878,12 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_z_compress=yes -else case e in #( - e) ac_cv_lib_z_compress=no ;; -esac +else $as_nop + ac_cv_lib_z_compress=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_compress" >&5 printf "%s\n" "$ac_cv_lib_z_compress" >&6; } @@ -24159,10 +23892,12 @@ then : LIBS="$LIBS -lz" fi - if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then - : - else - LIBS="$LIBS -l:libssp.a" + if echo "$host" | $GREP -i -e linux >/dev/null; then + if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then + : + else + LIBS="$LIBS -l:libssp.a" + fi fi fi fi @@ -24188,22 +23923,16 @@ printf %s "checking for compress in -lz. if test ${ac_cv_lib_z_compress+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS +else $as_nop + ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char compress (void); + builtin and then its argument prototype would still apply. */ +char compress (); int main (void) { @@ -24215,14 +23944,12 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_z_compress=yes -else case e in #( - e) ac_cv_lib_z_compress=no ;; -esac +else $as_nop + ac_cv_lib_z_compress=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac +LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_compress" >&5 printf "%s\n" "$ac_cv_lib_z_compress" >&6; } @@ -24231,10 +23958,12 @@ then : LIBS="$LIBS -lz" fi - if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then - : - else - LIBS="$LIBS -l:libssp.a" + if echo "$host" | $GREP -i -e linux >/dev/null; then + if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then + : + else + LIBS="$LIBS -l:libssp.a" + fi fi fi fi @@ -24291,8 +24020,8 @@ printf "%s\n" "#define USE_WINSOCK 1" >> fi fi -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_WS2TCPIP_H @@ -24319,8 +24048,8 @@ printf "%s\n" "#define USE_WINSOCK 1" >> USE_WINSOCK="1" -else case e in #( - e) ORIGLIBS="$LIBS" +else $as_nop + ORIGLIBS="$LIBS" LIBS="$LIBS -lws2_32" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24349,22 +24078,19 @@ printf "%s\n" "#define USE_WINSOCK 1" >> USE_WINSOCK="1" -else case e in #( - e) +else $as_nop + ac_cv_func_getaddrinfo="no" LIBS="$ORIGLIBS" - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -24399,8 +24125,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_WINDRES+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$WINDRES"; then +else $as_nop + if test -n "$WINDRES"; then ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -24422,8 +24148,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi WINDRES=$ac_cv_prog_WINDRES if test -n "$WINDRES"; then @@ -24445,8 +24170,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_prog_ac_ct_WINDRES+y} then : printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_WINDRES"; then +else $as_nop + if test -n "$ac_ct_WINDRES"; then ac_cv_prog_ac_ct_WINDRES="$ac_ct_WINDRES" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -24468,8 +24193,7 @@ done done IFS=$as_save_IFS -fi ;; -esac +fi fi ac_ct_WINDRES=$ac_cv_prog_ac_ct_WINDRES if test -n "$ac_ct_WINDRES"; then @@ -24559,10 +24283,9 @@ printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_IOCTLSOCKET 1" >>confdefs.h -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } ;; -esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -24585,8 +24308,8 @@ cache=`echo daemon | sed 'y%.=/+-%___p_% if eval test \${cv_cc_deprecated_$cache+y} then : printf %s "(cached) " >&6 -else case e in #( - e) +else $as_nop + echo ' #include #include @@ -24598,8 +24321,7 @@ else eval "cv_cc_deprecated_$cache=yes" fi rm -f conftest conftest.o conftest.c - ;; -esac + fi if eval "test \"`echo '$cv_cc_deprecated_'$cache`\" = yes"; then @@ -24619,6 +24341,23 @@ fi fi +ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimensec" "ac_cv_member_struct_stat_st_mtimensec" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_mtimensec" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1" >>confdefs.h + + +fi +ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim.tv_nsec" "ac_cv_member_struct_stat_st_mtim_tv_nsec" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_mtim_tv_nsec" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1" >>confdefs.h + + +fi + ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" " $ac_includes_default #ifdef HAVE_SYS_UN_H @@ -24706,10 +24445,9 @@ printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_HTOBE64 1" >>confdefs.h -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } ;; -esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -24742,10 +24480,9 @@ printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_BE64TOH 1" >>confdefs.h -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } ;; -esac +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -24755,21 +24492,15 @@ printf %s "checking for library containi if test ${ac_cv_search_setusercontext+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char setusercontext (void); + builtin and then its argument prototype would still apply. */ +char setusercontext (); int main (void) { @@ -24800,13 +24531,11 @@ done if test ${ac_cv_search_setusercontext+y} then : -else case e in #( - e) ac_cv_search_setusercontext=no ;; -esac +else $as_nop + ac_cv_search_setusercontext=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_setusercontext" >&5 printf "%s\n" "$ac_cv_search_setusercontext" >&6; } @@ -24937,6 +24666,12 @@ then : printf "%s\n" "#define HAVE_GLOB 1" >>confdefs.h fi +ac_fn_c_check_func "$LINENO" "fnmatch" "ac_cv_func_fnmatch" +if test "x$ac_cv_func_fnmatch" = xyes +then : + printf "%s\n" "#define HAVE_FNMATCH 1" >>confdefs.h + +fi ac_fn_c_check_func "$LINENO" "initgroups" "ac_cv_func_initgroups" if test "x$ac_cv_func_initgroups" = xyes then : @@ -25030,15 +24765,14 @@ if test "x$ac_cv_func_setresuid" = xyes then : printf "%s\n" "#define HAVE_SETRESUID 1" >>confdefs.h -else case e in #( - e) ac_fn_c_check_func "$LINENO" "setreuid" "ac_cv_func_setreuid" +else $as_nop + ac_fn_c_check_func "$LINENO" "setreuid" "ac_cv_func_setreuid" if test "x$ac_cv_func_setreuid" = xyes then : printf "%s\n" "#define HAVE_SETREUID 1" >>confdefs.h fi - ;; -esac + fi done @@ -25050,15 +24784,14 @@ if test "x$ac_cv_func_setresgid" = xyes then : printf "%s\n" "#define HAVE_SETRESGID 1" >>confdefs.h -else case e in #( - e) ac_fn_c_check_func "$LINENO" "setregid" "ac_cv_func_setregid" +else $as_nop + ac_fn_c_check_func "$LINENO" "setregid" "ac_cv_func_setregid" if test "x$ac_cv_func_setregid" = xyes then : printf "%s\n" "#define HAVE_SETREGID 1" >>confdefs.h fi - ;; -esac + fi done @@ -25102,12 +24835,11 @@ printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_LINK_ATOMIC_STORE 1" >>confdefs.h -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -25138,9 +24870,8 @@ $ac_includes_default if test "x$ac_cv_have_decl_inet_pton" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_INET_PTON $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "inet_ntop" "ac_cv_have_decl_inet_ntop" " @@ -25169,9 +24900,8 @@ $ac_includes_default if test "x$ac_cv_have_decl_inet_ntop" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_INET_NTOP $ac_have_decl" >>confdefs.h @@ -25180,14 +24910,13 @@ if test "x$ac_cv_func_inet_aton" = xyes then : printf "%s\n" "#define HAVE_INET_ATON 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" inet_aton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_aton.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "inet_pton" "ac_cv_func_inet_pton" @@ -25195,14 +24924,13 @@ if test "x$ac_cv_func_inet_pton" = xyes then : printf "%s\n" "#define HAVE_INET_PTON 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" inet_pton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_pton.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop" @@ -25210,14 +24938,13 @@ if test "x$ac_cv_func_inet_ntop" = xyes then : printf "%s\n" "#define HAVE_INET_NTOP 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" inet_ntop.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_ntop.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" @@ -25225,14 +24952,13 @@ if test "x$ac_cv_func_snprintf" = xyes then : printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" snprintf.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS snprintf.$ac_objext" ;; esac - ;; -esac + fi # test if snprintf return the proper length @@ -25244,8 +24970,8 @@ printf %s "checking for correct snprintf then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: maybe" >&5 printf "%s\n" "maybe" >&6; } -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default @@ -25256,8 +24982,8 @@ if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } @@ -25269,12 +24995,10 @@ printf "%s\n" "#define SNPRINTF_RET_BROK ;; esac - ;; -esac + fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac + conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi @@ -25284,14 +25008,13 @@ if test "x$ac_cv_func_strlcat" = xyes then : printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" strlcat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcat.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" @@ -25299,14 +25022,13 @@ if test "x$ac_cv_func_strlcpy" = xyes then : printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" strlcpy.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" @@ -25314,14 +25036,13 @@ if test "x$ac_cv_func_memmove" = xyes then : printf "%s\n" "#define HAVE_MEMMOVE 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" memmove.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memmove.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "gmtime_r" "ac_cv_func_gmtime_r" @@ -25329,14 +25050,13 @@ if test "x$ac_cv_func_gmtime_r" = xyes then : printf "%s\n" "#define HAVE_GMTIME_R 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" gmtime_r.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS gmtime_r.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "isblank" "ac_cv_func_isblank" @@ -25344,14 +25064,13 @@ if test "x$ac_cv_func_isblank" = xyes then : printf "%s\n" "#define HAVE_ISBLANK 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" isblank.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS isblank.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" @@ -25359,14 +25078,13 @@ if test "x$ac_cv_func_explicit_bzero" = then : printf "%s\n" "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" explicit_bzero.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS explicit_bzero.$ac_objext" ;; esac - ;; -esac + fi LIBOBJ_WITHOUT_CTIMEARC4="$LIBOBJS" @@ -25396,8 +25114,8 @@ printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_REALLOCARRAY 1" >>confdefs.h -else case e in #( - e) +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } case " $LIBOBJS " in @@ -25406,8 +25124,7 @@ printf "%s\n" "no" >&6; } ;; esac - ;; -esac + fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -25415,9 +25132,8 @@ ac_fn_check_decl "$LINENO" "reallocarray if test "x$ac_cv_have_decl_reallocarray" = xyes then : ac_have_decl=1 -else case e in #( - e) ac_have_decl=0 ;; -esac +else $as_nop + ac_have_decl=0 fi printf "%s\n" "#define HAVE_DECL_REALLOCARRAY $ac_have_decl" >>confdefs.h @@ -25427,14 +25143,13 @@ if test "x$ac_cv_func_arc4random" = xyes then : printf "%s\n" "#define HAVE_ARC4RANDOM 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" arc4random.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS arc4random.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "arc4random_uniform" "ac_cv_func_arc4random_uniform" @@ -25442,14 +25157,13 @@ if test "x$ac_cv_func_arc4random_uniform then : printf "%s\n" "#define HAVE_ARC4RANDOM_UNIFORM 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" arc4random_uniform.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS arc4random_uniform.$ac_objext" ;; esac - ;; -esac + fi if test "$ac_cv_func_arc4random" = "no"; then @@ -25467,8 +25181,8 @@ if test "x$ac_cv_func_getentropy" = xyes then : printf "%s\n" "#define HAVE_GETENTROPY 1" >>confdefs.h -else case e in #( - e) +else $as_nop + if test "$USE_WINSOCK" = 1; then case " $LIBOBJS " in *" getentropy_win.$ac_objext "* ) ;; @@ -25501,8 +25215,8 @@ if test "x$ac_cv_header_sys_sha2_h" = xy then : printf "%s\n" "#define HAVE_SYS_SHA2_H 1" >>confdefs.h -else case e in #( - e) +else $as_nop + for ac_func in SHA512_Update do : @@ -25511,21 +25225,19 @@ if test "x$ac_cv_func_SHA512_Update" = x then : printf "%s\n" "#define HAVE_SHA512_UPDATE 1" >>confdefs.h -else case e in #( - e) +else $as_nop + case " $LIBOBJS " in *" sha512.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS sha512.$ac_objext" ;; esac - ;; -esac + fi done - ;; -esac + fi done @@ -25538,21 +25250,15 @@ printf %s "checking for library containi if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char clock_gettime (void); + builtin and then its argument prototype would still apply. */ +char clock_gettime (); int main (void) { @@ -25583,13 +25289,11 @@ done if test ${ac_cv_search_clock_gettime+y} then : -else case e in #( - e) ac_cv_search_clock_gettime=no ;; -esac +else $as_nop + ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } @@ -25624,8 +25328,8 @@ if test "x$ac_cv_func_SHA512_Update" = x then : printf "%s\n" "#define HAVE_SHA512_UPDATE 1" >>confdefs.h -else case e in #( - e) +else $as_nop + printf "%s\n" "#define COMPAT_SHA512 1" >>confdefs.h @@ -25635,8 +25339,7 @@ printf "%s\n" "#define COMPAT_SHA512 1" ;; esac - ;; -esac + fi done @@ -25660,21 +25363,15 @@ printf %s "checking for library containi if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char clock_gettime (void); + builtin and then its argument prototype would still apply. */ +char clock_gettime (); int main (void) { @@ -25705,13 +25402,11 @@ done if test ${ac_cv_search_clock_gettime+y} then : -else case e in #( - e) ac_cv_search_clock_gettime=no ;; -esac +else $as_nop + ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } @@ -25725,8 +25420,7 @@ fi ;; esac fi - ;; -esac + fi done @@ -25739,14 +25433,13 @@ if test "x$ac_cv_func_ctime_r" = xyes then : printf "%s\n" "#define HAVE_CTIME_R 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" ctime_r.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS ctime_r.$ac_objext" ;; esac - ;; -esac + fi ac_fn_c_check_func "$LINENO" "strsep" "ac_cv_func_strsep" @@ -25754,14 +25447,13 @@ if test "x$ac_cv_func_strsep" = xyes then : printf "%s\n" "#define HAVE_STRSEP 1" >>confdefs.h -else case e in #( - e) case " $LIBOBJS " in +else $as_nop + case " $LIBOBJS " in *" strsep.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strsep.$ac_objext" ;; esac - ;; -esac + fi @@ -25812,9 +25504,8 @@ fi if test ${enable_dnstap+y} then : enableval=$enable_dnstap; opt_dnstap=$enableval -else case e in #( - e) opt_dnstap=no ;; -esac +else $as_nop + opt_dnstap=no fi @@ -25823,9 +25514,8 @@ fi if test ${with_dnstap_socket_path+y} then : withval=$with_dnstap_socket_path; opt_dnstap_socket_path=$withval -else case e in #( - e) opt_dnstap_socket_path="$UNBOUND_RUN_DIR/dnstap.sock" ;; -esac +else $as_nop + opt_dnstap_socket_path="$UNBOUND_RUN_DIR/dnstap.sock" fi @@ -25837,8 +25527,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_PROTOC+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $PROTOC in +else $as_nop + case $PROTOC in [\\/]* | ?:[\\/]*) ac_cv_path_PROTOC="$PROTOC" # Let the user override the test with a path. ;; @@ -25863,7 +25553,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi PROTOC=$ac_cv_path_PROTOC @@ -25886,8 +25575,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_PROTOC_C+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $PROTOC_C in +else $as_nop + case $PROTOC_C in [\\/]* | ?:[\\/]*) ac_cv_path_PROTOC_C="$PROTOC_C" # Let the user override the test with a path. ;; @@ -25912,7 +25601,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi PROTOC_C=$ac_cv_path_PROTOC_C @@ -25940,8 +25628,8 @@ printf %s "checking for $ac_word... " >& if test ${ac_cv_path_PROTOC_GEN_C+y} then : printf %s "(cached) " >&6 -else case e in #( - e) case $PROTOC_GEN_C in +else $as_nop + case $PROTOC_GEN_C in [\\/]* | ?:[\\/]*) ac_cv_path_PROTOC_GEN_C="$PROTOC_GEN_C" # Let the user override the test with a path. ;; @@ -25966,7 +25654,6 @@ done IFS=$as_save_IFS ;; -esac ;; esac fi PROTOC_GEN_C=$ac_cv_path_PROTOC_GEN_C @@ -26016,8 +25703,8 @@ then : fi LDFLAGS="$LDFLAGS -L$withval/lib" -else case e in #( - e) +else $as_nop + if test -n "$PKG_CONFIG"; then pkg_failed=no @@ -26133,8 +25820,7 @@ fi fi fi - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing protobuf_c_message_pack" >&5 @@ -26142,21 +25828,15 @@ printf %s "checking for library containi if test ${ac_cv_search_protobuf_c_message_pack+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char protobuf_c_message_pack (void); + builtin and then its argument prototype would still apply. */ +char protobuf_c_message_pack (); int main (void) { @@ -26187,13 +25867,11 @@ done if test ${ac_cv_search_protobuf_c_message_pack+y} then : -else case e in #( - e) ac_cv_search_protobuf_c_message_pack=no ;; -esac +else $as_nop + ac_cv_search_protobuf_c_message_pack=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_protobuf_c_message_pack" >&5 printf "%s\n" "$ac_cv_search_protobuf_c_message_pack" >&6; } @@ -26202,9 +25880,8 @@ if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -else case e in #( - e) as_fn_error $? "The protobuf-c library was not found. Please install the development libraries for protobuf-c!" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "The protobuf-c library was not found. Please install the development libraries for protobuf-c!" "$LINENO" 5 fi @@ -26244,9 +25921,8 @@ printf "%s\n" "#define DNSTAP_SOCKET_PAT if test ${enable_dnscrypt+y} then : enableval=$enable_dnscrypt; opt_dnscrypt=$enableval -else case e in #( - e) opt_dnscrypt=no ;; -esac +else $as_nop + opt_dnscrypt=no fi @@ -26266,21 +25942,15 @@ printf %s "checking for library containi if test ${ac_cv_search_sodium_init+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char sodium_init (void); + builtin and then its argument prototype would still apply. */ +char sodium_init (); int main (void) { @@ -26311,13 +25981,11 @@ done if test ${ac_cv_search_sodium_init+y} then : -else case e in #( - e) ac_cv_search_sodium_init=no ;; -esac +else $as_nop + ac_cv_search_sodium_init=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sodium_init" >&5 printf "%s\n" "$ac_cv_search_sodium_init" >&6; } @@ -26326,9 +25994,8 @@ if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -else case e in #( - e) as_fn_error $? "The sodium library was not found. Please install sodium!" "$LINENO" 5 ;; -esac +else $as_nop + as_fn_error $? "The sodium library was not found. Please install sodium!" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing crypto_box_curve25519xchacha20poly1305_beforenm" >&5 @@ -26336,21 +26003,15 @@ printf %s "checking for library containi if test ${ac_cv_search_crypto_box_curve25519xchacha20poly1305_beforenm+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char crypto_box_curve25519xchacha20poly1305_beforenm (void); + builtin and then its argument prototype would still apply. */ +char crypto_box_curve25519xchacha20poly1305_beforenm (); int main (void) { @@ -26381,13 +26042,11 @@ done if test ${ac_cv_search_crypto_box_curve25519xchacha20poly1305_beforenm+y} then : -else case e in #( - e) ac_cv_search_crypto_box_curve25519xchacha20poly1305_beforenm=no ;; -esac +else $as_nop + ac_cv_search_crypto_box_curve25519xchacha20poly1305_beforenm=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypto_box_curve25519xchacha20poly1305_beforenm" >&5 printf "%s\n" "$ac_cv_search_crypto_box_curve25519xchacha20poly1305_beforenm" >&6; } @@ -26402,12 +26061,11 @@ then : printf "%s\n" "#define USE_DNSCRYPT_XCHACHA20 1" >>confdefs.h -else case e in #( - e) +else $as_nop + ENABLE_DNSCRYPT_XCHACHA20=0 - ;; -esac + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing sodium_set_misuse_handler" >&5 @@ -26415,21 +26073,15 @@ printf %s "checking for library containi if test ${ac_cv_search_sodium_set_misuse_handler+y} then : printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char sodium_set_misuse_handler (void); + builtin and then its argument prototype would still apply. */ +char sodium_set_misuse_handler (); int main (void) { @@ -26460,13 +26112,11 @@ done if test ${ac_cv_search_sodium_set_misuse_handler+y} then : -else case e in #( - e) ac_cv_search_sodium_set_misuse_handler=no ;; -esac +else $as_nop + ac_cv_search_sodium_set_misuse_handler=no fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac +LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sodium_set_misuse_handler" >&5 printf "%s\n" "$ac_cv_search_sodium_set_misuse_handler" >&6; } @@ -26579,17 +26229,16 @@ if test "x$ac_cv_header_net_pfvar_h" = x then : printf "%s\n" "#define HAVE_NET_PFVAR_H 1" >>confdefs.h -else case e in #( - e) +else $as_nop + # mnl # Check whether --with-libmnl was given. if test ${with_libmnl+y} then : withval=$with_libmnl; -else case e in #( - e) withval="yes" ;; -esac +else $as_nop + withval="yes" fi found_libmnl="no" @@ -26620,8 +26269,7 @@ printf "%s\n" "found in $dir" >&6; } if test x_$found_libmnl != x_yes; then as_fn_error $? "Could not find libmnl, libmnl.h" "$LINENO" 5 fi - ;; -esac + fi done @@ -26819,7 +26467,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 1 -version=1.24.2 +version=1.26.1 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5 printf %s "checking for build time... " >&6; } @@ -26827,17 +26475,15 @@ ax_date_fmt="%b %e, %Y" if test x"$SOURCE_DATE_EPOCH" = x then : date=`date "+$ax_date_fmt"` -else case e in #( - e) ax_build_date=`date -u -d "@$SOURCE_DATE_EPOCH" "+$ax_date_fmt" 2>/dev/null \ +else $as_nop + ax_build_date=`date -u -d "@$SOURCE_DATE_EPOCH" "+$ax_date_fmt" 2>/dev/null \ || date -u -r "$SOURCE_DATE_EPOCH" "+$ax_date_fmt" 2>/dev/null` if test x"$ax_build_date" = x then : as_fn_error $? "malformed SOURCE_DATE_EPOCH" "$LINENO" 5 -else case e in #( - e) date=$ax_build_date ;; -esac -fi ;; -esac +else $as_nop + date=$ax_build_date +fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $date" >&5 printf "%s\n" "$date" >&6; } @@ -26858,8 +26504,8 @@ cat >confcache <<\_ACEOF # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # -# 'ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* 'ac_cv_foo' will be assigned the +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF @@ -26889,14 +26535,14 @@ printf "%s\n" "$as_me: WARNING: cache va (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) - # 'set' does not quote correctly, so add quotes: double-quote + # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) - # 'set' quotes correctly as required by POSIX, so do not add quotes. + # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | @@ -26957,12 +26603,6 @@ LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs -# Check whether --enable-year2038 was given. -if test ${enable_year2038+y} -then : - enableval=$enable_year2038; -fi - if test -z "${USE_SYSTEMD_TRUE}" && test -z "${USE_SYSTEMD_FALSE}"; then as_fn_error $? "conditional \"USE_SYSTEMD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -26996,6 +26636,7 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_wri # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh +as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -27004,13 +26645,12 @@ then : # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else case e in #( - e) case `(set -o) 2>/dev/null` in #( +else $as_nop + case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; -esac ;; esac fi @@ -27082,7 +26722,7 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' +# We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -27111,6 +26751,7 @@ as_fn_error () } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -27150,12 +26791,11 @@ then : { eval $1+=\$2 }' -else case e in #( - e) as_fn_append () +else $as_nop + as_fn_append () { eval $1=\$$1\$2 - } ;; -esac + } fi # as_fn_append # as_fn_arith ARG... @@ -27169,12 +26809,11 @@ then : { as_val=$(( $* )) }' -else case e in #( - e) as_fn_arith () +else $as_nop + as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } ;; -esac + } fi # as_fn_arith @@ -27257,9 +26896,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -27340,12 +26979,10 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 @@ -27360,8 +26997,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_wri # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by unbound $as_me 1.24.2, which was -generated by GNU Autoconf 2.72. Invocation command line was +This file was extended by unbound $as_me 1.26.1, which was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -27393,7 +27030,7 @@ _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -'$as_me' instantiates files and other configuration actions +\`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. @@ -27428,11 +27065,11 @@ ac_cs_config_escaped=`printf "%s\n" "$ac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -unbound config.status 1.24.2 -configured by $0, generated by GNU Autoconf 2.72, +unbound config.status 1.26.1 +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2023 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -27492,8 +27129,8 @@ do ac_need_defaults=false;; --he | --h) # Conflict between --help and --header - as_fn_error $? "ambiguous option: '$1' -Try '$0 --help' for more information.";; + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ @@ -27501,8 +27138,8 @@ Try '$0 --help' for more information.";; ac_cs_silent=: ;; # This is an error. - -*) as_fn_error $? "unrecognized option: '$1' -Try '$0 --help' for more information." ;; + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; @@ -27855,7 +27492,7 @@ do "dnscrypt/dnscrypt_config.h") CONFIG_FILES="$CONFIG_FILES dnscrypt/dnscrypt_config.h" ;; "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done @@ -27875,7 +27512,7 @@ fi # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to '$tmp'. +# after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= @@ -27899,7 +27536,7 @@ ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. -# This happens for instance with './config.status config.h'. +# This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then @@ -28057,13 +27694,13 @@ fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with './config.status Makefile'. +# This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF -# Transform confdefs.h into an awk script 'defines.awk', embedded as +# Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. @@ -28173,7 +27810,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -28195,19 +27832,19 @@ do -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain ':'. + # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done - # Let's still pretend it is 'configure' which instantiates (i.e., don't + # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` @@ -28331,7 +27968,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_writ esac _ACEOF -# Neutralize VPATH when '$srcdir' = '.'. +# Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 @@ -28360,9 +27997,9 @@ test -z "$ac_datarootdir_hack$ac_dataroo { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" Index: usr.sbin/unbound/configure.ac =================================================================== RCS file: /cvs/src/usr.sbin/unbound/configure.ac,v diff -u -p -r1.61 configure.ac --- usr.sbin/unbound/configure.ac 15 Dec 2025 16:07:13 -0000 1.61 +++ usr.sbin/unbound/configure.ac 21 Sep 2026 16:28:03 -0000 @@ -11,15 +11,15 @@ sinclude(dnscrypt/dnscrypt.m4) # must be numbers. ac_defun because of later processing m4_define([VERSION_MAJOR],[1]) -m4_define([VERSION_MINOR],[24]) -m4_define([VERSION_MICRO],[2]) +m4_define([VERSION_MINOR],[26]) +m4_define([VERSION_MICRO],[1]) AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound]) AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR]) AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR]) AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO]) LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=34 +LIBUNBOUND_REVISION=40 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -122,6 +122,11 @@ LIBUNBOUND_AGE=1 # 1.24.0 had 9:33:1 # 1.24.1 had 9:34:1 # 1.24.2 had 9:35:1 +# 1.25.0 had 9:36:1 +# 1.25.1 had 9:37:1 +# 1.25.2 had 9:38:1 +# 1.26.0 had 9:39:1 +# 1.26.1 had 9:40:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -330,6 +335,7 @@ fi AC_C_INLINE ACX_CHECK_FORMAT_ATTRIBUTE ACX_CHECK_UNUSED_ATTRIBUTE +ACX_CHECK_NONSTRING_ATTRIBUTE AC_DEFUN([CHECK_WEAK_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) @@ -360,7 +366,14 @@ AC_MSG_CHECKING(whether the C compiler ( AC_CACHE_VAL(ac_cv_c_noreturn_attribute, [ac_cv_c_noreturn_attribute=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include -__attribute__((noreturn)) void f(int x) { printf("%d", x); } +#ifdef STDC_HEADERS +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +__attribute__((noreturn)) void f(int x) { printf("%d", x); exit(1); } ]], [[ f(1); ]])],[ac_cv_c_noreturn_attribute="yes"],[ac_cv_c_noreturn_attribute="no"]) @@ -472,7 +485,7 @@ PKG_PROG_PKG_CONFIG fi # Checks for header files. -AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT]) +AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h fnmatch.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT]) # net/if.h portability for Darwin see: # https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Header-Portability.html AC_CHECK_HEADERS([net/if.h],,, [ @@ -635,19 +648,19 @@ AC_ARG_ENABLE(alloc-nonregional, AS_HELP if test x_$enable_alloc_nonregional = x_yes; then AC_DEFINE(UNBOUND_ALLOC_NONREGIONAL, 1, [use malloc not regions, for debug use]) fi -if test x_$enable_alloc_checks = x_yes; then +AS_IF([test x_$enable_alloc_checks = x_yes],[ AC_DEFINE(UNBOUND_ALLOC_STATS, 1, [use statistics for allocs and frees, for debug use]) SLDNS_ALLOCCHECK_EXTRA_OBJ="alloc.lo log.lo" AC_SUBST(SLDNS_ALLOCCHECK_EXTRA_OBJ) ASYNCLOOK_ALLOCCHECK_EXTRA_OBJ="alloc.lo" AC_SUBST(ASYNCLOOK_ALLOCCHECK_EXTRA_OBJ) -else - if test x_$enable_alloc_lite = x_yes; then +],[ + AS_IF([test x_$enable_alloc_lite = x_yes],[ AC_DEFINE(UNBOUND_ALLOC_LITE, 1, [use to enable lightweight alloc assertions, for debug use]) - else + ],[ ACX_FUNC_MALLOC([unbound]) - fi -fi + ]) +]) # check windows threads (we use them, not pthreads, on windows). if test "$on_mingw" = "yes"; then @@ -722,6 +735,76 @@ int main(void) {return 0;} ]) fi +if test x_$ub_have_pthreads != x_no; then + # Long checks to support pthread_setname_np(). + # Some OSes have the extra non-portable functions in a specific + # header file. + AC_CHECK_HEADERS([pthread_np.h],,, [AC_INCLUDES_DEFAULT]) + BAKCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror" + # MacOS only has 1 argument, the name. + AC_MSG_CHECKING([whether pthread_setname_np has only 1 argument]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + ],[ + (void)pthread_setname_np(""); + ])],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_SETNAME_NP1, 1, [Define if pthread_setname_np has only 1 argument.]) + ],[ + AC_MSG_RESULT(no) + ]) + # NetBSD has 3 arguments to allow for formatting of the name. + AC_MSG_CHECKING([whether pthread_setname_np has 3 arguments]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + ],[ + (void)pthread_setname_np(0, "", NULL); + ])],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_SETNAME_NP3, 1, [Define if pthread_setname_np has 3 arguments.]) + ],[ + AC_MSG_RESULT(no) + ]) + # Most OSes have the common 2 arguments, thread and name. + AC_MSG_CHECKING([whether pthread_setname_np has the common 2 arguments]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + ],[ + (void)pthread_setname_np(0, ""); + ])],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_SETNAME_NP, 1, [Define if pthread_setname_np has the common 2 arguments.]) + ],[ + AC_MSG_RESULT(no) + ]) + # FreeBSD/OpenBSD use a slightly different function name. + AC_MSG_CHECKING([whether pthread_setname_np exists as pthread_set_name_np instead]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + ],[ + (void)pthread_set_name_np(0, ""); + ])],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_SET_NAME_NP, 1, [Define if pthread_setname_np exists as pthread_set_name_np instead.]) + ],[ + AC_MSG_RESULT(no) + ]) + CFLAGS="$BAKCFLAGS" +fi + # check solaris thread library AC_ARG_WITH(solaris-threads, AS_HELP_STRING([--with-solaris-threads],[use solaris native thread library.]), [ ],[ withval="no" ]) ub_have_sol_threads=no @@ -999,12 +1082,19 @@ else AC_MSG_RESULT([no]) fi AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h openssl/core_names.h openssl/param_build.h],,, [AC_INCLUDES_DEFAULT]) -AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex]) +AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex OPENSSL_cleanup]) # these check_funcs need -lssl BAKLIBS="$LIBS" LIBS="-lssl $LIBS" -AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate]) +AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername SSL_set1_dnsname X509_get_key_usage ASN1_STRING_get0_data X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate]) +AC_CHECK_FUNCS([X509_NAME_get_text_by_NID]) +if test $ac_cv_func_X509_NAME_get_text_by_NID = yes; then + ACX_FUNC_DEPRECATED([X509_NAME_get_text_by_NID], [ + (void)X509_NAME_get_text_by_NID(NULL, 0, NULL, 0);], [ +#include "openssl/x509.h" +]) +fi LIBS="$BAKLIBS" AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto,SSL_CTX_set_tmp_ecdh], [], [], [ @@ -1253,7 +1343,7 @@ case "$enable_ecdsa" in # see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency) AC_MSG_CHECKING([if openssl supports SHA2 and ECDSA with EVP]) if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then - if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then + if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL 0\." >/dev/null; then AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED([USE_ECDSA_EVP_WORKAROUND], [1], [Define this to enable an EVP workaround for older openssl]) else @@ -1623,6 +1713,9 @@ if test x_$withval = x_yes -o x_$withval AC_CHECK_LIB([ngtcp2_crypto_ossl], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_ossl" AC_DEFINE(USE_NGTCP2_CRYPTO_OSSL, 1, [Define this to use ngtcp2_crypto_ossl.]) + AC_CHECK_DECLS([ngtcp2_crypto_ossl_ctx_new], [], [AC_MSG_ERROR([No declaration of ngtcp2_crypto_ossl_ctx_new in the ngtcp2_crypto_ossl header file. Perhaps the ngtcp2_crypto_ossl devel header files need to be installed.])], [AC_INCLUDES_DEFAULT + #include + ]) ], [ AC_CHECK_LIB([ngtcp2_crypto_openssl], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_openssl" ], [ AC_CHECK_LIB([ngtcp2_crypto_quictls], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_quictls" ]) @@ -1634,6 +1727,7 @@ if test x_$withval = x_yes -o x_$withval BAKLIBS="$LIBS" LIBS="-lssl $LIBS" AC_CHECK_FUNCS([SSL_is_quic], [], [AC_MSG_ERROR([No QUIC support detected in OpenSSL. Need OpenSSL version with QUIC support to enable DNS over QUIC with libngtcp2.])]) + AC_CHECK_FUNCS([SSL_set_quic_tls_early_data_enabled]) LIBS="$BAKLIBS" AC_CHECK_TYPES([struct ngtcp2_version_cid, ngtcp2_encryption_level],,,[AC_INCLUDES_DEFAULT @@ -1655,6 +1749,22 @@ if test x_$withval = x_yes -o x_$withval AC_MSG_RESULT(no) ]) + AC_CHECK_DECL([CLOCK_MONOTONIC] + , [] + , [AC_MSG_ERROR([ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system])] + , [AC_INCLUDES_DEFAULT +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + ]) + fi # set static linking for uninstalled libraries if requested @@ -1673,10 +1783,12 @@ if test x_$enable_static_exe = x_yes; th LIBS="$LIBS -lgdi32" fi AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ]) - if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then - : - else - LIBS="$LIBS -l:libssp.a" + if echo "$host" | $GREP -i -e linux >/dev/null; then + if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then + : + else + LIBS="$LIBS -l:libssp.a" + fi fi fi fi @@ -1694,10 +1806,12 @@ if test x_$enable_fully_static = x_yes; LIBS="$LIBS -lgdi32" fi AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ]) - if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then - : - else - LIBS="$LIBS -l:libssp.a" + if echo "$host" | $GREP -i -e linux >/dev/null; then + if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then + : + else + LIBS="$LIBS -l:libssp.a" + fi fi fi fi @@ -1756,6 +1870,7 @@ if test $ac_cv_func_daemon = yes; then ]) fi +AC_CHECK_MEMBERS([struct stat.st_mtimensec, struct stat.st_mtim.tv_nsec]) AC_CHECK_MEMBERS([struct sockaddr_un.sun_len],,,[ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_UN_H @@ -1826,7 +1941,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([ AC_MSG_RESULT(no)) AC_SEARCH_LIBS([setusercontext], [util]) -AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid]) +AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob fnmatch initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid]) AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])]) AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])]) @@ -2293,6 +2408,7 @@ dnl includes AHX_CONFIG_FORMAT_ATTRIBUTE AHX_CONFIG_UNUSED_ATTRIBUTE +AHX_CONFIG_NONSTRING_ATTRIBUTE AHX_CONFIG_FSEEKO AHX_CONFIG_MAXHOSTNAMELEN #if !defined(HAVE_SNPRINTF) || defined(SNPRINTF_RET_BROKEN) Index: usr.sbin/unbound/cachedb/cachedb.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/cachedb/cachedb.c,v diff -u -p -r1.22 cachedb.c --- usr.sbin/unbound/cachedb/cachedb.c 31 Aug 2025 21:41:09 -0000 1.22 +++ usr.sbin/unbound/cachedb/cachedb.c 21 Sep 2026 16:28:03 -0000 @@ -401,12 +401,15 @@ prep_data(struct module_qstate* qstate, FLAGS_GET_RCODE(qstate->return_msg->rep->flags) != LDNS_RCODE_YXDOMAIN) return 0; - /* We don't store the reply if its TTL is 0 unless serve-expired is - * enabled. Such a reply won't be reusable and simply be a waste for - * the backend. It's also compatible with the default behavior of - * dns_cache_store_msg(). */ - if(qstate->return_msg->rep->ttl == 0 && - !qstate->env->cfg->serve_expired) + /* Do not persist data the validator has not yet seen, or has rejected. + * Otherwise an expired blob could maybe reach clients via + * serve-expired. */ + if(qstate->env->need_to_validate && + qstate->return_msg->rep->security == sec_status_bogus) + return 0; + /* We don't store the reply if its TTL is 0. This is probably coming + * from upstream and it is not meant to be stored. */ + if(qstate->return_msg->rep->ttl == 0) return 0; /* The EDE is added to the out-list so it is encoded in the cached message */ @@ -460,7 +463,7 @@ good_expiry_and_qinfo(struct module_qsta * - serve_expired needs to be set * - if SERVE_EXPIRED_TTL is set make sure that the record is not older * than that. */ - if((time_t)expiry < *qstate->env->now && + if(TTL_IS_EXPIRED((time_t)expiry, *qstate->env->now) && (!qstate->env->cfg->serve_expired || (SERVE_EXPIRED_TTL && *qstate->env->now - (time_t)expiry > SERVE_EXPIRED_TTL))) @@ -472,7 +475,8 @@ good_expiry_and_qinfo(struct module_qsta /* Adjust the TTL of the given RRset by 'subtract'. If 'subtract' is * negative, set the TTL to 0. */ static void -packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract) +packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract, + time_t timestamp) { size_t i; size_t total = data->count + data->rrsig_count; @@ -484,13 +488,13 @@ packed_rrset_ttl_subtract(struct packed_ data->rr_ttl[i] -= subtract; else data->rr_ttl[i] = 0; } - data->ttl_add = (subtract < data->ttl_add) ? (data->ttl_add - subtract) : 0; + data->ttl_add = timestamp; } /* Adjust the TTL of a DNS message and its RRs by 'adjust'. If 'adjust' is * negative, set the TTLs to 0. */ static void -adjust_msg_ttl(struct dns_msg* msg, time_t adjust) +adjust_msg_ttl(struct dns_msg* msg, time_t adjust, time_t timestamp) { size_t i; if(adjust >= 0 && msg->rep->ttl > adjust) @@ -502,13 +506,13 @@ adjust_msg_ttl(struct dns_msg* msg, time for(i=0; irep->rrset_count; i++) { packed_rrset_ttl_subtract((struct packed_rrset_data*)msg-> - rep->rrsets[i]->entry.data, adjust); + rep->rrsets[i]->entry.data, adjust, timestamp); } } /* Set the TTL of the given RRset to fixed value. */ static void -packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl) +packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl, time_t timestamp) { size_t i; size_t total = data->count + data->rrsig_count; @@ -516,12 +520,12 @@ packed_rrset_ttl_set(struct packed_rrset for(i=0; irr_ttl[i] = ttl; } - data->ttl_add = 0; + data->ttl_add = timestamp; } /* Set the TTL of a DNS message and its RRs by to a fixed value. */ static void -set_msg_ttl(struct dns_msg* msg, time_t ttl) +set_msg_ttl(struct dns_msg* msg, time_t ttl, time_t timestamp) { size_t i; msg->rep->ttl = ttl; @@ -530,14 +534,14 @@ set_msg_ttl(struct dns_msg* msg, time_t for(i=0; irep->rrset_count; i++) { packed_rrset_ttl_set((struct packed_rrset_data*)msg-> - rep->rrsets[i]->entry.data, ttl); + rep->rrsets[i]->entry.data, ttl, timestamp); } } /** convert dns message in buffer to return_msg */ static int parse_data(struct module_qstate* qstate, struct sldns_buffer* buf, - int* msg_expired) + int* msg_expired, time_t* msg_timestamp, time_t* msg_expiry) { struct msg_parse* prs; struct edns_data edns; @@ -554,6 +558,9 @@ parse_data(struct module_qstate* qstate, ×tamp, sizeof(timestamp)); expiry = be64toh(expiry); timestamp = be64toh(timestamp); + log_assert(timestamp <= expiry); + *msg_expiry = (time_t)expiry; + *msg_timestamp = (time_t)timestamp; /* parse DNS packet */ regional_free_all(qstate->env->scratch); @@ -605,11 +612,9 @@ parse_data(struct module_qstate* qstate, return 1; /* message from the future (clock skew?) */ } adjust = *qstate->env->now - (time_t)timestamp; - if(qstate->return_msg->rep->ttl < adjust) { + if(TTL_IS_EXPIRED((time_t)expiry, *qstate->env->now)) { verbose(VERB_ALGO, "cachedb msg expired"); *msg_expired = 1; - /* If serve-expired is enabled, we still use an expired message - * setting the TTL to 0. */ if(!qstate->env->cfg->serve_expired || (FLAGS_GET_RCODE(qstate->return_msg->rep->flags) != LDNS_RCODE_NOERROR && @@ -618,23 +623,21 @@ parse_data(struct module_qstate* qstate, FLAGS_GET_RCODE(qstate->return_msg->rep->flags) != LDNS_RCODE_YXDOMAIN)) return 0; /* message expired */ - else - adjust = -1; + /* If serve-expired is enabled, we still use an expired message. + * Set the TTL to 0 now and it will be handled specially later + * when we need to store it internally. */ + adjust = -1; } + adjust_msg_ttl(qstate->return_msg, adjust, timestamp); verbose(VERB_ALGO, "cachedb msg adjusted down by %d", (int)adjust); - adjust_msg_ttl(qstate->return_msg, adjust); if(qstate->env->cfg->aggressive_nsec) { limit_nsec_ttl(qstate->return_msg); } /* Similar to the unbound worker, if serve-expired is enabled and * the msg would be considered to be expired, mark the state so a - * refetch will be scheduled. The comparison between 'expiry' and - * 'now' should be redundant given how these values were calculated, - * but we check it just in case as does good_expiry_and_qinfo(). */ - if(qstate->env->cfg->serve_expired && - !qstate->env->cfg->serve_expired_client_timeout && - (adjust == -1 || (time_t)expiry < *qstate->env->now)) { + * refetch will be scheduled. */ + if(*msg_expired && !qstate->env->cfg->serve_expired_client_timeout) { qstate->need_refetch = 1; } @@ -647,7 +650,7 @@ parse_data(struct module_qstate* qstate, */ static int cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie, - int* msg_expired) + int* msg_expired, time_t* msg_timestamp, time_t* msg_expiry) { char key[(CACHEDB_HASHSIZE/8)*2+1]; calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key)); @@ -664,7 +667,8 @@ cachedb_extcache_lookup(struct module_qs } /* parse dns message into return_msg */ - if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired) ) { + if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired, + msg_timestamp, msg_expiry) ) { return 0; } return 1; @@ -736,24 +740,30 @@ cachedb_intcache_lookup(struct module_qs * Store query into the internal cache of unbound. */ static void -cachedb_intcache_store(struct module_qstate* qstate, int msg_expired) +cachedb_intcache_store(struct module_qstate* qstate, int msg_expired, + time_t msg_timestamp, time_t msg_expiry) { uint32_t store_flags = qstate->query_flags; int serve_expired = qstate->env->cfg->serve_expired; - - if(qstate->env->cfg->serve_expired) - store_flags |= DNSCACHE_STORE_ZEROTTL; if(!qstate->return_msg) return; if(serve_expired && msg_expired) { - /* Set TTLs to a value such that value + *env->now is - * going to be now-3 seconds. Making it expired - * in the cache. */ - set_msg_ttl(qstate->return_msg, (time_t)-3); + time_t original_ttl = msg_expiry - msg_timestamp; + store_flags |= DNSCACHE_STORE_EXPIRED_MSG_CACHEDB; + /* Pass the original TTL of the expired message and signal with + * the DNSCACHE_STORE_EXPIRED_MSG_CACHEDB flag that + * dns_cache_store_msg() needs to set absolute expired TTLs + * based on the original message TTL. + * Results as expired message in the cache */ + set_msg_ttl(qstate->return_msg, original_ttl, 0); + verbose(VERB_ALGO, "cachedb expired msg set to be expired now " + "(original ttl: %d)", (int)original_ttl); /* The expired entry does not get checked by the validator * and we need a validation value for it. */ + /* By setting this to unchecked, bogus data is not returned + * as non-bogus. */ if(qstate->env->cfg->cachedb_check_when_serve_expired) - qstate->return_msg->rep->security = sec_status_insecure; + qstate->return_msg->rep->security = sec_status_unchecked; } (void)dns_cache_store(qstate->env, &qstate->qinfo, qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0, @@ -767,12 +777,14 @@ cachedb_intcache_store(struct module_qst * of cache. */ return; } - /* set TTLs to zero again */ - adjust_msg_ttl(qstate->return_msg, -1); /* Send serve expired responses based on the cachedb * returned message, that was just stored in the cache. * It can then continue to work on this query. */ mesh_respond_serve_expired(qstate->mesh_info); + /* set TTLs as expired for this return_msg in case it is used + * later on */ + set_msg_ttl(qstate->return_msg, + EXPIRED_REPLY_TTL_CALC(msg_expiry, msg_timestamp), 0); } } @@ -790,6 +802,7 @@ cachedb_handle_query(struct module_qstat struct cachedb_env* ie, int id) { int msg_expired = 0; + time_t msg_timestamp, msg_expiry; qstate->is_cachedb_answer = 0; /* check if we are enabled, and skip if so */ if(!ie->enabled) { @@ -798,8 +811,11 @@ cachedb_handle_query(struct module_qstat return; } - if(qstate->blacklist || qstate->no_cache_lookup) { - /* cache is blacklisted or we are instructed from edns to not look */ + if(qstate->blacklist || qstate->no_cache_lookup + || iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, + NULL, 0)) { + /* cache is blacklisted or we are instructed from edns to not + * look or a forwarder/stub forbids it */ /* pass request to next module */ qstate->ext_state[id] = module_wait_module; return; @@ -824,13 +840,15 @@ cachedb_handle_query(struct module_qstat } /* ask backend cache to see if we have data */ - if(cachedb_extcache_lookup(qstate, ie, &msg_expired)) { + if(cachedb_extcache_lookup(qstate, ie, &msg_expired, &msg_timestamp, + &msg_expiry)) { if(verbosity >= VERB_ALGO) log_dns_msg(ie->backend->name, &qstate->return_msg->qinfo, qstate->return_msg->rep); /* store this result in internal cache */ - cachedb_intcache_store(qstate, msg_expired); + cachedb_intcache_store(qstate, + msg_expired, msg_timestamp, msg_expiry); /* In case we have expired data but there is a client timer for expired * answers, pass execution to next module in order to try updating the * data first. @@ -850,6 +868,13 @@ cachedb_handle_query(struct module_qstat qstate->ext_state[id] = module_wait_module; return; } + /* No 0TTL answers escaping from external cache. */ + if(qstate->return_msg->rep->ttl == 0) { + qstate->return_msg = NULL; + qstate->ext_state[id] = module_wait_module; + return; + } + log_assert(qstate->return_msg->rep->ttl > 0); qstate->is_cachedb_answer = 1; /* we are done with the query */ qstate->ext_state[id] = module_finished; @@ -883,7 +908,9 @@ cachedb_handle_response(struct module_qs { qstate->is_cachedb_answer = 0; /* check if we are not enabled or instructed to not cache, and skip */ - if(!ie->enabled || qstate->no_cache_store) { + if(!ie->enabled || qstate->no_cache_store + || iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, + NULL, 0)) { /* we are done with the query */ qstate->ext_state[id] = module_finished; return; Index: usr.sbin/unbound/cachedb/redis.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/cachedb/redis.c,v diff -u -p -r1.1.1.7 redis.c --- usr.sbin/unbound/cachedb/redis.c 26 Sep 2025 07:30:48 -0000 1.1.1.7 +++ usr.sbin/unbound/cachedb/redis.c 21 Sep 2026 16:28:03 -0000 @@ -143,6 +143,12 @@ redis_connect(const char* host, int port { struct timeval now_val; redisContext* ctx; +#ifdef THREADS_DISABLED + /* Fix attribute unused warning. + * wait_lock is only used with lock_basic_* functions that are nop'ed + * when compiled without thread support. */ + (void)wait_lock; +#endif /* THREADS_DISABLED */ /* See if the redis server is down, and reconnect has to wait. */ if(*reconnect_attempts > REDIS_RECONNECT_ATTEMPT_LIMIT) { Index: usr.sbin/unbound/daemon/cachedump.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/daemon/cachedump.c,v diff -u -p -r1.13 cachedump.c --- usr.sbin/unbound/daemon/cachedump.c 26 Sep 2025 07:32:37 -0000 1.13 +++ usr.sbin/unbound/daemon/cachedump.c 21 Sep 2026 16:28:03 -0000 @@ -99,7 +99,7 @@ static void dump_rrset_line(struct config_strlist_head* txt, struct ub_packed_rrset_key* k, time_t now, size_t i) { - char s[65535]; + char s[65535*4+2048]; if(!packed_rr_to_string(k, i, now, s, sizeof(s))) { spool_txt_string(txt, "BADRR\n"); return; @@ -455,7 +455,7 @@ load_rr(RES* ssl, sldns_buffer* buf, str /* read the line */ if(!ssl_read_buf(ssl, buf)) return 0; - if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) { + if(strcmp((char*)sldns_buffer_begin(buf), "BADRR") == 0) { *go_on = 0; return 1; } Index: usr.sbin/unbound/daemon/daemon.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/daemon/daemon.c,v diff -u -p -r1.28 daemon.c --- usr.sbin/unbound/daemon/daemon.c 31 Aug 2025 21:41:09 -0000 1.28 +++ usr.sbin/unbound/daemon/daemon.c 21 Sep 2026 16:28:04 -0000 @@ -79,6 +79,7 @@ #include "util/tcp_conn_limit.h" #include "util/edns.h" #include "services/listen_dnsport.h" +#include "services/outside_network.h" #include "services/cache/rrset.h" #include "services/cache/infra.h" #include "services/localzone.h" @@ -199,6 +200,267 @@ signal_handling_playback(struct worker* sig_record_reload = 0; } +#ifdef HAVE_SSL +/* setup a listening ssl context, fatal_exit() on any failure */ +static void +setup_listen_sslctx(void** ctx, int is_dot, int is_doh, + struct config_file* cfg, char* chroot) +{ + char* key = cfg->ssl_service_key; + char* pem = cfg->ssl_service_pem; + if(chroot && strncmp(key, chroot, strlen(chroot)) == 0) + key += strlen(chroot); + if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0) + pem += strlen(chroot); + if(!(*ctx = listen_sslctx_create(key, pem, NULL, + cfg->tls_ciphers, cfg->tls_ciphersuites, + (cfg->tls_session_ticket_keys.first && + cfg->tls_session_ticket_keys.first->str[0] != 0), + is_dot, is_doh, cfg->tls_protocols))) { + log_err("could not set up listen SSL_CTX"); + *ctx = NULL; + } +} +#endif /* HAVE_SSL */ + +#ifdef HAVE_SSL +void* daemon_setup_listen_dot_sslctx(struct daemon* daemon, + struct config_file* cfg) +{ + void* ctx; + (void)setup_listen_sslctx(&ctx, 1, 0, cfg, daemon->chroot); + return ctx; +} +#endif /* HAVE_SSL */ + +#ifdef HAVE_SSL +#ifdef HAVE_NGHTTP2_NGHTTP2_H +void* daemon_setup_listen_doh_sslctx(struct daemon* daemon, + struct config_file* cfg) +{ + void* ctx; + (void)setup_listen_sslctx(&ctx, 0, 1, cfg, daemon->chroot); + return ctx; +} +#endif /* HAVE_NGHTTP2_NGHTTP2_H */ +#endif /* HAVE_SSL */ + +#ifdef HAVE_SSL +#ifdef HAVE_NGTCP2 +void* daemon_setup_listen_quic_sslctx(struct daemon* daemon, + struct config_file* cfg) +{ + void* ctx; + char* chroot = daemon->chroot; + char* key = cfg->ssl_service_key; + char* pem = cfg->ssl_service_pem; + if(chroot && strncmp(key, chroot, strlen(chroot)) == 0) + key += strlen(chroot); + if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0) + pem += strlen(chroot); + + if(!(ctx = quic_sslctx_create(key, pem, NULL))) { + log_err("could not set up quic SSL_CTX"); + return NULL; + } + return ctx; +} +#endif /* HAVE_NGTCP2 */ +#endif /* HAVE_SSL */ + +#ifdef HAVE_SSL +void* daemon_setup_connect_dot_sslctx(struct daemon* daemon, + struct config_file* cfg) +{ + void* ctx; + char* bundle, *chroot = daemon->chroot; + bundle = cfg->tls_cert_bundle; + if(chroot && bundle && strncmp(bundle, chroot, strlen(chroot)) == 0) + bundle += strlen(chroot); + + if(!(ctx = connect_sslctx_create(NULL, NULL, bundle, + cfg->tls_win_cert))) { + log_err("could not set up connect SSL_CTX"); + return NULL; + } + return ctx; +} +#endif /* HAVE_SSL */ + +/* setups the needed ssl contexts, fatal_exit() on any failure */ +void +daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg) +{ +#ifdef HAVE_SSL + char* chroot = daemon->chroot; + if(cfg->ssl_service_key && cfg->ssl_service_key[0]) { + char* key = cfg->ssl_service_key; + char* pem = cfg->ssl_service_pem; + if(chroot && strncmp(key, chroot, strlen(chroot)) == 0) + key += strlen(chroot); + if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0) + pem += strlen(chroot); + + /* setup the session keys; the callback to use them will be + * attached to each sslctx separately */ + if(cfg->tls_session_ticket_keys.first && + cfg->tls_session_ticket_keys.first->str[0] != 0) { + if(!listen_sslctx_setup_ticket_keys( + cfg->tls_session_ticket_keys.first, chroot)) { + fatal_exit("could not set session ticket SSL_CTX"); + } + } + daemon->listen_dot_sslctx = daemon_setup_listen_dot_sslctx( + daemon, cfg); + if(!daemon->listen_dot_sslctx) + fatal_exit("Could not set up listen dot sslctx"); +#ifdef HAVE_NGHTTP2_NGHTTP2_H + if(cfg_has_https(cfg)) { + daemon->listen_doh_sslctx = + daemon_setup_listen_doh_sslctx(daemon, cfg); + if(!daemon->listen_doh_sslctx) + fatal_exit("Could not set up listen doh sslctx"); + } +#endif +#ifdef HAVE_NGTCP2 + if(cfg_has_quic(cfg)) { + daemon->listen_quic_sslctx = + daemon_setup_listen_quic_sslctx(daemon, cfg); + if(!daemon->listen_quic_sslctx) + fatal_exit("Could not set up listen quic sslctx"); + } +#endif /* HAVE_NGTCP2 */ + + /* Store the file name and mtime to detect changes later. */ + daemon->ssl_service_key = strdup(cfg->ssl_service_key); + if(!daemon->ssl_service_key) + fatal_exit("could not setup ssl ctx: out of memory"); + if(cfg->ssl_service_pem) { + daemon->ssl_service_pem = strdup(cfg->ssl_service_pem); + if(!daemon->ssl_service_pem) + fatal_exit("could not setup ssl ctx: out of memory"); + } else { + daemon->ssl_service_pem = NULL; + } + if(!file_get_mtime(key, + &daemon->mtime_ssl_service_key, + &daemon->mtime_ns_ssl_service_key, NULL)) + log_err("Could not stat(%s): %s", + key, strerror(errno)); + if(pem) { + if(!file_get_mtime(pem, + &daemon->mtime_ssl_service_pem, + &daemon->mtime_ns_ssl_service_pem, NULL)) + log_err("Could not stat(%s): %s", + pem, strerror(errno)); + } else { + daemon->mtime_ssl_service_pem = 0; + daemon->mtime_ns_ssl_service_pem = 0; + } + } + daemon->connect_dot_sslctx = daemon_setup_connect_dot_sslctx( + daemon, cfg); + if(!daemon->connect_dot_sslctx) + fatal_exit("could not setup connect dot sslctx"); +#else /* HAVE_SSL */ + (void)daemon;(void)cfg; +#endif /* HAVE_SSL */ +} + +/** Delete the ssl ctxs */ +static void +daemon_delete_sslctxs(struct daemon* daemon) +{ +#ifdef HAVE_SSL + listen_sslctx_delete_ticket_keys(); + SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx); + daemon->listen_dot_sslctx = NULL; + SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx); + daemon->listen_doh_sslctx = NULL; + SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx); + daemon->connect_dot_sslctx = NULL; + free(daemon->ssl_service_key); + daemon->ssl_service_key = NULL; + free(daemon->ssl_service_pem); + daemon->ssl_service_pem = NULL; +#else + (void)daemon; +#endif +#ifdef HAVE_NGTCP2 + SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx); + daemon->listen_quic_sslctx = NULL; +#endif +} + +int +ssl_cert_changed(struct daemon* daemon, struct config_file* cfg) +{ + time_t mtime = 0; + long ns = 0; + char* chroot = daemon->chroot; + char* key = cfg->ssl_service_key; + char* pem = cfg->ssl_service_pem; + log_assert(daemon->ssl_service_key && cfg->ssl_service_key); + if(chroot && strncmp(key, chroot, strlen(chroot)) == 0) + key += strlen(chroot); + if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0) + pem += strlen(chroot); + + if(strcmp(daemon->ssl_service_key, cfg->ssl_service_key) != 0) + return 1; + if(daemon->ssl_service_pem && cfg->ssl_service_pem && + strcmp(daemon->ssl_service_pem, cfg->ssl_service_pem) != 0) + return 1; + if(!file_get_mtime(key, &mtime, &ns, NULL)) { + log_err("Could not stat(%s): %s", + key, strerror(errno)); + /* It has probably changed, but file read is likely going to + * fail. */ + return 0; + } + if(mtime != daemon->mtime_ssl_service_key || + ns != daemon->mtime_ns_ssl_service_key) + return 1; + if(pem) { + if(!file_get_mtime(pem, &mtime, &ns, NULL)) { + log_err("Could not stat(%s): %s", + pem, strerror(errno)); + /* It has probably changed, but file read is likely going to + * fail. */ + return 0; + } + if(mtime != daemon->mtime_ssl_service_pem || + ns != daemon->mtime_ns_ssl_service_pem) + return 1; + } + return 0; +} + +/** Reload the sslctxs if they have changed */ +static void +daemon_reload_sslctxs(struct daemon* daemon) +{ +#ifdef HAVE_SSL + if(daemon->cfg->ssl_service_key && daemon->cfg->ssl_service_key[0]) { + /* See if changed */ + if(!daemon->ssl_service_key || + ssl_cert_changed(daemon,daemon->cfg)) { + verbose(VERB_ALGO, "Reloading certificates"); + daemon_delete_sslctxs(daemon); + daemon_setup_sslctxs(daemon, daemon->cfg); + } + } else { + /* See if sslctxs are removed from config. */ + if(daemon->ssl_service_key) { + verbose(VERB_ALGO, "Removing certificates"); + daemon_delete_sslctxs(daemon); + } + } +#else + (void)daemon; +#endif +} + struct daemon* daemon_init(void) { @@ -235,7 +497,11 @@ daemon_init(void) # else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); # endif # if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS /* grab the COMP method ptr because openssl leaks it */ @@ -244,7 +510,11 @@ daemon_init(void) # if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); # else - (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); # endif # if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) if(!ub_openssl_lock_init()) @@ -343,7 +613,7 @@ int setup_acl_for_ports(struct acl_list* return 1; } -int +int daemon_open_shared_ports(struct daemon* daemon) { log_assert(daemon); @@ -556,11 +826,17 @@ daemon_create_workers(struct daemon* dae fatal_exit("out of memory during daemon init"); numport = daemon_get_shufport(daemon, shufport); verbose(VERB_ALGO, "total of %d outgoing ports available", numport); + if(!(daemon->shared_ports = shared_ports_create(daemon->cfg->out_ifs, + daemon->cfg->num_out_ifs, daemon->cfg->do_ip4, + daemon->cfg->do_ip6, shufport, numport))) + fatal_exit("could not setup shared ports: out of memory"); #ifdef HAVE_NGTCP2 - daemon->doq_table = doq_table_create(daemon->cfg, daemon->rand); - if(!daemon->doq_table) - fatal_exit("could not create doq_table: out of memory"); + if (cfg_has_quic(daemon->cfg)) { + daemon->doq_table = doq_table_create(daemon->cfg, daemon->rand); + if(!daemon->doq_table) + fatal_exit("could not create doq_table: out of memory"); + } #endif daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1); @@ -584,10 +860,7 @@ daemon_create_workers(struct daemon* dae #endif } for(i=0; inum; i++) { - if(!(daemon->workers[i] = worker_create(daemon, i, - shufport+numport*i/daemon->num, - numport*(i+1)/daemon->num - numport*i/daemon->num))) - /* the above is not ports/numthr, due to rounding */ + if(!(daemon->workers[i] = worker_create(daemon, i))) fatal_exit("could not create worker"); } /* create per-worker alloc caches if not reusing existing ones. */ @@ -632,6 +905,25 @@ static void close_other_pipes(struct dae #endif /* THREADS_DISABLED */ /** + * Function to set the thread local log ID. + * Either the internal thread number, or the LWP ID on Linux based on + * configuration. + */ +static void +set_log_thread_id(struct worker* worker, struct config_file* cfg) +{ + (void)cfg; + log_assert(worker); +#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED) + worker->thread_tid = gettid(); + if(cfg->log_thread_id) + log_thread_set(&worker->thread_tid); + else +#endif + log_thread_set(&worker->thread_num); +} + +/** * Function to start one thread. * @param arg: user argument. * @return: void* user return value could be used for thread_join results. @@ -641,7 +933,15 @@ thread_start(void* arg) { struct worker* worker = (struct worker*)arg; int port_num = 0; - log_thread_set(&worker->thread_num); + set_log_thread_id(worker, worker->daemon->cfg); + { + char name[16]; /* seems to be the safest size between + different OSes */ + snprintf(name, sizeof(name), "unbound/%u", worker->thread_num); + /* worker->thr_id can be written to after the thread was made + * by the creating thread, so this uses pthread_self. */ + ub_thread_setname(ub_thread_self(), name); + } ub_thread_blocksigs(); #ifdef THREADS_DISABLED /* close pipe ends used by main */ @@ -655,8 +955,9 @@ thread_start(void* arg) port_num = 0; #endif if(!worker_init(worker, worker->daemon->cfg, - worker->daemon->ports[port_num], 0)) + worker->daemon->ports[port_num], 0)) { fatal_exit("Could not initialize thread"); + } worker_work(worker); return NULL; @@ -716,6 +1017,7 @@ daemon_fork(struct daemon* daemon) #endif log_assert(daemon); + daemon_reload_sslctxs(daemon); if(!(daemon->env->views = views_create())) fatal_exit("Could not create views: out of memory"); /* create individual views and their localzone/data trees */ @@ -801,14 +1103,25 @@ daemon_fork(struct daemon* daemon) fatal_exit("RPZ requires the respip module"); /* first create all the worker structures, so we can pass - * them to the newly created threads. + * them to the newly created threads. */ daemon_create_workers(daemon); + /* Set it for the first (main) worker since it does not take part in + * the thread_start() procedure. + */ + set_log_thread_id(daemon->workers[0], daemon->cfg); + /* If shm stats need an offset, calculate it */ + if(daemon->cfg->shm_enable && daemon->cfg->stat_interval > 0) { + daemon->stat_time_specific = 1; + daemon->stat_time_offset = + ((int)time(NULL))%daemon->cfg->stat_interval; + } #if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) /* in libev the first inited base gets signals */ - if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) + if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) { fatal_exit("Could not initialize main thread"); + } #endif /* Now create the threads and init the workers. @@ -821,8 +1134,9 @@ daemon_fork(struct daemon* daemon) */ #if !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) /* libevent has the last inited base get signals (or any base) */ - if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) + if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) { fatal_exit("Could not initialize main thread"); + } #endif signal_handling_playback(daemon->workers[0]); @@ -866,7 +1180,6 @@ daemon_cleanup(struct daemon* daemon) /* before stopping main worker, handle signals ourselves, so we don't die on multiple reload signals for example. */ signal_handling_record(); - log_thread_set(NULL); /* clean up caches because * a) RRset IDs will be recycled after a reload, causing collisions * b) validation config can change, thus rrset, msg, keycache clear @@ -908,6 +1221,8 @@ daemon_cleanup(struct daemon* daemon) if(!daemon->reuse_cache || daemon->need_to_exit) daemon_clear_allocs(daemon); daemon->num = 0; + shared_ports_delete(daemon->shared_ports); + daemon->shared_ports = NULL; #ifdef USE_DNSTAP dt_delete(daemon->dtenv); daemon->dtenv = NULL; @@ -917,8 +1232,10 @@ daemon_cleanup(struct daemon* daemon) daemon->dnscenv = NULL; #endif #ifdef HAVE_NGTCP2 - doq_table_delete(daemon->doq_table); - daemon->doq_table = NULL; + if (daemon->doq_table) { + doq_table_delete(daemon->doq_table); + daemon->doq_table = NULL; + } #endif daemon->cfg = NULL; } @@ -956,15 +1273,7 @@ daemon_delete(struct daemon* daemon) free(daemon->pidfile); free(daemon->cfgfile); free(daemon->env); -#ifdef HAVE_SSL - listen_sslctx_delete_ticket_keys(); - SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx); - SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx); - SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx); -#endif -#ifdef HAVE_NGTCP2 - SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx); -#endif + daemon_delete_sslctxs(daemon); free(daemon); /* lex cleanup */ ub_c_lex_destroy(); @@ -976,7 +1285,7 @@ daemon_delete(struct daemon* daemon) # if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE # ifndef S_SPLINT_S # if OPENSSL_VERSION_NUMBER < 0x10100000 - sk_SSL_COMP_pop_free(comp_meth, (void(*)())CRYPTO_free); + sk_SSL_COMP_pop_free(comp_meth, (void(*)(SSL_COMP*))CRYPTO_free); # endif # endif # endif @@ -999,6 +1308,9 @@ daemon_delete(struct daemon* daemon) # if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) ub_openssl_lock_delete(); # endif +#ifdef HAVE_OPENSSL_CLEANUP + OPENSSL_cleanup(); +#endif #ifndef HAVE_ARC4RANDOM _ARC4_LOCK_DESTROY(); #endif Index: usr.sbin/unbound/daemon/daemon.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/daemon/daemon.h,v diff -u -p -r1.11 daemon.h --- usr.sbin/unbound/daemon/daemon.h 31 Aug 2025 21:41:09 -0000 1.11 +++ usr.sbin/unbound/daemon/daemon.h 21 Sep 2026 16:28:04 -0000 @@ -62,6 +62,7 @@ struct doq_table; struct cookie_secrets; struct fast_reload_thread; struct fast_reload_printq; +struct shared_ports; #include "dnstap/dnstap_config.h" #ifdef USE_DNSTAP @@ -97,6 +98,8 @@ struct daemon { int rc_port; /** listening ports for remote control */ struct listen_port* rc_ports; + /** the shared ports structure, with random ports numbers. */ + struct shared_ports* shared_ports; /** remote control connections management (for first worker) */ struct daemon_remote* rc; /** ssl context for listening to dnstcp over ssl */ @@ -107,6 +110,18 @@ struct daemon { void* listen_doh_sslctx; /** ssl context for listening to quic */ void* listen_quic_sslctx; + /** the file name that the ssl context is made with, private key. */ + char* ssl_service_key; + /** the file name that the ssl context is made with, certificate. */ + char* ssl_service_pem; + /** modification time for ssl_service_key, in sec and ns. Like + * in a struct timespec, but without that for portability. */ + time_t mtime_ssl_service_key; + long mtime_ns_ssl_service_key; + /** modification time for ssl_service_pem, in sec and ns. Like + * in a struct timespec, but without that for portability. */ + time_t mtime_ssl_service_pem; + long mtime_ns_ssl_service_pem; /** num threads allocated */ int num; /** num threads allocated in the previous config or 0 at first */ @@ -143,7 +158,14 @@ struct daemon { /** the dnstap environment master value, copied and changed by threads*/ struct dt_env* dtenv; #endif + /** The SHM info for shared memory stats. */ struct shm_main_info* shm_info; + /** if the timeout for statistics is attempted at specific offset. + * If it is true, the stat timeout is the interval+offset, and that + * picks (roughly) the same time offset every time period. */ + int stat_time_specific; + /** if the timeout is specific, what offset in the period. */ + int stat_time_offset; /** some response-ip tags or actions are configured if true */ int use_response_ip; /** some RPZ policies are configured */ @@ -228,5 +250,27 @@ void daemon_apply_cfg(struct daemon* dae * @return false on failure */ int setup_acl_for_ports(struct acl_list* list, struct listen_port* port_list); + +/* setups the needed ssl contexts, fatal_exit() on any failure */ +void daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg); + +/** See if the SSL cert files have changed */ +int ssl_cert_changed(struct daemon* daemon, struct config_file* cfg); + +/** Setup the listening DoT SSL_CTX, returns the ssl ctx. */ +void* daemon_setup_listen_dot_sslctx(struct daemon* daemon, + struct config_file* cfg); + +/** Setup the listening DoH SSL_CTX, returns the ssl ctx. */ +void* daemon_setup_listen_doh_sslctx(struct daemon* daemon, + struct config_file* cfg); + +/** Setup the listening Quic SSL_CTX, returns the ssl ctx */ +void* daemon_setup_listen_quic_sslctx(struct daemon* daemon, + struct config_file* cfg); + +/** Setup the connect DoT SSL_CTX, returns the ssl ctx */ +void* daemon_setup_connect_dot_sslctx(struct daemon* daemon, + struct config_file* cfg); #endif /* DAEMON_H */ Index: usr.sbin/unbound/daemon/remote.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/daemon/remote.c,v diff -u -p -r1.44 remote.c --- usr.sbin/unbound/daemon/remote.c 23 Oct 2025 12:50:29 -0000 1.44 +++ usr.sbin/unbound/daemon/remote.c 21 Sep 2026 16:28:04 -0000 @@ -153,7 +153,7 @@ remote_setup_ctx(struct daemon_remote* r log_crypto_err("could not SSL_CTX_new"); return 0; } - if(!listen_sslctx_setup(rc->ctx)) { + if(!listen_sslctx_setup(rc->ctx, cfg->tls_protocols)) { return 0; } @@ -307,6 +307,26 @@ add_open(const char* ip, int nr, struct #endif } } else { + const char* s = strchr(ip, '@'); + char newif[128]; + if(s) { + /* override port with ifspec@port */ + int portnr; + if((size_t)(s-ip) >= sizeof(newif)) { + log_err("ifname too long: %s", ip); + return -1; + } + portnr = atoi(s+1); + if(portnr < 0 || 0 == portnr || portnr > 65535) { + log_err("invalid portnumber in control-interface: %s", ip); + return -1; + } + (void)strlcpy(newif, ip, sizeof(newif)); + newif[s-ip] = 0; + ip = newif; + snprintf(port, sizeof(port), "%d", portnr); + port[sizeof(port)-1]=0; + } hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) { @@ -801,6 +821,8 @@ print_stats(RES* ssl, const char* nm, st (unsigned long)s->svr.num_queries_cookie_invalid)) return 0; if(!ssl_printf(ssl, "%s.num.queries_discard_timeout"SQ"%lu\n", nm, (unsigned long)s->svr.num_queries_discard_timeout)) return 0; + if(!ssl_printf(ssl, "%s.num.queries_replyaddr_limit"SQ"%lu\n", nm, + (unsigned long)s->svr.num_queries_replyaddr_limit)) return 0; if(!ssl_printf(ssl, "%s.num.queries_wait_limit"SQ"%lu\n", nm, (unsigned long)s->svr.num_queries_wait_limit)) return 0; if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%lu\n", nm, @@ -845,6 +867,8 @@ print_stats(RES* ssl, const char* nm, st (unsigned long)s->mesh_num_states)) return 0; if(!ssl_printf(ssl, "%s.requestlist.current.user"SQ"%lu\n", nm, (unsigned long)s->mesh_num_reply_states)) return 0; + if(!ssl_printf(ssl, "%s.requestlist.current.replies"SQ"%lu\n", nm, + (unsigned long)s->mesh_num_reply_addrs)) return 0; #ifndef S_SPLINT_S sumwait.tv_sec = s->mesh_replies_sum_wait_sec; sumwait.tv_usec = s->mesh_replies_sum_wait_usec; @@ -1509,18 +1533,95 @@ do_datas_add(struct daemon_remote* rc, R (void)ssl_printf(ssl, "added %d datas\n", num); } +static int +perform_data_remove_rr(RES* ssl, struct local_zones* local_zones, + uint8_t* rr, size_t len, size_t dname_len, char *arg) +{ + uint16_t rr_class, rr_type; + int labs; + struct local_zone* z; + struct local_data* ld; + uint8_t *rdata; + size_t rdata_len, index; + struct packed_rrset_data* d; + struct local_rrset* p; + + rdata = sldns_wirerr_get_rdatawl(rr, len, dname_len); + rdata_len = ((size_t)sldns_wirerr_get_rdatalen(rr, len, dname_len))+2; + + labs = dname_count_labels(rr); + + rr_class = sldns_wirerr_get_class(rr, len, dname_len); + rr_type = sldns_wirerr_get_type(rr, len, dname_len); + + z = local_zones_lookup(local_zones, rr, dname_len, + labs, rr_class, rr_type, 1); + if (!z) { + ssl_printf(ssl, "error no zone for rr %s\n", arg); + return 0; + } + + ld = local_zone_find_data(z, rr, dname_len, labs); + if (!ld) { + ssl_printf(ssl, "error no local data for rr %s\n", arg); + return 0; + } + + p = ld->rrsets; + while (p && ntohs(p->rrset->rk.type) != rr_type) { + p = p->next; + } + + if (!p) { + ssl_printf(ssl, "error no rrset for rr %s\n", arg); + return 0; + } + + d = (struct packed_rrset_data*)p->rrset->entry.data; + if (!packed_rrset_find_rr(d, rdata, rdata_len, &index)) { + ssl_printf(ssl, "error rr %s not found in rrset\n", arg); + return 0; + } + + if (!local_rrset_remove_rr(d, index)) { + ssl_printf(ssl, "error unable to delete rr %s\n", arg); + return 0; + } + + return 1; +} + /** Remove RR data */ static int perform_data_remove(RES* ssl, struct local_zones* zones, char* arg) { - uint8_t* nm; - int nmlabs; - size_t nmlen; - if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) + uint8_t rr[LDNS_RR_BUF_SIZE], *nm; + size_t len = sizeof(rr); + int status, nmlabs; + size_t nmlen, dname_len; + + /* try to parse as a rr first */ + status = sldns_str2wire_rr_buf(arg, rr, &len, &dname_len, 3600, + NULL, 0, NULL, 0); + + /* try to parse as a domain name second */ + if (status != 0) { + if (parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) { + local_zones_del_data(zones, nm, + nmlen, nmlabs, LDNS_RR_CLASS_IN); + free(nm); + return 1; + } + ssl_printf(ssl, "error cannot parse rr %s at %d: %s\n", arg, + LDNS_WIREPARSE_OFFSET(status), + sldns_get_errorstr_parse(status)); return 0; - local_zones_del_data(zones, nm, - nmlen, nmlabs, LDNS_RR_CLASS_IN); - free(nm); + } + + /* handle the rr case */ + if (!perform_data_remove_rr(ssl, zones, rr, len, dname_len, arg)) + return 0; + return 1; } @@ -1634,6 +1735,14 @@ do_view_data_add(RES* ssl, struct worker ssl_printf(ssl,"error out of memory\n"); return; } + if(!v->isfirst) { + /* Global local-zone is not used for this view, + * therefore add defaults to this view-specific + * local-zone. */ + struct config_file lz_cfg; + memset(&lz_cfg, 0, sizeof(lz_cfg)); + local_zone_enter_defaults(v->local_zones, &lz_cfg); + } } do_data_add(ssl, v->local_zones, arg2); lock_rw_unlock(&v->lock); @@ -1659,6 +1768,14 @@ do_view_datas_add(struct daemon_remote* ssl_printf(ssl,"error out of memory\n"); return; } + if(!v->isfirst) { + /* Global local-zone is not used for this view, + * therefore add defaults to this view-specific + * local-zone. */ + struct config_file lz_cfg; + memset(&lz_cfg, 0, sizeof(lz_cfg)); + local_zone_enter_defaults(v->local_zones, &lz_cfg); + } } /* put the view name in the command buf */ (void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg); @@ -2275,6 +2392,9 @@ zone_del_rrset(struct lruhash_entry* e, (struct packed_rrset_data*)e->data; if(d->ttl > inf->expired) { d->ttl = inf->expired; + if(d->ttl_add > inf->expired) + d->ttl_add = inf->expired; /* for 0TTL rrsets, + means that d->ttl_add <= d->ttl */ inf->num_rrsets++; } } @@ -3198,6 +3318,10 @@ do_auth_zone_reload(RES* ssl, struct wor return; } if(!auth_zone_read_zonefile(z, worker->env.cfg)) { + /* The old tree was already cleared. Do not answer from the + * failed load. */ + z->zone_expired = 1; + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); if(xfr) { lock_basic_unlock(&xfr->lock); @@ -3209,6 +3333,7 @@ do_auth_zone_reload(RES* ssl, struct wor z->zone_expired = 0; if(xfr) { xfr->zone_expired = 0; + xfr->num_ixfrs = 0; if(!xfr_find_soa(z, xfr)) { if(z->data.count == 0) { lock_rw_unlock(&z->lock); @@ -4629,6 +4754,26 @@ fr_init_time(struct timeval* time_start, * are kept in here. They can then be deleted. */ struct fast_reload_construct { + /** ssl context for listening to dnstcp over ssl */ + void* listen_dot_sslctx; + /** ssl context for connecting to dnstcp over ssl */ + void* connect_dot_sslctx; + /** ssl context for listening to DoH */ + void* listen_doh_sslctx; + /** ssl context for listening to quic */ + void* listen_quic_sslctx; + /** the file name that the ssl context is made with, private key. */ + char* ssl_service_key; + /** the file name that the ssl context is made with, certificate. */ + char* ssl_service_pem; + /** modification time for ssl_service_key, in sec and ns. Like + * in a struct timespec, but without that for portability. */ + time_t mtime_ssl_service_key; + long mtime_ns_ssl_service_key; + /** modification time for ssl_service_pem, in sec and ns. Like + * in a struct timespec, but without that for portability. */ + time_t mtime_ssl_service_pem; + long mtime_ns_ssl_service_pem; /** construct for views */ struct views* views; /** construct for auth zones */ @@ -4881,6 +5026,74 @@ fr_check_changed_cfg_str2list(struct con } } +/** fast reload thread, check if config str3list has changed. */ +#define FR_CHECK_CHANGED_CFG_STR3LIST(desc, var, buff) do { \ + fr_check_changed_cfg_str3list(cfg->var, newcfg->var, desc, buff,\ + sizeof(buff)); \ + } while(0); +static void +fr_check_changed_cfg_str3list(struct config_str3list* cmp1, + struct config_str3list* cmp2, const char* desc, char* str, size_t len) +{ + struct config_str3list* p1 = cmp1, *p2 = cmp2; + while(p1 && p2) { + if((!p1->str && p2->str) || + (p1->str && !p2->str) || + (p1->str && p2->str && strcmp(p1->str, p2->str) != 0)) { + /* The str3list is different. */ + fr_add_incompatible_option(desc, str, len); + return; + } + if((!p1->str2 && p2->str2) || + (p1->str2 && !p2->str2) || + (p1->str2 && p2->str2 && + strcmp(p1->str2, p2->str2) != 0)) { + /* The str3list is different. */ + fr_add_incompatible_option(desc, str, len); + return; + } + if((!p1->str3 && p2->str3) || + (p1->str3 && !p2->str3) || + (p1->str3 && p2->str3 && + strcmp(p1->str3, p2->str3) != 0)) { + /* The str3list is different. */ + fr_add_incompatible_option(desc, str, len); + return; + } + p1 = p1->next; + p2 = p2->next; + } + if((!p1 && p2) || (p1 && !p2)) { + fr_add_incompatible_option(desc, str, len); + } +} + +/** fast reload thread, check tag datas. */ +static int +fr_check_tag_datas(struct fast_reload_thread* fr, struct config_file* newcfg) +{ + char changed_str[1024]; + struct config_file* cfg = fr->worker->env.cfg; + changed_str[0]=0; + + /* Check for tag_datas in acl_addr. */ + FR_CHECK_CHANGED_CFG_STR3LIST("interface-tag-data", interface_tag_datas, changed_str); + FR_CHECK_CHANGED_CFG_STR3LIST("access-control-tag-data", acl_tag_datas, changed_str); + + if(changed_str[0] != 0) { + if(fr->fr_drop_mesh) + return 1; /* already dropping queries */ + fr->fr_drop_mesh = 1; + fr->worker->daemon->fast_reload_drop_mesh = fr->fr_drop_mesh; + if(!fr_output_printf(fr, "recursion referenced data has changed, with: '%s" + "', and the queries have to be dropped" + ", setting '+d'\n", changed_str)) + return 0; + fr_send_notification(fr, fast_reload_notification_printout); + } + return 1; +} + /** fast reload thread, check compatible config items */ static int fr_check_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg) @@ -4932,9 +5145,7 @@ fr_check_compat_cfg(struct fast_reload_t FR_CHECK_CHANGED_CFG("http_notls_downstream", http_notls_downstream, changed_str); FR_CHECK_CHANGED_CFG("https-port", https_port, changed_str); FR_CHECK_CHANGED_CFG("tls-port", ssl_port, changed_str); - FR_CHECK_CHANGED_CFG_STR("tls-service-key", ssl_service_key, changed_str); - FR_CHECK_CHANGED_CFG_STR("tls-service-pem", ssl_service_pem, changed_str); - FR_CHECK_CHANGED_CFG_STR("tls-cert-bundle", tls_cert_bundle, changed_str); + FR_CHECK_CHANGED_CFG_STR("tls-protocols", tls_protocols, changed_str); FR_CHECK_CHANGED_CFG_STRLIST("proxy-protocol-port", proxy_protocol_port, changed_str); FR_CHECK_CHANGED_CFG_STRLIST("tls-additional-port", tls_additional_port, changed_str); FR_CHECK_CHANGED_CFG_STR("interface-automatic-ports", if_automatic_ports, changed_str); @@ -5043,6 +5254,19 @@ fr_construct_clear(struct fast_reload_co wait_limits_free(&ct->wait_limits_netblock); wait_limits_free(&ct->wait_limits_cookie_netblock); domain_limits_free(&ct->domain_limits); +#ifdef HAVE_SSL + /* The SSL contexts can be SSL_CTX_free here. It is reference + * counted. So ongoing transfers with can continue. + * Once they are done, the context is freed. */ + SSL_CTX_free((SSL_CTX*)ct->listen_dot_sslctx); + SSL_CTX_free((SSL_CTX*)ct->connect_dot_sslctx); + SSL_CTX_free((SSL_CTX*)ct->listen_doh_sslctx); +#endif /* HAVE_SSL */ +#ifdef HAVE_NGTCP2 + SSL_CTX_free((SSL_CTX*)ct->listen_quic_sslctx); +#endif + free(ct->ssl_service_key); + free(ct->ssl_service_pem); /* Delete the log identity here so that the global value is not * reset by config_delete. */ if(ct->oldcfg && ct->oldcfg->log_identity) { @@ -5175,6 +5399,7 @@ config_file_getmem(struct config_file* c m += getmem_config_strlist(cfg->tls_session_ticket_keys.first); m += getmem_str(cfg->tls_ciphers); m += getmem_str(cfg->tls_ciphersuites); + m += getmem_str(cfg->tls_protocols); m += getmem_str(cfg->http_endpoint); m += (cfg->outgoing_avail_ports?65536*sizeof(int):0); m += getmem_str(cfg->target_fetch_policy); @@ -5291,6 +5516,8 @@ fr_printmem(struct fast_reload_thread* f size_t mem = 0; if(fr_poll_for_quit(fr)) return 1; + mem += getmem_str(ct->ssl_service_key); + mem += getmem_str(ct->ssl_service_pem); mem += views_get_mem(ct->views); mem += respip_set_get_mem(ct->respip_set); mem += auth_zones_get_mem(ct->auth_zones); @@ -5403,6 +5630,23 @@ xfr_masterlist_equal(struct auth_master* return 0; } +/** See if configuration has changed. */ +static int +xfr_config_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2) +{ + if(xfr1 == NULL && xfr2 == NULL) + return 1; + if(xfr1 == NULL && xfr2 != NULL) + return 0; + if(xfr1 != NULL && xfr2 == NULL) + return 0; + if(xfr1->max_transfer_size != xfr2->max_transfer_size) + return 0; + if(xfr1->max_transfer_time != xfr2->max_transfer_time) + return 0; + return 1; +} + /** See if the list of masters has changed. */ static int xfr_masters_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2) @@ -5491,8 +5735,31 @@ auth_zones_check_changes(struct fast_rel &old_serial)!=0); have_new = (auth_zone_get_serial(new_z, &new_serial)!=0); + /* A change in primaries, also means it is different + * and the change makes it fire new transfers, from + * the new primaries. */ + /* Treat as changed when the old zone has an + * outstanding ZONEMD DS/DNSKEY mesh callback. + * This will make the worker pickup change code + * remove the mesh callback, before the old zone is + * deleted. Also it makes a new zonemd lookup. + * The new lookup is needed, because the new zone + * entry needs to have a valid zonemd result, + * and if that is bad, needs to be invalidated. + * Also if there is a race event where the + * outstanding callback makes the zone invalid, + * before fast-reload completes, the change makes + * the new zone entry have a new zonemd lookup, + * to then invalidate that new zone. + * There is also a brief operational window at + * program start when a zonemd has to be looked + * up on-line, where the zone is operational. + * And this copies that for such a race event. + */ if(have_old != have_new || old_serial != new_serial - || !xfr_masters_equal(old_xfr, new_xfr)) { + || !xfr_masters_equal(old_xfr, new_xfr) + || !xfr_config_equal(old_xfr, new_xfr) + || old_z->zonemd_callback_env != NULL) { /* The zone has been changed. */ if(!fr_add_auth_zone_change(fr, old_z, new_z, 0, 0, 1)) { @@ -5524,6 +5791,106 @@ auth_zones_check_changes(struct fast_rel return 1; } +/** Check if the sslctxs have changed. */ +static int +fr_check_sslctx_change(struct fast_reload_thread* fr, + struct config_file* newcfg) +{ +#ifdef HAVE_SSL + struct daemon* daemon = fr->worker->daemon; + if(newcfg->ssl_service_key && newcfg->ssl_service_key[0]) { + if(!daemon->ssl_service_key || + ssl_cert_changed(daemon, newcfg)) + return 1; + } else { + if(daemon->ssl_service_key) + return 1; /* it is removed */ + } + if((daemon->cfg->tls_cert_bundle && !newcfg->tls_cert_bundle) || + (!daemon->cfg->tls_cert_bundle && newcfg->tls_cert_bundle) || + (daemon->cfg->tls_cert_bundle && newcfg->tls_cert_bundle && + strcmp(daemon->cfg->tls_cert_bundle, newcfg->tls_cert_bundle)!=0)) + return 1; /* The tls-cert-bundle has changed and return + true here makes it reload the connect_dot_sslctx. */ +#else + (void)fr; (void)newcfg; +#endif /* HAVE_SSL */ + return 0; +} + +/** Create the SSL CTXs when they have changed. */ +static int +ct_create_sslctxs(struct fast_reload_construct* ct, + struct config_file* newcfg, struct daemon* daemon) +{ +#ifdef HAVE_SSL + char* chroot = daemon->chroot; + char* key = newcfg->ssl_service_key; + char* pem = newcfg->ssl_service_pem; + + if(!(newcfg->ssl_service_key && newcfg->ssl_service_key[0])) { + /* Leave listen ctxs and file str at NULL */ + ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx( + daemon, newcfg); + if(!ct->connect_dot_sslctx) + return 0; + return 1; + } + + if(chroot && strncmp(key, chroot, strlen(chroot)) == 0) + key += strlen(chroot); + if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0) + pem += strlen(chroot); + + ct->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(daemon, newcfg); + if(!ct->listen_dot_sslctx) + return 0; +#ifdef HAVE_NGHTTP2_NGHTTP2_H + if(cfg_has_https(newcfg)) { + ct->listen_doh_sslctx = daemon_setup_listen_doh_sslctx( + daemon, newcfg); + if(!ct->listen_doh_sslctx) + return 0; + } +#endif +#ifdef HAVE_NGTCP2 + if(cfg_has_quic(newcfg)) { + ct->listen_quic_sslctx = daemon_setup_listen_quic_sslctx( + daemon, newcfg); + if(!ct->listen_quic_sslctx) + return 0; + } +#endif /* HAVE_NGTCP2 */ + ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(daemon, + newcfg); + if(!ct->connect_dot_sslctx) + return 0; + + /* Store mtime and names */ + ct->ssl_service_key = strdup(newcfg->ssl_service_key); + if(!ct->ssl_service_key) { + log_err("ct_create_sslctxs: out of memory"); + return 0; + } + ct->ssl_service_pem = strdup(newcfg->ssl_service_pem); + if(!ct->ssl_service_pem) { + log_err("ct_create_sslctxs: out of memory"); + return 0; + } + if(!file_get_mtime(key, &ct->mtime_ssl_service_key, + &ct->mtime_ns_ssl_service_key, NULL)) + log_err("Could not stat(%s): %s", + key, strerror(errno)); + if(!file_get_mtime(pem, &ct->mtime_ssl_service_pem, + &ct->mtime_ns_ssl_service_pem, NULL)) + log_err("Could not stat(%s): %s", + pem, strerror(errno)); +#else + (void)ct; (void)newcfg; (void)daemon; +#endif /* HAVE_SSL */ + return 1; +} + /** fast reload thread, construct from config the new items */ static int fr_construct_from_config(struct fast_reload_thread* fr, @@ -5531,6 +5898,13 @@ fr_construct_from_config(struct fast_rel { int have_view_respip_cfg = 0; + fr->sslctxs_changed = fr_check_sslctx_change(fr, newcfg); + if(fr->sslctxs_changed) { + if(!ct_create_sslctxs(ct, newcfg, fr->worker->daemon)) { + fr_construct_clear(ct); + return 0; + } + } if(!(ct->views = views_create())) { fr_construct_clear(ct); return 0; @@ -5808,6 +6182,44 @@ auth_zones_swap(struct auth_zones* az, s * the xfer elements can continue to be their callbacks. */ } +/** Swap two void* */ +static void +void_ptr_swap(void** a, void **b) +{ + void* tmp = *a; + *a = *b; + *b = tmp; +} + +/** Swap two char* */ +static void +char_ptr_swap(char** a, char **b) +{ + char* tmp = *a; + *a = *b; + *b = tmp; +} + +/** Swap and set ssl ctx information */ +static void +sslctxs_swap(struct daemon* daemon, struct fast_reload_construct* ct) +{ + void_ptr_swap(&daemon->listen_dot_sslctx, &ct->listen_dot_sslctx); + void_ptr_swap(&daemon->connect_dot_sslctx, &ct->connect_dot_sslctx); +#ifdef HAVE_NGHTTP2_NGHTTP2_H + void_ptr_swap(&daemon->listen_doh_sslctx, &ct->listen_doh_sslctx); +#endif +#ifdef HAVE_NGTCP2 + void_ptr_swap(&daemon->listen_quic_sslctx, &ct->listen_quic_sslctx); +#endif /* HAVE_NGTCP2 */ + char_ptr_swap(&daemon->ssl_service_key, &ct->ssl_service_key); + char_ptr_swap(&daemon->ssl_service_pem, &ct->ssl_service_pem); + daemon->mtime_ssl_service_key = ct->mtime_ssl_service_key; + daemon->mtime_ns_ssl_service_key = ct->mtime_ns_ssl_service_key; + daemon->mtime_ssl_service_pem = ct->mtime_ssl_service_pem; + daemon->mtime_ns_ssl_service_pem = ct->mtime_ns_ssl_service_pem; +} + #if defined(ATOMIC_POINTER_LOCK_FREE) && defined(HAVE_LINK_ATOMIC_STORE) /** Fast reload thread, if atomics are available, copy the config items * one by one with atomic store operations. */ @@ -5869,6 +6281,7 @@ fr_atomic_copy_cfg(struct config_file* o COPY_VAR_ptr(tls_session_ticket_keys.last); COPY_VAR_ptr(tls_ciphers); COPY_VAR_ptr(tls_ciphersuites); + COPY_VAR_ptr(tls_protocols); COPY_VAR_int(tls_use_sni); COPY_VAR_int(https_port); COPY_VAR_ptr(http_endpoint); @@ -5967,6 +6380,7 @@ fr_atomic_copy_cfg(struct config_file* o COPY_VAR_int(log_servfail); COPY_VAR_ptr(log_identity); COPY_VAR_int(log_destaddr); + COPY_VAR_int(log_thread_id); COPY_VAR_int(hide_identity); COPY_VAR_int(hide_version); COPY_VAR_int(hide_trustanchor); @@ -6176,7 +6590,22 @@ fr_atomic_copy_cfg(struct config_file* o COPY_VAR_ptr(ipset_name_v6); #endif COPY_VAR_int(ede); + COPY_VAR_int(val_validation_attempts); + COPY_VAR_int(val_hash_attempts); + COPY_VAR_int(iter_scrub_ns); + COPY_VAR_int(iter_scrub_cname); + COPY_VAR_int(iter_scrub_rrsig); + COPY_VAR_int(max_global_quota); COPY_VAR_int(iter_scrub_promiscuous); + +#undef COPY_VAR_int +#undef COPY_VAR_ptr +#undef COPY_VAR_unsigned_int +#undef COPY_VAR_size_t +#undef COPY_VAR_uint8_t +#undef COPY_VAR_uint16_t +#undef COPY_VAR_uint32_t +#undef COPY_VAR_int32_t } #endif /* ATOMIC_POINTER_LOCK_FREE && HAVE_LINK_ATOMIC_STORE */ @@ -6402,11 +6831,17 @@ fr_reload_config(struct fast_reload_thre daemon->env->cachedb_enabled = cachedb_is_enabled(&daemon->mods, daemon->env); #endif + if(fr->sslctxs_changed) { + sslctxs_swap(daemon, ct); + } #ifdef USE_DNSTAP if(env->cfg->dnstap) { - if(!fr->fr_nopause) - dt_apply_cfg(daemon->dtenv, env->cfg); - else dt_apply_logcfg(daemon->dtenv, env->cfg); + if(!fr->fr_nopause) { + if(!dt_apply_cfg(daemon->dtenv, env->cfg)) + log_warn("fast_reload: dnstap identity/version metadata not updated due to allocation failure"); + } else { + dt_apply_logcfg(daemon->dtenv, env->cfg); + } } #endif fr_adjust_cache(env, ct->oldcfg); @@ -6546,6 +6981,10 @@ fr_load_config(struct fast_reload_thread config_delete(newcfg); return 0; } + if(!fr_check_tag_datas(fr, newcfg)) { + config_delete(newcfg); + return 0; + } if(!fr_check_compat_cfg(fr, newcfg)) { config_delete(newcfg); return 0; @@ -6626,7 +7065,19 @@ static void* fast_reload_thread_main(voi struct fast_reload_thread* fast_reload_thread = (struct fast_reload_thread*)arg; struct timeval time_start, time_read, time_construct, time_reload, time_end; - log_thread_set(&fast_reload_thread->threadnum); + const char name[16] = "unbound/freload"; /* seems to be the safest size + between different OSes */ + +#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED) + fast_reload_thread->thread_tid = gettid(); + if(fast_reload_thread->thread_tid_log) + log_thread_set(&fast_reload_thread->thread_tid); + else +#endif + log_thread_set(&fast_reload_thread->threadnum); + + ub_thread_setname(ub_thread_self(), name); + (void)name; /* When setname is not defined, ignore the name variable. */ verbose(VERB_ALGO, "start fast reload thread"); if(fast_reload_thread->fr_verb >= 1) { @@ -7014,6 +7465,9 @@ fast_reload_thread_setup(struct worker* lock_basic_init(&fr->fr_output_lock); lock_protect(&fr->fr_output_lock, fr->fr_output, sizeof(*fr->fr_output)); +#ifdef HAVE_GETTID + fr->thread_tid_log = worker->env.cfg->log_thread_id; +#endif return 1; } @@ -7345,7 +7799,8 @@ auth_zone_zonemd_stop_lookup(struct auth qinfo.local_alias = NULL; mesh_remove_callback(mesh, &qinfo, qflags, - &auth_zonemd_dnskey_lookup_callback, z); + &auth_zonemd_dnskey_lookup_callback, z, + z->zonemd_callback_unique_info); } /** Pick up the auth zone locks. */ @@ -7454,6 +7909,9 @@ auth_xfr_pickup_config(struct auth_xfer* log_assert(loadxfr->namelabs == xfr->namelabs); log_assert(loadxfr->dclass == xfr->dclass); + xfr->max_transfer_size = loadxfr->max_transfer_size; + xfr->max_transfer_time = loadxfr->max_transfer_time; + /* The lists can be swapped in, the other xfr struct will be deleted * afterwards. */ probe_masters = xfr->task_probe->masters; @@ -7478,6 +7936,16 @@ fr_worker_auth_add(struct worker* worker /* The xfr item needs to be created. The auth zones lock * is held to make this possible. */ xfr = auth_xfer_create(worker->env.auth_zones, item->new_z); + if(!xfr) { + log_err("out of memory in fr_worker_auth_add"); + lock_rw_unlock(&item->new_z->lock); + lock_rw_unlock(&worker->env.auth_zones->lock); + lock_rw_unlock(&worker->daemon->fast_reload_thread->old_auth_zones->lock); + if(loadxfr) { + lock_basic_unlock(&loadxfr->lock); + } + return; + } auth_xfr_pickup_config(loadxfr, xfr); /* Serial information is copied into the xfr struct. */ if(!xfr_find_soa(item->new_z, xfr)) { @@ -7547,6 +8015,17 @@ fr_worker_auth_cha(struct worker* worker } else if(loadxfr && !xfr) { /* Create the xfr. */ xfr = auth_xfer_create(worker->env.auth_zones, item->new_z); + if(!xfr) { + log_err("out of memory in fr_worker_auth_cha"); + lock_rw_unlock(&item->new_z->lock); + lock_rw_unlock(&item->old_z->lock); + lock_rw_unlock(&worker->daemon->fast_reload_thread->old_auth_zones->lock); + lock_rw_unlock(&worker->env.auth_zones->lock); + if(loadxfr) { + lock_basic_unlock(&loadxfr->lock); + } + return; + } auth_xfr_pickup_config(loadxfr, xfr); item->new_z->zone_is_slave = 1; } @@ -7588,6 +8067,44 @@ fr_worker_pickup_auth_changes(struct wor } } +/** Fast reload, the worker picks up changes in listen_dnsport. */ +static void +fr_worker_pickup_listen_dnsport(struct worker* worker) +{ + struct listen_dnsport* front = worker->front; + struct daemon* daemon = worker->daemon; + if(worker->daemon->fast_reload_thread->sslctxs_changed) { + struct listen_list* ll; + void* dot_sslctx = daemon->listen_dot_sslctx; + void* doh_sslctx = daemon->listen_doh_sslctx; +#ifdef HAVE_NGTCP2 + void* quic_sslctx = daemon->listen_quic_sslctx; +#endif /* HAVE_NGTCP2 */ + for(ll = front->cps; ll; ll = ll->next) { + struct comm_point* cp = ll->com; + if(cp->type == comm_tcp_accept && + cp->tcp_handlers && + cp->max_tcp_count > 0 && + cp->tcp_handlers[0]->type == comm_http) { + if(cp->ssl) + cp->ssl = doh_sslctx; + } else if(cp->type == comm_tcp_accept) { + if(cp->ssl) + cp->ssl = dot_sslctx; +#ifdef HAVE_NGTCP2 + } else if(cp->type == comm_doq) { + if(cp->ssl) { + cp->ssl = quic_sslctx; + if(cp->doq_socket) + cp->doq_socket->ctx = + (SSL_CTX*)quic_sslctx; + } +#endif /* HAVE_NGTCP2 */ + } + } + } +} + /** Fast reload, the worker picks up changes in outside_network. */ static void fr_worker_pickup_outside_network(struct worker* worker) @@ -7603,6 +8120,8 @@ fr_worker_pickup_outside_network(struct outnet->tcp_reuse_timeout = cfg->tcp_reuse_timeout; outnet->tcp_auth_query_timeout = cfg->tcp_auth_query_timeout; outnet->delayclose = cfg->delay_close; + if(worker->daemon->fast_reload_thread->sslctxs_changed) + outnet->sslctx = worker->daemon->connect_dot_sslctx; if(outnet->delayclose) { #ifndef S_SPLINT_S outnet->delay_tv.tv_sec = cfg->delay_close/1000; @@ -7611,6 +8130,41 @@ fr_worker_pickup_outside_network(struct } } +#ifdef USE_DNSTAP +/** Fast reload, the worker picks up changes to DNSTAP configuration. */ +static void +fr_worker_pickup_dnstap_changes(struct worker* worker) +{ + struct dt_env* w_dtenv = &worker->dtenv; + struct dt_env* d_dtenv = worker->daemon->dtenv; + log_assert(d_dtenv != NULL || !worker->daemon->cfg->dnstap); + if(d_dtenv == NULL) { + /* There is no environment when DNSTAP was not enabled + * in the configuration. */ + return; + } + w_dtenv->identity = d_dtenv->identity; + w_dtenv->len_identity = d_dtenv->len_identity; + w_dtenv->version = d_dtenv->version; + w_dtenv->len_version = d_dtenv->len_version; + w_dtenv->log_resolver_query_messages = + d_dtenv->log_resolver_query_messages; + w_dtenv->log_resolver_response_messages = + d_dtenv->log_resolver_response_messages; + w_dtenv->log_client_query_messages = + d_dtenv->log_client_query_messages; + w_dtenv->log_client_response_messages = + d_dtenv->log_client_response_messages; + w_dtenv->log_forwarder_query_messages = + d_dtenv->log_forwarder_query_messages; + w_dtenv->log_forwarder_response_messages = + d_dtenv->log_forwarder_response_messages; + lock_basic_lock(&d_dtenv->sample_lock); + w_dtenv->sample_rate = d_dtenv->sample_rate; + lock_basic_unlock(&d_dtenv->sample_lock); +} +#endif /* USE_DNSTAP */ + void fast_reload_worker_pickup_changes(struct worker* worker) { @@ -7638,7 +8192,11 @@ fast_reload_worker_pickup_changes(struct #ifdef USE_CACHEDB worker->env.cachedb_enabled = worker->daemon->env->cachedb_enabled; #endif + fr_worker_pickup_listen_dnsport(worker); fr_worker_pickup_outside_network(worker); +#ifdef USE_DNSTAP + fr_worker_pickup_dnstap_changes(worker); +#endif } /** fast reload thread, handle reload_stop notification, send reload stop Index: usr.sbin/unbound/daemon/remote.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/daemon/remote.h,v diff -u -p -r1.10 remote.h --- usr.sbin/unbound/daemon/remote.h 31 Aug 2025 21:41:09 -0000 1.10 +++ usr.sbin/unbound/daemon/remote.h 21 Sep 2026 16:28:04 -0000 @@ -49,6 +49,26 @@ #include #endif #include "util/locks.h" + +struct comm_reply; +struct comm_point; + +/** fast reload thread commands to remote service thread event callback */ +void fast_reload_service_cb(int fd, short bits, void* arg); + +/** fast reload callback for the remote control client connection */ +int fast_reload_client_callback(struct comm_point* c, void* arg, int err, + struct comm_reply* rep); + +/** handle remote control accept callbacks */ +int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*); + +/** handle remote control data callbacks */ +int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*); + +/** routine to printout option values over SSL */ +void remote_get_opt_ssl(char* line, void* arg); + struct config_file; struct listen_list; struct listen_port; @@ -206,6 +226,12 @@ struct fast_reload_thread { int commpair[2]; /** thread id, of the io thread */ ub_thread_type tid; +#ifdef HAVE_GETTID + /** thread tid, the LWP id */ + pid_t thread_tid; + /** if logging should include the LWP id */ + int thread_tid_log; +#endif /** if the io processing has started */ int started; /** if the thread has to quit */ @@ -249,6 +275,8 @@ struct fast_reload_thread { struct fast_reload_auth_change* auth_zone_change_list; /** the old tree of auth zones, to lookup. */ struct auth_zones* old_auth_zones; + /** If the ssl ctxs have changed. */ + int sslctxs_changed; }; /** @@ -356,13 +384,6 @@ void fast_reload_thread_start(RES* ssl, * @param fast_reload_thread: the thread struct. */ void fast_reload_thread_stop(struct fast_reload_thread* fast_reload_thread); - -/** fast reload thread commands to remote service thread event callback */ -void fast_reload_service_cb(int fd, short bits, void* arg); - -/** fast reload callback for the remote control client connection */ -int fast_reload_client_callback(struct comm_point* c, void* arg, int err, - struct comm_reply* rep); /** fast reload printq delete list */ void fast_reload_printq_list_delete(struct fast_reload_printq* list); Index: usr.sbin/unbound/daemon/stats.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/daemon/stats.c,v diff -u -p -r1.19 stats.c --- usr.sbin/unbound/daemon/stats.c 26 Sep 2025 07:32:37 -0000 1.19 +++ usr.sbin/unbound/daemon/stats.c 21 Sep 2026 16:28:04 -0000 @@ -262,6 +262,7 @@ server_stats_compile(struct worker* work s->svr = worker->stats; s->mesh_num_states = (long long)worker->env.mesh->all.count; s->mesh_num_reply_states = (long long)worker->env.mesh->num_reply_states; + s->mesh_num_reply_addrs = (long long)worker->env.mesh->num_reply_addrs; s->mesh_jostled = (long long)worker->env.mesh->stats_jostled; s->mesh_dropped = (long long)worker->env.mesh->stats_dropped; s->mesh_replies_sent = (long long)worker->env.mesh->replies_sent; @@ -284,6 +285,8 @@ server_stats_compile(struct worker* work NUM_BUCKETS_HIST); s->svr.num_queries_discard_timeout += (long long)worker->env.mesh->num_queries_discard_timeout; + s->svr.num_queries_replyaddr_limit += + (long long)worker->env.mesh->num_queries_replyaddr_limit; s->svr.num_queries_wait_limit += (long long)worker->env.mesh->num_queries_wait_limit; s->svr.num_dns_error_reports += @@ -419,12 +422,28 @@ void server_stats_obtain(struct worker* # endif #endif ); + log_err("server_stats_obtain: no response from worker %d " + "(stats timeout); returning zero stats for this worker", + who->thread_num); + /* A later reply from the worker, would be sizeof stats reply, + * and the worker_handle_control_cmd routine discards if + * it is not a 4byte command, when that is received here. */ + memset(s, 0, sizeof(*s)); + return; + } + if(!tube_read_msg(worker->cmd, &reply, &len, 0)) { + log_err("server_stats_obtain: failed to read stats from worker " + "(tube read error); returning zero stats for this worker"); + memset(s, 0, sizeof(*s)); + return; + } + if(len != (uint32_t)sizeof(*s)) { + log_err("server_stats_obtain: wrong stats length %d (expected %d); " + "discarding", (int)len, (int)sizeof(*s)); + free(reply); + memset(s, 0, sizeof(*s)); + return; } - if(!tube_read_msg(worker->cmd, &reply, &len, 0)) - fatal_exit("failed to read stats over cmd channel"); - if(len != (uint32_t)sizeof(*s)) - fatal_exit("stats on cmd channel wrong length %d %d", - (int)len, (int)sizeof(*s)); memcpy(s, reply, (size_t)len); free(reply); } @@ -436,7 +455,7 @@ void server_stats_reply(struct worker* w verbose(VERB_ALGO, "write stats replymsg"); if(!tube_write_msg(worker->daemon->workers[0]->cmd, (uint8_t*)&s, sizeof(s), 0)) - fatal_exit("could not write stat values over cmd channel"); + log_err("could not write stat values over cmd channel"); } void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a) @@ -448,6 +467,8 @@ void server_stats_add(struct ub_stats_in total->svr.num_queries_cookie_invalid += a->svr.num_queries_cookie_invalid; total->svr.num_queries_discard_timeout += a->svr.num_queries_discard_timeout; + total->svr.num_queries_replyaddr_limit += + a->svr.num_queries_replyaddr_limit; total->svr.num_queries_wait_limit += a->svr.num_queries_wait_limit; total->svr.num_dns_error_reports += a->svr.num_dns_error_reports; total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache; @@ -519,6 +540,7 @@ void server_stats_add(struct ub_stats_in total->mesh_num_states += a->mesh_num_states; total->mesh_num_reply_states += a->mesh_num_reply_states; + total->mesh_num_reply_addrs += a->mesh_num_reply_addrs; total->mesh_jostled += a->mesh_jostled; total->mesh_dropped += a->mesh_dropped; total->mesh_replies_sent += a->mesh_replies_sent; Index: usr.sbin/unbound/daemon/unbound.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/daemon/unbound.c,v diff -u -p -r1.35 unbound.c --- usr.sbin/unbound/daemon/unbound.c 26 Sep 2025 07:32:37 -0000 1.35 +++ usr.sbin/unbound/daemon/unbound.c 21 Sep 2026 16:28:04 -0000 @@ -463,57 +463,13 @@ detach(void) #endif /* HAVE_DAEMON */ } -#ifdef HAVE_SSL -/* setup a listening ssl context, fatal_exit() on any failure */ +/** setup the remote and ticket keys */ static void -setup_listen_sslctx(void** ctx, int is_dot, int is_doh, struct config_file* cfg) -{ - if(!(*ctx = listen_sslctx_create( - cfg->ssl_service_key, cfg->ssl_service_pem, NULL, - cfg->tls_ciphers, cfg->tls_ciphersuites, - (cfg->tls_session_ticket_keys.first && - cfg->tls_session_ticket_keys.first->str[0] != 0), - is_dot, is_doh))) { - fatal_exit("could not set up listen SSL_CTX"); - } -} -#endif /* HAVE_SSL */ - -/* setups the needed ssl contexts, fatal_exit() on any failure */ -static void -setup_sslctxs(struct daemon* daemon, struct config_file* cfg) +setup_sslctx_remote(struct daemon* daemon, struct config_file* cfg) { #ifdef HAVE_SSL if(!(daemon->rc = daemon_remote_create(cfg))) fatal_exit("could not set up remote-control"); - if(cfg->ssl_service_key && cfg->ssl_service_key[0]) { - /* setup the session keys; the callback to use them will be - * attached to each sslctx separately */ - if(cfg->tls_session_ticket_keys.first && - cfg->tls_session_ticket_keys.first->str[0] != 0) { - if(!listen_sslctx_setup_ticket_keys( - cfg->tls_session_ticket_keys.first)) { - fatal_exit("could not set session ticket SSL_CTX"); - } - } - (void)setup_listen_sslctx(&daemon->listen_dot_sslctx, 1, 0, cfg); -#ifdef HAVE_NGHTTP2_NGHTTP2_H - if(cfg_has_https(cfg)) { - (void)setup_listen_sslctx(&daemon->listen_doh_sslctx, 0, 1, cfg); - } -#endif -#ifdef HAVE_NGTCP2 - if(cfg_has_quic(cfg)) { - if(!(daemon->listen_quic_sslctx = quic_sslctx_create( - cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) { - fatal_exit("could not set up quic SSL_CTX"); - } - } -#endif /* HAVE_NGTCP2 */ - } - if(!(daemon->connect_dot_sslctx = connect_sslctx_create(NULL, NULL, - cfg->tls_cert_bundle, cfg->tls_win_cert))) - fatal_exit("could not set up connect SSL_CTX"); #else /* HAVE_SSL */ (void)daemon;(void)cfg; #endif /* HAVE_SSL */ @@ -545,7 +501,8 @@ perform_setup(struct daemon* daemon, str #endif /* read ssl keys while superuser and outside chroot */ - (void)setup_sslctxs(daemon, cfg); + setup_sslctx_remote(daemon, cfg); + daemon_setup_sslctxs(daemon, cfg); /* init syslog (as root) if needed, before daemonize, otherwise * a fork error could not be printed since daemonize closed stderr.*/ Index: usr.sbin/unbound/daemon/worker.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/daemon/worker.c,v diff -u -p -r1.44 worker.c --- usr.sbin/unbound/daemon/worker.c 26 Sep 2025 07:32:37 -0000 1.44 +++ usr.sbin/unbound/daemon/worker.c 21 Sep 2026 16:28:04 -0000 @@ -255,7 +255,8 @@ worker_handle_service_reply(struct comm_ return 0; } /* sanity check. */ - if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) + if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE + || !LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != LDNS_PACKET_QUERY || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { @@ -293,6 +294,44 @@ worker_err_ratelimit(struct worker* work } /** + * Reply with an error. + * This reply includes the qname if it has been parsed. + * For error ratelimiting, the err ratelimit routine should be checked + * beforehand. The reply is without EDNS, and copies RD and sets QR flag. + * @param pkt: the packet buffer from the comm point. + * @param err: the error code that would be wanted. + * @param qname_len: 0 if not parsed, and the qname length in packet. + */ +static void +query_error(sldns_buffer* pkt, int err, size_t qname_len) +{ + /* Preserve the RD flag. + * The CD flag must be cleared in authoritative answers, + * also the AD flag need not be copied into answers. + * The other flags need not be copied into the answer. */ + sldns_buffer_write_u16_at(pkt, 2, + sldns_buffer_read_u16_at(pkt, 2)&0x0100U); + LDNS_QR_SET(sldns_buffer_begin(pkt)); /* Set QR flag. */ + LDNS_RCODE_SET(sldns_buffer_begin(pkt), err); /* Set rcode */ + + if(qname_len && LDNS_QDCOUNT(sldns_buffer_begin(pkt))>=1 && + qname_len <= LDNS_MAX_DOMAINLEN) { + /* Copy query into the answer. */ + LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 1); + sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE + + qname_len + 2 /* type */ + 2 /* class */ ); + } else { + /* No query section in answer. */ + LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 0); + sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE); + } + LDNS_ANCOUNT_SET(sldns_buffer_begin(pkt), 0); + LDNS_NSCOUNT_SET(sldns_buffer_begin(pkt), 0); + LDNS_ARCOUNT_SET(sldns_buffer_begin(pkt), 0); + sldns_buffer_flip(pkt); +} + +/** * Structure holding the result of the worker_check_request function. * Based on configuration it could be called up to four times; ideally should * be called once. @@ -329,7 +368,6 @@ worker_check_request(sldns_buffer* pkt, return; } if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) { - LDNS_TC_CLR(sldns_buffer_begin(pkt)); verbose(VERB_QUERY, "request bad, has TC bit on"); out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); return; @@ -463,7 +501,9 @@ worker_handle_control_cmd(struct tube* A return; } if(len != sizeof(uint32_t)) { - fatal_exit("bad control msg length %d", (int)len); + verbose(VERB_ALGO, "bad control msg length %d", (int)len); + free(msg); + return; } cmd = sldns_read_uint32(msg); free(msg); @@ -676,7 +716,8 @@ apply_respip_action(struct worker* worke struct respip_client_info* cinfo, struct reply_info* rep, struct sockaddr_storage* addr, socklen_t addrlen, struct ub_packed_rrset_key** alias_rrset, - struct reply_info** encode_repp, struct auth_zones* az) + struct reply_info** encode_repp, struct auth_zones* az, + int* rpz_passthru) { struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; actinfo.action = respip_none; @@ -687,7 +728,7 @@ apply_respip_action(struct worker* worke return 1; if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo, - alias_rrset, 0, worker->scratchpad, az, NULL, + alias_rrset, 0, worker->scratchpad, az, rpz_passthru, worker->env.views, worker->env.respip_set)) return 0; @@ -734,7 +775,7 @@ answer_from_cache(struct worker* worker, int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset, struct reply_info** partial_repp, struct reply_info* rep, uint16_t id, uint16_t flags, - struct comm_reply* repinfo, struct edns_data* edns) + struct comm_reply* repinfo, struct edns_data* edns, int* rpz_passthru) { time_t timenow = *worker->env.now; uint16_t udpsize = edns->udp_size; @@ -746,7 +787,7 @@ answer_from_cache(struct worker* worker, *partial_repp = NULL; /* avoid accidental further pass */ /* Check TTL */ - if(rep->ttl < timenow) { + if(TTL_IS_EXPIRED(rep->ttl, timenow)) { /* Check if we need to serve expired now */ if(worker->env.cfg->serve_expired && /* if serve-expired-client-timeout is set, serve @@ -822,7 +863,7 @@ answer_from_cache(struct worker* worker, "validation"); goto bail_out; /* need to validate cache entry first */ } else if(rep->security == sec_status_secure) { - if(reply_all_rrsets_secure(rep)) { + if(reply_an_ns_rrsets_secure(rep)) { *is_secure_answer = 1; } else { if(must_validate) { @@ -844,7 +885,7 @@ answer_from_cache(struct worker* worker, if((worker->daemon->use_response_ip || worker->daemon->use_rpz) && !partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep, &repinfo->client_addr, repinfo->client_addrlen, alias_rrset, - &encode_rep, worker->env.auth_zones)) { + &encode_rep, worker->env.auth_zones, rpz_passthru)) { goto bail_out; } else if(partial_rep && !respip_merge_cname(partial_rep, qinfo, rep, cinfo, @@ -971,6 +1012,7 @@ chaos_replystr(sldns_buffer* pkt, char** size_t udpsize = edns->udp_size; edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; + edns->ext_rcode = 0; edns->bits &= EDNS_DO; if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL, LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad, @@ -1229,9 +1271,7 @@ deny_refuse(struct comm_point* c, enum a worker_check_request(c->buffer, worker, check_result); if(check_result->value != 0) { if(check_result->value != -1) { - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - check_result->value); + query_error(c->buffer, check_result->value, 0); return 1; } comm_point_drop_reply(repinfo); @@ -1248,41 +1288,17 @@ deny_refuse(struct comm_point* c, enum a /* check additional section is present and that we respond with EDEs */ if(LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) != 1 || !ede) { - LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_REFUSED); - sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); - sldns_buffer_flip(c->buffer); + query_error(c->buffer, LDNS_RCODE_REFUSED, 0); return 1; } if (!query_dname_len(c->buffer)) { - LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_FORMERR); - sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); - sldns_buffer_flip(c->buffer); + query_error(c->buffer, LDNS_RCODE_FORMERR, 0); return 1; } /* space available for query type and class? */ if (sldns_buffer_remaining(c->buffer) < 2 * sizeof(uint16_t)) { - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_FORMERR); - LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); - sldns_buffer_flip(c->buffer); + query_error(c->buffer, LDNS_RCODE_FORMERR, 0); return 1; } LDNS_QR_SET(sldns_buffer_begin(c->buffer)); @@ -1304,35 +1320,27 @@ deny_refuse(struct comm_point* c, enum a if(!skip_pkt_rrs(c->buffer, ((int)LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)))+ ((int)LDNS_NSCOUNT(sldns_buffer_begin(c->buffer))))) { - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_FORMERR); - LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - sldns_buffer_set_position(c->buffer, opt_rr_mark); - sldns_buffer_flip(c->buffer); + query_error(c->buffer, LDNS_RCODE_FORMERR, + opt_rr_mark - LDNS_HEADER_SIZE + - 2 /* qtype */ - 2 /* qclass */); return 1; } } /* Do we have a valid OPT RR here? If not return REFUSED (could be a valid TSIG or something so no FORMERR) */ /* domain name must be the root of length 1. */ if(sldns_buffer_remaining(c->buffer) < 1 || *sldns_buffer_current(c->buffer) != 0) { - LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - sldns_buffer_set_position(c->buffer, opt_rr_mark); - sldns_buffer_flip(c->buffer); + query_error(c->buffer, LDNS_RCODE_REFUSED, + opt_rr_mark - LDNS_HEADER_SIZE + - 2 /* qtype */ - 2 /* qclass */); return 1; } else { sldns_buffer_skip(c->buffer, 1); /* skip root label */ } if(sldns_buffer_remaining(c->buffer) < 2 || sldns_buffer_read_u16(c->buffer) != LDNS_RR_TYPE_OPT) { - LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); - sldns_buffer_set_position(c->buffer, opt_rr_mark); - sldns_buffer_flip(c->buffer); + query_error(c->buffer, LDNS_RCODE_REFUSED, + opt_rr_mark - LDNS_HEADER_SIZE + - 2 /* qtype */ - 2 /* qclass */); return 1; } /* Write OPT RR directly after the query, @@ -1444,6 +1452,24 @@ check_ip_ratelimit(struct worker* worker return 1; } +/* + * This is the callback function when a request arrives. It is passed + * the packet and user argument. Return true to send a reply. + * This is of type comm_point_callback_type. The struct comm_point contains + * more comments on the comm_point.callback member about the function. + * @param c: the comm_point where the request arrives on. + * @param arg: the user argument for the callback, the worker. + * @param error: This can be NETEVENT_NOERROR, NETEVENT_TIMEOUT, + * NETEVENT_CLOSED or other comm point callback error values. + * @param repinfo: The reply info, use it to send a reply. If the reply + * is immediate, return 1. If the reply is later on return 0 and save + * the repinfo, to call comm_point_send_reply on. + * @return 1 to sent a reply straight away, for like cache response so that + * no allocation needs to be done. And only internal preallocated buffers + * are used. Return 0 and save the repinfo to reply later, for responses + * that need to be looked up. Return 0 and call comm_point_drop_reply on + * the repinfo to drop the response. + */ int worker_handle_request(struct comm_point* c, void* arg, int error, struct comm_reply* repinfo) @@ -1471,6 +1497,8 @@ worker_handle_request(struct comm_point* struct reply_info* partial_rep = NULL; struct query_info* lookup_qinfo = &qinfo; struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */ + uint8_t* alias_orig_qname = NULL; /* original qname for logs, if + a local_alias is used to change the qname. */ struct respip_client_info* cinfo = NULL, cinfo_tmp; struct timeval wait_time; struct check_request_result check_result = {0,0}; @@ -1488,7 +1516,7 @@ worker_handle_request(struct comm_point* if (worker->stats.max_query_time_us < wait_queue_time) worker->stats.max_query_time_us = wait_queue_time; if(wait_queue_time > - (long long)(worker->env.cfg->sock_queue_timeout * 1000000)) { + (long long)worker->env.cfg->sock_queue_timeout * 1000000) { /* count and drop queries that were sitting in the socket queue too long */ worker->stats.num_queries_timed_out++; return 0; @@ -1510,6 +1538,10 @@ worker_handle_request(struct comm_point* "dnscrypt: worker check request: bad query."); log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen); + if(check_result.value != -1) { + query_error(c->buffer, check_result.value, 0); + return 1; + } comm_point_drop_reply(repinfo); return 0; } @@ -1518,8 +1550,13 @@ worker_handle_request(struct comm_point* "dnscrypt: worker parse request: formerror."); log_addr(VERB_CLIENT, "from", &repinfo->client_addr, repinfo->client_addrlen); - comm_point_drop_reply(repinfo); - return 0; + if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { + comm_point_drop_reply(repinfo); + return 0; + } + query_error(c->buffer, LDNS_RCODE_FORMERR, 0); + sldns_buffer_copy(c->dnscrypt_buffer, c->buffer); + return 1; } dname_str(qinfo.qname, buf); if(!(qinfo.qtype == LDNS_RR_TYPE_TXT && @@ -1530,9 +1567,15 @@ worker_handle_request(struct comm_point* worker->daemon->dnscenv->provider_name, sldns_rr_descript(qinfo.qtype)->_name, buf); - comm_point_drop_reply(repinfo); + if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) { + comm_point_drop_reply(repinfo); + return 0; + } + query_error(c->buffer, LDNS_RCODE_SERVFAIL, + qinfo.qname_len); worker->stats.num_query_dnscrypt_cleartext++; - return 0; + sldns_buffer_copy(c->dnscrypt_buffer, c->buffer); + return 1; } worker->stats.num_query_dnscrypt_cert++; sldns_buffer_rewind(c->buffer); @@ -1572,9 +1615,7 @@ worker_handle_request(struct comm_point* verbose(VERB_ALGO, "worker check request: bad query."); log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen); if(check_result.value != -1) { - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - check_result.value); + query_error(c->buffer, check_result.value, 0); return 1; } comm_point_drop_reply(repinfo); @@ -1608,10 +1649,7 @@ worker_handle_request(struct comm_point* comm_point_drop_reply(repinfo); return 0; } - sldns_buffer_rewind(c->buffer); - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_FORMERR); + query_error(c->buffer, LDNS_RCODE_FORMERR, 0); goto send_reply; } if(worker->env.cfg->log_queries) { @@ -1624,10 +1662,11 @@ worker_handle_request(struct comm_point* verbose(VERB_ALGO, "worker request: refused zone transfer."); log_addr(VERB_CLIENT, "from", &repinfo->client_addr, repinfo->client_addrlen); - sldns_buffer_rewind(c->buffer); - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_REFUSED); + if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) { + comm_point_drop_reply(repinfo); + return 0; + } + query_error(c->buffer, LDNS_RCODE_REFUSED, qinfo.qname_len); if(worker->stats.extended) { worker->stats.qtype[qinfo.qtype]++; } @@ -1646,10 +1685,7 @@ worker_handle_request(struct comm_point* comm_point_drop_reply(repinfo); return 0; } - sldns_buffer_rewind(c->buffer); - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_FORMERR); + query_error(c->buffer, LDNS_RCODE_FORMERR, qinfo.qname_len); if(worker->stats.extended) { worker->stats.qtype[qinfo.qtype]++; } @@ -1657,13 +1693,17 @@ worker_handle_request(struct comm_point* } if((ret=parse_edns_from_query_pkt( c->buffer, &edns, worker->env.cfg, c, repinfo, - (worker->env.now ? *worker->env.now : time(NULL)), - worker->scratchpad, + *worker->env.now, worker->scratchpad, worker->daemon->cookie_secrets)) != 0) { struct edns_data reply_edns; verbose(VERB_ALGO, "worker parse edns: formerror."); log_addr(VERB_CLIENT, "from", &repinfo->client_addr, repinfo->client_addrlen); + if(worker_err_ratelimit(worker, ret) == -1) { + comm_point_drop_reply(repinfo); + regional_free_all(worker->scratchpad); + return 0; + } memset(&reply_edns, 0, sizeof(reply_edns)); reply_edns.edns_present = 1; error_encode(c->buffer, ret, &qinfo, @@ -1680,6 +1720,11 @@ worker_handle_request(struct comm_point* verbose(VERB_ALGO, "query with bad edns version."); log_addr(VERB_CLIENT, "from", &repinfo->client_addr, repinfo->client_addrlen); + if(worker_err_ratelimit(worker, EDNS_RCODE_BADVERS) == -1) { + comm_point_drop_reply(repinfo); + regional_free_all(worker->scratchpad); + return 0; + } extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns); @@ -1725,6 +1770,11 @@ worker_handle_request(struct comm_point* else if(edns.cookie_present) { /* Cookie present, but not valid: Cookie was bad! */ + if(worker_err_ratelimit(worker, LDNS_EXT_RCODE_BADCOOKIE) == -1) { + comm_point_drop_reply(repinfo); + regional_free_all(worker->scratchpad); + return 0; + } extended_error_encode(c->buffer, LDNS_EXT_RCODE_BADCOOKIE, &qinfo, *(uint16_t*)(void *) @@ -1739,6 +1789,11 @@ worker_handle_request(struct comm_point* "need cookie or stateful transport"); log_addr(VERB_ALGO, "from",&repinfo->remote_addr , repinfo->remote_addrlen); + if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) { + comm_point_drop_reply(repinfo); + regional_free_all(worker->scratchpad); + return 0; + } EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out, worker->scratchpad, LDNS_EDE_OTHER, "DNS Cookie needed for UDP replies"); @@ -1765,14 +1820,14 @@ worker_handle_request(struct comm_point* verbose(VERB_ALGO, "worker request: edns is too small."); log_addr(VERB_CLIENT, "from", &repinfo->client_addr, repinfo->client_addrlen); - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); + if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) { + comm_point_drop_reply(repinfo); + regional_free_all(worker->scratchpad); + return 0; + } + /* A small error without qname, and TC flag on. */ + query_error(c->buffer, LDNS_RCODE_SERVFAIL, 0); LDNS_TC_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_SERVFAIL); - sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); - sldns_buffer_write_at(c->buffer, 4, - (uint8_t*)"\0\0\0\0\0\0\0\0", 8); - sldns_buffer_flip(c->buffer); regional_free_all(worker->scratchpad); goto send_reply; } @@ -1780,7 +1835,13 @@ worker_handle_request(struct comm_point* server_stats_insquery(&worker->stats, c, qinfo.qtype, qinfo.qclass, &edns, repinfo); if(c->type != comm_udp) +#ifdef USE_DNSCRYPT + edns.udp_size = (c->dnscrypt && repinfo->is_dnscrypted) + ? sldns_buffer_capacity(c->buffer) - DNSCRYPT_REPLY_HEADER_SIZE + : 65535; +#else edns.udp_size = 65535; /* max size for TCP replies */ +#endif if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, &edns, repinfo, c->buffer)) { regional_free_all(worker->scratchpad); @@ -1857,6 +1918,15 @@ worker_handle_request(struct comm_point* * ACLs allow the snooping. */ if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) && acl != acl_allow_snoop ) { + log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from", + &repinfo->client_addr, repinfo->client_addrlen); + /* This ratelimited error query is accounted in the stats, + * as an incoming query. */ + if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) { + comm_point_drop_reply(repinfo); + regional_free_all(worker->scratchpad); + return 0; + } if(worker->env.cfg->ede) { EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out, worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, ""); @@ -1865,15 +1935,17 @@ worker_handle_request(struct comm_point* *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), &edns); regional_free_all(worker->scratchpad); - log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from", - &repinfo->client_addr, repinfo->client_addrlen); - goto send_reply; } /* If we've found a local alias, replace the qname with the alias * target before resolving it. */ if(qinfo.local_alias) { + if(qinfo.local_alias->rrset && + qinfo.local_alias->rrset->rk.dname) + /* Store the original qname, used for logs, since + * local_alias can be removed by region_free_all. */ + alias_orig_qname = qinfo.local_alias->rrset->rk.dname; if(!local_alias_shallow_copy_qname(qinfo.local_alias, &qinfo.qname, &qinfo.qname_len)) { regional_free_all(worker->scratchpad); @@ -1921,7 +1993,7 @@ lookup_cache: &alias_rrset, &partial_rep, rep, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), repinfo, - &edns)) { + &edns, &rpz_passthru)) { /* prefetch it if the prefetch TTL expired. * Note that if there is more than one pass * its qname must be that used for cache @@ -1929,11 +2001,11 @@ lookup_cache: if((worker->env.cfg->prefetch && rep->prefetch_ttl <= *worker->env.now) || (worker->env.cfg->serve_expired && - rep->ttl < *worker->env.now && + TTL_IS_EXPIRED(rep->ttl, *worker->env.now) && !(*worker->env.now < rep->serve_expired_norec_ttl))) { - time_t leeway = rep->ttl - *worker->env.now; - if(rep->ttl < *worker->env.now) - leeway = 0; + time_t leeway = + TTL_IS_EXPIRED(rep->ttl, *worker->env.now) + ? 0 : rep->ttl - *worker->env.now; lock_rw_unlock(&e->lock); reply_and_prefetch(worker, lookup_qinfo, @@ -2039,11 +2111,10 @@ send_reply_rc: { struct timeval tv; memset(&tv, 0, sizeof(tv)); - if(qinfo.local_alias && qinfo.local_alias->rrset && - qinfo.local_alias->rrset->rk.dname) { + if(alias_orig_qname) { /* log original qname, before the local alias was * used to resolve that CNAME to something else */ - qinfo.qname = qinfo.local_alias->rrset->rk.dname; + qinfo.qname = alias_orig_qname; log_reply_info(NO_VERBOSE, &qinfo, &repinfo->client_addr, repinfo->client_addrlen, tv, 1, c->buffer, @@ -2058,7 +2129,7 @@ send_reply_rc: } } #ifdef USE_DNSCRYPT - if(!dnsc_handle_uncurved_request(repinfo)) { + if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) { return 0; } #endif @@ -2106,10 +2177,37 @@ worker_restart_timer(struct worker* work { if(worker->env.cfg->stat_interval > 0) { struct timeval tv; + if(worker->daemon->stat_time_specific) { + struct timeval dest, now; + int interval = worker->env.cfg->stat_interval; + int offset = worker->daemon->stat_time_offset; + int nows, spec; + if(gettimeofday(&now, NULL) < 0) + log_err("gettimeofday: %s", strerror(errno)); #ifndef S_SPLINT_S - tv.tv_sec = worker->env.cfg->stat_interval; - tv.tv_usec = 0; + nows = (int)now.tv_sec; + /* The next time is on the timer interval, at the + * specific offset, time value % interval = offset. */ + /* It relies on the integer division below to drop the + * remainder in order to calculate the expected + * result. */ + spec = ((nows-offset)/interval+1)*interval+offset; + /* This is instead of an assertion, and should not + * be needed. So assert(spec > nows), tv is going to + * be positive. */ + if(spec<=nows) spec += interval; + dest.tv_sec = spec; + dest.tv_usec = 0; +#endif + /* Subtract in timeval, so the fractions of a second + * are rounded to the whole specific time. */ + timeval_subtract(&tv, &dest, &now); + } else { +#ifndef S_SPLINT_S + tv.tv_sec = worker->env.cfg->stat_interval; + tv.tv_usec = 0; #endif + } comm_timer_set(worker->stat_timer, &tv); } } @@ -2144,23 +2242,16 @@ void worker_probe_timer_cb(void* arg) } struct worker* -worker_create(struct daemon* daemon, int id, int* ports, int n) +worker_create(struct daemon* daemon, int id) { unsigned int seed; struct worker* worker = (struct worker*)calloc(1, sizeof(struct worker)); if(!worker) return NULL; - worker->numports = n; - worker->ports = (int*)memdup(ports, sizeof(int)*n); - if(!worker->ports) { - free(worker); - return NULL; - } worker->daemon = daemon; worker->thread_num = id; if(!(worker->cmd = tube_create())) { - free(worker->ports); free(worker); return NULL; } @@ -2168,7 +2259,6 @@ worker_create(struct daemon* daemon, int if(!(worker->rndstate = ub_initstate(daemon->rand))) { log_err("could not init random numbers."); tube_delete(worker->cmd); - free(worker->ports); free(worker); return NULL; } @@ -2185,9 +2275,6 @@ worker_init(struct worker* worker, struc #else void* dtenv = NULL; #endif -#ifdef HAVE_GETTID - worker->thread_tid = gettid(); -#endif worker->need_to_exit = 0; worker->base = comm_base_create(do_sigs); if(!worker->base) { @@ -2270,14 +2357,14 @@ worker_init(struct worker* worker, struc cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, worker->daemon->env->infra_cache, worker->rndstate, - cfg->use_caps_bits_for_id, worker->ports, worker->numports, + cfg->use_caps_bits_for_id, cfg->unwanted_threshold, cfg->outgoing_tcp_mss, &worker_alloc_cleanup, worker, cfg->do_udp || cfg->udp_upstream_without_downstream, worker->daemon->connect_dot_sslctx, cfg->delay_close, cfg->tls_use_sni, dtenv, cfg->udp_connect, cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout, - cfg->tcp_auth_query_timeout); + cfg->tcp_auth_query_timeout, worker->daemon->shared_ports); if(!worker->back) { log_err("could not create outgoing sockets"); worker_delete(worker); @@ -2296,6 +2383,8 @@ worker_init(struct worker* worker, struc worker_stat_timer_cb, worker); if(!worker->stat_timer) { log_err("could not create statistics timer"); + worker_delete(worker); + return 0; } /* we use the msg_buffer_size as a good estimate for what the @@ -2428,7 +2517,6 @@ worker_delete(struct worker* worker) tube_delete(worker->cmd); comm_timer_delete(worker->stat_timer); comm_timer_delete(worker->env.probe_timer); - free(worker->ports); if(worker->thread_num == 0) { #ifdef UB_ON_WINDOWS wsvc_desetup_worker(worker); @@ -2449,6 +2537,8 @@ worker_delete(struct worker* worker) /* don't touch worker->alloc, as it's maintained in daemon */ regional_destroy(worker->env.scratch); regional_destroy(worker->scratchpad); + /* The thread id can reference this worker's id value, so clear it. */ + log_thread_set(NULL); free(worker); } @@ -2457,7 +2547,8 @@ worker_send_query(struct query_info* qin int want_dnssec, int nocaps, int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, - struct module_qstate* q, int* was_ratelimited) + struct module_qstate* q, int* was_ratelimited, + int* ratelimit_incremented) { struct worker* worker = q->env->worker; struct outbound_entry* e = (struct outbound_entry*)regional_alloc( @@ -2469,7 +2560,7 @@ worker_send_query(struct query_info* qin want_dnssec, nocaps, check_ratelimit, tcp_upstream, ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q, worker_handle_service_reply, e, worker->back->udp_buff, q->env, - was_ratelimited); + was_ratelimited, ratelimit_incremented); if(!e->qsent) { return NULL; } @@ -2518,7 +2609,8 @@ struct outbound_entry* libworker_send_qu struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), - struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) + struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited), + int* ATTR_UNUSED(ratelimit_incremented)) { log_assert(0); return 0; @@ -2556,6 +2648,11 @@ void libworker_bg_done_cb(void* ATTR_UNU void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) +{ + log_assert(0); +} + +void libworker_alloc_cleanup(void* ATTR_UNUSED(arg)) { log_assert(0); } Index: usr.sbin/unbound/daemon/worker.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/daemon/worker.h,v diff -u -p -r1.10 worker.h --- usr.sbin/unbound/daemon/worker.h 31 Aug 2025 21:41:09 -0000 1.10 +++ usr.sbin/unbound/daemon/worker.h 21 Sep 2026 16:28:04 -0000 @@ -104,10 +104,6 @@ struct worker { struct listen_dnsport* front; /** the backside outside network interface to the auth servers */ struct outside_network* back; - /** ports to be used by this worker. */ - int* ports; - /** number of ports for this worker */ - int numports; /** the signal handler */ struct comm_signal* comsig; /** commpoint to listen to commands. */ @@ -146,11 +142,9 @@ struct worker { * with backpointers only. Use worker_init on it later. * @param daemon: the daemon that this worker thread is part of. * @param id: the thread number from 0.. numthreads-1. - * @param ports: the ports it is allowed to use, array. - * @param n: the number of ports. * @return: the new worker or NULL on alloc failure. */ -struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n); +struct worker* worker_create(struct daemon* daemon, int id); /** * Initialize worker. Index: usr.sbin/unbound/dns64/dns64.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/dns64/dns64.c,v diff -u -p -r1.24 dns64.c --- usr.sbin/unbound/dns64/dns64.c 26 Sep 2025 07:32:37 -0000 1.24 +++ usr.sbin/unbound/dns64/dns64.c 21 Sep 2026 16:28:04 -0000 @@ -366,22 +366,23 @@ static int dns64_apply_cfg(struct dns64_env* dns64_env, struct config_file* cfg) { struct config_strlist* s; - verbose(VERB_ALGO, "dns64-prefix: %s", cfg->dns64_prefix); - if (!netblockstrtoaddr(cfg->dns64_prefix ? cfg->dns64_prefix : - DEFAULT_DNS64_PREFIX, 0, &dns64_env->prefix_addr, + const char* dns64_prefix = cfg->dns64_prefix ? + cfg->dns64_prefix : DEFAULT_DNS64_PREFIX; + verbose(VERB_ALGO, "dns64-prefix: %s", dns64_prefix); + if (!netblockstrtoaddr(dns64_prefix, 0, &dns64_env->prefix_addr, &dns64_env->prefix_addrlen, &dns64_env->prefix_net)) { - log_err("cannot parse dns64-prefix netblock: %s", cfg->dns64_prefix); + log_err("cannot parse dns64-prefix netblock: %s", dns64_prefix); return 0; } if (!addr_is_ip6(&dns64_env->prefix_addr, dns64_env->prefix_addrlen)) { - log_err("dns64_prefix is not IPv6: %s", cfg->dns64_prefix); + log_err("dns64_prefix is not IPv6: %s", dns64_prefix); return 0; } if (dns64_env->prefix_net != 32 && dns64_env->prefix_net != 40 && dns64_env->prefix_net != 48 && dns64_env->prefix_net != 56 && dns64_env->prefix_net != 64 && dns64_env->prefix_net != 96 ) { - log_err("dns64-prefix length it not 32, 40, 48, 56, 64 or 96: %s", - cfg->dns64_prefix); + log_err("dns64-prefix length is not 32, 40, 48, 56, 64 or 96: %s", + dns64_prefix); return 0; } for(s = cfg->dns64_ignore_aaaa; s; s = s->next) { @@ -496,8 +497,8 @@ handle_ipv6_ptr(struct module_qstate* qs /* Create the new sub-query. */ fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0, 0, - &subq)) + if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->client_info, + qstate->query_flags, 0, 0, &subq)) return module_error; if (subq) { subq->curmod = id; @@ -522,8 +523,8 @@ generate_type_A_query(struct module_qsta /* Start the sub-query. */ fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0, - 0, &subq)) + if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->client_info, + qstate->query_flags, 0, 0, &subq)) { verbose(VERB_ALGO, "dns64: sub-query creation failed"); return module_error; @@ -642,6 +643,12 @@ handle_event_moddone(struct module_qstat qstate->return_msg->rep && reply_find_answer_rrset(&qstate->qinfo, qstate->return_msg->rep); int synth_qname = 0; + if(could_synth && !has_data && qstate->env->need_to_validate && + qstate->return_msg && qstate->return_msg->rep && + qstate->return_msg->rep->security == sec_status_bogus) { + verbose(VERB_ALGO, "dns64: bogus AAAA reply not synthesized"); + could_synth = 0; + } if(could_synth && (!has_data || @@ -653,8 +660,11 @@ handle_event_moddone(struct module_qstat /* Store the response in cache. */ if( (!iq || !iq->started_no_cache_store) && + !qstate->rpz_applied && !qstate->rpz_passthru && + !qstate->is_subnet_answer && qstate->return_msg && qstate->return_msg->rep && + !qstate->fwd_stub_no_cache && !dns_cache_store( qstate->env, &qstate->qinfo, qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0, NULL, @@ -716,8 +726,15 @@ dns64_operate(struct module_qstate* qsta } if(qstate->ext_state[id] == module_finished) { iq = (struct dns64_qstate*)qstate->minfo[id]; - if(iq && iq->state != DNS64_INTERNAL_QUERY) - qstate->no_cache_store = iq->started_no_cache_store; + if(iq && iq->state != DNS64_INTERNAL_QUERY) { + if(qstate->fwd_stub_no_cache) { + /* If the forward/stub has no cache, then + * continue with the query with no cache. */ + qstate->no_cache_store = qstate->fwd_stub_no_cache; + } else { + qstate->no_cache_store = iq->started_no_cache_store; + } + } } } @@ -824,6 +841,7 @@ dns64_adjust_a(int id, struct module_qst size_t i, s; struct packed_rrset_data* fd, *dd; struct ub_packed_rrset_key* fk, *dk; + int allocated_return_msg = 0; verbose(VERB_ALGO, "converting A answers to AAAA answers"); @@ -839,6 +857,7 @@ dns64_adjust_a(int id, struct module_qst return; memset(super->return_msg, 0, sizeof(*super->return_msg)); super->return_msg->qinfo = super->qinfo; + allocated_return_msg = 1; } rep = qstate->return_msg->rep; @@ -851,11 +870,14 @@ dns64_adjust_a(int id, struct module_qst rep->serve_expired_norec_ttl, rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count, rep->security, LDNS_EDE_NONE); - if(!cp) + if(!cp) { + if(allocated_return_msg) super->return_msg = NULL; return; + } /* allocate ub_key structures special or not */ if(!reply_info_alloc_rrset_keys(cp, NULL, super->region)) { + if(allocated_return_msg) super->return_msg = NULL; return; } @@ -870,8 +892,10 @@ dns64_adjust_a(int id, struct module_qst if(ian_numrrsets && fk->rk.type == htons(LDNS_RR_TYPE_A)) { /* also sets dk->entry.hash */ dns64_synth_aaaa_data(fk, fd, dk, &dd, super->region, dns64_env); - if(!dd) + if(!dd) { + if(allocated_return_msg) super->return_msg = NULL; return; + } /* Delete negative AAAA record from cache stored by * the iterator module */ rrset_cache_remove(super->env->rrset_cache, dk->rk.dname, @@ -888,15 +912,19 @@ dns64_adjust_a(int id, struct module_qst dk->rk.dname = (uint8_t*)regional_alloc_init(super->region, fk->rk.dname, fk->rk.dname_len); - if(!dk->rk.dname) + if(!dk->rk.dname) { + if(allocated_return_msg) super->return_msg = NULL; return; + } s = packed_rrset_sizeof(fd); dd = (struct packed_rrset_data*)regional_alloc_init( super->region, fd, s); - if(!dd) + if(!dd) { + if(allocated_return_msg) super->return_msg = NULL; return; + } } packed_rrset_ptr_fixup(dd); @@ -927,8 +955,10 @@ dns64_adjust_ptr(struct module_qstate* q return; super->return_msg->qinfo = super->qinfo; if (!(super->return_msg->rep = reply_info_copy(qstate->return_msg->rep, - NULL, super->region))) + NULL, super->region))) { + super->return_msg = NULL; return; + } /* * Adjust the domain name of the answer RR set so that it matches the @@ -997,6 +1027,21 @@ dns64_inform_super(struct module_qstate* /* Use return code from A query in response to client. */ if (super->return_rcode != LDNS_RCODE_NOERROR) super->return_rcode = qstate->return_rcode; + /* RPZ applied to the subquery need to then change (not cache) + * the super query. With the super query not cached, it is + * going to run the state machine modules on incoming queries, + * that fetch the subquery (cache) response, and modify it + * according to the rpz policy. That makes the synthesized + * super query also adjusted by rpz policies. But loses cache + * hits. Even though the subquery likely is answered from cache, + * internally in its state machine process. */ + if(qstate->rpz_applied) + super->rpz_applied = 1; + if(qstate->rpz_passthru) + super->rpz_passthru = 1; + + /* Since the super qstate has a new response, its errinf is removed. */ + super->errinf = NULL; /* Generate a response suitable for the original query. */ if (qstate->qinfo.qtype == LDNS_RR_TYPE_A) { @@ -1005,9 +1050,16 @@ dns64_inform_super(struct module_qstate* log_assert(qstate->qinfo.qtype == LDNS_RR_TYPE_PTR); dns64_adjust_ptr(qstate, super); } + /* If the sub-query has no cache store, then also the super query. */ + if(qstate->fwd_stub_no_cache) + super->fwd_stub_no_cache = 1; /* Store the generated response in cache. */ - if ( (!super_dq || !super_dq->started_no_cache_store) && + if ( super->return_msg && super->return_msg->rep && + (!super_dq || !super_dq->started_no_cache_store) && + !qstate->fwd_stub_no_cache && + !super->rpz_applied && !super->rpz_passthru && + !super->is_subnet_answer && !dns_cache_store(super->env, &super->qinfo, super->return_msg->rep, 0, super->prefetch_leeway, 0, NULL, super->query_flags, qstate->qstarttime, qstate->is_valrec)) Index: usr.sbin/unbound/dnscrypt/dnscrypt.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/dnscrypt/dnscrypt.c,v diff -u -p -r1.8 dnscrypt.c --- usr.sbin/unbound/dnscrypt/dnscrypt.c 23 Feb 2022 12:04:05 -0000 1.8 +++ usr.sbin/unbound/dnscrypt/dnscrypt.c 21 Sep 2026 16:28:04 -0000 @@ -361,7 +361,7 @@ dnscrypt_server_uncurve(struct dnsc_env* len -= DNSCRYPT_QUERY_HEADER_SIZE; - while (*sldns_buffer_at(buffer, --len) == 0) + while (len>0 && *sldns_buffer_at(buffer, --len) == 0) ; if (*sldns_buffer_at(buffer, len) != 0x80) { @@ -474,10 +474,18 @@ dnscrypt_server_curve(const dnsccert *ce uint8_t *const buf = sldns_buffer_begin(buffer); size_t len = sldns_buffer_limit(buffer); + if(len + DNSCRYPT_REPLY_HEADER_SIZE > sldns_buffer_capacity(buffer)) + return -1; + sldns_buffer_clear(buffer); + if(udp){ if (max_len > max_reply_size) max_len = max_reply_size; } + if(max_len > sldns_buffer_capacity(buffer)) + max_len = sldns_buffer_capacity(buffer); + if(max_len > 65535) + max_len = 65535; memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES); @@ -520,6 +528,7 @@ dnscrypt_server_curve(const dnsccert *ce DNSCRYPT_MAGIC_HEADER_LEN, nonce, crypto_box_NONCEBYTES); + sldns_buffer_flip(buffer); sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE); return 0; } @@ -663,6 +672,8 @@ dnsc_find_cert(struct dnsc_env* dnscenv, } dnscrypt_header = (struct dnscrypt_query_header *)sldns_buffer_begin(buffer); for (i = 0U; i < dnscenv->signed_certs_count; i++) { + if(!certs[i].keypair) + continue; if (memcmp(certs[i].magic_query, dnscrypt_header->magic_query, DNSCRYPT_MAGIC_HEADER_LEN) == 0) { return &certs[i]; @@ -804,6 +815,7 @@ dnsc_parse_keys(struct dnsc_env *env, st sizeof *env->keypairs); env->certs = sodium_allocarray(env->signed_certs_count, sizeof *env->certs); + memset(env->certs, 0, env->signed_certs_count * sizeof(*env->certs)); cert_id = 0U; keypair_id = 0U; @@ -830,7 +842,14 @@ dnsc_parse_keys(struct dnsc_env *env, st if(memcmp(current_keypair->crypt_publickey, env->signed_certs[c].server_publickey, crypto_box_PUBLICKEYBYTES) == 0) { - dnsccert *current_cert = &env->certs[cert_id++]; + dnsccert* current_cert; + if(cert_id >= env->signed_certs_count) { + log_err("dnscrypt: secret key %s matches a cert that " + "is already bound to another key (duplicate " + "dnscrypt-secret-key?)", head->str); + return -1; + } + current_cert = &env->certs[cert_id++]; found_cert = 1; current_cert->keypair = current_keypair; memcpy(current_cert->magic_query, @@ -912,12 +931,13 @@ dnsc_handle_curved_request(struct dnsc_e } int -dnsc_handle_uncurved_request(struct comm_reply *repinfo) +dnsc_handle_uncurved_request(struct comm_reply *repinfo, + struct sldns_buffer* buffer) { if(!repinfo->c->dnscrypt) { return 1; } - sldns_buffer_copy(repinfo->c->dnscrypt_buffer, repinfo->c->buffer); + sldns_buffer_copy(repinfo->c->dnscrypt_buffer, buffer); if(!repinfo->is_dnscrypted) { return 1; } @@ -963,11 +983,18 @@ dnsc_create(void) int dnsc_apply_cfg(struct dnsc_env *env, struct config_file *cfg) { + int nkeys; if(dnsc_parse_certs(env, cfg) <= 0) { fatal_exit("dnsc_apply_cfg: no cert file loaded"); } - if(dnsc_parse_keys(env, cfg) <= 0) { + nkeys = dnsc_parse_keys(env, cfg); + if(nkeys <= 0) { fatal_exit("dnsc_apply_cfg: no key file loaded"); + } + if((size_t)nkeys < env->signed_certs_count) { + fatal_exit("dnsc_apply_cfg: %u dnscrypt-provider-cert file(s) have no " + "matching dnscrypt-secret-key", + (unsigned)(env->signed_certs_count - (size_t)nkeys)); } randombytes_buf(env->hash_key, sizeof env->hash_key); env->provider_name = cfg->dnscrypt_provider; Index: usr.sbin/unbound/dnscrypt/dnscrypt.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/dnscrypt/dnscrypt.h,v diff -u -p -r1.4 dnscrypt.h --- usr.sbin/unbound/dnscrypt/dnscrypt.h 23 Feb 2022 12:04:05 -0000 1.4 +++ usr.sbin/unbound/dnscrypt/dnscrypt.h 21 Sep 2026 16:28:04 -0000 @@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dn * \return 0 in case of failure. */ -int dnsc_handle_uncurved_request(struct comm_reply *repinfo); +int dnsc_handle_uncurved_request(struct comm_reply *repinfo, + struct sldns_buffer* buffer); /** * Computes the size of the shared secret cache entry. Index: usr.sbin/unbound/dnstap/dnstap.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/dnstap/dnstap.c,v diff -u -p -r1.14 dnstap.c --- usr.sbin/unbound/dnstap/dnstap.c 26 Sep 2025 07:32:37 -0000 1.14 +++ usr.sbin/unbound/dnstap/dnstap.c 21 Sep 2026 16:28:04 -0000 @@ -176,26 +176,29 @@ dt_create(struct config_file* cfg) env->dtio = dt_io_thread_create(); if(!env->dtio) { log_err("malloc failure"); - free(env); + dt_delete(env); return NULL; } if(!dt_io_thread_apply_cfg(env->dtio, cfg)) { - dt_io_thread_delete(env->dtio); - free(env); + dt_delete(env); + return NULL; + } + if(!dt_apply_cfg(env, cfg)) { + dt_delete(env); return NULL; } - dt_apply_cfg(env, cfg); return env; } -static void +static int dt_apply_identity(struct dt_env *env, struct config_file *cfg) { char buf[MAXHOSTNAMELEN+1]; if (!cfg->dnstap_send_identity) { free(env->identity); env->identity = NULL; - return; + env->len_identity = 0; + return 1; } free(env->identity); if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) { @@ -203,36 +206,49 @@ dt_apply_identity(struct dt_env *env, st buf[MAXHOSTNAMELEN] = 0; env->identity = strdup(buf); } else { - fatal_exit("dt_apply_identity: gethostname() failed"); + log_err("dt_apply_identity: gethostname() failed: %s", + strerror(errno)); + env->identity = NULL; + env->len_identity = 0; + return 0; } } else { env->identity = strdup(cfg->dnstap_identity); } - if (env->identity == NULL) - fatal_exit("dt_apply_identity: strdup() failed"); + if (env->identity == NULL) { + log_err("dt_apply_identity: strdup() failed"); + env->len_identity = 0; + return 0; + } env->len_identity = (unsigned int)strlen(env->identity); verbose(VERB_OPS, "dnstap identity field set to \"%s\"", env->identity); + return 1; } -static void +static int dt_apply_version(struct dt_env *env, struct config_file *cfg) { if (!cfg->dnstap_send_version) { free(env->version); env->version = NULL; - return; + env->len_version = 0; + return 1; } free(env->version); if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0) env->version = strdup(PACKAGE_STRING); else env->version = strdup(cfg->dnstap_version); - if (env->version == NULL) - fatal_exit("dt_apply_version: strdup() failed"); + if (env->version == NULL) { + log_err("dt_apply_version: strdup() failed"); + env->len_version = 0; + return 0; + } env->len_version = (unsigned int)strlen(env->version); verbose(VERB_OPS, "dnstap version field set to \"%s\"", env->version); + return 1; } void @@ -276,15 +292,18 @@ dt_apply_logcfg(struct dt_env *env, stru lock_basic_unlock(&env->sample_lock); } -void +int dt_apply_cfg(struct dt_env *env, struct config_file *cfg) { if (!cfg->dnstap) - return; + return 1; - dt_apply_identity(env, cfg); - dt_apply_version(env, cfg); dt_apply_logcfg(env, cfg); + if(!dt_apply_identity(env, cfg)) + return 0; + if(!dt_apply_version(env, cfg)) + return 0; + return 1; } int Index: usr.sbin/unbound/dnstap/dnstap.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/dnstap/dnstap.h,v diff -u -p -r1.1.1.8 dnstap.h --- usr.sbin/unbound/dnstap/dnstap.h 31 Aug 2025 21:36:34 -0000 1.1.1.8 +++ usr.sbin/unbound/dnstap/dnstap.h 21 Sep 2026 16:28:04 -0000 @@ -102,9 +102,9 @@ dt_create(struct config_file* cfg); * Apply config settings. * @param env: dnstap environment object. * @param cfg: new config settings. + * @return false on failure. */ -void -dt_apply_cfg(struct dt_env *env, struct config_file *cfg); +int dt_apply_cfg(struct dt_env *env, struct config_file *cfg); /** * Apply config settings for log enable for message types. Index: usr.sbin/unbound/dnstap/dtstream.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/dnstap/dtstream.c,v diff -u -p -r1.3 dtstream.c --- usr.sbin/unbound/dnstap/dtstream.c 26 Sep 2025 07:32:37 -0000 1.3 +++ usr.sbin/unbound/dnstap/dtstream.c 21 Sep 2026 16:28:04 -0000 @@ -222,7 +222,7 @@ dt_msg_queue_start_timer(struct dt_msg_q tv.tv_usec = 0; /* If it is already set, keep it running. */ if(!comm_timer_is_set(mq->wakeup_timer)) - comm_timer_set(mq->wakeup_timer, &tv); + comm_timer_set(mq->wakeup_timer, &tv); } else { tv.tv_sec = 0; tv.tv_usec = 0; @@ -448,6 +448,9 @@ int dt_io_thread_apply_cfg(struct dt_io_ dtio->tls_use_sni = cfg->tls_use_sni; #endif /* HAVE_SSL */ } +#ifdef HAVE_GETTID + dtio->thread_tid_log = cfg->log_thread_id; +#endif return 1; } @@ -1551,7 +1554,7 @@ void dtio_output_cb(int ATTR_UNUSED(fd), } } if(!dtio->cur_msg) - return; /* nothing to do */ + return; /* nothing to do */ } } @@ -2130,7 +2133,18 @@ static void* dnstap_io(void* arg) struct dt_io_thread* dtio = (struct dt_io_thread*)arg; time_t secs = 0; struct timeval now; - log_thread_set(&dtio->threadnum); + const char name[16] = "unbound/dnstap"; /* seems to be the safest size + between different OSes */ + +#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED) + dtio->thread_tid = gettid(); + if(dtio->thread_tid_log) + log_thread_set(&dtio->thread_tid); + else +#endif + log_thread_set(&dtio->threadnum); + + ub_thread_setname(ub_thread_self(), name); /* setup */ verbose(VERB_ALGO, "start dnstap io thread"); Index: usr.sbin/unbound/dnstap/dtstream.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/dnstap/dtstream.h,v diff -u -p -r1.1.1.2 dtstream.h --- usr.sbin/unbound/dnstap/dtstream.h 28 Oct 2020 11:30:15 -0000 1.1.1.2 +++ usr.sbin/unbound/dnstap/dtstream.h 21 Sep 2026 16:28:04 -0000 @@ -131,6 +131,12 @@ struct dt_io_thread { struct dt_io_list_item* io_list_iter; /** thread id, of the io thread */ ub_thread_type tid; +#ifdef HAVE_GETTID + /** thread tid, the LWP id */ + pid_t thread_tid; + /** if logging should include the LWP id */ + int thread_tid_log; +#endif /** if the io processing has started */ int started; /** ssl context for the io thread, for tls connections. type SSL_CTX* */ Index: usr.sbin/unbound/dnstap/unbound-dnstap-socket.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/dnstap/unbound-dnstap-socket.c,v diff -u -p -r1.4 unbound-dnstap-socket.c --- usr.sbin/unbound/dnstap/unbound-dnstap-socket.c 31 Aug 2025 21:41:09 -0000 1.4 +++ usr.sbin/unbound/dnstap/unbound-dnstap-socket.c 21 Sep 2026 16:28:04 -0000 @@ -75,18 +75,18 @@ static void usage(char* argv[]) { printf("usage: %s [options]\n", argv[0]); - printf(" Listen to dnstap messages\n"); + printf(" Listen to dnstap messages\n"); printf("stdout has dnstap log, stderr has verbose server log\n"); - printf("-u listen to unix socket with this file name\n"); - printf("-s listen for TCP on the IP and port\n"); - printf("-t listen for TLS on IP and port\n"); - printf("-x server key file for TLS service\n"); - printf("-y server cert file for TLS service\n"); - printf("-z cert file to verify client connections\n"); - printf("-l long format for DNS printout\n"); - printf("-v more verbose log output\n"); + printf("-u listen to unix socket with this file name\n"); + printf("-s listen for TCP on the IP and port\n"); + printf("-t listen for TLS on IP and port\n"); + printf("-x server key file for TLS service\n"); + printf("-y server cert file for TLS service\n"); + printf("-z cert file to verify client connections\n"); + printf("-l long format for DNS printout\n"); + printf("-v more verbose log output\n"); printf("-c internal unit test and exit\n"); - printf("-h this help text\n"); + printf("-h this help text\n"); exit(1); } @@ -330,7 +330,7 @@ static struct tap_socket* tap_socket_new /** create new socket (unconnected, not base-added), or NULL malloc fail */ static struct tap_socket* tap_socket_new_tlsaccept(char* ip, void (*ev_cb)(int, short, void*), void* data, char* server_key, - char* server_cert, char* verifypem) + char* server_cert, char* verifypem, char* tls_protocols) { struct tap_socket* s = calloc(1, sizeof(*s)); if(!s) { @@ -347,7 +347,7 @@ static struct tap_socket* tap_socket_new s->ev_cb = ev_cb; s->data = data; s->sslctx = listen_sslctx_create(server_key, server_cert, verifypem, - NULL, NULL, 0, 0, 0); + NULL, NULL, 0, 0, 0, tls_protocols); if(!s->sslctx) { log_err("could not create ssl context"); free(s->ip); @@ -1261,13 +1261,13 @@ static void setup_tcp_list(struct main_t /** setup tls accept sockets */ static void setup_tls_list(struct main_tap_data* maindata, struct config_strlist_head* tls_list, char* server_key, - char* server_cert, char* verifypem) + char* server_cert, char* verifypem, char* tls_protocols) { struct config_strlist* item; for(item = tls_list->first; item; item = item->next) { struct tap_socket* s; s = tap_socket_new_tlsaccept(item->str, &dtio_mainfdcallback, - maindata, server_key, server_cert, verifypem); + maindata, server_key, server_cert, verifypem, tls_protocols); if(!s) fatal_exit("out of memory"); if(!tap_socket_list_insert(&maindata->acceptlist, s)) fatal_exit("out of memory"); @@ -1300,7 +1300,7 @@ static void setup_and_run(struct config_strlist_head* local_list, struct config_strlist_head* tcp_list, struct config_strlist_head* tls_list, char* server_key, - char* server_cert, char* verifypem) + char* server_cert, char* verifypem, char* tls_protocols) { time_t secs = 0; struct timeval now; @@ -1326,7 +1326,7 @@ setup_and_run(struct config_strlist_head setup_local_list(maindata, local_list); setup_tcp_list(maindata, tcp_list); setup_tls_list(maindata, tls_list, server_key, server_cert, - verifypem); + verifypem, tls_protocols); if(!tap_socket_list_addevs(maindata->acceptlist, base)) fatal_exit("could not setup accept events"); if(verbosity) log_info("start of service"); @@ -1462,6 +1462,8 @@ int main(int argc, char** argv) struct config_strlist_head tcp_list; struct config_strlist_head tls_list; char* server_key = NULL, *server_cert = NULL, *verifypem = NULL; + + char* tls_protocols = "TLSv1.2 TLSv1.3"; #ifdef USE_WINSOCK WSADATA wsa_data; if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) { @@ -1561,17 +1563,25 @@ int main(int argc, char** argv) #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else - (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #endif /* HAVE_SSL */ } setup_and_run(&local_list, &tcp_list, &tls_list, server_key, - server_cert, verifypem); + server_cert, verifypem, tls_protocols); config_delstrlist(local_list.first); config_delstrlist(tcp_list.first); config_delstrlist(tls_list.first); @@ -1649,7 +1659,8 @@ struct outbound_entry* worker_send_query socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), - struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) + struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited), + int* ATTR_UNUSED(ratelimit_incremented)) { log_assert(0); return 0; @@ -1683,7 +1694,8 @@ struct outbound_entry* libworker_send_qu socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), - struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) + struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited), + int* ATTR_UNUSED(ratelimit_incremented)) { log_assert(0); return 0; @@ -1721,6 +1733,11 @@ void libworker_bg_done_cb(void* ATTR_UNU void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) +{ + log_assert(0); +} + +void libworker_alloc_cleanup(void* ATTR_UNUSED(arg)) { log_assert(0); } Index: usr.sbin/unbound/doc/Changelog =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/Changelog,v diff -u -p -r1.56 Changelog --- usr.sbin/unbound/doc/Changelog 26 Sep 2025 07:32:37 -0000 1.56 +++ usr.sbin/unbound/doc/Changelog 21 Sep 2026 16:28:05 -0000 @@ -1,3 +1,1094 @@ +24 July 2026: Wouter + - Merge #1433 from jisakiel: Add new static zone type + block_aaaa to suppress AAAA queries. + - Unit test for block_a and block_aaaa. + - Fix #1477: respip + dns64: dns64 uses A records modified by + respip instead of original A records. Adds local-zone types + block_a_wdata and block_aaaa_wdata, that are like block_a + and block_aaaa, and uses local-data if present. + - set code repository version to 1.26.0. + - Update generated man pages. + - Fix to allow test fake sha1 on systems with possible sha1 + support. + - Fix to use sha256 for unbound-anchor unit test. + - Fix unbound-anchor check for return value of + X509_NAME_get_text_by_NID of the emailaddress. + - Fix lock test protect for auth zone change. + - Fix to lock shared_ports structure during initialisation. + - Fix to lock anchor structure when file is set for it in + parse of the header. + - Merge #1480 from petrvaganoff: authzone: fix memory leak in + xfer_set_masters() error path. + - Fix unused variable warnings in shared_ports_fetch_random + and shared_ports_return_port when compiled without threads. + - Fix to guard access to shared ports interface array during + set up, for analyzer. + - Fix sign of comparison warning in shared ports setup. + - Fix #1481: Fix to use tls-port after referral if + tls-upstream is set. + - Merge #1479 from psumbera: Fix pthread detection on + Solaris 11.4. + - Fix to call OPENSSL_cleanup on exit when that is defined. + +23 July 2026: Wouter + - Updated credits for Xuanchao Xie in 22 july changelog. + - Merge #1478 from petrvaganoff: pythonmod: add check return + value after ftell(). + - Fix that for NSEC3 proofs the NSEC3 zone, as the b32.name is + checked to be the same as the signer name. Also RRSIGs are + not considered valid when an NSEC3 is not b32.signerzone. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that the aggressive negative cache does not insert NSEC + records with overreaching next owner name. Also the result + is not above the trust anchor's bailiwick. Also RRSIGS are + not considered valid when an NSEC next owner name is not + under the signer zone name. Thanks to Qifan Zhang, Palo + Alto Networks, for the report. + - Fix mesh cycle detection for configuration with respip CNAME + loop and tagged clients. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + +22 July 2026: Wouter + - Release tag for 1.25.2, with the security commits: + - Fix CVE-2026-14586, Assertion in libngtcp2 when under pressure + in high concurrency DNS-over-QUIC environments. Thanks to Kunta + Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University, + for the report. + - Fix CVE-2026-32665, Remote DNS-over-QUIC denial of + service due to `quic-size` budget bypass. Thanks to N0zoM1z0 + (https://github.com/N0zoM1z0) for the report. In addition, thanks to + Kunta Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University, + for also reporting this issue. In addition, thanks to Qifan Zhang, + Palo Alto Networks, for also reporting this issue. In addition, + thanks to Xuanchao Xie, Lutong Chen, and Kaiping Xue of the + University of Science and Technology of China (USTC), for also + reporting this issue. + - Fix CVE-2026-40691, Packet of death for DNSCrypt over TCP. Thanks + to Qifan Zhang, Palo Alto Networks, for the report. In addition, + thanks to Trung Nguyen (@everping) of CyStack, for also reporting + this issue. + - Fix CVE-2026-41637, Degradation of resolution service from + improperly accounted client-terminated DNS-over-QUIC queries. Thanks + to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-42955, Extra fix for CVE-2026-40622 to also clamp + the TTL of A/AAAA records disallowing a one-time 'ghost domain' + delegation renewal via glue records. Thanks to Qifan Zhang, Palo + Alto Networks, for the report. + - Fix CVE-2026-44621, Libunbound applications configured with + 'unwanted-reply-threshold' could eventually be abruptly + terminated. Thanks to Qifan Zhang, Palo Alto Networks, for the + report. + - Fix CVE-2026-44687, Off-by-one error in 'harden-below-nxdomain' + logic can shadow a stub/forward zone by a legitimate parent's + NXDOMAIN. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-44690, Cross-zone wildcard cache poisoning via + RRSIG.labels manipulation. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix CVE-2026-46582, A wildcard replay, as another piece of data, + triggers poisoning in the serve expired reply path. Thanks to + Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-50045, 'max-global-quota' reset by DNSSEC validation + restarts. Thanks to Kunjie Shang, University of Science and + Technology of China, for the report. + - Fix CVE-2026-50046, Possible heap use-after-free in an error path + when a DoT forwarded query is jostled out. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix CVE-2026-50243, 'response-ip'/'rpz' can rewrite BOGUS answers + instead of returning SERVFAIL. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix CVE-2026-50248, BOGUS configured primary hostname accepted for + XFR in auth/rpz zones. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix CVE-2026-50251, Attacker supplied `0.0.0.0`/`::` glue triggers + defensive full-cache flush. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix CVE-2026-50252, Possible cache poisoning attack by mapping + source port population per thread. Thanks to Inbal Schussheim and + Amit Klein, Hebrew University, for the report. + - Fix CVE-2026-52863, Memory corruption could lead to crash and + denial of service. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix CVE-2026-54478, DNS Cookie bypass when combined with + proxy-protocol use. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix CVE-2026-55708, Privacy/configuration issue when adding local + data in views through 'unbound-control'. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix CVE-2026-55717, 'serve-expired-client-timeout' and 'response-ip' + CNAME redirect could lead to a crash. Thanks to Qifan Zhang, Palo + Alto Networks, for the report. In addition, thanks to Xin Wang, + Jiapeng Li, and Jiajia Liu, Northwestern Polytechnical University, + for also reporting this issue. + - Fix CVE-2026-55973, 'dns-error-reporting: yes' leads to stack buffer + overflow. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-55990, Packet of death for a DNSCrypt misconfigured + Unbound. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-55991, Remote DNS-over-QUIC (DoQ) flow-control + assertion failure in libngtcp2. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. In addition, thanks to Xuanchao Xie, + Lutong Chen, and Kaiping Xue of the University of Science and + Technology of China (USTC), for also reporting this issue. + - Fix CVE-2026-56416, Possible heap buffer overflow when validator + canonicalizes RDATA that contains domain name. Thanks to Qifan + Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-56444, Degradation of resolution service when + 'discard-timeout' and 'serve-expired-client-timeout' are combined in + unusual configuration. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. In addition, thanks to Xin Wang, Jiapeng Li, + and Jiajia Liu, Northwestern Polytechnical University, for also + reporting this issue. In addition, thanks to Haruki Oyama (Waseda + University), for also reporting this issue. + - Set the repository to 1.25.3, it continues with the previous + changes. + - Unit test for CVE-2026-42955. + - Unit test for CVE-2026-44687. + - Unit test for CVE-2026-44690. + - Unit test for CVE-2026-46582. + - Unit test for CVE-2026-50045. + - Unit test for CVE-2026-50243. + - Unit test for CVE-2026-50248. + - Unit test for CVE-2026-55717. + - Unit test for CVE-2026-55973. + - Unit test for CVE-2026-56416. + - Fix error in log printout in fix for CVE-2026-50248, when the + primary name is bogus. + - iana portlist update. + +21 July 2026: Wouter + - Merge #1476 from petrvaganoff: ipsecmod: fix possible deref + on null after reply_find_answer_rrset(). + +20 July 2026: Wouter + - Merge #1475 from petrvaganoff: ipsecmod: fix deref on null + in ipsecmod-whitelist after OOM. + - Fix #1474: DoQ responses are never padded - pad-responses + does not apply to comm_doq (RFC 9250 §5.4 MUST). + +9 July 2026: Wouter + - Merge #1383 from jdek: Fix randomness generation on + macOS/iOS under chroot. + - Fix unit test for malformed svcb for test on Windows. + +2 July 2026: Wouter + - Merge #1087: Overload `local_data_remove` to support removing + specific records. + +30 June 2026: Wouter + - Fix #1469: dohclient: DoH POST missing content-length → :status + 400 from strict resolvers (Cloudflare, Mullvad). + - iana portlist updated. + +26 June 2026: Wouter + - Merge #1467: daemon: fix DEREF_AFTER_NULL.EX.COND on + worker_init. This fixes error handling if the worker + stat_timer allocation has an out of memory error. That + makes the server not crash later, attempting to use it. + +24 June 2026: Wouter + - Merge #1465 from dag-erling: Add libunbound/remote.h. Add + a shared header containing prototypes for functions that + both ends of a remote control connection need to implement. + +19 June 2026: Wouter + - Fix for #1457: fix thread setname for thread start of + dnstap, and fast_reload. + - Fix to update github ci actions/checkout to v7. + - Fix warning about file_string_matches in unbound-checkconf. + +17 June 2026: Wouter + - Fix that after fast_reload the disown of the auth zone + transfer task cleans the chunk list. Also fix the + auth_transfer_limit test to use a forwarder for each type + of failure, so the one is not blocked by the other waiting. + - Fix to remove debug from auth_transfer_limit test. + - Fix that unbound-checkconf checks if an auth-zone download + can overwrite another file, by filename collision. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that malloc failure in auth-zone insert rr does + not create an empty node and does not cause an infinite + loop. Thanks to Qifan Zhang, Palo Alto Networks, for + the report. + - Fix that unbound-control auth_zone_reload stops the + server answering from the zone after a failure to read. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that malloc failure in dns64_inform_super does + not set up a half-built reply for cache store, that could + lead to a crash. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix that malloc failure for new_local_rrset for RPZ qname + trigger RR insert does not crash. It does not link a + partial RRset, and logs an error on failure, and cleans + up the dname allocation. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix that malloc failure in doq connection setup, does + not crash in doq connection delete later. Thanks to Qifan + Zhang, Palo Alto Networks, for the report. + - Fix that malloc failure for ngtcp2_conn_server_new + cleans up reference that older ngtcp2 versions can leave. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that on malloc failure during accept of TCP, the + socket is not left to cause a read event loop. It uses + slow-accept to delay accepting new connections, if + that fails it drops the new connections. When the tcp + connection usage is full, it waits for 50msec, to allow + existing queries to be resolved. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix that malloc failure for rpz_strip_nsdname is + checked and handled, so that it does not crash later. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that malloc failure during edns subnet addrtree + insert is checked, so it does not crash later. Thanks to + Qifan Zhang, Palo Alto Networks, for the report. + - Fix to check the return value of auth_xfer_create + during fast_reload auth-zone add and change processing. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix to check for malloc failure in rpz response create, + for nodata and nxdomain, so it does not crash later. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that fast_reload does not terminate the server + on malloc failure for dnstap, or if gethostname fails. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix after malloc failure for stats, then it drains the pipe + so the internal messaging stays correct. Also it does + not exit the server if stats pipe communication fails. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that fast_reload does not terminate the server + on config read failure after malloc failure. Thanks to + Qifan Zhang, Palo Alto Networks, for the report. + - Fix that fast_reload does not terminate the server if + random init for DNS cookies fails. The data is only random + generated if cookies are enabled, and the random data + is necessary. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + +17 June 2026: Yorgos + - Fix memory leak on DNAME 0TTL records. + +16 June 2026: Wouter + - Fix to disallow $INCLUDE for secondary zones. Start up + of server continues if a secondary zone fails to load. + Failed loads clear the zone data, so there is no partial + zone. Thanks to Qifan Zhang, Palo Alto Networks, for + the report. + - Fix that when SVCB records cannot be written out, and + are written in unknown format, that the zone read allows + such unknown format SVCB records. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix that a half-written trust anchor file does not crash + the server at runtime. It unlinks a wrong file from the list. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that auth-zone, and RPZ zones, do not allow out-of-zone + records. These are records that are not under the zone apex. + The out-of-zone records are dropped from the zone contents. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that dns64 does not ignore the `forward-no-cache` and + `stub-no-cache` options. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix that a signed wildcard NSEC, is checked before use, + so it does not allow insecure DS proofs inappropriately. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that after malloc failure a half-built local_alias does + not crash the server. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix that for a zonefile only zone, if that file does not + exist on server start, the server continues to start with + a warning log message. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix that after malloc failure in RPZ load a half built + list does not crash later. The newly created RRset is + linked after creation has succeeded. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix that dnscrypt configuration does not crash, due to + inconsistency between secret and public keys. Also + duplicate files are skipped. Thanks to Qifan Zhang, Palo + Alto Networks, for the report. + - Fix locking in libunbound ub_ctx_set_event call. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that libunbound pipe functions fail with error after + an event base is set. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix for neater solution to clear log thread id after + worker init failure. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix incorrect cleanup after an allocation failure for + a delegation point. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix that after malloc failure in find_tag_datas, the + local_alias is cleaned up. Thanks to Qifan Zhang, Palo + Alto Networks, for the report. + - Fix that after shared memory cannot be created, from + `shm-enable`, the server does not crash. Thanks to Qifan + Zhang, Palo Alto Networks, for the report. + - Fix incorrect cleanup after an allocation failure for + a delegation point in a region. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix after malloc failure the rrset_insert_rr in + localzone processing, during RPZ qname trigger processing, + the RRset retains its previous data correcly. Thanks to + Qifan Zhang, Palo Alto Networks, for the report. + - Fix for #1462: Fix that auth primary host name lookup + allows CNAMEs. + +15 June 2026: Wouter + - Fix to add `max-transfer-size` and `max-transfer-time` that + limit auth-zone and rpz transfer amount and time taken. + Default is disabled. This hardens against unbounded + transfers. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix perform a full transfer every number of incremental + transfers, to stop increasing memory usage, for rpz + zones. Thanks to Qifan Zhang, Palo Alto Networks, for + the report. + - Fix assertion failure for long HTTP header that fills + buffer. Thanks to Qifan Zhang, Palo Alto Networks, for + the report. + - Fix buffer overflow when configured with lower than + default size and http transfer. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix that misconfigured `iter-scrub-ns: 0` causes request + failures. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix that fast_reload when a zonemd verification lookup + it in progress with subnet loaded, deregisters the + callback. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix for fast_reload that removes an auth zone while its + lookups are in progress, for a primary name. Also after the + change, it no longer picks up the old results. Thanks to + Qifan Zhang, Palo Alto Networks, for the report. + - Fix integer overflow in infra-cache-max-rtt calculation. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix erroneous DNS error report values after bogus AAAA + query caused error information that was not cleared by + a successful A subquery. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix integer overflow for very high values of + `sock-queue-timeout`. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix that fast_reload does not terminate the server for + errors in config, for key files. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix log of an aliased qname, to not use freed region + memory. Thanks to Qifan Zhang, Palo Alto Networks, for + the report. + - Fix DNAME synthesis from cache that keeps use of 0TTL + entries in a sliding window. It did not surpass RRSIG + expiry. Thanks to Qifan Zhang, Palo Alto Networks, for + the report. + - Fix misconfigured ipsecmod hook causing path name + similarity with other file. The ipsecmod is changed for + exec of the hook. The ipsecmod hook, if a script, has to + start now with a line like `#!/bin/sh`. Thanks to Qifan + Zhang, Palo Alto Networks, for the report. + - Fix that dns64 bypasses rpz-passthru rule during + synthesis. This restricted more than necessary. Thanks to + Qifan Zhang, Palo Alto Networks, for the report. + +12 June 2026: Wouter + - Fix that for auth-zone and rpz zones the allow-notify + addresses and netblocks are available from start, and + fix the probe step skip. + +11 June 2026: Wouter + - Fix for #1306: configure detects specifically the call to + SSL_set_quic_tls_early_data_enabled and + SSL_set_quic_early_data_enabled, so the correct one is used. + - Fix for #1306: configure checks if the ngtcp2_crypto_ossl + header file is available, and prints an error otherwise. + - Fix #1437: Fix compile with OpenSSL 4.0.1. + - Fix compile for OpenSSL 1.0.2 and before in server cleanup. + +10 June 2026: Wouter + - Fix pythonmod script read for numeric overflow. + - Fix warnings with gcc in compat/inet_pton.c. + +9 June 2026: Wouter + - Fix unit test for ecs to check for malloc success. + +3 June 2026: Wouter + - Fix that the processing of class responses does not have + a heap use-after-free. That could happen if at least two + distinct classes are configured for resolution. Thanks + to Qifan Zhang, Palo Alto Networks for the report. + In addition, thanks to Xin Wang, Jiapeng Li, and Jiajia + Liu, Northwestern Polytechnical University, for also + reporting this. + - Fix negative cache to work with NSEC3 records without salt. + Thanks to Xin Wang, Jiapeng Li, and Jiajia Liu, Northwestern + Polytechnical University, for the report. + - Fix parse of svcbparam ech, it had incorrect length. Thanks + to Qifan Zhang, Palo Alto Networks for the report. + - Fix that quotation and escaping works the same in auth-zone + url content, as in the zonefile read. Thanks to Qifan Zhang, + Palo Alto Networks for the report. + - Fix ipset module to use larger domain name buffers, and + check buffer lengths. Thanks to Qifan Zhang, Palo Alto + Networks for the report. + - Fix PROXYv2 header read and consume, it checks the header + size. Thanks to Qifan Zhang, Palo Alto Networks for + the report. + - Fix negative cache NSEC3 nodata proof, to use the correct + message size. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix fast_reload for when a ZONEMD lookup is in progress. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that validation canonicalization of domain names + in rdata checks for buffer bounds. Thanks to Qifan Zhang, + Palo Alto Networks, for the report. + - Fix that dump_cache has a larger buffer for records, + and it checks that an owner name does not collide with BADRR + on the input, and changes verbosity on the log of failure in + rrset to string. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix that dns64 cleans up the allocated message if the adjust + routines fail, and checks if there is a reply before cache + store, also unbound checks if A and AAAA are malformed + for auth-zones. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + +3 June 2026: Yorgos + - Fix const as reported by newest compiler warnings. + +29 May 2026: Wouter + - Fix header_seen detection for trust anchor files, so that it + detects the id line. + - iana portlist updated. + - Update icannbundle.pem certificates in unbound-anchor. It + has the public keys for 2009 to 2029 and for 2025 to 2045. + - Fix unit test to check for new icannbundle.pem. + +28 May 2026: Wouter + - Fix #1457: race condition causes segfault when starting + threads. + +27 May 2026: Wouter + - Fix for autotrust state-file line overflow, that can give + hold-down bypass. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix to limit the DSNS per-label walk in the iterator. Thanks + to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that the ratelimit is decremented on successful + referrals. Thanks to Qifan Zhang, Palo Alto Networks, for + the report. + - Fix that msgencode insert_query has the correct assertion, + for a local_alias. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix to reset the tcp-timeout before applying a load based + reduction. Thanks to Qifan Zhang, Palo Alto Networks, for the + report. + - Fix to decrement the per-netblock tcp connection limits, so + it keeps usable. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix manual to document ratelimit, that it is for target + nameservers for a domain, and keeps queries limited. Thanks + to Qifan Zhang, Palo Alto Networks, for the report. + - Fix, in depth, for respip rewrite of dns64 responses. Thanks + to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that dns64 with subnetcache does not write ECS scoped + answers to global cache. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix ipset module for name too long checks, race conditions + on local name buffer, and for socket close race condition. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that validator caps number of ANY RRsets it can + validate, and the wait timer is shortened. Thanks to Qifan + Zhang, Palo Alto Networks, for the report. + - Fix analyzer warning in mesh_new_client. + +26 May 2026: Wouter + - Fix for mesh new client and mesh new callback to rollback the + added address, tcp mesh state and callback when there is a failure + to initialize. This fixes the mesh accounting of reply addresses. + Thanks to Xin Wang, Jiapeng Li, and Jiajia Liu, Northwestern + Polytechnical University, for the report + +20 May 2026: Wouter + - Fix CVE-2026-33278, Possible remote code execution during DNSSEC + validation. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-42944, Heap overflow and crash with multiple nsid, + cookie, padding EDNS options. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix CVE-2026-42959, Crash during DNSSEC validation of malicious + content. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-32792, Packet of death with DNSCrypt. Thanks to Andrew + Griffiths from 'calif.io' for the report. + - Fix CVE-2026-40622, "Ghost domain name" variant. Thanks to Qifan + Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-41292, Parsing a long list of incoming EDNS options + degrades performance. Thanks to GitHub user 'N0zoM1z0', also Qifan + Zhang from Palo Alto Networks, for the report. + - Fix CVE-2026-42534, Jostle logic bypass degrades resolution + performance. Thanks to Qifan Zhang, Palo Alto Networks, for the + report. + - Fix CVE-2026-42923, Degradation of service with unbounded NSEC3 + hash calculations. Thanks to Qifan Zhang, Palo Alto Networks, for + the report. + - Fix CVE-2026-42960, Possible cache poisoning attack while following + delegation. Thanks to TaoFei Guo from Peking University, Yang Luo + and JianJun Chen, Tsinghua University, for the report. + - Fix CVE-2026-44390, Unbounded name compression in certain cases + causes degradation of service. Thanks to Qifan Zhang, Palo Alto + Networks, for the report. + - Fix CVE-2026-44608, Use after free and crash in RPZ code. Thanks + to Qifan Zhang, Palo Alto Networks, for the report. + - Tag for 1.25.1 release, it contains the security fixes on 1.25.0. + the code repository continues with in addition the previous fixes, + for 1.25.2. + - Unit test for CVE-2026-33278. + - Unit test for CVE-2026-42944. + - Unit test for CVE-2026-42959. + - Unit test for CVE-2026-40622. + - Unit test for CVE-2026-42960. + - Fix in depth for serve-expired responses from cachedb, that it + does not store bogus. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix lame server detection, for selfpointed glue records. + Thanks to Shuhan Zhang, Dan Li, and Baojun Liu from Tsinghua + University for the report. + - Fix cleaning up DoH session. The same query can be on multiple + streams in a session. Thanks to Qifan Zhang, Palo Alto Networks, + for the report. + - Fix for signed same-owner CNAME and ordinary RRset responses. + Thanks to Xin Wang and Jiajia Liu, Northwestern Polytechnical + University, for the report. + +18 May 2026: Wouter + - Fix for mixed class referrals, the resolver uses the query + class. Thanks to Xin Wang and Jiajia Liu, Northwestern + Polytechnical University, for the report. + +15 May 2026: Wouter + - Fix man page entry for so-sndbuf, it is for responses sent out. + - Fix val_find_DS for robustness, to check the result of + packet_rrset_copy_region before using it. Thanks to Xin Wang + and Jiajia Liu, Northwestern Polytechnical University, for + the report. + - Fix that for dns64 answers, the AAAA query is checked to be + DNSSEC validated, when DNSSEC is enabled. This improves + the RFC6147 conformance of Unbound. Thanks to Xin Wang + and Jiajia Liu, Northwestern Polytechnical University, for + the report. In addition, thanks to Qifan Zhang, Palo Alto + Networks, for reporting it. + - Fix for allocation-failure hardening of rrset cache wildcard + storage and canonical NSEC owner replacement. Thanks to Xin + Wang and Jiajia Liu, Northwestern Polytechnical University, + for the report. + - Fix DNSSEC validation with libnettle for noncanonical RSA + DNSKEYs with leading zeroes for n. Thanks to Xin Wang and + Jiajia Liu, Northwestern Polytechnical University, for + the report. + - Fix DNSKEY size calculation for noncanonical RSA DNSKEYs + with leading zeroes for n. Thanks to Xin Wang and Jiajia Liu, + Northwestern Polytechnical University, for the report. + +11 May 2026: Yorgos + - Fix comment and verbose logging for EDNS fallback buffer size. + +8 May 2026: Wouter + - Fix to relax assertions after the TTL 0 handling change. + This relaxes an assertion in cachedb (it fails instead), + and for packet_rrset_copy_region. + +7 May 2026: Wouter + - Fix for Heap Out-of-Bounds Write via size_t-to-int Truncation + in setup_if() - outside_network_create(). This fixes that + large values for num_ports do not overflow and create + invalid references after integer truncation. Thanks + to Karnakar Reddy (@karnakarreddi) for the report. + - Fix to clean up log ids after a failure to start a worker thread. + +1 May 2026: Wouter + - iana portlist updated. + +29 April 2026: Wouter + - tag for 1.25.0. The code repository continues with 1.25.1 in + development. + - Fix windows 64bit build for libssp dependency. + +23 April 2026: Wouter + - Merge #1441: Fix buffer overrun in + doq_repinfo_retrieve_localaddr(). + - For #1441: Fix type of ipv6 addr struct. + +21 April 2026: Wouter + - Add test case for malformed SVCB records. Thanks to + Qifan Zhang, Palo Alto Networks for the additional test. + - Fix for the Jiggle Attack. The server is fixed to answer + with errors for error cases, and does not stay silent. + In addition, the error replies do not contain parts of the + incoming query. This is more conformant, stops reflection + and stops it as a covert channel. Thanks to Yuqi Qiu and + Xiang Li, Nankai University (AOSP Lab) for the report. + In addition, thanks to Qifan Zhang, Palo Alto Networks, for + noting the fingerprinting possibility, that is also fixed + with this. + - Fix EDNS extended RCODE reflection. This fixes that + the server does not echo extended rcode values after class + chaos queries. Thanks to Qifan Zhang, Palo Alto Networks + for the report. + - Fix for iterator RCODE handling of YXDOMAIN. This fixes + that the server only accepts YXDOMAIN answers that contain + a DNAME record. This stops bad answers, and checks that + the authoritative server gives correct replies. + Thanks to Qifan Zhang, Palo Alto Networks for the report. + - Fix for missing bounds check for decompressing dnames + for downloaded authority zones. This fixes that the server + could end up with malformed zone content after receiving + truncated packet contents from an AXFR. In addition, the + domain names in the SOA rdata are checked before the + authority code picks up the zone serial. + Thanks to Halil Oktay for the report. + - Fix that upstream TLS connections are not reused as TLS + connections for a different name, at the same IP. This + checks that the tls name is correct when reusing the + upstream connections. Thanks to TaoFei Guo from Peking + University and JianJun Chen from Tsinghua University for + the report. + - Fix that signatures are not allowed with revoked dnskeys. + Thanks to Qifan Zhang, Palo Alto Networks for the report. + - Fix that a DNAME with an unsigned CNAME is checked for + the correct match. This stops that for certain zone + configurations an unchecked unsigned CNAME could get + secure status. Thanks to Qifan Zhang, Palo Alto Networks + for the report. + - Fix handling of wildcard CNAMEs in the chain of trust. + An improper wildcard in the chain of trust would send + the retries to the wrong upstream. Also it could label + the step in the chain of trust as secure, when it was not. + Thanks to Qifan Zhang, Palo Alto Networks for the report. + - Set version number to 1.25.0 of code repository. + - Fix doxygen comment syntax. + +20 April 2026: Wouter + - Fix compile warnings for thread setname routine, and test compile. + - Fix unused variable warning when compiled without ssl. + - Fix test with https zone for libressl. + +17 April 2026: Wouter + - Fix setup of ssl context copy of the tls service pem option, + from a clang analyzer warning. + - Fix setup of ssl context copy, to check for the tls service + pem option for stat calls. + - Fix to compile the shm code when there is no shmget. + - Update github ci to use actions/checkout@v6. + - Update github ci cross platform to use + cross-platform-actions/action@v1.0.0. + - Fix github ci to speed up with parralel build, for windows ci. + - Fix compat/chacha_private sigma and tau definitions to use + nonstring attribute. + - Fix compat/gmtime_r old style definition syntax. + - Fix to increase size of the buffer for the win_svc reportev log + function. + - Fix ttl comparisons in rdata_copy for 32bit signed or unsigned. + - Fix subnet store of servfail to not leak memory. + - Update generated man pages. + - Update generated configure, with autoconf. + - Fix pthread_setname detection to fail on warnings. + +17 April 2026: Yorgos + - Merge #1400: Support pthread_setname_np. Adds support for + pthread_setname_np and variants to set the name on spawned threads + for easier debugging/monitoring. + +16 April 2026: Yorgos + - Merge #1406: Introduce new 'tls-protocols' configuration option. + - Introduce new 'tls-protocols' configuration option that specifies + which of the supported TLS protocols will be used. + This change invalidates some previous changes: + - TLSv1.2 is again enabled by default, but can be selectively turned + off if desired (related to #1303). + - The biefly introduced (not yet released) 'tls-use-system-versions' + configuration option, that addressed #1346, is reverted in favor of + 'tls-protocols'. + - The briefly introduced (not yet released) '--enable-system-tls' + configure option, related to #1401, is no longer needed with the new + option and the current default. + - Fix cleaning up DoH session. The same query can be on multiple + streams in a session. + +16 April 2026: Wouter + - Fix configure, autoconf for #1406. + +15 April 2026: Wouter + - Fix RFC7766 compliance when client sends EOF over TCP. It stops + pending replies and closes. Thanks to Yuxiao Wu, Tsinghua + University for the report. + - Fix to shorten RRSIG count in scrubber, this protects against + an overly large number of RRSIGs. It can be configured with + `iter-scrub-rrsig: 8`, it has default 8. Thanks to Yuxiao Wu, + Tsinghua University for the report. + +14 April 2026: Wouter + - Fix #1017: memory corruption related core dumps. + When alloc_reg_obtain has an empty list, return a new allocation. + - Fix clang analyzer warning for subnetmod, when return_msg is + NULL for update cache, like when it stores servfail status. + - iana portlist updated. + +13 April 2026: Yorgos + - Update the documentation of 'max-query-restarts' in the man page. + +10 April 2026: Wouter + - Fix for EDNS client subnet so that it does not store SERVFAIL in + the global cache after a failed lookup, such as timeouts. A failure + entry is stored in the subnet cache, for the query name, for a + couple of seconds. Queries can continue to use the subnet cache + during that time. + +7 April 2026: Yorgos + - Fix unused variable warning. + +30 March 2026: Wouter + - Merge #1408: Fix shared memory stats with threads. + +27 March 2026: Wouter + - Fix to allow the control-interface config to use ip@port notation. + - Fix test code to allow empty hex answer packets from testbound. + - Fix defense in depth for service callback with empty packet. + +24 March 2026: Wouter + - Fix to check for invalid http content length and chunk size, + and to check the RR rdata field lengths when decompressing and + inserting RRs from an authority zone transfer. This stops + large memory use and heap buffer-overflow read errors. Thanks + to Haruto Kimura (Stella) for the report. + +20 March 2026: Wouter + - Fix for testcode pktview to check buffer size and log errors. + +13 March 2026: Yorgos + - Fix to ignore out-of-zone DNAME records for CNAME synthesis. Thanks + to Yuxiao Wu, Yiyi Wang, Zhang Chao, Baojun Liu, and Haixin Duan from + Tsinghua University. + +13 March 2026: Wouter + - Fix #278: DoT: complete unbound restart required on certificate + renew. Fix so that a reload checks if the files have changed, and + if so, reload the contexts. Also for DoH, DoQ and outgoing DoT. + - iana portlist updated. + - For #278: fast_reload can reload tls-service-key, tls-service-pem + and tls-cert-bundle changes. It checks the modification time of + the tls-service-key and tls-service-pem files for update. + - Fix detection of http listening port in fast_reload. + - Fix to add tls-service-key to memory printout for fast_reload. + +9 March 2026: Wouter + - Fix compile failure in unbound-checkconf for older gcc compiler. + - Merge #1418: Apply cache TTL policy to DNAME and synthesized + CNAME on wire path. + +6 March 2026: Wouter + - Merge #1415: Add lock unlock for view in memory error handling. + +6 March 2026: Yorgos + - Document the suggestion for a higher value for 'outgoing-range'; + helps when the request list is full. + - Warn for unused 'nodefault' local-zone configuration in + unbound-checkconf (related to #1416). + +5 March 2026: Wouter + - Fix for DNS Rebinding Bypass via SVCB/HTTPS Records in Unbound. + Thanks to Kunta Chu, School of Software, Tsinghua University, + Taofei Guo, Peking University, and Jianjun Chen, Institute for + Network Sciences and Cyberspace, Tsinghua University for the + report. The private-address option is fixed to also elide + SVCB and HTTPS records that match the filter. + - Update generated man pages. + +4 March 2026: Yorgos + - For #1411: Introduce a failing case in the rpl test so that it only + passes with the fix in place. + +3 March 2026: Wouter + - Merge #1411: Allow synthesized DNAME TTL=0 to be served from cache + within grace period. The responses are served from cache within + a 1-second grace period. Reduces recursion when authoritative + servers return DNAME with TTL=0 (RFC 2308). Response + still returns TTL=0 to clients. Adds a test for it. + - For #1411: Fix that the lookup for DNAME uses flag. Fix assertion + in expired calc debug routine. + +27 February 2026: Wouter + - Merge #1409: Documentation CNAME in redirect-type local-zone. + - Update generated man pages. + +25 February 2026: Wouter + - Fix validator to set unchecked when validation recursion + requests are passed. The edns subnet module checks if validation + is needed for a cache response, and set the validator to protect + the cache with validation for non-subnet lookups. + +23 February 2026: Wouter + - Fix to have cachedb not return expired bogus data as non-bogus. + - Fix to make the cachedb_val_expired.crpl succeed. + +23 February 2026: Yorgos + - Fix to disallow cache lookup/store in external cachedb when a + forwarder/stub forbids it with the no-cache option. + - Fixed some typos reported in #1395 by rezky_nightky. + +17 February 2026: Wouter + - Fix to remove unused conditional from cookie timestamp at + worker env. + - For #1405: local-zone always_refuse also blocks queries of type DS. + +16 February 2026: Yorgos + - Fix #1404: Priming the root key fails after loading ipfire.org RPZ + zones. Fixed by including the ZONEMD RRtype in the list of types to + ignore for RPZ zones. Analysis and patch provided by ummeegge. + +16 February 2026: Wouter + - Fix that cachedb aggressive negative responses have the RA flag set. + +11 February 2026: Wouter + - Fix #1403: Inconsistency between do-nat64 and do-not-query-address + during retries. + +9 February 2026: Wouter + - Merge #1401: Add a new build-time option for system TLS. + The --enable-system-tls flag enables the + tls-use-system-policy-versions setting by default. + - Update generated man pages. + +6 February 2026: Yorgos + - Fix #1389: [FR] replacement with ECC-GOST12 according to RFC9558. + Patch contributed by Igor V. Ruzanov, available in + contrib/gost12.patch. + +4 February 2026: Wouter + - Fix local privilege escalation on Windows. Thanks to Hao Huang and + CrisprXiang with Fudan University for the report. The OpenSSL + init calls are set to not load the openssl.cnf file when compiled + for Windows. + +3 February 2026: Yorgos + - Eagerly remove .skip mark files in between mini_tdir.sh runs in case + there has been a change on the environment. + +27 January 2026: Wouter + - Add test for allow-notify with a host name. + +26 January 2026: Wouter + - Fix that allow-notify entries with hostnames are copied after IPv4 + and IPv6 lookup. + - Fix to not skip allow-notify hostname lookups when there are only + urls. + +23 January 2026: Yorgos + - Merge #1396: Log Linux thread ID. + - On Linux systems log the system-wide unique thread ID instead of + Unbound's internal thread counter. + - Introduce the 'log-thread-id' configuration option to manage logging + the system-wide Linux thread ID for easier debugging with system + tools. + - Update generated man pages. + +22 January 2026: Wouter + - Fix that fast reload copies the iter_scrub_ns, iter_scrub_cname + and max_global_quota options. + - Fix http test tool petal to not print errors when there is no + error. + +21 January 2026: Wouter + - Merge #1388: QNX Porting support for unbound. + +19 January 2026: Wouter + - Merge #1392: Include "V" (version) option in synopsis. + +15 January 2026: Wouter + - Fix documentation for requestlist.overwritten and + requestlist.exceeded, it explains which query was dropped. + +8 January 2026: Wouter + - Merge #1381: Do not initialize quic_table unless it is enabled. + +6 January 2026: Wouter + - Fix edns subnet, that scope zero queries, when there is a + subquery without subnet, and the forward-no-cache or + stub-no-cache option is set, it is not stored in cache due to + the forward or stub option. + +6 January 2026: Yorgos + - Merge #1391 from Götz Görisch: Fix documentation to adhere to + RFC5952. + +31 December 2025: Yorgos + - Update the unbound-anchor man page to note write permissions of the + generated file if it is to be used with Unbound's + auto-trust-anchor-file option. + - Use the same EDE removal logic when encoding errors as when encoding + replies. + +30 December 2025: Yorgos + - Mark "THROWAWAY" and "(DNSSEC) LAME" responses clearly as Unbound's + categorization in the log output. + +24 December 2025: Yorgos + - More specific wording in the unbound.conf man page for stub-first + and forward-first options. + +3 December 2025: Wouter + - Fix http2 drop handling to clear the postpone_drop state so that + other streams on the http2 session are not affected by a drop, + and can clean up properly if also dropped. Fix http2 send reply + so that when there is a send failure is does not recurse into + the mesh functions and also does not drop the connection due to + the condition of one stream. + +2 December 2025: Wouter + - Fix to remove http2 stream mesh state when mesh new request is + dropping the new request. + +1 December 2025: Wouter + - Fix to add EDNS CO flag to testbound and debug message log. + - Fix header comment about EDE reference in validator/val_sigcrypt.h. + +28 November 2025: Yorgos + - For #1375, there is no DNSTAP environment if it wasn't configured. + +26 November 2025: Yorgos + - Tag for 1.24.2 release. + The repository continues with version 1.24.3. + +13 November 2025: Wouter + - Merge #1374: Mesh reply counters. + This adds the statistics num.queries.replyaddr_limit and + requestlist.current.replies. + - Merge #1375: Copy DNSTAP changes from daemon to workers after + fast_reload. + +12 November 2025: Wouter + - Fix that when discard timeout drops packet, they are accounted as + less reply addresses in use in the mesh area. + - iana portlist updated. + +6 November 2025: Wouter + - Fix add comment to worker_handle_request function that explain it. + - Fix configure test for noreturn attribute so it compiles without + warning. + - Fix configure test for nonstring attribute so that it does not + accept when the compiler prints a warning about an unknown + attribute. + +4 November 2025: Wouter + - Fix dns64 log output to log the default instead of a null string. + +1 November 2025: Yorgos + - Fix #1366: Infra cache does not work correctly for NAT64, by + moving the NAT64 synthesis from the iterator when selecting a target + address, to the delegation point itself when adding target + addresses. + +27 October 2025: Yorgos + - Merge #1331 from Jitka Plesníková: Replace deprecated $function by + new $action, for SWIG. + - Fix #1165, document the possible circular dependency when using + host names instead of IP addresses for name servers in stub/forward + zones and log a warning when spotted in the configuration. + +24 October 2025: Yorgos + - unbound.conf man page updates to include a preview of the section + clauses and some reformatting around the use of "clause", "option" + and "attributes". Based on Havard Eidnes' suggestions on the + mailing list. + - Fix unused attribute warning in redis.c when threads are not + supported. + - For #1364, use OPENSSL_VERSION_TEXT instead of OPENSSL_VERSION_NUMBER + for part of the configure script. OPENSSL_VERSION_TEXT is more + consistent across versions. + +22 October 2025: Yorgos + - Tag for 1.24.1 release. + The repository continues with version 1.24.2. + +15 October 2025: Wouter + - Fix to drop UDP for discard-timeout, but not stream connections. + - Fix to reply with SERVFAIL when the wait-limit is exceeded. + - Add extended dns error code for invalid query type to definition + list. + - Fix unbound.conf man page entry for root-hints to say it can + be used without strongly recommending it. + - Remove iPhone armv7s, and iPhoneSimulator i386 from ios ci. + The lib system does not provide symbols for it on the new macos + runner. + - Fix to exclude libssp for windows compiles. + +10 October 2025: Wouter + - Fix #1358 Enabling FIPS in OpenSSL causes unit test to fail. + +3 October 2025: Yorgos + - Note 'respip' and 'dns64' module order in the unbound.conf + man page. + - Note clearly that 'wait-limit: 0' disables all wait limits. + - 'wait-limit-cookie: 0' can now disable cookie validated wait + limits. + +2 October 2025: Wouter + - Fix that https is set up as enabled when the port is listed in + interface-automatic-ports. Also for the set up of quic it is + enabled when listed there. + +30 September 2025: Wouter + - Fix for #1344: Fix that respip and dns64 can be enabled at the + same time, the client info is copied for attach_sub and add_sub + calls. That makes respip work on dns64 synthesized answers, and + also makes RPZ work with DNS64. The order for the modules is + module-config: "respip dns64 validator iterator". + +29 September 2025: Wouter + - Rebuild configure script from its sources. + - Fix modstack_call_init to use the original string when it has + changed, to call modstack_config with. And skip the changed name + in the string correctly. Thanks to Jan Komissar. + - Neaten up the change in acx_nlnetlabs.m4 to version 49. + - Fix fr_atomic_copy_cfg. + - Rebuild configure script from its sources. + - Fix #1353: auth-zone can not use empty label for $ORIGIN when + http download. + - Fix #1344: module conf 'respip dns64 validator cachedb iterator' + is not known to work. + +29 September 2025: Yorgos + - Merge #1349: Fix #1346: [FR] Please allow back TLS 1.2. + - Merge #1351: ac_cv_func_malloc_0_nonnull for malloc(0) check. + +26 September 2025: Yorgos + - Test for nonstring attribute in configure and add + nonstring attribute annotations. + +24 September 2025: Yorgos + - Avoid calling mesh_detect_cycle_found() when there is no mesh state + to begin with. + +23 September 2025: Yorgos + - Merge #1352 from Petr Vaganov: pythonmod: fix HANDLE_LEAK on + pythonmod_init. + - For #1352, align with the current Python<3 code. + - Merge #1350 from Maryse47: unbound.service.in: allow CAP_NET_ADMIN. + - For #1350, same CAP_NET_ADMIN change for unbound_portable.service.in + as well. + +19 September 2025: Wouter + - Fix to remove configure~ from release tarballs. + +19 September 2025: Yorgos + - Update README.man with clearer text. + - Merge #1337: 0 TTL cached replies and some TTL behavior changes. + - TTL change: Cached records that reach TTL 0 are expired. + - TTL change: TTL 0 upstream answers are no longer cached by + cachedb, as they should. + - TTL change: 'serve-expired-reply-ttl' is now capped by the original + TTL value of the record to try and make some sense when replying + with expired records. + - TTL change: TTL decoding was updated to adhere to RFC8767 section 4 + where a 'set high-order bit' means the value is positive instead of + 0. + - unbound.conf manpage: explicitly mention RFC6891. + +18 September 2025: Wouter + - Tag for 1.24.0 release. Includes the fixes below after rc1. + The repository continues with version 1.24.1. + 17 September 2025: Yorgos - Too many quotes for the EDE message debug printout. Index: usr.sbin/unbound/doc/README =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/README,v diff -u -p -r1.45 README --- usr.sbin/unbound/doc/README 15 Dec 2025 16:07:13 -0000 1.45 +++ usr.sbin/unbound/doc/README 21 Sep 2026 16:28:05 -0000 @@ -1,4 +1,4 @@ -README for Unbound 1.24.2 +README for Unbound 1.26.1 Copyright 2007 NLnet Labs http://unbound.net Index: usr.sbin/unbound/doc/README.DNS64 =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/README.DNS64,v diff -u -p -r1.1.1.2 README.DNS64 --- usr.sbin/unbound/doc/README.DNS64 5 Sep 2023 11:07:46 -0000 1.1.1.2 +++ usr.sbin/unbound/doc/README.DNS64 21 Sep 2026 16:28:05 -0000 @@ -13,7 +13,7 @@ If you're not using DNSSEC then you may 2. The "dns64-prefix" directive indicates your DNS64 prefix. For example: - dns64-prefix: 64:FF9B::/96 + dns64-prefix: 64:ff9b::/96 The prefix must be a /96 or shorter. @@ -42,9 +42,9 @@ To enable NAT64 in Unbound, add to unbou do-nat64: yes The NAT64 prefix defaults to the DNS64 prefix, which in turn defaults to the -standard 64:FF9B::/96 prefix. You can reconfigure it with: +standard 64:ff9b::/96 prefix. You can reconfigure it with: - nat64-prefix: 64:FF9B::/96 + nat64-prefix: 64:ff9b::/96 To test NAT64 operation, pick a domain that only has IPv4 reachability for its nameservers and try resolving any names in that domain. Index: usr.sbin/unbound/doc/README.man =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/README.man,v diff -u -p -r1.1.1.1 README.man --- usr.sbin/unbound/doc/README.man 26 Sep 2025 07:30:47 -0000 1.1.1.1 +++ usr.sbin/unbound/doc/README.man 21 Sep 2026 16:28:05 -0000 @@ -6,11 +6,16 @@ and makes it easier to maintain and cont The templated man pages (*.in) are still part of the code repository as to not alter current procedures that could be in place by users/packagers. +These man pages (*.in) are still the ones being used when +configuring/installing Unbound. +Packagers/users do not have to generate any man pages themselves, this is done +by the core developers during development and upon releasing new versions. + The templated man pages (*.in) are generated by Sphinx (used for the online documentation). The online documentation has its own repository at https://github.com/NLnetLabs/unbound-manual. -In the README.md there (branch test-auto for now), there are further simple -instructions on how to generate the templated man pages there and update them -in this repository. +In that README.md (https://github.com/NLnetLabs/unbound-manual/README.md) +there are further simple instructions on how to generate the templated man +pages there and update them in this repository. Index: usr.sbin/unbound/doc/example.conf.in =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/example.conf.in,v diff -u -p -r1.50 example.conf.in --- usr.sbin/unbound/doc/example.conf.in 15 Dec 2025 16:07:13 -0000 1.50 +++ usr.sbin/unbound/doc/example.conf.in 21 Sep 2026 16:28:05 -0000 @@ -1,7 +1,7 @@ # # Example configuration file. # -# See unbound.conf(5) man page, version 1.24.2. +# See unbound.conf(5) man page, version 1.26.1. # # this is a comment. @@ -54,7 +54,7 @@ server: # interface: 192.0.2.153 # interface: 192.0.2.154 # interface: 192.0.2.154@5003 - # interface: 2001:DB8::5 + # interface: 2001:db8::5 # interface: eth0@5003 # enable this feature to copy the source address of queries to reply. @@ -72,12 +72,12 @@ server: # server from by ip-address. If none, the default (all) interface # is used. Specify every interface on a 'outgoing-interface:' line. # outgoing-interface: 192.0.2.153 - # outgoing-interface: 2001:DB8::5 - # outgoing-interface: 2001:DB8::6 + # outgoing-interface: 2001:db8::5 + # outgoing-interface: 2001:db8::6 # Specify a netblock to use remainder 64 bits as random bits for # upstream queries. Uses freebind option (Linux). - # outgoing-interface: 2001:DB8::/64 + # outgoing-interface: 2001:db8::/64 # Also (Linux:) ip -6 addr add 2001:db8::/64 dev lo # And: ip -6 route add local 2001:db8::/64 dev lo # And set prefer-ip6: yes to use the ip6 randomness from a netblock. @@ -193,6 +193,9 @@ server: # Limit on number of CNAME, DNAME records for incoming packets. # iter-scrub-cname: 11 + # Limit on number of RRSIGs for an RRset for incoming packets. + # iter-scrub-rrsig: 8 + # Limit on upstream queries for an incoming query and its recursion. # max-global-quota: 200 @@ -200,6 +203,12 @@ server: # protects against poison attempts. # iter-scrub-promiscuous: yes + # Limit on number of DNSSEC validation attempts for a query. + # val-validation-attempts: 32 + + # Limit on number of DNSSEC hash attempts for a query. + # val-hash-attempts: 32 + # msec for waiting for an unknown server to reply. Increase if you # are behind a slow satellite link, to eg. 1128. # unknown-server-time-limit: 376 @@ -379,7 +388,7 @@ server: # interface-action: 192.0.2.153 allow # interface-action: 192.0.2.154 allow # interface-action: 192.0.2.154@5003 allow - # interface-action: 2001:DB8::5 allow + # interface-action: 2001:db8::5 allow # interface-action: eth0@5003 allow # Similar to 'access-control-tag:' but for interfaces. @@ -496,6 +505,10 @@ server: # print log lines that say why queries return SERVFAIL to clients. # log-servfail: no + # log system-wide Linux thread ID, insted of Unbound's internal thread + # counter. Only on Linux and only when threads are available. + # log-thread-id: no + # the pid file. Can be an absolute path outside of chroot/work dir. # pidfile: "@UNBOUND_PIDFILE@" @@ -658,7 +671,7 @@ server: # or, just before the iterator). # module-config: "validator iterator" - # File with trusted keys, kept uptodate using RFC5011 probes, + # File with trusted keys, kept up-to-date using RFC5011 probes, # initial file like trust-anchor-file, then it stores metadata. # Use several entries, one per domain name, to track multiple zones. # @@ -718,10 +731,10 @@ server: # val-max-restart: 5 # Should additional section of secure message also be kept clean of - # unsecure data. Useful to shield the users of this validator from + # non-secure data. Useful to shield the users of this validator from # potential bogus data in the additional section. All unsigned data # in the additional section is removed from secure messages. - # val-clean-additional: yes + # val-clean-additional: no # Turn permissive mode on to permit bogus messages. Thus, messages # for which security checks failed will be returned to clients, @@ -756,6 +769,7 @@ server: # serve-expired-ttl-reset: no # # TTL value to use when replying with expired data. + # Capped by the original TTL of the record. # serve-expired-reply-ttl: 30 # # Time in milliseconds before replying to the client with expired data. @@ -891,6 +905,10 @@ server: # that name # o block_a resolves all records normally but returns # NODATA for A queries and ignores local data for that name + # o block_aaaa similarly to block_a, resolves all records normally but + # returns NODATA for AAAA queries and ignores local data for that name + # o block_a_wdata like block_a but uses local data if present. + # o block_aaaa_wdata like block_aaaa but uses local data if present. # o always_null returns 0.0.0.0 or ::0 for any name in the zone. # o noview breaks out of that view towards global local-zones. # @@ -925,6 +943,22 @@ server: # add a netblock specific override to a localzone, with zone type # local-zone-override: "example.com" 192.0.2.0/24 refuse + # Action to apply when the IP address in an AAAA or A RR in the answer + # section of a response matches the specified IP netblock. + # Requires use of the respip module. + # response-ip: 192.0.2.0/24 redirect + + # Redirect as specified by the "resource record string" when the IP + # address in an AAAA or A RR in the answer section of a response + # matches the specified IP netblock. + # Requires use of the respip module. + # response-ip-data: 192.0.2.0/24 "example. A 192.0.2.1" + + # Apply tag(s) when the IP address in an AAAA or A RR in the answer + # section of a response matches the specified IP netblock. + # Requires use of the respip module. + # response-ip-tag: 192.0.2.0/24 "tag1 tag2" + # service clients over TLS (on the TCP sockets) with plain DNS inside # the TLS stream, and over HTTPS using HTTP/2 as specified in RFC8484. # Give the certificate to use and private key. @@ -935,21 +969,22 @@ server: # https-port: 443 # quic-port: 853 + # Also serve tls on these port numbers (eg. 443, ...), by listing + # tls-additional-port: portno for each of the port numbers. + # cipher setting for TLSv1.2 # tls-ciphers: "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256" # cipher setting for TLSv1.3 # tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" - # Pad responses to padded queries received over TLS - # pad-responses: yes - - # Padded responses will be padded to the closest multiple of this size. - # pad-responses-block-size: 468 - # Use the SNI extension for TLS connections. Default is yes. - # Changing the value requires a reload. + # Changing the value requires a restart. # tls-use-sni: yes + # TLS protocols. + # Changing the value requires a restart. + # tls-protocols: "TLSv1.2 TLSv1.3" + # Add the secret file for TLS Session Ticket. # Secret file must be 80 bytes of random data. # First key use to encrypt and decrypt TLS session tickets. @@ -970,15 +1005,18 @@ server: # and on other systems, the default openssl certificates # tls-system-cert: no + # Pad responses to padded queries received over TLS + # pad-responses: yes + + # Padded responses will be padded to the closest multiple of this size. + # pad-responses-block-size: 468 + # Pad queries over TLS upstreams # pad-queries: yes # Padded queries will be padded to the closest multiple of this size. # pad-queries-block-size: 128 - # Also serve tls on these port numbers (eg. 443, ...), by listing - # tls-additional-port: portno for each of the port numbers. - # HTTP endpoint to provide DNS-over-HTTPS service on. # http-endpoint: "/dns-query" @@ -1259,12 +1297,16 @@ remote-control: # zonemd-check: no # zonemd-reject-absence: no # zonefile: "example.org.zone" +# max-transfer-size: 0 +# max-transfer-time: 0 + # Views -# Create named views. Name must be unique. Map views to requests using -# the access-control-view option. Views can contain zero or more local-zone -# and local-data options. Options from matching views will override global -# options. Global options will be used if no matching view is found. +# Create named views. Name must be unique. +# Map views to requests using the access-control-view/interface-view options. +# Views can contain zero or more local-zone and local-data options. +# Options from matching views will override global options. +# Global options will be used if no matching view is found. # With view-first yes, it will try to answer using the global local-zone and # local-data elements if there is no view specific match. # view: @@ -1272,6 +1314,8 @@ remote-control: # local-zone: "example.com" redirect # local-data: "example.com A 192.0.2.3" # local-data-ptr: "192.0.2.3 www.example.com" +# response-ip: 192.0.2.0/24 redirect +# response-ip-data: 192.0.2.0/24 "example. A 192.0.2.1" # view-first: no # view: # name: "anotherview" @@ -1422,3 +1466,5 @@ remote-control: # rpz-signal-nxdomain-ra: no # for-downstream: no # tags: "example" +# max-transfer-size: 0 +# max-transfer-time: 0 Index: usr.sbin/unbound/doc/libunbound.3.in =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/libunbound.3.in,v diff -u -p -r1.48 libunbound.3.in --- usr.sbin/unbound/doc/libunbound.3.in 15 Dec 2025 16:07:13 -0000 1.48 +++ usr.sbin/unbound/doc/libunbound.3.in 21 Sep 2026 16:28:05 -0000 @@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "LIBUNBOUND" "3" "Nov 26, 2025" "1.24.2" "Unbound" +.TH "LIBUNBOUND" "3" "Sep 16, 2026" "1.26.1" "Unbound" .SH NAME -libunbound \- Unbound DNS validating resolver 1.24.2 functions. +libunbound \- Unbound DNS validating resolver 1.26.1 functions. .SH SYNOPSIS .sp \fB#include \fP @@ -416,6 +416,6 @@ on a function return with file read fail .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . Index: usr.sbin/unbound/doc/unbound-anchor.8.in =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound-anchor.8.in,v diff -u -p -r1.47 unbound-anchor.8.in --- usr.sbin/unbound/doc/unbound-anchor.8.in 15 Dec 2025 16:07:13 -0000 1.47 +++ usr.sbin/unbound/doc/unbound-anchor.8.in 21 Sep 2026 16:28:05 -0000 @@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "UNBOUND-ANCHOR" "8" "Nov 26, 2025" "1.24.2" "Unbound" +.TH "UNBOUND-ANCHOR" "8" "Sep 16, 2026" "1.26.1" "Unbound" .SH NAME -unbound-anchor \- Unbound 1.24.2 anchor utility. +unbound-anchor \- Unbound 1.26.1 anchor utility. .SH SYNOPSIS .sp \fBunbound\-anchor\fP [\fBopts\fP] @@ -39,9 +39,17 @@ unbound-anchor \- Unbound 1.24.2 anchor validation. The program fetches the trust anchor with the method from \fI\%RFC 7958\fP when regular \fI\%RFC 5011\fP update fails to bring it up to date. -It can be run (as root) from the commandline, or run as part of startup -scripts. -Before you start the \fI\%unbound(8)\fP DNS server. +It can be run from the commandline, or run as part of startup scripts before +you start the \fI\%unbound(8)\fP DNS server. +.sp +Note that if you want to use \fI\%RFC 5011\fP with Unbound (i.e., the +\fI\%auto\-trust\-anchor\-file\fP option) so +that trust anchor information is automatically tracked by Unbound during +operation, the user that Unbound runs under (by default \(aqunbound\(aq) must have +write permissions to the file and the directory the file lives in (for creating +temporary files). +In this case you would probably want to run this program as the designated +Unbound user. .sp Suggested usage: .INDENT 0.0 @@ -52,6 +60,7 @@ Suggested usage: # in the init scripts. # provide or update the root anchor (if necessary) unbound\-anchor \-a \(dq@UNBOUND_ROOTKEY_FILE@\(dq + # Please note usage of this root anchor is at your own risk # and under the terms of our LICENSE (see source). # @@ -295,6 +304,6 @@ Signature on the root key information. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . Index: usr.sbin/unbound/doc/unbound-anchor.rst =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound-anchor.rst,v diff -u -p -r1.1.1.1 unbound-anchor.rst --- usr.sbin/unbound/doc/unbound-anchor.rst 26 Sep 2025 07:30:47 -0000 1.1.1.1 +++ usr.sbin/unbound/doc/unbound-anchor.rst 21 Sep 2026 16:28:05 -0000 @@ -51,9 +51,17 @@ Description validation. The program fetches the trust anchor with the method from :rfc:`7958` when regular :rfc:`5011` update fails to bring it up to date. -It can be run (as root) from the commandline, or run as part of startup -scripts. -Before you start the :doc:`unbound(8)` DNS server. +It can be run from the commandline, or run as part of startup scripts before +you start the :doc:`unbound(8)` DNS server. + +Note that if you want to use :rfc:`5011` with Unbound (i.e., the +:ref:`auto-trust-anchor-file` option) so +that trust anchor information is automatically tracked by Unbound during +operation, the user that Unbound runs under (by default 'unbound') must have +write permissions to the file and the directory the file lives in (for creating +temporary files). +In this case you would probably want to run this program as the designated +Unbound user. Suggested usage: @@ -62,6 +70,7 @@ Suggested usage: # in the init scripts. # provide or update the root anchor (if necessary) unbound-anchor -a "@UNBOUND_ROOTKEY_FILE@" + # Please note usage of this root anchor is at your own risk # and under the terms of our LICENSE (see source). # Index: usr.sbin/unbound/doc/unbound-checkconf.8.in =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound-checkconf.8.in,v diff -u -p -r1.47 unbound-checkconf.8.in --- usr.sbin/unbound/doc/unbound-checkconf.8.in 15 Dec 2025 16:07:13 -0000 1.47 +++ usr.sbin/unbound/doc/unbound-checkconf.8.in 21 Sep 2026 16:28:05 -0000 @@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "UNBOUND-CHECKCONF" "8" "Nov 26, 2025" "1.24.2" "Unbound" +.TH "UNBOUND-CHECKCONF" "8" "Sep 16, 2026" "1.26.1" "Unbound" .SH NAME -unbound-checkconf \- Check Unbound 1.24.2 configuration file for errors. +unbound-checkconf \- Check Unbound 1.26.1 configuration file for errors. .SH SYNOPSIS .sp \fBunbound\-checkconf\fP [\fB\-hf\fP] [\fB\-o option\fP] [cfgfile] @@ -88,6 +88,6 @@ Unbound configuration file. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . Index: usr.sbin/unbound/doc/unbound-control.8.in =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound-control.8.in,v diff -u -p -r1.49 unbound-control.8.in --- usr.sbin/unbound/doc/unbound-control.8.in 15 Dec 2025 16:07:13 -0000 1.49 +++ usr.sbin/unbound/doc/unbound-control.8.in 21 Sep 2026 16:28:06 -0000 @@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "UNBOUND-CONTROL" "8" "Nov 26, 2025" "1.24.2" "Unbound" +.TH "UNBOUND-CONTROL" "8" "Sep 16, 2026" "1.26.1" "Unbound" .SH NAME -unbound-control \- Unbound 1.24.2 remote server control utility. +unbound-control \- Unbound 1.26.1 remote server control utility. .SH SYNOPSIS .sp \fBunbound\-control\fP [\fB\-hq\fP] [\fB\-c cfgfile\fP] [\fB\-s server\fP] command @@ -168,6 +168,8 @@ ipset, \fI\%tcp\-auth\-query\-timeout\fP, \fI\%delay\-close\fP\&. \fI\%iter\-scrub\-promiscuous\fP\&. +\fI\%tls\-service\-key\fP\&. +\fI\%tls\-service\-pem\fP\&. .sp It does not work with \fI\%interface\fP and @@ -352,6 +354,8 @@ If the name already has no items, nothin Often results in NXDOMAIN for the name (in a static zone), but if the name has become an empty nonterminal (there is still data in domain names below the removed name), NOERROR nodata answers are the result for that name. +With a specific RR instead of a domain name, that specific record is +removed from the local data, and not all the RR data. .UNINDENT .INDENT 0.0 .TP @@ -880,6 +884,11 @@ number of queries removed due to discard .UNINDENT .INDENT 0.0 .TP +.B threadX.num.queries_replyaddr_limit +number of queries removed due to replyaddr limits by thread +.UNINDENT +.INDENT 0.0 +.TP .B threadX.num.queries_wait_limit number of queries removed due to wait\-limit by thread .UNINDENT @@ -973,6 +982,10 @@ Number of requests in the request list t entries. This happens if there is a flood of queries that recursive processing and the server has a hard time. +The counter is increased when during the flood the +\fI\%jostle\-timeout\fP +allows a query to be removed in favor of a new incoming query. +The older query is then dropped to make space. .UNINDENT .INDENT 0.0 .TP @@ -980,6 +993,12 @@ the server has a hard time. Queries that were dropped because the request list was full. This happens if a flood of queries need recursive processing, and the server can not keep up. +The counter is increased when during the flood there is no space +to be made with the jostle out of an older query, and the new query +is dropped. +Since no older queries are removed, see +\fI\%jostle\-timeout\fP setting, there +is no space for the new query. .UNINDENT .INDENT 0.0 .TP @@ -994,6 +1013,13 @@ Current size of the request list, only t .UNINDENT .INDENT 0.0 .TP +.B threadX.requestlist.current.replies +Current count of the number of reply entries waiting on request list +entries. Because a request list entry can send results to multiple reply +addresses, this number may be larger than the size of the request list. +.UNINDENT +.INDENT 0.0 +.TP .B threadX.recursion.time.avg Average time it took to answer queries that needed recursive processing. Note that queries that were answered from the cache are not in this average. @@ -1048,6 +1074,11 @@ summed over threads. .UNINDENT .INDENT 0.0 .TP +.B total.num.queries_replyaddr_limit +summed over threads. +.UNINDENT +.INDENT 0.0 +.TP .B total.num.queries_wait_limit summed over threads. .UNINDENT @@ -1138,6 +1169,16 @@ summed over threads. .UNINDENT .INDENT 0.0 .TP +.B total.requestlist.current.user +summed over threads. +.UNINDENT +.INDENT 0.0 +.TP +.B total.requestlist.current.replies +summed over threads. +.UNINDENT +.INDENT 0.0 +.TP .B total.recursion.time.median averaged over threads. .UNINDENT @@ -1543,6 +1584,6 @@ directory with private keys (\fBunbound_ .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . Index: usr.sbin/unbound/doc/unbound-control.rst =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound-control.rst,v diff -u -p -r1.1.1.2 unbound-control.rst --- usr.sbin/unbound/doc/unbound-control.rst 23 Oct 2025 12:48:52 -0000 1.1.1.2 +++ usr.sbin/unbound/doc/unbound-control.rst 21 Sep 2026 16:28:06 -0000 @@ -170,6 +170,8 @@ There are several commands that the serv :ref:`tcp-auth-query-timeout`, :ref:`delay-close`. :ref:`iter-scrub-promiscuous`. + :ref:`tls-service-key`. + :ref:`tls-service-pem`. It does not work with :ref:`interface` and @@ -345,6 +347,8 @@ There are several commands that the serv Often results in NXDOMAIN for the name (in a static zone), but if the name has become an empty nonterminal (there is still data in domain names below the removed name), NOERROR nodata answers are the result for that name. + With a specific RR instead of a domain name, that specific record is + removed from the local data, and not all the RR data. @@UAHL@unbound-control.commands@local_zones@@ @@ -815,6 +819,10 @@ number of statistic counters: number of queries removed due to discard-timeout by thread +@@UAHL@unbound-control.stats@threadX.num.queries_replyaddr_limit@@ + number of queries removed due to replyaddr limits by thread + + @@UAHL@unbound-control.stats@threadX.num.queries_wait_limit@@ number of queries removed due to wait-limit by thread @@ -893,12 +901,22 @@ number of statistic counters: entries. This happens if there is a flood of queries that recursive processing and the server has a hard time. + The counter is increased when during the flood the + :ref:`jostle-timeout` + allows a query to be removed in favor of a new incoming query. + The older query is then dropped to make space. @@UAHL@unbound-control.stats@threadX.requestlist.exceeded@@ Queries that were dropped because the request list was full. This happens if a flood of queries need recursive processing, and the server can not keep up. + The counter is increased when during the flood there is no space + to be made with the jostle out of an older query, and the new query + is dropped. + Since no older queries are removed, see + :ref:`jostle-timeout` setting, there + is no space for the new query. @@UAHL@unbound-control.stats@threadX.requestlist.current.all@@ @@ -910,6 +928,12 @@ number of statistic counters: Current size of the request list, only the requests from client queries. +@@UAHL@unbound-control.stats@threadX.requestlist.current.replies@@ + Current count of the number of reply entries waiting on request list + entries. Because a request list entry can send results to multiple reply + addresses, this number may be larger than the size of the request list. + + @@UAHL@unbound-control.stats@threadX.recursion.time.avg@@ Average time it took to answer queries that needed recursive processing. Note that queries that were answered from the cache are not in this average. @@ -955,6 +979,10 @@ number of statistic counters: summed over threads. +@@UAHL@unbound-control.stats@total.num.queries_replyaddr_limit@@ + summed over threads. + + @@UAHL@unbound-control.stats@total.num.queries_wait_limit@@ summed over threads. @@ -1024,6 +1052,14 @@ number of statistic counters: @@UAHL@unbound-control.stats@total.requestlist.current.all@@ + summed over threads. + + +@@UAHL@unbound-control.stats@total.requestlist.current.user@@ + summed over threads. + + +@@UAHL@unbound-control.stats@total.requestlist.current.replies@@ summed over threads. Index: usr.sbin/unbound/doc/unbound-host.1.in =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound-host.1.in,v diff -u -p -r1.49 unbound-host.1.in --- usr.sbin/unbound/doc/unbound-host.1.in 15 Dec 2025 16:07:13 -0000 1.49 +++ usr.sbin/unbound/doc/unbound-host.1.in 21 Sep 2026 16:28:06 -0000 @@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "UNBOUND-HOST" "1" "Nov 26, 2025" "1.24.2" "Unbound" +.TH "UNBOUND-HOST" "1" "Sep 16, 2026" "1.26.1" "Unbound" .SH NAME -unbound-host \- Unbound 1.24.2 DNS lookup utility. +unbound-host \- Unbound 1.26.1 DNS lookup utility. .SH SYNOPSIS .sp \fBunbound\-host\fP [\fB\-C configfile\fP] [\fB\-vdhr46D\fP] [\fB\-c class\fP] @@ -185,6 +185,6 @@ encountered a fatal error. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . Index: usr.sbin/unbound/doc/unbound.8.in =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound.8.in,v diff -u -p -r1.50 unbound.8.in --- usr.sbin/unbound/doc/unbound.8.in 15 Dec 2025 16:07:13 -0000 1.50 +++ usr.sbin/unbound/doc/unbound.8.in 21 Sep 2026 16:28:06 -0000 @@ -27,12 +27,12 @@ level margin: \\n[rst2man-indent\\n[rst2 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "UNBOUND" "8" "Nov 26, 2025" "1.24.2" "Unbound" +.TH "UNBOUND" "8" "Sep 16, 2026" "1.26.1" "Unbound" .SH NAME -unbound \- Unbound DNS validating resolver 1.24.2. +unbound \- Unbound DNS validating resolver 1.26.1. .SH SYNOPSIS .sp -\fBunbound\fP [\fB\-hdpv\fP] [\fB\-c \fP] +\fBunbound\fP [\fB\-hdpVv\fP] [\fB\-c \fP] .SH DESCRIPTION .sp \fBunbound\fP is a caching DNS resolver. @@ -118,6 +118,6 @@ Show the version number and build option .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . Index: usr.sbin/unbound/doc/unbound.conf.5.in =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound.conf.5.in,v diff -u -p -r1.55 unbound.conf.5.in --- usr.sbin/unbound/doc/unbound.conf.5.in 15 Dec 2025 16:07:13 -0000 1.55 +++ usr.sbin/unbound/doc/unbound.conf.5.in 21 Sep 2026 16:28:06 -0000 @@ -27,32 +27,93 @@ level margin: \\n[rst2man-indent\\n[rst2 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "UNBOUND.CONF" "5" "Nov 26, 2025" "1.24.2" "Unbound" +.TH "UNBOUND.CONF" "5" "Sep 16, 2026" "1.26.1" "Unbound" .SH NAME -unbound.conf \- Unbound 1.24.2 configuration file. +unbound.conf \- Unbound 1.26.1 configuration file. .SH SYNOPSIS .sp \fBunbound.conf\fP .SH DESCRIPTION .sp \fBunbound.conf\fP is used to configure \fI\%unbound(8)\fP\&. -The file format has attributes and values. -Some attributes have attributes inside them. -The notation is: \fBattribute: value\fP\&. -.sp -Comments start with \fB#\fP and last to the end of line. -Empty lines are ignored as is whitespace at the beginning of a line. .sp The utility \fI\%unbound\-checkconf(8)\fP can be used to check \fBunbound.conf\fP prior to usage. .SH FILE FORMAT .sp -There must be whitespace between keywords. -Attribute keywords end with a colon \fB\(aq:\(aq\fP\&. -An attribute is followed by a value, or its containing attributes in which case -it is referred to as a clause. -Clauses can be repeated throughout the file (or included files) to group -attributes under the same clause. +Whitespace is used to separate keywords. +Whitespace indentation is insignificant, but is still recommended for visual +clarity. +Comments start with \fB#\fP and last to the end of line. +Empty lines are ignored, as is whitespace at the beginning of a line. +.sp +Attribute keywords end with a colon (\fB:\fP) and they are either options or +section clauses (group options together). +.sp +The configuration file is logically divided into \fBsections\fP where each section +is introduced by a \fI\%section clause\fP\&. +.SH SECTION CLAUSES +.sp +The recognized section clauses are: +.INDENT 0.0 +.INDENT 3.5 +.INDENT 0.0 +.TP +.B \fI\%server:\fP +Most of the configuration is found in this section. +.TP +.B \fI\%remote\-control:\fP +Configuration for the facility used by +\fI\%unbound\-control(8)\fP\&. +.TP +.B \fI\%stub\-zone:\fP +Configuration for a zone that redirects to specific authoritative name +servers, e.g. for zones not generally available on the greater +Internet. +.TP +.B \fI\%forward\-zone:\fP +Configuration for a zone that forwards to specific DNS resolvers. +.TP +.B \fI\%auth\-zone:\fP +Configuration for local authoritative zones. +.TP +.B \fI\%view:\fP +Overriding a small subset of configuration for incoming requests. +Requests are mapped to views with +\fI\%access\-control\-view\fP and +\fI\%interface\-view\fP\&. +.TP +.B \fI\%python:\fP +Configuration for the optional \fBpython\fP script module. +.TP +.B \fI\%dynlib:\fP +Configuration for the optional \fBdynlib\fP module that loads dynamic +libraries into Unbound. +.TP +.B \fI\%dnscrypt:\fP +Configuration for the optional DNSCrypt feature. +.TP +.B \fI\%cachedb:\fP +Configuration for the optional \fBcachedb\fP module that can interface +with second level caches, currently Redis or Redis\-complatible +databases. +.TP +.B \fI\%dnstap:\fP +Configuration of the optional dnstap logging feature; a flexible, +structured binary log format for DNS software. +.TP +.B \fI\%rpz:\fP +Configuration for Response Policy Zones that allows for DNS filtering. +Requires the \fBrespip\fP module. +.UNINDENT +.UNINDENT +.UNINDENT +.sp +Section clauses can be repeated throughout the file (or included files) to +logically group options in one visually cohesive group. +This may be particularly useful for the \fBserver:\fP clause with its myriad of +options. +.SH INCLUDING FILES .sp Files can be included using the \fBinclude:\fP directive. It can appear anywhere, it accepts a single file name as argument. @@ -67,11 +128,11 @@ Wildcards can be used to include multipl .sp For a more structural include option, the \fBinclude\-toplevel:\fP directive can be used. -This closes whatever clause is currently active (if any) and forces the use of -clauses in the included files and right after this directive. -.SS Server Options +This closes whatever section clause is currently active (if any) and forces the +use of section clauses in the included files and right after this directive. +.SH SERVER OPTIONS .sp -These options are part of the \fBserver:\fP clause. +These options are part of the \fBserver:\fP section. .INDENT 0.0 .TP .B verbosity: \fI\fP @@ -266,6 +327,10 @@ Default depends on compile options. Larger numbers need extra resources from the operating system. For performance a very large value is best, use libevent to make this possible. +Should be higher (preferably double) than the value of +\fI\%num\-queries\-per\-thread\fP to +account for cases where the request list is full and avoid file descriptor +starvation. .sp Default: 4096 (libevent) / 960 (minievent) / 48 (windows) .UNINDENT @@ -482,6 +547,9 @@ Default: 376 The wait time in msec where recursion requests are dropped. This is to stop a large number of replies from accumulating. They receive no reply, the work item continues to recurse. +For UDP the replies are dropped, for stream connections the reply +is not dropped if the stream connection is still open ready to receive +answers. It is nice to be a bit larger than \fI\%serve\-expired\-client\-timeout\fP if that is enabled. @@ -497,7 +565,7 @@ The number of replies that can wait for This makes a ratelimit per IP address of waiting replies for recursion. It stops very large amounts of queries waiting to be returned to one destination. -The value \fB0\fP disables wait limits. +The value \fB0\fP disables all wait limits. .sp Default: 1000 .UNINDENT @@ -506,7 +574,11 @@ Default: 1000 .B wait\-limit\-cookie: \fI\fP The number of replies that can wait for recursion, for an IP address that sent the query with a valid DNS Cookie. -Since the cookie validates the client address, this limit can be higher. +Since the cookie already validates the client address, this option allows +to override a configured +\fI\%wait\-limit\fP value usually with a higher one +for cookie validated queries. +The value \fB0\fP disables wait limits for cookie validated queries. .sp Default: 10000 .UNINDENT @@ -564,7 +636,7 @@ Default: 0 (use system value) .TP .B so\-sndbuf: \fI\fP If not 0, then set the SO_SNDBUF socket option to get more buffer space on -UDP port 53 outgoing queries. +UDP port 53 outgoing responses. This for very busy servers handles spikes in answer traffic, otherwise: .INDENT 7.0 .INDENT 3.5 @@ -591,7 +663,7 @@ bypass the limit, or the admin can use \ On BSD, Solaris changes are similar to \fI\%so\-rcvbuf\fP\&. .sp -Default: 1m +Default: 4m .UNINDENT .INDENT 0.0 .TP @@ -1012,9 +1084,13 @@ The file must contain the private key fo certificate is in the \fI\%tls\-service\-pem\fP file and it must also be specified if \fI\%tls\-service\-key\fP is specified. -Enabling or disabling this service requires a restart (a reload is not -enough), because the key is read while root permissions are held and before -chroot (if any). +If the key is stored with root permissions or outside of chroot, then +a change or enabling or disabling requires a restart (a reload is not +enough). +But if the key file (and tls\-service\-pem file) are accessible, then they +are read in on reload, and fast_reload. +The server checks the modification time of the file (and the filename) +to see if the file has changed for reload. The ports enabled implicitly or explicitly via \fI\%tls\-port\fP and \fI\%https\-port\fP do not provide normal DNS TCP @@ -1096,8 +1172,8 @@ Default: no .INDENT 0.0 .TP .B tls\-system\-cert: \fI\fP -This the same attribute as the -\fI\%tls\-win\-cert\fP attribute, under a +This the same as the +\fI\%tls\-win\-cert\fP option, under a different name. Because it is not windows specific. .UNINDENT @@ -1161,6 +1237,36 @@ Default: \(dq\(dq .UNINDENT .INDENT 0.0 .TP +.B tls\-use\-sni: \fI\fP +Enable or disable sending the SNI extension on TLS connections. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Changing the value requires a restart. +.UNINDENT +.UNINDENT +.sp +Default: yes +.UNINDENT +.INDENT 0.0 +.TP +.B tls\-protocols: \fI\(dq\(dq\fP +Specify the allowed TLS protocol versions to use, in no particular order. +Possible values are \fBTLSv1.2\fP and \fBTLSv1.3\fP\&. +Enclose list of protocols in quotes (\fB\(dq\(dq\fP) and put spaces between them. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Changing the value requires a restart. +.UNINDENT +.UNINDENT +.sp +Default: \(dqTLSv1.2 TLSv1.3\(dq +.UNINDENT +.INDENT 0.0 +.TP .B pad\-responses: \fI\fP If enabled, TLS serviced queries that contained an EDNS Padding option will cause responses padded to the closest multiple of the size specified in @@ -1194,20 +1300,6 @@ Default: 128 .UNINDENT .INDENT 0.0 .TP -.B tls\-use\-sni: \fI\fP -Enable or disable sending the SNI extension on TLS connections. -.sp -\fBNOTE:\fP -.INDENT 7.0 -.INDENT 3.5 -Changing the value requires a reload. -.UNINDENT -.UNINDENT -.sp -Default: yes -.UNINDENT -.INDENT 0.0 -.TP .B https\-port: \fI\fP The port number on which to provide DNS\-over\-HTTPS service. Only interfaces configured with that port number as @number get the HTTPS @@ -1300,6 +1392,9 @@ The port number on which to provide DNS\ Only interfaces configured with that port number as @number get the QUIC service. The interface uses QUIC for the UDP traffic on that port number. +If it is set to 0, the server does not init QUIC code, and QUIC is +disabled. +This is similar to if QUIC is not in use, but then explicitly. .sp Default: 853 .UNINDENT @@ -1523,8 +1618,8 @@ implicit default \(dqaccess\-control: 12 .INDENT 3.5 The interface needs to be already specified with \fI\%interface\fP and that any -\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP -attributes for targeted clients. +\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP +options for targeted clients. .UNINDENT .UNINDENT .UNINDENT @@ -1539,8 +1634,8 @@ for interfaces. .INDENT 3.5 The interface needs to be already specified with \fI\%interface\fP and that any -\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP -attributes for targeted clients. +\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP +options for targeted clients. .UNINDENT .UNINDENT .UNINDENT @@ -1556,8 +1651,8 @@ but for interfaces. .INDENT 3.5 The interface needs to be already specified with \fI\%interface\fP and that any -\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP -attributes for targeted clients. +\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP +options for targeted clients. .UNINDENT .UNINDENT .UNINDENT @@ -1573,8 +1668,8 @@ for interfaces. .INDENT 3.5 The interface needs to be already specified with \fI\%interface\fP and that any -\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP -attributes for targeted clients. +\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP +options for targeted clients. .UNINDENT .UNINDENT .UNINDENT @@ -1589,8 +1684,8 @@ but for interfaces. .INDENT 3.5 The interface needs to be already specified with \fI\%interface\fP and that any -\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP -attributes for targeted clients. +\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP +options for targeted clients. .UNINDENT .UNINDENT .UNINDENT @@ -1667,7 +1762,7 @@ The logfile is appended to, in the follo .UNINDENT .sp If this option is given, the \fI\%use\-syslog\fP -attribute is internally set to \fBno\fP\&. +option is internally set to \fBno\fP\&. .sp The logfile is reopened (for append) when the config file is reread, on SIGHUP. @@ -1777,17 +1872,29 @@ Default: no .UNINDENT .INDENT 0.0 .TP +.B log\-thread\-id: \fI\fP +(Only on Linux and only when threads are available) +Logs the system\-wide Linux thread ID instead of Unbound\(aqs internal thread +counter. +Can be useful when debugging with system tools. +.sp +Default: no +.UNINDENT +.INDENT 0.0 +.TP .B pidfile: \fI\fP The process id is written to the file. Default is to not write to a file. +.UNINDENT +.INDENT 0.0 .TP .B root\-hints: \fI\fP Read the root hints from this file. Default is nothing, using builtin hints for the IN class. The file has the format of zone files, with root nameserver names and addresses only. -The default may become outdated, when servers change, therefore it is good -practice to use a root hints file. +The default may become outdated, when servers change, and then it is +possible to use a root hints file with specific servers. .sp Default: \(dq\(dq .UNINDENT @@ -1883,7 +1990,7 @@ Default: \(dq3 2 1 0 0\(dq .B harden\-short\-bufsize: \fI\fP Very small EDNS buffer sizes from queries are ignored. .sp -Default: yes (as described in the standard) +Default: yes (per \fI\%RFC 6891\fP) .UNINDENT .INDENT 0.0 .TP @@ -2080,6 +2187,11 @@ This protects against so\-called DNS Reb turned into a network proxy, allowing remote access through the browser to other parts of your private network. .sp +The option removes resource records of types A, AAAA, SVCB and HTTPS +that match the filter. +Inside the SVCB and HTTPS records, the svcparams of type ipv4hint +and ipv6hint are checked for matches. +.sp Some names can be allowed to contain your private addresses, by default all the \fI\%local\-data\fP that you configured is allowed to, and you can specify additional names using @@ -2118,6 +2230,13 @@ The defensive action is to clear the rrs flushing away any poison. A value of 10 million is suggested. .sp +It is useful to add 0.0.0.0/8 and \(aq::\(aq to the +\fI\%do\-not\-query\-address\fP list. +Otherwise they may be answered, from localhost, and the different source +makes an unwanted reply that unnecessarily ticks up. +The \fI\%do\-not\-query\-localhost\fP +option includes them, the zero subnets, when it is enabled. +.sp Default: 0 (disabled) .UNINDENT .INDENT 0.0 @@ -2168,6 +2287,8 @@ If yes, deny queries of type ANY with an If disabled, Unbound responds with a short list of resource records if some can be found in the cache and makes the upstream type ANY query if there are none. +The option stops the DNSSEC validation from processing, possibly lengthy, +ANY responses, when the option is enabled. .sp Default: no .UNINDENT @@ -2514,6 +2635,12 @@ If \fI\%serve\-expired\-client\-timeout\fP is also used then it is RECOMMENDED to use 30 as the value (\fI\%RFC 8767\fP). .sp +This value is capped by the original TTL of the record. +This means that records with higher original TTL than this value will use +this value for expired replies. +Records with lower original TTL than this value will use their original TTL +for expired replies. +.sp Default: 30 .UNINDENT .INDENT 0.0 @@ -2710,6 +2837,9 @@ The types are \fI\%inform_redirect\fP, \fI\%always_transparent\fP, \fI\%block_a\fP, +\fI\%block_aaaa\fP, +\fI\%block_a_wdata\fP, +\fI\%block_aaaa_wdata\fP, \fI\%always_refuse\fP, \fI\%always_nxdomain\fP, \fI\%always_null\fP, @@ -2812,6 +2942,39 @@ local\-data: \(dqexample.com. A 127.0.0. queries for \fBwww.example.com\fP and \fBwww.foo.example.com\fP are redirected, so that users with web browsers cannot access sites with suffix example.com. +.sp +A \fBCNAME\fP record can also be provided via local\-data: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +local\-zone: \(dqexample.com.\(dq redirect +local\-data: \(dqexample.com. CNAME www.example.org.\(dq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +In that case, the \fBCNAME\fP is resolved and the answer +includes resolved target records as well. +The \fBCNAME\fP record has to be with the zone name of the local\-zone, +and there can be one CNAME, not more. +The \fBCNAME\fP record has to be at the zone apex of the +\fBredirect\fP zone, then it is used for redirection. +The resolution proceeds with upstream DNS resolution, and +that does not include the lookup in local zones. +So the record is not able to point in local zones, but it +can point to upstream DNS answers. +.sp +\fBCNAME\fP resolution is supported only in type \fBredirect\fP +local\-zone, and in type \fBinform_redirect\fP local\-zone. +.sp +As different from \fBCNAME\fP records that are used elsewhere, in +the \fBredirect\fP type local\-zone, it is supported that in the target +of the record a wildcard label gets expanded to the query name, with +for example: \fBexample.com. CNAME *.foo.net.\fP gets expanded +to \fBwww.example.com. CNAME www.example.com.foo.net.\fP\&. .UNINDENT .INDENT 7.0 .TP @@ -2867,9 +3030,38 @@ use IPv6 protocol and avoid any queries .UNINDENT .INDENT 7.0 .TP +.B block_aaaa +Like \fI\%transparent\fP or +\fI\%block_a\fP, but +ignores local data and resolves normally all query types excluding AAAA. +For AAAA queries it unconditionally returns NODATA. +Useful in cases when there is a need to explicitly force all apps to +use IPv4 protocol and avoid any queries to IPv6. +.UNINDENT +.INDENT 7.0 +.TP +.B block_a_wdata +Like \fI\%block_a\fP, but +uses local data if present. +If there is local data that is returned, and it acts like transparent. +For A queries it returns NODATA. +.UNINDENT +.INDENT 7.0 +.TP +.B block_aaaa_wdata +Like \fI\%block_aaaa\fP, but +uses local data if present. +If there is local data that is returned, and it acts like transparent. +For AAAA queries it returns NODATA. +.UNINDENT +.INDENT 7.0 +.TP .B always_refuse Like \fI\%refuse\fP, but ignores local data and refuses the query. +This type also blocks queries of type DS for the zone name. +That can break the DNSSEC chain of trust, but it is refused anyway. +The block for type DS assists in more completely blocking the zone. .UNINDENT .INDENT 7.0 .TP @@ -3192,7 +3384,7 @@ zone section below. Configure local data shorthand for a PTR record with the reversed IPv4 or IPv6 address and the host name. For example \fB\(dq192.0.2.4 www.example.com\(dq\fP\&. -TTL can be inserted like this: \fB\(dq2001:DB8::4 7200 www.example.com\(dq\fP +TTL can be inserted like this: \fB\(dq2001:db8::4 7200 www.example.com\(dq\fP .UNINDENT .INDENT 0.0 .TP @@ -3249,7 +3441,7 @@ This specifies the action data for \fI\%response\-ip\fP with action being to redirect as specified by \fI<\(dqresource record string\(dq>\fP\&. \fI<\(dqResource record string\(dq>\fP is similar to that of -\fI\%access\-control\-tag\-action\fP, +\fI\%access\-control\-tag\-data\fP, but it must be of either AAAA, A or CNAME types. If the \fI\fP is an IPv6/IPv4 prefix, the record must be AAAA/A respectively, unless it is a CNAME (which can be used for both versions of @@ -3331,6 +3523,18 @@ For example, 1000 may be a suitable valu overloaded with random names, and keeps unbound from sending traffic to the nameservers for those zones. .sp +It is intended to count the number of queries towards the nameservers +for the zone, and keep those queries limited. +When there is a delegation that needs a lot of lookups, those are +charged in the counters for the destination, the target name, of +the NS records. +Since that is where the nameserver lookup queries are sent to. +That keeps the target, the victim domain, from having many queries. +With the \fI\%ratelimit\-factor\fP, some +genuine queries that are also made to the target zone, can filter +through, and then end up in cache, where the genuine answers have +a chance to collect, keeping up service to some extent. +.sp \fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 @@ -3533,6 +3737,10 @@ Default: 32 Hard limit on the number of times Unbound is allowed to restart a query upon encountering a CNAME record. Results in SERVFAIL when reached. +This applies to chained CNAME records but not sporadic CNAME records that +could be encountered in the lifetime of the query\(aqs resolution effort. +When a CNAME chain concludes, the counter keeping track of this limit is +reset. Changing this value needs caution as it can allow long CNAME chains to be accepted, where Unbound needs to verify (resolve) each link individually. .sp @@ -3560,6 +3768,16 @@ Default: 11 .UNINDENT .INDENT 0.0 .TP +.B iter\-scrub\-rrsig: \fI\fP +Limit on the number of RRSIGs allowed for an RRset, from the iterator +scrubber. +This protects against an overly large number of RRSIGs. +Clips off the remainder of the RRSIG list at that point. +.sp +Default: 8 +.UNINDENT +.INDENT 0.0 +.TP .B max\-global\-quota: \fI\fP Limit on the number of upstream queries sent out for an incoming query and its subqueries from recursion. @@ -3719,17 +3937,18 @@ enabled to increase privacy on the outgo .sp Default: no .UNINDENT -.SS Remote Control Options +.SH REMOTE CONTROL OPTIONS +.sp +These options are part of the \fBremote\-control:\fP section and are the +declarations for the remote control facility. .sp -In the \fBremote\-control:\fP clause are the declarations for the remote control -facility. If this is enabled, the \fI\%unbound\-control(8)\fP utility can be used to send commands to the running Unbound server. -The server uses these clauses to setup TLSv1 security for the connection. -The \fI\%unbound\-control(8)\fP utility also reads the -\fBremote\-control:\fP section for options. +The server uses these options to setup TLS security for the connection. +The \fI\%unbound\-control(8)\fP utility also reads +this \fBremote\-control:\fP section for options. To setup the correct self\-signed certificates use the -\fIunbound\-control\-setup(8)\fP utility. +\fBunbound\-control\-setup(8)\fP utility. .INDENT 0.0 .TP .B control\-enable: \fI\fP @@ -3740,7 +3959,7 @@ Default: no .UNINDENT .INDENT 0.0 .TP -.B control\-interface: \fI\fP +.B control\-interface: \fI\fP Give IPv4 or IPv6 addresses or local socket path to listen on for control commands. If an interface name is used instead of an IP address, the list of IP @@ -3829,9 +4048,11 @@ This file is used by \fI\%unbound\-contr .sp Default: unbound_control.pem .UNINDENT -.SS Stub Zone Options +.SH STUB ZONE OPTIONS .sp -There may be multiple \fBstub\-zone:\fP clauses. +These options are part of the \fBstub\-zone:\fP section. +.sp +There may be multiple \fBstub\-zone:\fP sections. Each with a \fI\%name\fP and zero or more hostnames or IP addresses. For the stub zone this list of nameservers is used. @@ -3870,9 +4091,10 @@ Consider adding \fI\%server\fP statement \fI\%domain\-insecure\fP and for \fI\%local\-zone: nodefault\fP for the zone if it is a locally served zone. -The insecure clause stops DNSSEC from invalidating the zone. +The \fI\%domain\-insecure\fP option stops DNSSEC +from invalidating the zone. The \fI\%local\-zone: nodefault\fP (or -\fI\%transparent\fP) clause makes the +\fI\%transparent\fP) option makes the (reverse\-) zone bypass Unbound\(aqs filtering of \fI\%RFC 1918\fP zones. .INDENT 0.0 .TP @@ -3886,6 +4108,23 @@ This is the full domain name of the zone Name of stub zone nameserver. Is itself resolved before it is used. .sp +\fBCAUTION:\fP +.INDENT 7.0 +.INDENT 3.5 +If the domain (or a subdomain) from this zone is used as the host, it +will unavoidably introduce a circular dependency on retrieving the IP +addresses of the name server. +In that case, it is suggested to use +\fI\%stub\-addr\fP instead. +Alternatively, +\fI\%stub\-first: yes\fP can also work +around the circular dependency by trying resolution outside of this +zone. +However this has the caveat that it would allow escaping this zone when +any resolution attempt fails within this zone. +.UNINDENT +.UNINDENT +.sp To use a non\-default port for DNS communication append \fB\(aq@\(aq\fP with the port number. .sp @@ -3926,9 +4165,12 @@ Default: no .INDENT 0.0 .TP .B stub\-first: \fI\fP -If enabled, a query is attempted without the stub clause if it fails. +If enabled, a query is attempted without this stub section if it fails. The data could not be retrieved and would have caused SERVFAIL because the -servers are unreachable, instead it is tried without this clause. +servers are unreachable, instead it is tried without this stub section. +This can lead to using less specific configured forward/stub/auth zones if +any, or end up to otherwise normal recursive resolution for that particular +query. .sp Default: no .UNINDENT @@ -3961,9 +4203,11 @@ This is useful when you want immediate c .sp Default: no .UNINDENT -.SS Forward Zone Options +.SH FORWARD ZONE OPTIONS .sp -There may be multiple \fBforward\-zone:\fP clauses. +These options are part of the \fBforward\-zone:\fP section. +.sp +There may be multiple \fBforward\-zone:\fP sections. Each with a \fI\%name\fP and zero or more hostnames or IP addresses. For the forward zone this list of nameservers is used to forward the queries @@ -3994,6 +4238,23 @@ This is the full domain name of the zone Name of server to forward to. Is itself resolved before it is used. .sp +\fBCAUTION:\fP +.INDENT 7.0 +.INDENT 3.5 +If the domain (or a subdomain) from this zone is used as the host, it +will unavoidably introduce a circular dependency on retrieving the IP +addresses of the name server. +In that case, it is suggested to use +\fI\%forward\-addr\fP instead. +Alternatively, +\fI\%forward\-first: yes\fP can also +work around the circular dependency by trying resolution outside of +this zone. +However this has the caveat that it would allow escaping this zone when +any resolution attempt fails within this zone. +.UNINDENT +.UNINDENT +.sp To use a non\-default port for DNS communication append \fB\(aq@\(aq\fP with the port number. .sp @@ -4030,9 +4291,11 @@ The cert must also match a CA from the .INDENT 0.0 .TP .B forward\-first: \fI\fP -If a forwarded query is met with a SERVFAIL error, and this option is -enabled, Unbound will fall back to normal recursive resolution for this -query as if no query forwarding had been specified. +If a forwarded query is met with a SERVFAIL error and this option is +enabled Unbound will fall back to less specific resolution. +This can lead to using less specific configured forward/stub/auth zones if +any, or end up to otherwise normal recursive resolution for that particular +query. .sp Default: no .UNINDENT @@ -4070,12 +4333,14 @@ This is useful when you want immediate c .sp Default: no .UNINDENT -.SS Authority Zone Options +.SH AUTHORITY ZONE OPTIONS +.sp +These options are part of the \fBauth\-zone:\fP section. .sp Authority zones are configured with \fBauth\-zone:\fP, and each one must have a \fI\%name\fP\&. -There can be multiple ones, by listing multiple auth\-zone clauses, each with a -different name, pertaining to that part of the namespace. +There can be multiple ones, by listing multiple \fBauth\-zone\fP section clauses, +each with a different name, pertaining to that part of the namespace. The authority zone with the name closest to the name looked up is used. Authority zones can be processed on two distinct, non\-exclusive, configurable stages. @@ -4106,7 +4371,7 @@ consult the local zone data while resolv In this case, the aforementioned CNAME example will result in a thoroughly resolved answer. .sp -Authority zones can be read from zonefile. +Authority zones can be read from a zonefile. And can be kept updated via AXFR and IXFR. After update the zonefile is rewritten. The update mechanism uses the SOA timer values and performs SOA UDP queries to @@ -4143,9 +4408,15 @@ does not support AXFR/IXFR for the zone, \fI\%url\fP to download the zonefile as a text file from a webserver that would work. .sp -If you specify the hostname, you cannot use the domain from the zonefile, -because it may not have that when retrieving that data, instead use a plain -IP address to avoid a circular dependency on retrieving that IP address. +\fBCAUTION:\fP +.INDENT 7.0 +.INDENT 3.5 +If you specify the hostname, you cannot use the domain from the +zonefile, because it may not have that when retrieving that data, +instead use a plain IP address to avoid a circular dependency on +retrieving that IP address. +.UNINDENT +.UNINDENT .UNINDENT .INDENT 0.0 .TP @@ -4291,18 +4562,46 @@ If not given then no zonefile is used. If the file does not exist or is empty, Unbound will attempt to fetch zone data (eg. from the primary servers). .UNINDENT -.SS View Options +.INDENT 0.0 +.TP +.B max\-transfer\-size: \fI\fP +Number of bytes size of the maximum zone transfer size. +Larger transfers, over AXFR, IXFR and HTTP, are not allowed. +A plain number is in bytes, append \(aqk\(aq, \(aqm\(aq or \(aqg\(aq for kilobytes, megabytes +or gigabytes (1024*1024 bytes in a megabyte). +The value \fB0\fP disables the feature. .sp -There may be multiple \fBview:\fP clauses. +Only consider for untrusted/misbehaving primaries that could hog resources +and bring down the resolver. +.sp +Default: 0 +.UNINDENT +.INDENT 0.0 +.TP +.B max\-transfer\-time: \fI\fP +Maximum time in milliseconds that a zone transfer is allowed to take from +the start. +The value \fB0\fP disables the feature. +.sp +Only consider for untrusted/misbehaving primaries that could hog resources +and bring down the resolver. +.sp +Default: 0 +.UNINDENT +.SH VIEW OPTIONS +.sp +These options are part of the \fBview:\fP section. +.sp +There may be multiple \fBview:\fP sections. Each with a \fI\%name\fP and zero or more \fI\%local\-zone\fP and -\fI\%local\-data\fP attributes. +\fI\%local\-data\fP options. Views can also contain \fI\%view\-first\fP, \fI\%response\-ip\fP, \fI\%response\-ip\-data\fP and -\fI\%local\-data\-ptr\fP attributes. +\fI\%local\-data\-ptr\fP options. View can be mapped to requests by specifying the view name in an -\fI\%access\-control\-view\fP attribute. +\fI\%access\-control\-view\fP option. Options from matching views will override global options. Global options will be used if no matching view is found, or when the matching view does not have the option specified. @@ -4312,7 +4611,7 @@ view does not have the option specified. Name of the view. Must be unique. This name is used in the -\fI\%access\-control\-view\fP attribute. +\fI\%access\-control\-view\fP option. .UNINDENT .INDENT 0.0 .TP @@ -4345,6 +4644,22 @@ Has the same behaviour as the global .UNINDENT .INDENT 0.0 .TP +.B response\-ip: \fI \fP +This requires use of the \fBrespip\fP module. +.sp +Similar to \fI\%response\-ip\fP but +only applies to this view. +.UNINDENT +.INDENT 0.0 +.TP +.B response\-ip\-data: \fI <\(dqresource record string\(dq>\fP +This requires use of the \fBrespip\fP module. +.sp +Similar to \fI\%response\-ip\-data\fP but +only applies to this view. +.UNINDENT +.INDENT 0.0 +.TP .B view\-first: \fI\fP If enabled, it attempts to use the global \fI\%local\-zone\fP and @@ -4353,9 +4668,11 @@ view specific options. .sp Default: no .UNINDENT -.SS Python Module Options +.SH PYTHON MODULE OPTIONS .sp -The \fBpython:\fP clause gives the settings for the \fIpython(1)\fP script module. +These options are part of the \fBpython:\fP section. +.sp +The \fBpython:\fP section gives the settings for the \fIpython(1)\fP script module. This module acts like the iterator and validator modules do, on queries and answers. To enable the script module it has to be compiled into the daemon, and the word @@ -4378,14 +4695,16 @@ The script file to load. Repeat this option for every python module instance added to the \fI\%module\-config\fP option. .UNINDENT -.SS Dynamic Library Module Options +.SH DYNAMIC LIBRARY MODULE OPTIONS +.sp +These options are part of the \fBdynlib:\fP section. .sp -The \fBdynlib:\fP clause gives the settings for the \fBdynlib\fP module. +The \fBdynlib:\fP section gives the settings for the \fBdynlib\fP module. This module is only a very small wrapper that allows dynamic modules to be loaded on runtime instead of being compiled into the application. To enable the dynlib module it has to be compiled into the daemon, and the word \fBdynlib\fP has to be put in the -\fI\%module\-config\fP attribute. +\fI\%module\-config\fP option. Multiple instances of dynamic libraries are supported by adding the word \fBdynlib\fP more than once. .sp @@ -4400,7 +4719,9 @@ The dynamic library file to load. Repeat this option for every dynlib module instance added to the \fI\%module\-config\fP option. .UNINDENT -.SS DNS64 Module Options +.SH DNS64 MODULE OPTIONS +.sp +These options are part of the \fBserver:\fP section. .sp The \fBdns64\fP module must be configured in the \fI\%module\-config\fP directive, e.g.: @@ -4420,7 +4741,11 @@ and be compiled into the daemon to be en \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -These settings go in the \fI\%server:\fP section. +If combining the \fBrespip\fP and \fBdns64\fP modules, the \fBrespip\fP module +needs to appear before the \fBdns64\fP module in the +\fI\%module\-config\fP +configuration option so that response IP and/or RPZ feeds can properly +filter responses regardless of DNS64 synthesis. .UNINDENT .UNINDENT .INDENT 0.0 @@ -4456,12 +4781,12 @@ Can be entered multiple times, list a ne per line. Applies also to names underneath the name given. .UNINDENT -.SS NAT64 Operation +.SH NAT64 OPTIONS +.sp +These options are part of the \fBserver:\fP section. .sp NAT64 operation allows using a NAT64 prefix for outbound requests to IPv4\-only servers. -It is controlled by two options in the -\fI\%server:\fP section: .INDENT 0.0 .TP .B do\-nat64: \fI\fP @@ -4477,11 +4802,24 @@ Default: no Use a specific NAT64 prefix to reach IPv4\-only servers. The prefix length must be one of /32, /40, /48, /56, /64 or /96. .sp +The NAT64 prefix is allowed by the +\fI\%do\-not\-query\-address\fP option, +so that there is a clear outcome of addresses in both; the NAT64 prefix +is allowed. +The IPv4 address could be filtered by the +\fI\%do\-not\-query\-address\fP option, +if needed. +Allowing the NAT64 prefix is useful when using do\-not\-query\-address +for a cluster of machines that is IPv6\-only and uses NAT64, but does +not have internet access. +.sp Default: 64:ff9b::/96 (same as \fI\%dns64\-prefix\fP) .UNINDENT -.SS DNSCrypt Options +.SH DNSCRYPT OPTIONS +.sp +These options are part of the \fBdnscrypt:\fP section. .sp -The \fBdnscrypt:\fP clause gives the settings of the dnscrypt channel. +The \fBdnscrypt:\fP section gives the settings of the dnscrypt channel. While those options are available, they are only meaningful if Unbound was compiled with \fB\-\-enable\-dnscrypt\fP\&. Currently certificate and secret/public keys cannot be generated by Unbound. @@ -4611,7 +4949,9 @@ If left unconfigured, it will be configu .sp Default: (unconfigured) .UNINDENT -.SS EDNS Client Subnet Module Options +.SH EDNS CLIENT SUBNET MODULE OPTIONS +.sp +These options are part of the \fBserver:\fP section. .sp The ECS module must be configured in the \fI\%module\-config\fP directive, e.g.: @@ -4628,13 +4968,6 @@ module\-config: \(dqsubnetcache validato .sp and be compiled into the daemon to be enabled. .sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -These settings go in the \fI\%server:\fP section. -.UNINDENT -.UNINDENT -.sp If the destination address is allowed in the configuration Unbound will add the EDNS0 option to the query containing the relevant part of the client\(aqs address. When an answer contains the ECS option the response and the option are placed @@ -4756,7 +5089,9 @@ This number applies for each qname/qclas .sp Default: 100 .UNINDENT -.SS Opportunistic IPsec Support Module Options +.SH OPPORTUNISTIC IPSEC SUPPORT MODULE OPTIONS +.sp +These options are part of the \fBserver:\fP section. .sp The IPsec module must be configured in the \fI\%module\-config\fP directive, e.g.: @@ -4773,13 +5108,6 @@ module\-config: \(dqipsecmod validator i .sp and be compiled into Unbound by using \fB\-\-enable\-ipsecmod\fP to be enabled. .sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -These settings go in the \fI\%server:\fP section. -.UNINDENT -.UNINDENT -.sp When Unbound receives an A/AAAA query that is not in the cache and finds a valid answer, it will withhold returning the answer and instead will generate an IPSECKEY subquery for the same domain name. @@ -4877,7 +5205,9 @@ If the option is not specified, all doma .B ipsecmod\-whitelist: \fI\fP Alternate syntax for \fI\%ipsecmod\-allow\fP\&. .UNINDENT -.SS Cache DB Module Options +.SH CACHE DB MODULE OPTIONS +.sp +These options are part of the \fBcachedb:\fP section. .sp The Cache DB module must be configured in the \fI\%module\-config\fP directive, e.g.: @@ -4939,7 +5269,7 @@ If connection close or timeout happens t unusable with this backend. It\(aqs the administrator\(aqs responsibility to make the assumption hold. .sp -The \fBcachedb:\fP clause gives custom settings of the cache DB module. +The \fBcachedb:\fP section gives custom settings of the cache DB module. .INDENT 0.0 .TP .B backend: \fI\fP @@ -5167,10 +5497,13 @@ for the Redis replica server. .sp Default: 0 .UNINDENT -.SS DNSTAP Logging Options +.SH DNSTAP OPTIONS +.sp +These options are part of the \fBdnstap:\fP section. .sp -DNSTAP support, when compiled in by using \fB\-\-enable\-dnstap\fP, is enabled in -the \fBdnstap:\fP section. +DNSTAP is a flexible, structured binary log format for DNS software. +When compiled in by using \fB\-\-enable\-dnstap\fP, it can be enabled in the +\fBdnstap:\fP section. This starts an extra thread (when compiled with threading) that writes the log information to the destination. If Unbound is compiled without threading it does not spawn a thread, but @@ -5336,15 +5669,18 @@ Enable to log forwarder response message .sp Default: no .UNINDENT -.SS Response Policy Zone Options +.SH RESPONSE POLICY ZONE OPTIONS .sp -Response Policy Zones are configured with \fBrpz:\fP, and each one must have a -\fI\%name\fP attribute. -There can be multiple ones, by listing multiple RPZ clauses, each with a -different name. -RPZ clauses are applied in order of configuration and any match from an earlier -RPZ zone will terminate the RPZ lookup. +These options are part of the \fBrpz:\fP section. +.sp +Response Policy Zones are configured with \fBrpz:\fP section clauses, and each +one must have a \fI\%name\fP option. +There can be multiple ones, by listing multiple \fBrpz:\fP section clauses, each +with a different name. +RPZ sections are applied in order of configuration and any match from an +earlier RPZ zone will terminate the RPZ lookup. Note that a PASSTHRU action is still considered a match. +.sp The respip module needs to be added to the \fI\%module\-config\fP, e.g.: .INDENT 0.0 @@ -5358,6 +5694,17 @@ module\-config: \(dqrespip validator ite .UNINDENT .UNINDENT .sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +If combining the \fBrespip\fP and \fBdns64\fP modules, the \fBrespip\fP module +needs to appear before the \fBdns64\fP module in the +\fI\%module\-config\fP +configuration option so that response IP and/or RPZ feeds can properly +filter responses regardless of DNS64 synthesis. +.UNINDENT +.UNINDENT +.sp QNAME, Response IP Address, nsdname, nsip and clientip triggers are supported. Supported actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp\-only and drop. @@ -5426,9 +5773,6 @@ A 192.0.2.1 answer with .sp Other records like AAAA, TXT and other CNAMEs (not rpz\-..) can also be used to answer queries with that content. -.sp -The RPZ zones can be configured in the config file with these settings in the -\fBrpz:\fP block. .INDENT 0.0 .TP .B name: \fI\fP @@ -5456,6 +5800,10 @@ from a webserver that would work. If you specify the hostname, you cannot use the domain from the zonefile, because it may not have that when retrieving that data, instead use a plain IP address to avoid a circular dependency on retrieving that IP address. +.sp +Every number of IXFR transfers, a full AXFR is performed. +This is to consolidate the rpz memory, that would otherwise grow. +The fixed value is after 5 IXFR transfers. .UNINDENT .INDENT 0.0 .TP @@ -5567,7 +5915,7 @@ Default: no .INDENT 0.0 .TP .B tags: \fI\(dq\(dq\fP -Limit the policies from this RPZ clause to clients with a matching tag. +Limit the policies from this RPZ section to clients with a matching tag. .sp Tags need to be defined in \fI\%define\-tag\fP and can be assigned to client addresses using @@ -5575,9 +5923,35 @@ can be assigned to client addresses usin \fI\%interface\-tag\fP\&. Enclose list of tags in quotes (\fB\(dq\(dq\fP) and put spaces between tags. .sp -If no tags are specified the policies from this clause will be applied for +If no tags are specified the policies from this section will be applied for all clients. .UNINDENT +.INDENT 0.0 +.TP +.B max\-transfer\-size: \fI\fP +Number of bytes size of the maximum zone transfer size. +Larger transfers, over AXFR, IXFR and HTTP, are not allowed. +A plain number is in bytes, append \(aqk\(aq, \(aqm\(aq or \(aqg\(aq for kilobytes, megabytes +or gigabytes (1024*1024 bytes in a megabyte). +The value \fB0\fP disables the feature. +.sp +Only consider for untrusted/misbehaving primaries that could hog resources +and bring down the resolver. +.sp +Default: 0 +.UNINDENT +.INDENT 0.0 +.TP +.B max\-transfer\-time: \fI\fP +Maximum time in milliseconds that a zone transfer is allowed to take from +the start. +The value \fB0\fP disables the feature. +.sp +Only consider for untrusted/misbehaving primaries that could hog resources +and bring down the resolver. +.sp +Default: 0 +.UNINDENT .SH MEMORY CONTROL EXAMPLE .sp In the example config settings below memory usage is reduced. @@ -5630,6 +6004,9 @@ default \fIchroot(2)\fP location. .B @ub_conf_file@ Unbound configuration file. .TP +.B @UNBOUND_PIDFILE@ +default Unbound pidfile with process ID of the running daemon. +.TP .B unbound.log Unbound log file. Default is to log to \fIsyslog(3)\fP\&. @@ -5641,6 +6018,6 @@ Default is to log to \fIsyslog(3)\fP\&. .SH AUTHOR Unbound developers are mentioned in the CREDITS file in the distribution. .SH COPYRIGHT -1999-2025, NLnet Labs +1999-2026, NLnet Labs .\" Generated by docutils manpage writer. . Index: usr.sbin/unbound/doc/unbound.conf.rst =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound.conf.rst,v diff -u -p -r1.4 unbound.conf.rst --- usr.sbin/unbound/doc/unbound.conf.rst 23 Oct 2025 12:50:29 -0000 1.4 +++ usr.sbin/unbound/doc/unbound.conf.rst 21 Sep 2026 16:28:06 -0000 @@ -46,12 +46,6 @@ Description ----------- **unbound.conf** is used to configure :doc:`unbound(8)`. -The file format has attributes and values. -Some attributes have attributes inside them. -The notation is: ``attribute: value``. - -Comments start with ``#`` and last to the end of line. -Empty lines are ignored as is whitespace at the beginning of a line. The utility :doc:`unbound-checkconf(8)` can be used to check ``unbound.conf`` prior to usage. @@ -59,16 +53,122 @@ used to check ``unbound.conf`` prior to File Format ----------- -There must be whitespace between keywords. -Attribute keywords end with a colon ``':'``. -An attribute is followed by a value, or its containing attributes in which case -it is referred to as a clause. -Clauses can be repeated throughout the file (or included files) to group -attributes under the same clause. +Whitespace is used to separate keywords. +Whitespace indentation is insignificant, but is still recommended for visual +clarity. +Comments start with ``#`` and last to the end of line. +Empty lines are ignored, as is whitespace at the beginning of a line. + +Attribute keywords end with a colon (``:``) and they are either options or +section clauses (group options together). + +The configuration file is logically divided into **sections** where each section +is introduced by a :ref:`section clause`. + +Example +------- + +An example minimal config file is shown below; most settings are the defaults. +Copy this to ``@ub_conf_file@`` and start the server with: + +.. code-block:: text + + $ unbound -c @ub_conf_file@ + +Stop the server with: + +.. code-block:: text + + $ kill `cat @UNBOUND_PIDFILE@` + +The source distribution contains an extensive :file:`example.conf` file with +all the options. + +.. code-block:: text + + # unbound.conf(5) config file for unbound(8). + server: + directory: "@UNBOUND_RUN_DIR@" + username: unbound + # make sure unbound can access entropy from inside the chroot. + # e.g. on linux the use these commands (on BSD, devfs(8) is used): + # mount --bind -n /dev/urandom @UNBOUND_RUN_DIR@/dev/urandom + # and mount --bind -n /dev/log @UNBOUND_RUN_DIR@/dev/log + chroot: "@UNBOUND_CHROOT_DIR@" + # logfile: "@UNBOUND_RUN_DIR@/unbound.log" #uncomment to use logfile. + pidfile: "@UNBOUND_PIDFILE@" + # verbosity: 1 # uncomment and increase to get more logging. + # listen on all interfaces, answer queries from the local subnet. + interface: 0.0.0.0 + interface: ::0 + access-control: 10.0.0.0/8 allow + access-control: 2001:db8::/64 allow + +.. _unbound.conf.clauses: + +Section Clauses +--------------- + +The recognized section clauses are: + + :ref:`server:` + Most of the configuration is found in this section. + + :ref:`remote-control:` + Configuration for the facility used by + :doc:`unbound-control(8)`. + + :ref:`stub-zone:` + Configuration for a zone that redirects to specific authoritative name + servers, e.g. for zones not generally available on the greater + Internet. + + :ref:`forward-zone:` + Configuration for a zone that forwards to specific DNS resolvers. + + :ref:`auth-zone:` + Configuration for local authoritative zones. + + :ref:`view:` + Overriding a small subset of configuration for incoming requests. + Requests are mapped to views with + :ref:`access-control-view` and + :ref:`interface-view`. + + :ref:`python:` + Configuration for the optional ``python`` script module. + + :ref:`dynlib:` + Configuration for the optional ``dynlib`` module that loads dynamic + libraries into Unbound. + + :ref:`dnscrypt:` + Configuration for the optional DNSCrypt feature. + + :ref:`cachedb:` + Configuration for the optional ``cachedb`` module that can interface + with second level caches, currently Redis or Redis-complatible + databases. + + :ref:`dnstap:` + Configuration of the optional dnstap logging feature; a flexible, + structured binary log format for DNS software. + + :ref:`rpz:` + Configuration for Response Policy Zones that allows for DNS filtering. + Requires the ``respip`` module. + +Section clauses can be repeated throughout the file (or included files) to +logically group options in one visually cohesive group. +This may be particularly useful for the ``server:`` clause with its myriad of +options. .. _unbound.conf.include: -Files can be included using the **include:** directive. +Including Files +--------------- + +Files can be included using the ``include:`` directive. It can appear anywhere, it accepts a single file name as argument. Processing continues as if the text from the included file was copied into the config file at that point. @@ -81,17 +181,17 @@ Wildcards can be used to include multipl .. _unbound.conf.include-toplevel: -For a more structural include option, the **include-toplevel:** directive can +For a more structural include option, the ``include-toplevel:`` directive can be used. -This closes whatever clause is currently active (if any) and forces the use of -clauses in the included files and right after this directive. +This closes whatever section clause is currently active (if any) and forces the +use of section clauses in the included files and right after this directive. .. _unbound.conf.server: Server Options -^^^^^^^^^^^^^^ +-------------- -These options are part of the **server:** clause. +These options are part of the ``server:`` section. @@UAHL@unbound.conf@verbosity@@: ** @@ -266,6 +366,10 @@ These options are part of the **server:* Larger numbers need extra resources from the operating system. For performance a very large value is best, use libevent to make this possible. + Should be higher (preferably double) than the value of + :ref:`num-queries-per-thread` to + account for cases where the request list is full and avoid file descriptor + starvation. Default: 4096 (libevent) / 960 (minievent) / 48 (windows) @@ -455,6 +559,9 @@ These options are part of the **server:* The wait time in msec where recursion requests are dropped. This is to stop a large number of replies from accumulating. They receive no reply, the work item continues to recurse. + For UDP the replies are dropped, for stream connections the reply + is not dropped if the stream connection is still open ready to receive + answers. It is nice to be a bit larger than :ref:`serve-expired-client-timeout` if that is enabled. @@ -469,7 +576,7 @@ These options are part of the **server:* This makes a ratelimit per IP address of waiting replies for recursion. It stops very large amounts of queries waiting to be returned to one destination. - The value ``0`` disables wait limits. + The value ``0`` disables all wait limits. Default: 1000 @@ -477,7 +584,11 @@ These options are part of the **server:* @@UAHL@unbound.conf@wait-limit-cookie@@: ** The number of replies that can wait for recursion, for an IP address that sent the query with a valid DNS Cookie. - Since the cookie validates the client address, this limit can be higher. + Since the cookie already validates the client address, this option allows + to override a configured + :ref:`wait-limit` value usually with a higher one + for cookie validated queries. + The value ``0`` disables wait limits for cookie validated queries. Default: 10000 @@ -531,7 +642,7 @@ These options are part of the **server:* @@UAHL@unbound.conf@so-sndbuf@@: ** If not 0, then set the SO_SNDBUF socket option to get more buffer space on - UDP port 53 outgoing queries. + UDP port 53 outgoing responses. This for very busy servers handles spikes in answer traffic, otherwise: .. code-block:: text @@ -552,7 +663,7 @@ These options are part of the **server:* On BSD, Solaris changes are similar to :ref:`so-rcvbuf`. - Default: 1m + Default: 4m @@UAHL@unbound.conf@so-reuseport@@: ** @@ -937,9 +1048,13 @@ These options are part of the **server:* certificate is in the :ref:`tls-service-pem` file and it must also be specified if :ref:`tls-service-key` is specified. - Enabling or disabling this service requires a restart (a reload is not - enough), because the key is read while root permissions are held and before - chroot (if any). + If the key is stored with root permissions or outside of chroot, then + a change or enabling or disabling requires a restart (a reload is not + enough). + But if the key file (and tls-service-pem file) are accessible, then they + are read in on reload, and fast_reload. + The server checks the modification time of the file (and the filename) + to see if the file has changed for reload. The ports enabled implicitly or explicitly via :ref:`tls-port` and :ref:`https-port` do not provide normal DNS TCP @@ -1008,8 +1123,8 @@ These options are part of the **server:* @@UAHL@unbound.conf@tls-system-cert@@: ** - This the same attribute as the - :ref:`tls-win-cert` attribute, under a + This the same as the + :ref:`tls-win-cert` option, under a different name. Because it is not windows specific. @@ -1062,6 +1177,24 @@ These options are part of the **server:* Default: "" +@@UAHL@unbound.conf@tls-use-sni@@: ** + Enable or disable sending the SNI extension on TLS connections. + + .. note:: Changing the value requires a restart. + + Default: yes + + +@@UAHL@unbound.conf@tls-protocols@@: *""* + Specify the allowed TLS protocol versions to use, in no particular order. + Possible values are ``TLSv1.2`` and ``TLSv1.3``. + Enclose list of protocols in quotes (``""``) and put spaces between them. + + .. note:: Changing the value requires a restart. + + Default: "TLSv1.2 TLSv1.3" + + @@UAHL@unbound.conf@pad-responses@@: ** If enabled, TLS serviced queries that contained an EDNS Padding option will cause responses padded to the closest multiple of the size specified in @@ -1091,14 +1224,6 @@ These options are part of the **server:* Default: 128 -@@UAHL@unbound.conf@tls-use-sni@@: ** - Enable or disable sending the SNI extension on TLS connections. - - .. note:: Changing the value requires a reload. - - Default: yes - - @@UAHL@unbound.conf@https-port@@: ** The port number on which to provide DNS-over-HTTPS service. Only interfaces configured with that port number as @number get the HTTPS @@ -1183,6 +1308,9 @@ These options are part of the **server:* Only interfaces configured with that port number as @number get the QUIC service. The interface uses QUIC for the UDP traffic on that port number. + If it is set to 0, the server does not init QUIC code, and QUIC is + disabled. + This is similar to if QUIC is not in use, but then explicitly. Default: 853 @@ -1380,8 +1508,8 @@ These options are part of the **server:* .. note:: The interface needs to be already specified with :ref:`interface` and that any - **access-control\*:** attribute overrides all **interface-\*:** - attributes for targeted clients. + **access-control\*:** option overrides all **interface-\*:** + options for targeted clients. @@UAHL@unbound.conf@interface-tag@@: * <"list of tags">* @@ -1391,8 +1519,8 @@ These options are part of the **server:* .. note:: The interface needs to be already specified with :ref:`interface` and that any - **access-control\*:** attribute overrides all **interface-\*:** - attributes for targeted clients. + **access-control\*:** option overrides all **interface-\*:** + options for targeted clients. @@UAHL@unbound.conf@interface-tag-action@@: * * @@ -1403,8 +1531,8 @@ These options are part of the **server:* .. note:: The interface needs to be already specified with :ref:`interface` and that any - **access-control\*:** attribute overrides all **interface-\*:** - attributes for targeted clients. + **access-control\*:** option overrides all **interface-\*:** + options for targeted clients. @@UAHL@unbound.conf@interface-tag-data@@: * <"resource record string">* @@ -1415,8 +1543,8 @@ These options are part of the **server:* .. note:: The interface needs to be already specified with :ref:`interface` and that any - **access-control\*:** attribute overrides all **interface-\*:** - attributes for targeted clients. + **access-control\*:** option overrides all **interface-\*:** + options for targeted clients. @@UAHL@unbound.conf@interface-view@@: * * @@ -1426,8 +1554,8 @@ These options are part of the **server:* .. note:: The interface needs to be already specified with :ref:`interface` and that any - **access-control\*:** attribute overrides all **interface-\*:** - attributes for targeted clients. + **access-control\*:** option overrides all **interface-\*:** + options for targeted clients. @@UAHL@unbound.conf@chroot@@: ** @@ -1492,7 +1620,7 @@ These options are part of the **server:* [seconds since 1970] unbound[pid:tid]: type: message. If this option is given, the :ref:`use-syslog` - attribute is internally set to ``no``. + option is internally set to ``no``. The logfile is reopened (for append) when the config file is reread, on SIGHUP. @@ -1591,9 +1719,33 @@ These options are part of the **server:* Default: no +@@UAHL@unbound.conf@log-thread-id@@: ** + (Only on Linux and only when threads are available) + Logs the system-wide Linux thread ID instead of Unbound's internal thread + counter. + Can be useful when debugging with system tools. + + Default: no + + @@UAHL@unbound.conf@pidfile@@: ** The process id is written to the file. - Default is to not write a file. + Default is :file:`"@UNBOUND_PIDFILE@"`. + So, + + .. code-block:: text + + kill -HUP `cat @UNBOUND_PIDFILE@` + + triggers a reload, + + .. code-block:: text + + kill -TERM `cat @UNBOUND_PIDFILE@` + + gracefully terminates. + + Default: @UNBOUND_PIDFILE@ @@UAHL@unbound.conf@root-hints@@: ** @@ -1601,8 +1753,8 @@ These options are part of the **server:* Default is nothing, using builtin hints for the IN class. The file has the format of zone files, with root nameserver names and addresses only. - The default may become outdated, when servers change, therefore it is good - practice to use a root hints file. + The default may become outdated, when servers change, and then it is + possible to use a root hints file with specific servers. Default: "" @@ -1688,7 +1840,7 @@ These options are part of the **server:* @@UAHL@unbound.conf@harden-short-bufsize@@: ** Very small EDNS buffer sizes from queries are ignored. - Default: yes (as described in the standard) + Default: yes (per :rfc:`6891`) @@UAHL@unbound.conf@harden-large-queries@@: ** @@ -1862,6 +2014,11 @@ These options are part of the **server:* turned into a network proxy, allowing remote access through the browser to other parts of your private network. + The option removes resource records of types A, AAAA, SVCB and HTTPS + that match the filter. + Inside the SVCB and HTTPS records, the svcparams of type ipv4hint + and ipv6hint are checked for matches. + Some names can be allowed to contain your private addresses, by default all the :ref:`local-data` that you configured is allowed to, and you can specify additional names using @@ -1898,6 +2055,13 @@ These options are part of the **server:* flushing away any poison. A value of 10 million is suggested. + It is useful to add 0.0.0.0/8 and '::' to the + :ref:`do-not-query-address` list. + Otherwise they may be answered, from localhost, and the different source + makes an unwanted reply that unnecessarily ticks up. + The :ref:`do-not-query-localhost` + option includes them, the zero subnets, when it is enabled. + Default: 0 (disabled) @@ -1943,6 +2107,8 @@ These options are part of the **server:* If disabled, Unbound responds with a short list of resource records if some can be found in the cache and makes the upstream type ANY query if there are none. + The option stops the DNSSEC validation from processing, possibly lengthy, + ANY responses, when the option is enabled. Default: no @@ -2066,7 +2232,7 @@ These options are part of the **server:* @@UAHL@unbound.conf@trust-anchor-signaling@@: ** Send :rfc:`8145` key tag query after trust anchor priming. - Default: no + Default: yes @@UAHL@unbound.conf@root-key-sentinel@@: ** @@ -2154,7 +2320,7 @@ These options are part of the **server:* Use this setting to protect the users that rely on this validator for authentication from potentially bad data in the additional section. - Default: yes + Default: no @@UAHL@unbound.conf@val-log-level@@: ** @@ -2250,6 +2416,12 @@ These options are part of the **server:* :ref:`serve-expired-client-timeout` is also used then it is RECOMMENDED to use 30 as the value (:rfc:`8767`). + This value is capped by the original TTL of the record. + This means that records with higher original TTL than this value will use + this value for expired replies. + Records with lower original TTL than this value will use their original TTL + for expired replies. + Default: 30 @@ -2420,6 +2592,9 @@ These options are part of the **server:* :ref:`inform_redirect`, :ref:`always_transparent`, :ref:`block_a`, + :ref:`block_aaaa`, + :ref:`block_a_wdata`, + :ref:`block_aaaa_wdata`, :ref:`always_refuse`, :ref:`always_nxdomain`, :ref:`always_null`, @@ -2506,6 +2681,33 @@ These options are part of the **server:* redirected, so that users with web browsers cannot access sites with suffix example.com. + A ``CNAME`` record can also be provided via local-data: + + .. code-block:: text + + local-zone: "example.com." redirect + local-data: "example.com. CNAME www.example.org." + + In that case, the ``CNAME`` is resolved and the answer + includes resolved target records as well. + The ``CNAME`` record has to be with the zone name of the local-zone, + and there can be one CNAME, not more. + The ``CNAME`` record has to be at the zone apex of the + ``redirect`` zone, then it is used for redirection. + The resolution proceeds with upstream DNS resolution, and + that does not include the lookup in local zones. + So the record is not able to point in local zones, but it + can point to upstream DNS answers. + + ``CNAME`` resolution is supported only in type ``redirect`` + local-zone, and in type ``inform_redirect`` local-zone. + + As different from ``CNAME`` records that are used elsewhere, in + the ``redirect`` type local-zone, it is supported that in the target + of the record a wildcard label gets expanded to the query name, with + for example: ``example.com. CNAME *.foo.net.`` gets expanded + to ``www.example.com. CNAME www.example.com.foo.net.``. + @@UAHL@unbound.conf.local-zone.type@inform@@ The query is answered normally, same as :ref:`transparent`. @@ -2542,9 +2744,32 @@ These options are part of the **server:* Useful in cases when there is a need to explicitly force all apps to use IPv6 protocol and avoid any queries to IPv4. + @@UAHL@unbound.conf.local-zone.type@block_aaaa@@ + Like :ref:`transparent` or + :ref:`block_a`, but + ignores local data and resolves normally all query types excluding AAAA. + For AAAA queries it unconditionally returns NODATA. + Useful in cases when there is a need to explicitly force all apps to + use IPv4 protocol and avoid any queries to IPv6. + + @@UAHL@unbound.conf.local-zone.type@block_a_wdata@@ + Like :ref:`block_a`, but + uses local data if present. + If there is local data that is returned, and it acts like transparent. + For A queries it returns NODATA. + + @@UAHL@unbound.conf.local-zone.type@block_aaaa_wdata@@ + Like :ref:`block_aaaa`, but + uses local data if present. + If there is local data that is returned, and it acts like transparent. + For AAAA queries it returns NODATA. + @@UAHL@unbound.conf.local-zone.type@always_refuse@@ Like :ref:`refuse`, but ignores local data and refuses the query. + This type also blocks queries of type DS for the zone name. + That can break the DNSSEC chain of trust, but it is refused anyway. + The block for type DS assists in more completely blocking the zone. @@UAHL@unbound.conf.local-zone.type@always_nxdomain@@ Like :ref:`static`, but ignores @@ -2752,7 +2977,7 @@ These options are part of the **server:* Configure local data shorthand for a PTR record with the reversed IPv4 or IPv6 address and the host name. For example ``"192.0.2.4 www.example.com"``. - TTL can be inserted like this: ``"2001:DB8::4 7200 www.example.com"`` + TTL can be inserted like this: ``"2001:db8::4 7200 www.example.com"`` @@UAHL@unbound.conf@local-zone-tag@@: * <"list of tags">* @@ -2805,7 +3030,7 @@ These options are part of the **server:* :ref:`response-ip` with action being to redirect as specified by *<"resource record string">*. *<"Resource record string">* is similar to that of - :ref:`access-control-tag-action`, + :ref:`access-control-tag-data`, but it must be of either AAAA, A or CNAME types. If the ** is an IPv6/IPv4 prefix, the record must be AAAA/A respectively, unless it is a CNAME (which can be used for both versions of @@ -2885,6 +3110,18 @@ These options are part of the **server:* overloaded with random names, and keeps unbound from sending traffic to the nameservers for those zones. + It is intended to count the number of queries towards the nameservers + for the zone, and keep those queries limited. + When there is a delegation that needs a lot of lookups, those are + charged in the counters for the destination, the target name, of + the NS records. + Since that is where the nameserver lookup queries are sent to. + That keeps the target, the victim domain, from having many queries. + With the :ref:`ratelimit-factor`, some + genuine queries that are also made to the target zone, can filter + through, and then end up in cache, where the genuine answers have + a chance to collect, keeping up service to some extent. + .. note:: Configured forwarders are excluded from ratelimiting. Default: 0 @@ -3067,6 +3304,10 @@ These options are part of the **server:* Hard limit on the number of times Unbound is allowed to restart a query upon encountering a CNAME record. Results in SERVFAIL when reached. + This applies to chained CNAME records but not sporadic CNAME records that + could be encountered in the lifetime of the query's resolution effort. + When a CNAME chain concludes, the counter keeping track of this limit is + reset. Changing this value needs caution as it can allow long CNAME chains to be accepted, where Unbound needs to verify (resolve) each link individually. @@ -3091,6 +3332,15 @@ These options are part of the **server:* Default: 11 +@@UAHL@unbound.conf@iter-scrub-rrsig@@: ** + Limit on the number of RRSIGs allowed for an RRset, from the iterator + scrubber. + This protects against an overly large number of RRSIGs. + Clips off the remainder of the RRSIG list at that point. + + Default: 8 + + @@UAHL@unbound.conf@max-global-quota@@: ** Limit on the number of upstream queries sent out for an incoming query and its subqueries from recursion. @@ -3108,6 +3358,26 @@ These options are part of the **server:* Default: yes +@@UAHL@unbound.conf@val-validation-attempts@@: ** + Limit on the number of DNSSEC validation attempts for a query. + This protects against too large numbers of cryptographic operations, + like for a deep delegation chain. + This counts attempts to validate RRSIGs. + When it is exceeded, the query fails. + + Default: 32 + + +@@UAHL@unbound.conf@val-hash-attempts@@: ** + Limit on the number of DNSSEC hash attempts for a query. + This protects against too large numbers of cryptographic operations, + like for a deep delegation chain. + This counts DS hash attempts to match DNSKEYs. + When it is exceeded, the query fails. + + Default: 32 + + @@UAHL@unbound.conf@fast-server-permil@@: ** Specify how many times out of 1000 to pick from the set of fastest servers. 0 turns the feature off. @@ -3234,17 +3504,18 @@ These options are part of the **server:* .. _unbound.conf.remote: Remote Control Options -^^^^^^^^^^^^^^^^^^^^^^ +---------------------- + +These options are part of the ``remote-control:`` section and are the +declarations for the remote control facility. -In the **remote-control:** clause are the declarations for the remote control -facility. If this is enabled, the :doc:`unbound-control(8)` utility can be used to send commands to the running Unbound server. -The server uses these clauses to setup TLSv1 security for the connection. -The :doc:`unbound-control(8)` utility also reads the -**remote-control:** section for options. +The server uses these options to setup TLS security for the connection. +The :doc:`unbound-control(8)` utility also reads +this ``remote-control:`` section for options. To setup the correct self-signed certificates use the -*unbound-control-setup(8)* utility. +``unbound-control-setup(8)`` utility. @@UAHL@unbound.conf.remote@control-enable@@: ** @@ -3254,7 +3525,7 @@ To setup the correct self-signed certifi Default: no -@@UAHL@unbound.conf.remote@control-interface@@: ** +@@UAHL@unbound.conf.remote@control-interface@@: ** Give IPv4 or IPv6 addresses or local socket path to listen on for control commands. If an interface name is used instead of an IP address, the list of IP @@ -3336,9 +3607,11 @@ To setup the correct self-signed certifi .. _unbound.conf.stub: Stub Zone Options -^^^^^^^^^^^^^^^^^ +----------------- -There may be multiple **stub-zone:** clauses. +These options are part of the ``stub-zone:`` section. + +There may be multiple ``stub-zone:`` sections. Each with a :ref:`name` and zero or more hostnames or IP addresses. For the stub zone this list of nameservers is used. @@ -3371,9 +3644,10 @@ Consider adding :ref:`server` and for :ref:`local-zone: \ nodefault` for the zone if it is a locally served zone. -The insecure clause stops DNSSEC from invalidating the zone. +The :ref:`domain-insecure` option stops DNSSEC +from invalidating the zone. The :ref:`local-zone: nodefault` (or -:ref:`transparent`) clause makes the +:ref:`transparent`) option makes the (reverse-) zone bypass Unbound's filtering of :rfc:`1918` zones. @@ -3386,6 +3660,19 @@ The :ref:`local-zone: nodefault` instead. + Alternatively, + :ref:`stub-first: yes` can also work + around the circular dependency by trying resolution outside of this + zone. + However this has the caveat that it would allow escaping this zone when + any resolution attempt fails within this zone. + To use a non-default port for DNS communication append ``'@'`` with the port number. @@ -3423,9 +3710,12 @@ The :ref:`local-zone: nodefault* - If enabled, a query is attempted without the stub clause if it fails. + If enabled, a query is attempted without this stub section if it fails. The data could not be retrieved and would have caused SERVFAIL because the - servers are unreachable, instead it is tried without this clause. + servers are unreachable, instead it is tried without this stub section. + This can lead to using less specific configured forward/stub/auth zones if + any, or end up to otherwise normal recursive resolution for that particular + query. Default: no @@ -3457,9 +3747,11 @@ The :ref:`local-zone: nodefault` and zero or more hostnames or IP addresses. For the forward zone this list of nameservers is used to forward the queries @@ -3489,6 +3781,19 @@ cache). Name of server to forward to. Is itself resolved before it is used. + .. caution:: + If the domain (or a subdomain) from this zone is used as the host, it + will unavoidably introduce a circular dependency on retrieving the IP + addresses of the name server. + In that case, it is suggested to use + :ref:`forward-addr` instead. + Alternatively, + :ref:`forward-first: yes` can also + work around the circular dependency by trying resolution outside of + this zone. + However this has the caveat that it would allow escaping this zone when + any resolution attempt fails within this zone. + To use a non-default port for DNS communication append ``'@'`` with the port number. @@ -3523,9 +3828,11 @@ cache). @@UAHL@unbound.conf.forward@forward-first@@: ** - If a forwarded query is met with a SERVFAIL error, and this option is - enabled, Unbound will fall back to normal recursive resolution for this - query as if no query forwarding had been specified. + If a forwarded query is met with a SERVFAIL error and this option is + enabled Unbound will fall back to less specific resolution. + This can lead to using less specific configured forward/stub/auth zones if + any, or end up to otherwise normal recursive resolution for that particular + query. Default: no @@ -3562,12 +3869,14 @@ cache). .. _unbound.conf.auth: Authority Zone Options -^^^^^^^^^^^^^^^^^^^^^^ +---------------------- -Authority zones are configured with **auth-zone:**, and each one must have a +These options are part of the ``auth-zone:`` section. + +Authority zones are configured with ``auth-zone:``, and each one must have a :ref:`name`. -There can be multiple ones, by listing multiple auth-zone clauses, each with a -different name, pertaining to that part of the namespace. +There can be multiple ones, by listing multiple ``auth-zone`` section clauses, +each with a different name, pertaining to that part of the namespace. The authority zone with the name closest to the name looked up is used. Authority zones can be processed on two distinct, non-exclusive, configurable stages. @@ -3598,7 +3907,7 @@ consult the local zone data while resolv In this case, the aforementioned CNAME example will result in a thoroughly resolved answer. -Authority zones can be read from zonefile. +Authority zones can be read from a zonefile. And can be kept updated via AXFR and IXFR. After update the zonefile is rewritten. The update mechanism uses the SOA timer values and performs SOA UDP queries to @@ -3634,9 +3943,11 @@ fallback activates to fetch from the ups :ref:`url` to download the zonefile as a text file from a webserver that would work. - If you specify the hostname, you cannot use the domain from the zonefile, - because it may not have that when retrieving that data, instead use a plain - IP address to avoid a circular dependency on retrieving that IP address. + .. caution:: + If you specify the hostname, you cannot use the domain from the + zonefile, because it may not have that when retrieving that data, + instead use a plain IP address to avoid a circular dependency on + retrieving that IP address. @@UAHL@unbound.conf.auth@master@@: ** @@ -3764,21 +4075,48 @@ fallback activates to fetch from the ups If the file does not exist or is empty, Unbound will attempt to fetch zone data (eg. from the primary servers). + +@@UAHL@unbound.conf.auth@max-transfer-size@@: ** + Number of bytes size of the maximum zone transfer size. + Larger transfers, over AXFR, IXFR and HTTP, are not allowed. + A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes + or gigabytes (1024*1024 bytes in a megabyte). + The value ``0`` disables the feature. + + Only consider for untrusted/misbehaving primaries that could hog resources + and bring down the resolver. + + Default: 0 + + +@@UAHL@unbound.conf.auth@max-transfer-time@@: ** + Maximum time in milliseconds that a zone transfer is allowed to take from + the start. + The value ``0`` disables the feature. + + Only consider for untrusted/misbehaving primaries that could hog resources + and bring down the resolver. + + Default: 0 + + .. _unbound.conf.view: View Options -^^^^^^^^^^^^ +------------ -There may be multiple **view:** clauses. +These options are part of the ``view:`` section. + +There may be multiple ``view:`` sections. Each with a :ref:`name` and zero or more :ref:`local-zone` and -:ref:`local-data` attributes. +:ref:`local-data` options. Views can also contain :ref:`view-first`, :ref:`response-ip`, :ref:`response-ip-data` and -:ref:`local-data-ptr` attributes. +:ref:`local-data-ptr` options. View can be mapped to requests by specifying the view name in an -:ref:`access-control-view` attribute. +:ref:`access-control-view` option. Options from matching views will override global options. Global options will be used if no matching view is found, or when the matching view does not have the option specified. @@ -3788,7 +4126,7 @@ view does not have the option specified. Name of the view. Must be unique. This name is used in the - :ref:`access-control-view` attribute. + :ref:`access-control-view` option. @@UAHL@unbound.conf.view@local-zone@@: * * @@ -3817,6 +4155,20 @@ view does not have the option specified. :ref:`local-data-ptr` elements. +@@UAHL@unbound.conf.view@response-ip@@: * * + This requires use of the ``respip`` module. + + Similar to :ref:`response-ip` but + only applies to this view. + + +@@UAHL@unbound.conf.view@response-ip-data@@: * <"resource record string">* + This requires use of the ``respip`` module. + + Similar to :ref:`response-ip-data` but + only applies to this view. + + @@UAHL@unbound.conf.view@view-first@@: ** If enabled, it attempts to use the global :ref:`local-zone` and @@ -3825,10 +4177,14 @@ view does not have the option specified. Default: no +.. _unbound.conf.python: + Python Module Options -^^^^^^^^^^^^^^^^^^^^^ +--------------------- + +These options are part of the ``python:`` section. -The **python:** clause gives the settings for the *python(1)* script module. +The ``python:`` section gives the settings for the *python(1)* script module. This module acts like the iterator and validator modules do, on queries and answers. To enable the script module it has to be compiled into the daemon, and the word @@ -3851,15 +4207,19 @@ path to the working directory. Repeat this option for every python module instance added to the :ref:`module-config` option. +.. _unbound.conf.dynlib: + Dynamic Library Module Options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +------------------------------ -The **dynlib:** clause gives the settings for the ``dynlib`` module. +These options are part of the ``dynlib:`` section. + +The ``dynlib:`` section gives the settings for the ``dynlib`` module. This module is only a very small wrapper that allows dynamic modules to be loaded on runtime instead of being compiled into the application. To enable the dynlib module it has to be compiled into the daemon, and the word ``dynlib`` has to be put in the -:ref:`module-config` attribute. +:ref:`module-config` option. Multiple instances of dynamic libraries are supported by adding the word ``dynlib`` more than once. @@ -3875,7 +4235,9 @@ directory. :ref:`module-config` option. DNS64 Module Options -^^^^^^^^^^^^^^^^^^^^ +-------------------- + +These options are part of the ``server:`` section. The ``dns64`` module must be configured in the :ref:`module-config` directive, e.g.: @@ -3887,7 +4249,11 @@ The ``dns64`` module must be configured and be compiled into the daemon to be enabled. .. note:: - These settings go in the :ref:`server:` section. + If combining the ``respip`` and ``dns64`` modules, the ``respip`` module + needs to appear before the ``dns64`` module in the + :ref:`module-config` + configuration option so that response IP and/or RPZ feeds can properly + filter responses regardless of DNS64 synthesis. @@UAHL@unbound.conf.dns64@dns64-prefix@@: ** @@ -3913,13 +4279,13 @@ and be compiled into the daemon to be en per line. Applies also to names underneath the name given. -NAT64 Operation -^^^^^^^^^^^^^^^ +NAT64 Options +------------- + +These options are part of the ``server:`` section. NAT64 operation allows using a NAT64 prefix for outbound requests to IPv4-only servers. -It is controlled by two options in the -:ref:`server:` section: @@UAHL@unbound.conf.nat64@do-nat64@@: ** @@ -3934,12 +4300,27 @@ It is controlled by two options in the Use a specific NAT64 prefix to reach IPv4-only servers. The prefix length must be one of /32, /40, /48, /56, /64 or /96. + The NAT64 prefix is allowed by the + :ref:`do-not-query-address` option, + so that there is a clear outcome of addresses in both; the NAT64 prefix + is allowed. + The IPv4 address could be filtered by the + :ref:`do-not-query-address` option, + if needed. + Allowing the NAT64 prefix is useful when using do-not-query-address + for a cluster of machines that is IPv6-only and uses NAT64, but does + not have internet access. + Default: 64:ff9b::/96 (same as :ref:`dns64-prefix`) +.. _unbound.conf.dnscrypt: + DNSCrypt Options -^^^^^^^^^^^^^^^^ +---------------- -The **dnscrypt:** clause gives the settings of the dnscrypt channel. +These options are part of the ``dnscrypt:`` section. + +The ``dnscrypt:`` section gives the settings of the dnscrypt channel. While those options are available, they are only meaningful if Unbound was compiled with ``--enable-dnscrypt``. Currently certificate and secret/public keys cannot be generated by Unbound. @@ -4046,7 +4427,9 @@ https://github.com/cofyc/dnscrypt-wrappe Default: (unconfigured) EDNS Client Subnet Module Options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +--------------------------------- + +These options are part of the ``server:`` section. The ECS module must be configured in the :ref:`module-config` directive, e.g.: @@ -4057,9 +4440,6 @@ The ECS module must be configured in the and be compiled into the daemon to be enabled. -.. note:: - These settings go in the :ref:`server:` section. - If the destination address is allowed in the configuration Unbound will add the EDNS0 option to the query containing the relevant part of the client's address. When an answer contains the ECS option the response and the option are placed @@ -4174,7 +4554,9 @@ This module does not interact with the Default: 100 Opportunistic IPsec Support Module Options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +------------------------------------------ + +These options are part of the ``server:`` section. The IPsec module must be configured in the :ref:`module-config` directive, e.g.: @@ -4185,9 +4567,6 @@ The IPsec module must be configured in t and be compiled into Unbound by using ``--enable-ipsecmod`` to be enabled. -.. note:: - These settings go in the :ref:`server:` section. - When Unbound receives an A/AAAA query that is not in the cache and finds a valid answer, it will withhold returning the answer and instead will generate an IPSECKEY subquery for the same domain name. @@ -4277,8 +4656,12 @@ answer given from cache is still relevan @@UAHL@unbound.conf@ipsecmod-whitelist@@: ** Alternate syntax for :ref:`ipsecmod-allow`. +.. _unbound.conf.cachedb: + Cache DB Module Options -^^^^^^^^^^^^^^^^^^^^^^^ +----------------------- + +These options are part of the ``cachedb:`` section. The Cache DB module must be configured in the :ref:`module-config` directive, e.g.: @@ -4330,7 +4713,7 @@ If connection close or timeout happens t unusable with this backend. It's the administrator's responsibility to make the assumption hold. -The **cachedb:** clause gives custom settings of the cache DB module. +The ``cachedb:`` section gives custom settings of the cache DB module. @@UAHL@unbound.conf.cachedb@backend@@: ** @@ -4378,7 +4761,7 @@ The **cachedb:** clause gives custom set Default: yes -The following **cachedb:** options are specific to the ``redis`` backend. +The following ``cachedb:`` options are specific to the ``redis`` backend. @@UAHL@unbound.conf.cachedb@redis-server-host@@: ** @@ -4537,11 +4920,14 @@ The following **cachedb:** options are s .. _unbound.conf.dnstap: -DNSTAP Logging Options -^^^^^^^^^^^^^^^^^^^^^^ +DNSTAP Options +-------------- -DNSTAP support, when compiled in by using ``--enable-dnstap``, is enabled in -the **dnstap:** section. +These options are part of the ``dnstap:`` section. + +DNSTAP is a flexible, structured binary log format for DNS software. +When compiled in by using ``--enable-dnstap``, it can be enabled in the +``dnstap:`` section. This starts an extra thread (when compiled with threading) that writes the log information to the destination. If Unbound is compiled without threading it does not spawn a thread, but @@ -4691,15 +5077,18 @@ connects per-process to the destination. .. _unbound.conf.rpz: Response Policy Zone Options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +---------------------------- + +These options are part of the ``rpz:`` section. -Response Policy Zones are configured with **rpz:**, and each one must have a -:ref:`name` attribute. -There can be multiple ones, by listing multiple RPZ clauses, each with a -different name. -RPZ clauses are applied in order of configuration and any match from an earlier -RPZ zone will terminate the RPZ lookup. +Response Policy Zones are configured with ``rpz:`` section clauses, and each +one must have a :ref:`name` option. +There can be multiple ones, by listing multiple ``rpz:`` section clauses, each +with a different name. +RPZ sections are applied in order of configuration and any match from an +earlier RPZ zone will terminate the RPZ lookup. Note that a PASSTHRU action is still considered a match. + The respip module needs to be added to the :ref:`module-config`, e.g.: @@ -4707,6 +5096,13 @@ The respip module needs to be added to t module-config: "respip validator iterator" +.. note:: + If combining the ``respip`` and ``dns64`` modules, the ``respip`` module + needs to appear before the ``dns64`` module in the + :ref:`module-config` + configuration option so that response IP and/or RPZ feeds can properly + filter responses regardless of DNS64 synthesis. + QNAME, Response IP Address, nsdname, nsip and clientip triggers are supported. Supported actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp-only and drop. @@ -4758,9 +5154,6 @@ The actions are specified with the recor Other records like AAAA, TXT and other CNAMEs (not rpz-..) can also be used to answer queries with that content. -The RPZ zones can be configured in the config file with these settings in the -**rpz:** block. - @@UAHL@unbound.conf.rpz@name@@: ** Name of the authority zone. @@ -4787,6 +5180,10 @@ The RPZ zones can be configured in the c because it may not have that when retrieving that data, instead use a plain IP address to avoid a circular dependency on retrieving that IP address. + Every number of IXFR transfers, a full AXFR is performed. + This is to consolidate the rpz memory, that would otherwise grow. + The fixed value is after 5 IXFR transfers. + @@UAHL@unbound.conf.rpz@master@@: ** Alternate syntax for :ref:`primary`. @@ -4876,7 +5273,7 @@ The RPZ zones can be configured in the c @@UAHL@unbound.conf.rpz@tags@@: *""* - Limit the policies from this RPZ clause to clients with a matching tag. + Limit the policies from this RPZ section to clients with a matching tag. Tags need to be defined in :ref:`define-tag` and can be assigned to client addresses using @@ -4884,9 +5281,34 @@ The RPZ zones can be configured in the c :ref:`interface-tag`. Enclose list of tags in quotes (``""``) and put spaces between tags. - If no tags are specified the policies from this clause will be applied for + If no tags are specified the policies from this section will be applied for all clients. + +@@UAHL@unbound.conf.rpz@max-transfer-size@@: ** + Number of bytes size of the maximum zone transfer size. + Larger transfers, over AXFR, IXFR and HTTP, are not allowed. + A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes + or gigabytes (1024*1024 bytes in a megabyte). + The value ``0`` disables the feature. + + Only consider for untrusted/misbehaving primaries that could hog resources + and bring down the resolver. + + Default: 0 + + +@@UAHL@unbound.conf.rpz@max-transfer-time@@: ** + Maximum time in milliseconds that a zone transfer is allowed to take from + the start. + The value ``0`` disables the feature. + + Only consider for untrusted/misbehaving primaries that could hog resources + and bring down the resolver. + + Default: 0 + + Memory Control Example ---------------------- @@ -4934,6 +5356,9 @@ Files @ub_conf_file@ Unbound configuration file. + +@UNBOUND_PIDFILE@ + default Unbound pidfile with process ID of the running daemon. unbound.log Unbound log file. Index: usr.sbin/unbound/doc/unbound.rst =================================================================== RCS file: /cvs/src/usr.sbin/unbound/doc/unbound.rst,v diff -u -p -r1.1.1.1 unbound.rst --- usr.sbin/unbound/doc/unbound.rst 26 Sep 2025 07:30:47 -0000 1.1.1.1 +++ usr.sbin/unbound/doc/unbound.rst 21 Sep 2026 16:28:06 -0000 @@ -42,7 +42,7 @@ unbound(8) Synopsis -------- -**unbound** [``-hdpv``] [``-c ``] +**unbound** [``-hdpVv``] [``-c ``] Description ----------- Index: usr.sbin/unbound/edns-subnet/addrtree.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/edns-subnet/addrtree.c,v diff -u -p -r1.4 addrtree.c --- usr.sbin/unbound/edns-subnet/addrtree.c 20 Oct 2022 08:26:14 -0000 1.4 +++ usr.sbin/unbound/edns-subnet/addrtree.c 21 Sep 2026 16:28:06 -0000 @@ -459,6 +459,7 @@ addrtree_insert(struct addrtree *tree, c /* Data is stored in other leafnode */ node = newnode; newnode = node_create(tree, elem, scope, ttl); + if (!newnode) return; if (!edge_create(newnode, addr, sourcemask, node, index^1)) { clean_node(tree, newnode); Index: usr.sbin/unbound/edns-subnet/subnetmod.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/edns-subnet/subnetmod.c,v diff -u -p -r1.19 subnetmod.c --- usr.sbin/unbound/edns-subnet/subnetmod.c 26 Sep 2025 07:32:37 -0000 1.19 +++ usr.sbin/unbound/edns-subnet/subnetmod.c 21 Sep 2026 16:28:06 -0000 @@ -70,6 +70,7 @@ subnet_data_delete(void *d, void *ATTR_U r = (struct subnet_msg_cache_data*)d; addrtree_delete(r->tree4); addrtree_delete(r->tree6); + free(r->reason_fail); free(r); } @@ -84,6 +85,8 @@ msg_cache_sizefunc(void *k, void *d) + q->key.qname_len + lock_get_mem(&q->entry.lock); s += addrtree_size(r->tree4); s += addrtree_size(r->tree6); + if(r->reason_fail) + s += strlen(r->reason_fail)+1; return s; } @@ -162,8 +165,15 @@ int ecs_whitelist_check(struct query_inf if(!ecs_is_whitelisted(sn_env->whitelist, addr, addrlen, qinfo->qname, qinfo->qname_len, qinfo->qclass)) { - verbose(VERB_ALGO, "subnet store subquery global, name and addr have no subnet treatment."); - qstate->no_cache_store = 0; + /* The stub or forward can have no_cache set.*/ + if(iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) { + verbose(VERB_ALGO, "subnet subquery is not stored globally, stuborfwd is no_cache"); + } else { + verbose(VERB_ALGO, "subnet store subquery global, name and addr have no subnet treatment.%s", + (sq->started_no_cache_store? + " But the subnet module was started with no_cache_store for the super query, and that is still applied to this query":"")); + qstate->no_cache_store = sq->started_no_cache_store; + } } } return 1; @@ -193,12 +203,18 @@ int ecs_whitelist_check(struct query_inf if(sq->ecs_server_out.subnet_source_mask == 0) { sq->subnet_sent_no_subnet = 1; sq->subnet_sent = 0; + /* The result should end up in subnet cache, + * not in global cache. */ + qstate->no_cache_store = 1; return 1; } subnet_ecs_opt_list_append(&sq->ecs_server_out, &qstate->edns_opts_back_out, qstate, region); } sq->subnet_sent = 1; + /* Do not store servfails in global cache, since the subnet + * option is sent out. */ + qstate->no_cache_store = 1; } else { /* Outgoing ECS option is set, but we don't want to sent it to @@ -420,6 +436,35 @@ update_cache(struct module_qstate *qstat } /* lru_entry->lock is locked regardless of how we got here, * either from the slabhash_lookup, or above in the new allocated */ + if(!qstate->return_msg && qstate->error_response_cache) { + struct subnet_msg_cache_data *data = + (struct subnet_msg_cache_data*)lru_entry->data; + data->ttl_servfail = *qstate->env->now + NORR_TTL; + data->ede_fail = errinf_to_reason_bogus(qstate); + diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0); + if(qstate->errinf) { + char* str = errinf_to_str_misc(qstate); + free(data->reason_fail); + data->reason_fail = NULL; + if(str) + data->reason_fail = strdup(str); + } + diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0) + - diff_size; + lock_rw_unlock(&lru_entry->lock); + if (need_to_insert) { + slabhash_insert(subnet_msg_cache, h, lru_entry, + lru_entry->data, NULL); + } else { + slabhash_update_space_used(subnet_msg_cache, h, NULL, + diff_size); + } + return; + } + if(!qstate->return_msg) { + lock_rw_unlock(&lru_entry->lock); + return; + } /* Step 2, find the correct tree */ if (!(tree = get_tree(lru_entry->data, edns, sne, qstate->env->cfg))) { lock_rw_unlock(&lru_entry->lock); @@ -463,6 +508,21 @@ update_cache(struct module_qstate *qstat } } +/** See if there is a stored servfail, returns true if so, and sets reply. */ +static int +lookup_check_servfail(struct module_qstate *qstate, + struct subnet_msg_cache_data *data) +{ + struct module_env *env = qstate->env; + if(!data) + return 0; + if(!data->ttl_servfail || TTL_IS_EXPIRED(data->ttl_servfail, *env->now)) + return 0; + qstate->return_rcode = LDNS_RCODE_SERVFAIL; + errinf_ede(qstate, data->reason_fail, data->ede_fail); + return 1; +} + /** Lookup in cache and reply true iff reply is sent. */ static int lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq, int prefetch) @@ -476,6 +536,8 @@ lookup_and_reply(struct module_qstate *q struct addrtree *tree; struct addrnode *node; uint8_t scope; + int must_validate = (!(qstate->query_flags&BIT_CD) + || qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate; memset(&sq->ecs_client_out, 0, sizeof(sq->ecs_client_out)); @@ -489,12 +551,20 @@ lookup_and_reply(struct module_qstate *q tree = (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4)? data->tree4 : data->tree6; if (!tree) { /* qinfo in cache but not for this family */ + if(lookup_check_servfail(qstate, data)) { + lock_rw_unlock(&e->lock); + return 1; + } lock_rw_unlock(&e->lock); return 0; } node = addrtree_find(tree, (addrkey_t*)ecs->subnet_addr, ecs->subnet_source_mask, *env->now); if (!node) { /* plain old cache miss */ + if(lookup_check_servfail(qstate, data)) { + lock_rw_unlock(&e->lock); + return 1; + } lock_rw_unlock(&e->lock); return 0; } @@ -503,12 +573,24 @@ lookup_and_reply(struct module_qstate *q (struct reply_info *)node->elem, qstate->region, *env->now, 0, env->scratch); scope = (uint8_t)node->scope; - lock_rw_unlock(&e->lock); if (!qstate->return_msg) { /* Failed allocation or expired TTL */ + if(lookup_check_servfail(qstate, data)) { + lock_rw_unlock(&e->lock); + return 1; + } + lock_rw_unlock(&e->lock); return 0; } - + lock_rw_unlock(&e->lock); + if(qstate->return_msg->rep->security == sec_status_unchecked + && must_validate) { + /* The message has to be validated first. */ + verbose(VERB_ALGO, "subnet: unchecked cache entry needs " + "validation"); + return 0; + } + if (sq->subnet_downstream) { /* relay to interested client */ sq->ecs_client_out.subnet_scope_mask = scope; sq->ecs_client_out.subnet_addr_fam = ecs->subnet_addr_fam; @@ -563,12 +645,15 @@ generate_sub_request(struct module_qstat qflags |= BIT_RD; if((qstate->query_flags & BIT_CD)!=0) { qflags |= BIT_CD; - valrec = 1; + /* The valrec is left off. Leave out: valrec = 1; + * So that the cache is protected with DNSSEC validation. + * Just like the global cache. DNSSEC validation is performed + * regardless of the setting of the querier's CD flag. */ } fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, valrec, - &subq)) { + if(!(*qstate->env->attach_sub)(qstate, &qinf, qstate->client_info, + qflags, prime, valrec, &subq)) { return 0; } if(subq) { @@ -580,6 +665,7 @@ generate_sub_request(struct module_qstat } subsq = (struct subnet_qstate*)subq->minfo[id]; subsq->is_subquery_nonsubnet = 1; + subsq->started_no_cache_store = sq->started_no_cache_store; /* When the client asks 0.0.0.0/0 and the name is not treated * as subnet, it is to be stored in the global cache. @@ -632,6 +718,12 @@ eval_response(struct module_qstate *qsta /* already an answer and its not a message, but retain * the actual rcode, instead of module_error, so send * module_finished */ + if(qstate->error_response_cache) { + verbose(VERB_ALGO, "subnet: store error response"); + lock_rw_wrlock(&sne->biglock); + update_cache(qstate, id); + lock_rw_unlock(&sne->biglock); + } return module_finished; } @@ -881,9 +973,11 @@ ecs_edns_back_parsed(struct module_qstat sq->max_scope = sq->ecs_server_in.subnet_scope_mask; } else if(sq->subnet_sent_no_subnet) { /* The answer can be stored as scope 0, not in global cache. */ + /* This was already set in ecs_whitelist_check */ qstate->no_cache_store = 1; } else if(sq->subnet_sent) { /* Need another query to be able to store in global cache. */ + /* This was already set in ecs_whitelist_check */ qstate->no_cache_store = 1; } @@ -921,6 +1015,7 @@ subnetmod_operate(struct module_qstate * subnet_ecs_opt_list_append(&sq->ecs_client_out, &qstate->edns_opts_front_out, qstate, qstate->region); + qstate->is_subnet_answer = 1; } sq->wait_subquery_done = 0; qstate->ext_state[id] = module_finished; @@ -1000,6 +1095,7 @@ subnetmod_operate(struct module_qstate * qstate->env->cfg->prefetch)) { sne->num_msg_cache++; lock_rw_unlock(&sne->biglock); + qstate->is_subnet_answer = 1; verbose(VERB_QUERY, "subnetcache: answered from cache"); qstate->ext_state[id] = module_finished; @@ -1071,6 +1167,7 @@ subnetmod_operate(struct module_qstate * subnet_ecs_opt_list_append(&sq->ecs_client_out, &qstate->edns_opts_front_out, qstate, qstate->region); + qstate->is_subnet_answer = 1; if(verbosity >= VERB_ALGO) { subnet_log_print("reply has edns subnet", edns_opt_list_find( Index: usr.sbin/unbound/edns-subnet/subnetmod.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/edns-subnet/subnetmod.h,v diff -u -p -r1.10 subnetmod.h --- usr.sbin/unbound/edns-subnet/subnetmod.h 26 Sep 2025 07:32:37 -0000 1.10 +++ usr.sbin/unbound/edns-subnet/subnetmod.h 21 Sep 2026 16:28:06 -0000 @@ -69,8 +69,18 @@ struct subnet_env { }; struct subnet_msg_cache_data { + /** Tree for nodes with IPv4 subnets. */ struct addrtree* tree4; + /** Tree for nodes with IPv6 subnets. */ struct addrtree* tree6; + /** If servfail is stored, for how long. Abs time in seconds. + * This protects against too much recusion on the item when + * resolution fails, for a couple of seconds. */ + time_t ttl_servfail; + /** servfail ede */ + sldns_ede_code ede_fail; + /** servfail reason */ + char* reason_fail; }; struct subnet_qstate { Index: usr.sbin/unbound/ipsecmod/ipsecmod-whitelist.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/ipsecmod/ipsecmod-whitelist.c,v diff -u -p -r1.1 ipsecmod-whitelist.c --- usr.sbin/unbound/ipsecmod/ipsecmod-whitelist.c 12 Aug 2017 11:22:46 -0000 1.1 +++ usr.sbin/unbound/ipsecmod/ipsecmod-whitelist.c 21 Sep 2026 16:28:06 -0000 @@ -100,6 +100,8 @@ ipsecmod_whitelist_apply_cfg(struct ipse struct config_file* cfg) { ie->whitelist = rbtree_create(name_tree_compare); + if (!ie->whitelist) + return 0; if(!read_whitelist(ie->whitelist, cfg)) return 0; name_tree_init_parents(ie->whitelist); Index: usr.sbin/unbound/ipsecmod/ipsecmod.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/ipsecmod/ipsecmod.c,v diff -u -p -r1.8 ipsecmod.c --- usr.sbin/unbound/ipsecmod/ipsecmod.c 31 Aug 2025 21:41:09 -0000 1.8 +++ usr.sbin/unbound/ipsecmod/ipsecmod.c 21 Sep 2026 16:28:06 -0000 @@ -51,6 +51,9 @@ #include "util/config_file.h" #include "services/cache/dns.h" #include "sldns/wire2str.h" +#ifdef HAVE_SYS_WAIT_H +#include +#endif /** Apply configuration to ipsecmod module 'global' state. */ static int @@ -60,6 +63,11 @@ ipsecmod_apply_cfg(struct ipsecmod_env* log_err("ipsecmod: missing ipsecmod-hook."); return 0; } + if(access(cfg->ipsecmod_hook, X_OK) != 0) { + log_err("ipsecmod: ipsecmod-hook '%s' is not an executable file: %s", + cfg->ipsecmod_hook, strerror(errno)); + return 0; + } if(cfg->ipsecmod_whitelist && !ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg)) return 0; @@ -163,7 +171,7 @@ generate_request(struct module_qstate* q } fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &ask, + if(!(*qstate->env->attach_sub)(qstate, &ask, NULL, (uint16_t)(BIT_RD|flags), 0, 0, &newq)){ log_err("Could not generate request: out of memory"); return 0; @@ -250,27 +258,16 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_env* ATTR_UNUSED(ie)) { size_t slen, tempdata_len, tempstring_len, i; - char str[65535], *s, *tempstring; + char qname_s[LDNS_MAX_DOMAINLEN*5+16], ttl_s[32], a_s[32768], k_s[32768]; + char *s, *tempstring; int w = 0, w_temp, qtype; struct ub_packed_rrset_key* rrset_key; struct packed_rrset_data* rrset_data; uint8_t *tempdata; + pid_t pid; + int st; + char* argv[6]; - /* Check if a shell is available */ - if(system(NULL) == 0) { - log_err("ipsecmod: no shell available for ipsecmod-hook"); - return 0; - } - - /* Zero the buffer. */ - s = str; - slen = sizeof(str); - memset(s, 0, slen); - - /* Copy the hook into the buffer. */ - w += sldns_str_print(&s, &slen, "%s", qstate->env->cfg->ipsecmod_hook); - /* Put space into the buffer. */ - w += sldns_str_print(&s, &slen, " "); /* Copy the qname into the buffer. */ tempstring = sldns_wire2str_dname(qstate->qinfo.qname, qstate->qinfo.qname_len); @@ -283,17 +280,24 @@ call_hook(struct module_qstate* qstate, free(tempstring); return 0; } - w += sldns_str_print(&s, &slen, "\"%s\"", tempstring); + if(strlen(tempstring)+1 > sizeof(qname_s)) { + log_err("ipsecmod: string too long"); + free(tempstring); + return 0; + } + snprintf(qname_s, sizeof(qname_s), "%s", tempstring); free(tempstring); - /* Put space into the buffer. */ - w += sldns_str_print(&s, &slen, " "); + /* Copy the IPSECKEY TTL into the buffer. */ rrset_data = (struct packed_rrset_data*)iq->ipseckey_rrset->entry.data; - w += sldns_str_print(&s, &slen, "\"%ld\"", (long)rrset_data->ttl); - /* Put space into the buffer. */ - w += sldns_str_print(&s, &slen, " "); + snprintf(ttl_s, sizeof(ttl_s), "%ld", (long)rrset_data->ttl); + rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo, qstate->return_msg->rep); + if(!rrset_key) { + log_err("ipsecmod: could not find answer rrset for A/AAAA"); + return 0; + } /* Double check that the records are indeed A/AAAA. * This should never happen as this function is only executed for A/AAAA * queries but make sure we don't pass anything other than A/AAAA to the @@ -304,9 +308,15 @@ call_hook(struct module_qstate* qstate, return 0; } rrset_data = (struct packed_rrset_data*)rrset_key->entry.data; - /* Copy the A/AAAA record(s) into the buffer. Start and end this section - * with a double quote. */ - w += sldns_str_print(&s, &slen, "\""); + if(!rrset_data) { + log_err("ipsecmod: Answer has no data"); + return 0; + } + /* Copy the A/AAAA record(s) into the buffer. */ + w = 0; + s = a_s; + slen = sizeof(a_s); + memset(s, 0, slen); for(i=0; icount; i++) { if(i > 0) { /* Put space into the buffer. */ @@ -322,7 +332,7 @@ call_hook(struct module_qstate* qstate, } else if((size_t)w_temp >= slen) { s = NULL; /* We do not want str to point outside of buffer. */ slen = 0; - log_err("ipsecmod: shell command too long"); + log_err("ipsecmod: command addr argument too long"); return 0; } else { s += w_temp; @@ -330,12 +340,17 @@ call_hook(struct module_qstate* qstate, w += w_temp; } } - w += sldns_str_print(&s, &slen, "\""); - /* Put space into the buffer. */ - w += sldns_str_print(&s, &slen, " "); + if(w >= (int)sizeof(a_s)) { + log_err("ipsecmod: command addr argument too long"); + return 0; + } + /* Copy the IPSECKEY record(s) into the buffer. Start and end this section * with a double quote. */ - w += sldns_str_print(&s, &slen, "\""); + w = 0; + s = k_s; + slen = sizeof(k_s); + memset(s, 0, slen); rrset_data = (struct packed_rrset_data*)iq->ipseckey_rrset->entry.data; for(i=0; icount; i++) { if(i > 0) { @@ -362,15 +377,44 @@ call_hook(struct module_qstate* qstate, w += w_temp; } } - w += sldns_str_print(&s, &slen, "\""); - if(w >= (int)sizeof(str)) { - log_err("ipsecmod: shell command too long"); + if(w >= (int)sizeof(k_s)) { + log_err("ipsecmod: command ipseckey argument too long"); return 0; } - verbose(VERB_ALGO, "ipsecmod: shell command: '%s'", str); + /* ipsecmod-hook should return 0 on success. */ - if(system(str) != 0) + /* exec the ipsecmod-hook */ + argv[0] = qstate->env->cfg->ipsecmod_hook; + argv[1] = qname_s; + argv[2] = ttl_s; + argv[3] = a_s; + argv[4] = k_s; + argv[5] = NULL; + verbose(VERB_ALGO, "ipsecmod: exec %s \"%s\" %s \"%s\" \"%s\"", + argv[0], argv[1], argv[2], argv[3], argv[4]); + if((pid = fork()) < 0) { + log_err("ipsecmod: for exec, can not fork: %s", + strerror(errno)); + return 0; + } + if(pid == 0) { + if(execv(argv[0], argv) < 0) + fprintf(stderr, "ipsecmod: execv: %s\n", + strerror(errno)); + _exit(127); + } + while(1) { + if(waitpid(pid, &st, 0) < 0) { + if(errno == EINTR) + continue; + log_err("ipsecmod: wait_pid: %s", strerror(errno)); + } + break; + } + if(!(WIFEXITED(st) && WEXITSTATUS(st) == 0)) { + /* the command failed */ return 0; + } return 1; } @@ -435,6 +479,12 @@ ipsecmod_handle_query(struct module_qsta * ipsecmod_max_ttl. */ rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo, qstate->return_msg->rep); + if(!rrset_key) { + log_err("ipsecmod: reply-find-answer failed"); + errinf(qstate, "ipsecmod: reply-find-answer failed"); + ipsecmod_error(qstate, id); + return; + } rrset_data = (struct packed_rrset_data*)rrset_key->entry.data; if(rrset_data->ttl > (time_t)qstate->env->cfg->ipsecmod_max_ttl) { /* Update TTL for rrset to fixed value. */ Index: usr.sbin/unbound/ipset/ipset.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/ipset/ipset.c,v diff -u -p -r1.2 ipset.c --- usr.sbin/unbound/ipset/ipset.c 4 Sep 2024 09:36:40 -0000 1.2 +++ usr.sbin/unbound/ipset/ipset.c 21 Sep 2026 16:28:06 -0000 @@ -129,7 +129,7 @@ static int add_to_ipset(filter_dev dev, default: errno = EAFNOSUPPORT; return -1; -} + } addr.pfra_af = af; if (ioctl(dev, DIOCRADDADDRS, &io) == -1) { @@ -143,7 +143,7 @@ static int add_to_ipset(filter_dev dev, struct nlmsghdr *nlh; struct nfgenmsg *nfg; struct nlattr *nested[2]; - static char buffer[BUFF_LEN]; + char buffer[BUFF_LEN]; if (strlen(setname) >= IPSET_MAXNAMELEN) { errno = ENAMETOOLONG; @@ -208,13 +208,6 @@ ipset_add_rrset_data(struct ipset_env *i ret = add_to_ipset((filter_dev)ie->dev, setname, rr_data + 2, af); if (ret < 0) { log_err("ipset: could not add %s into %s", dname, setname); - -#if HAVE_NET_PFVAR_H - /* don't close as we might not be able to open again due to dropped privs */ -#else - mnl_socket_close((filter_dev)ie->dev); - ie->dev = NULL; -#endif break; } } @@ -226,15 +219,15 @@ ipset_check_zones_for_rrset(struct modul struct ub_packed_rrset_key *rrset, const char *qname, int qlen, const char *setname, int af) { - static char dname[BUFF_LEN]; + char dname[LDNS_MAX_DOMAINLEN*4+16]; const char *ds, *qs; int dlen, plen; struct config_strlist *p; struct packed_rrset_data *d; - dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, BUFF_LEN); - if (dlen == 0) { + dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, sizeof(dname)); + if (dlen == 0 || dlen >= (int)sizeof(dname)) { log_err("bad domain name"); return -1; } @@ -276,7 +269,7 @@ static int ipset_update(struct module_en const char *setname; struct ub_packed_rrset_key *rrset; int af; - static char qname[BUFF_LEN]; + char qname[LDNS_MAX_DOMAINLEN*4+16]; int qlen; #ifdef HAVE_NET_PFVAR_H @@ -292,8 +285,8 @@ static int ipset_update(struct module_en #endif qlen = sldns_wire2str_dname_buf(qinfo.qname, qinfo.qname_len, - qname, BUFF_LEN); - if(qlen == 0) { + qname, sizeof(qname)); + if(qlen == 0 || qlen >= (int)sizeof(qname)) { log_err("bad domain name"); return -1; } @@ -351,7 +344,7 @@ void ipset_destartup(struct module_env* if (!env || !env->modinfo[id]) { return; } - ipset_env = (struct ipset_env *)env->modinfo[id]; + ipset_env = (struct ipset_env*)env->modinfo[id]; dev = (filter_dev)ipset_env->dev; if (dev) { @@ -372,6 +365,16 @@ int ipset_init(struct module_env* env, i ipset_env->name_v4 = env->cfg->ipset_name_v4; ipset_env->name_v6 = env->cfg->ipset_name_v6; +#ifndef HAVE_NET_PFVAR_H + if (ipset_env->name_v4 && strlen(ipset_env->name_v4) >= IPSET_MAXNAMELEN) { + log_err("ipset: name-v4 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN); + return 0; + } + if (ipset_env->name_v6 && strlen(ipset_env->name_v6) >= IPSET_MAXNAMELEN) { + log_err("ipset: name-v6 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN); + return 0; + } +#endif ipset_env->v4_enabled = !ipset_env->name_v4 || (strlen(ipset_env->name_v4) == 0) ? 0 : 1; ipset_env->v6_enabled = !ipset_env->name_v6 || (strlen(ipset_env->name_v6) == 0) ? 0 : 1; Index: usr.sbin/unbound/iterator/iter_delegpt.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_delegpt.c,v diff -u -p -r1.9 iter_delegpt.c --- usr.sbin/unbound/iterator/iter_delegpt.c 31 Aug 2025 21:41:09 -0000 1.9 +++ usr.sbin/unbound/iterator/iter_delegpt.c 21 Sep 2026 16:28:07 -0000 @@ -118,10 +118,10 @@ delegpt_add_ns(struct delegpt* dp, struc sizeof(struct delegpt_ns)); if(!ns) return 0; - ns->next = dp->nslist; ns->namelen = len; - dp->nslist = ns; ns->name = regional_alloc_init(region, name, ns->namelen); + if(!ns->name) + return 0; ns->cache_lookup_count = 0; ns->resolved = 0; ns->got4 = 0; @@ -137,7 +137,9 @@ delegpt_add_ns(struct delegpt* dp, struc } else { ns->tls_auth_name = NULL; } - return ns->name != 0; + ns->next = dp->nslist; + dp->nslist = ns; + return 1; } struct delegpt_ns* @@ -223,11 +225,7 @@ delegpt_add_addr(struct delegpt* dp, str sizeof(struct delegpt_addr)); if(!a) return 0; - a->next_target = dp->target_list; - dp->target_list = a; a->next_result = 0; - a->next_usable = dp->usable_list; - dp->usable_list = a; memcpy(&a->addr, addr, addrlen); a->addrlen = addrlen; a->attempts = 0; @@ -241,6 +239,10 @@ delegpt_add_addr(struct delegpt* dp, str } else { a->tls_auth_name = NULL; } + a->next_target = dp->target_list; + dp->target_list = a; + a->next_usable = dp->usable_list; + dp->usable_list = a; return 1; } @@ -398,30 +400,33 @@ delegpt_count_missing_targets(struct del /** find NS rrset in given list */ static struct ub_packed_rrset_key* -find_NS(struct reply_info* rep, size_t from, size_t to) +find_NS(struct reply_info* rep, size_t from, size_t to, uint16_t qclass) { size_t i; for(i=from; irrsets[i]->rk.type) == LDNS_RR_TYPE_NS) + if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS && + ntohs(rep->rrsets[i]->rk.rrset_class) == qclass) return rep->rrsets[i]; } return NULL; } struct delegpt* -delegpt_from_message(struct dns_msg* msg, struct regional* region) +delegpt_from_message(struct dns_msg* msg, struct regional* region, int port) { struct ub_packed_rrset_key* ns_rrset = NULL; struct delegpt* dp; size_t i; /* look for NS records in the authority section... */ ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets, - msg->rep->an_numrrsets+msg->rep->ns_numrrsets); + msg->rep->an_numrrsets+msg->rep->ns_numrrsets, + msg->qinfo.qclass); /* In some cases (even legitimate, perfectly legal cases), the * NS set for the "referral" might be in the answer section. */ if(!ns_rrset) - ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets); + ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets, + msg->qinfo.qclass); /* If there was no NS rrset in the authority section, then this * wasn't a referral message. (It might not actually be a @@ -436,7 +441,7 @@ delegpt_from_message(struct dns_msg* msg dp->has_parent_side_NS = 1; /* created from message */ if(!delegpt_set_name(dp, region, ns_rrset->rk.dname)) return NULL; - if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0)) + if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0, port)) return NULL; /* add glue, A and AAAA in answer and additional section */ @@ -447,10 +452,12 @@ delegpt_from_message(struct dns_msg* msg i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets)) continue; - if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { + if(ntohs(s->rk.type) == LDNS_RR_TYPE_A && + ntohs(s->rk.rrset_class) == msg->qinfo.qclass) { if(!delegpt_add_rrset_A(dp, region, s, 0, NULL)) return NULL; - } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { + } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA && + ntohs(s->rk.rrset_class) == msg->qinfo.qclass) { if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL)) return NULL; } @@ -460,7 +467,7 @@ delegpt_from_message(struct dns_msg* msg int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ns_rrset, uint8_t lame) + struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port) { struct packed_rrset_data* nsdata = (struct packed_rrset_data*) ns_rrset->entry.data; @@ -475,7 +482,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, continue; /* bad format */ /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame, - NULL, UNBOUND_DNS_PORT)) + NULL, (port==-1?UNBOUND_DNS_PORT:port))) return 0; } return 1; @@ -534,7 +541,7 @@ delegpt_add_rrset(struct delegpt* dp, st if(!rrset) return 1; if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) - return delegpt_rrset_add_ns(dp, region, rrset, lame); + return delegpt_rrset_add_ns(dp, region, rrset, lame, -1); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) return delegpt_add_rrset_A(dp, region, rrset, lame, additions); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) @@ -659,8 +666,6 @@ int delegpt_add_ns_mlc(struct delegpt* d free(ns); return 0; } - ns->next = dp->nslist; - dp->nslist = ns; ns->cache_lookup_count = 0; ns->resolved = 0; ns->got4 = 0; @@ -679,6 +684,8 @@ int delegpt_add_ns_mlc(struct delegpt* d } else { ns->tls_auth_name = NULL; } + ns->next = dp->nslist; + dp->nslist = ns; return 1; } @@ -704,11 +711,7 @@ int delegpt_add_addr_mlc(struct delegpt* a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr)); if(!a) return 0; - a->next_target = dp->target_list; - dp->target_list = a; a->next_result = 0; - a->next_usable = dp->usable_list; - dp->usable_list = a; memcpy(&a->addr, addr, addrlen); a->addrlen = addrlen; a->attempts = 0; @@ -724,6 +727,10 @@ int delegpt_add_addr_mlc(struct delegpt* } else { a->tls_auth_name = NULL; } + a->next_target = dp->target_list; + dp->target_list = a; + a->next_usable = dp->usable_list; + dp->usable_list = a; return 1; } Index: usr.sbin/unbound/iterator/iter_delegpt.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_delegpt.h,v diff -u -p -r1.12 iter_delegpt.h --- usr.sbin/unbound/iterator/iter_delegpt.h 26 Sep 2025 07:32:37 -0000 1.12 +++ usr.sbin/unbound/iterator/iter_delegpt.h 21 Sep 2026 16:28:07 -0000 @@ -221,10 +221,11 @@ int delegpt_add_ns(struct delegpt* dp, s * @param regional: where to allocate the info. * @param ns_rrset: NS rrset. * @param lame: rrset is lame, disprefer it. + * @param port: port or -1 if not set. * @return 0 on alloc error. */ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* ns_rrset, uint8_t lame); + struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port); /** * Add target address to the delegation point. @@ -365,11 +366,12 @@ size_t delegpt_count_targets(struct dele * * @param msg: the dns message, referral. * @param regional: where to allocate delegation point. + * @param port: if not -1 specifies a port number. * @return new delegation point or NULL on alloc error, or if the * message was not appropriate. */ struct delegpt* delegpt_from_message(struct dns_msg* msg, - struct regional* regional); + struct regional* regional, int port); /** * Mark negative return in delegation point for specific nameserver. Index: usr.sbin/unbound/iterator/iter_donotq.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_donotq.c,v diff -u -p -r1.1.1.2 iter_donotq.c --- usr.sbin/unbound/iterator/iter_donotq.c 16 Mar 2014 11:38:24 -0000 1.1.1.2 +++ usr.sbin/unbound/iterator/iter_donotq.c 21 Sep 2026 16:28:07 -0000 @@ -132,6 +132,18 @@ donotq_apply_cfg(struct iter_donotq* dq, if(cfg->do_ip6) { if(!donotq_str_cfg(dq, "::1")) return 0; + if(!donotq_str_cfg(dq, "::ffff:127.0.0.0/104")) + return 0; + } + /* RFC 1122 3.2.1.3 / RFC 6890 / RFC 4291 2.5.2: not valid as + * destination; on Linux these route to the local host. */ + if(!donotq_str_cfg(dq, "0.0.0.0/8")) + return 0; + if(cfg->do_ip6) { + if(!donotq_str_cfg(dq, "::")) + return 0; + if(!donotq_str_cfg(dq, "::ffff:0:0/96")) + return 0; } } addr_tree_init_parents(&dq->tree); Index: usr.sbin/unbound/iterator/iter_fwd.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_fwd.c,v diff -u -p -r1.11 iter_fwd.c --- usr.sbin/unbound/iterator/iter_fwd.c 26 Sep 2025 07:32:37 -0000 1.11 +++ usr.sbin/unbound/iterator/iter_fwd.c 21 Sep 2026 16:28:07 -0000 @@ -228,6 +228,11 @@ read_fwds_host(struct config_stub* s, st s->name, p->str); return 0; } + if(dname_subdomain_c(dname, dp->name)) { + log_warn("forward-host '%s' may have a circular " + "dependency on forward-zone '%s'", + p->str, s->name); + } #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) if(tls_auth_name) log_err("no name verification functionality in " Index: usr.sbin/unbound/iterator/iter_hints.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_hints.c,v diff -u -p -r1.19 iter_hints.c --- usr.sbin/unbound/iterator/iter_hints.c 31 Aug 2025 21:41:09 -0000 1.19 +++ usr.sbin/unbound/iterator/iter_hints.c 21 Sep 2026 16:28:07 -0000 @@ -231,6 +231,11 @@ read_stubs_host(struct config_stub* s, s s->name, p->str); return 0; } + if(dname_subdomain_c(dname, dp->name)) { + log_warn("stub-host '%s' may have a circular " + "dependency on stub-zone '%s'", + p->str, s->name); + } #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) if(tls_auth_name) log_err("no name verification functionality in " Index: usr.sbin/unbound/iterator/iter_priv.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_priv.c,v diff -u -p -r1.1.1.5 iter_priv.c --- usr.sbin/unbound/iterator/iter_priv.c 12 Apr 2024 15:44:27 -0000 1.1.1.5 +++ usr.sbin/unbound/iterator/iter_priv.c 21 Sep 2026 16:28:07 -0000 @@ -207,6 +207,168 @@ size_t priv_get_mem(struct iter_priv* pr return sizeof(*priv) + regional_get_mem(priv->region); } +/** + * Check if svcparam ipv4hint contains a private address. + * @param priv: private address lookup struct. + * @param d: the data bytes. + * @param data_len: number of data bytes in the svcparam. + * @param addr: address to return the private address to log in to. + * It has space for IPv4 and IPv6 addresses. + * @param addrlen: length of the addr. Returns the correct size for the addr. + * @return true if the rdata contains a private address. + */ +static int svcb_ipv4hint_contains_priv_addr(struct iter_priv* priv, + uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr, + socklen_t* addrlen) +{ + struct sockaddr_in sa; + *addrlen = (socklen_t)sizeof(struct sockaddr_in); + memset(&sa, 0, sizeof(struct sockaddr_in)); + sa.sin_family = AF_INET; + sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); + + while(data_len >= LDNS_IP4ADDRLEN) { + memmove(&sa.sin_addr, d, LDNS_IP4ADDRLEN); + memmove(addr, &sa, *addrlen); + if(priv_lookup_addr(priv, addr, *addrlen)) + return 1; + + d += LDNS_IP4ADDRLEN; + data_len -= LDNS_IP4ADDRLEN; + } + /* if data_len != 0 here, then the svcparam is malformed. */ + return 0; +} + +/** + * Check if svcparam ipv6hint contains a private address. + * @param priv: private address lookup struct. + * @param d: the data bytes. + * @param data_len: number of data bytes in the svcparam. + * @param addr: address to return the private address to log in to. + * It has space for IPv4 and IPv6 addresses. + * @param addrlen: length of the addr. Returns the correct size for the addr. + * @return true if the rdata contains a private address. + */ +static int svcb_ipv6hint_contains_priv_addr(struct iter_priv* priv, + uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr, + socklen_t* addrlen) +{ + struct sockaddr_in6 sa; + *addrlen = (socklen_t)sizeof(struct sockaddr_in6); + memset(&sa, 0, sizeof(struct sockaddr_in6)); + sa.sin6_family = AF_INET6; + sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); + + while(data_len >= LDNS_IP6ADDRLEN) { + memmove(&sa.sin6_addr, d, LDNS_IP6ADDRLEN); + memmove(addr, &sa, *addrlen); + if(priv_lookup_addr(priv, addr, *addrlen)) + return 1; + + d += LDNS_IP6ADDRLEN; + data_len -= LDNS_IP6ADDRLEN; + } + /* if data_len != 0 here, then the svcparam is malformed. */ + return 0; +} + +/** + * Check if type SVCB and HTTPS rdata contains a private address. + * @param priv: private address lookup struct. + * @param pkt: the packet. + * @param rr: the rr with rdata to check. + * @param addr: address to return the private address to log in to. + * @param addrlen: length of the addr. Initially the total size, on + * return the correct size for the addr. + * @return true if the rdata contains a private address. + */ +static int svcb_rr_contains_priv_addr(struct iter_priv* priv, + sldns_buffer* pkt, struct rr_parse* rr, struct sockaddr_storage* addr, + socklen_t* addrlen) +{ + uint8_t* d = rr->ttl_data; + uint16_t svcparamkey, data_len, rdatalen; + size_t oldpos, dname_len, dname_start, dname_compr_len; + d += 4; /* skip TTL */ + rdatalen = sldns_read_uint16(d); /* read rdata length */ + d += 2; + + if(rdatalen < 2 /* priority */ + 1 /* 1 length target */) + return 0; /* malformed, too short */ + d += 2; /* skip priority */ + rdatalen -= 2; + oldpos = sldns_buffer_position(pkt); + sldns_buffer_set_position(pkt, (size_t)(d - sldns_buffer_begin(pkt))); + dname_start = sldns_buffer_position(pkt); + dname_len = pkt_dname_len(pkt); + dname_compr_len = sldns_buffer_position(pkt) - dname_start; + sldns_buffer_set_position(pkt, oldpos); + if(dname_len == 0) + return 0; /* dname malformed */ + if(dname_compr_len > rdatalen) + return 0; /* malformed */ + d += dname_compr_len; /* skip target */ + rdatalen -= dname_compr_len; + + while(rdatalen >= 4) { + svcparamkey = sldns_read_uint16(d); + data_len = sldns_read_uint16(d+2); + d += 4; + rdatalen -= 4; + + /* verify that we have data_len data */ + if(data_len > rdatalen) { + /* It is malformed, but if there are addresses + * in there it can be rejected. */ + data_len = rdatalen; + } + + if(!data_len) + continue; /* no data for the svcparamkey */ + + if(svcparamkey == SVCB_KEY_IPV4HINT) { + if(svcb_ipv4hint_contains_priv_addr(priv, d, data_len, + addr, addrlen)) + return 1; + } else if(svcparamkey == SVCB_KEY_IPV6HINT) { + if(svcb_ipv6hint_contains_priv_addr(priv, d, data_len, + addr, addrlen)) + return 1; + } + d += data_len; + rdatalen -= data_len; + } + /* If rdatalen != 0 here, then the svcb rdata is malformed. */ + return 0; +} + +/** + * Check if the SVCB and HTTPS rrset is bad. + * @param priv: private address lookup struct. + * @param pkt: the packet. + * @param rrset: the rrset to check. + * @return 1 if the entire rrset has to be removed. 0 if not. + * It removes RRs if they have private addresses, and log that. + */ +static int priv_svcb_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt, + struct rrset_parse* rrset) +{ + struct rr_parse* rr, *prev = NULL; + struct sockaddr_storage addr; + socklen_t addrlen = (socklen_t)sizeof(addr); + for(rr = rrset->rr_first; rr; rr = rr->next) { + if(svcb_rr_contains_priv_addr(priv, pkt, rr, &addr, + &addrlen)) { + if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, addrlen)) + return 1; + continue; + } + prev = rr; + } + return 0; +} + int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt, struct rrset_parse* rrset) { @@ -268,7 +430,11 @@ int priv_rrset_bad(struct iter_priv* pri } prev = rr; } - } + } else if(rrset->type == LDNS_RR_TYPE_SVCB || + rrset->type == LDNS_RR_TYPE_HTTPS) { + if(priv_svcb_rrset_bad(priv, pkt, rrset)) + return 1; + } } return 0; } Index: usr.sbin/unbound/iterator/iter_resptype.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_resptype.c,v diff -u -p -r1.7 iter_resptype.c --- usr.sbin/unbound/iterator/iter_resptype.c 12 Apr 2024 15:45:24 -0000 1.7 +++ usr.sbin/unbound/iterator/iter_resptype.c 21 Sep 2026 16:28:07 -0000 @@ -107,7 +107,7 @@ response_type_from_cache(struct dns_msg* enum response_type response_type_from_server(int rdset, struct dns_msg* msg, struct query_info* request, struct delegpt* dp, - int* empty_nodata_found) + int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral) { uint8_t* origzone = (uint8_t*)"\000"; /* the default */ struct ub_packed_rrset_key* s; @@ -122,6 +122,10 @@ response_type_from_server(int rdset, /* If the message is NXDOMAIN, then it answers the question. */ if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) { + if(msg->rep->an_numrrsets == 0 && + msg->rep->ns_numrrsets == 0 && + msg_lame_empty) + return RESPONSE_TYPE_LAME; /* make sure its not recursive when we don't want it to */ if( (msg->rep->flags&BIT_RA) && !(msg->rep->flags&BIT_AA) && !rdset) @@ -143,6 +147,10 @@ response_type_from_server(int rdset, if(FLAGS_GET_RCODE(msg->rep->flags) != LDNS_RCODE_NOERROR) return RESPONSE_TYPE_THROWAWAY; + if(msg->rep->an_numrrsets == 0 && msg->rep->ns_numrrsets == 0 && + msg_lame_empty) + return RESPONSE_TYPE_LAME; + /* Note: TC bit has already been handled */ if(dp) { @@ -249,13 +257,16 @@ response_type_from_server(int rdset, * which gives ns==zone delegation from cache * without AA bit as well, with nodata nosoa*/ /* real answer must be +AA and SOA RFC(2308), - * so this is wrong, and we SERVFAIL it if - * this is the only possible reply, if it - * is misdeployed the THROWAWAY makes us pick - * the next server from the selection */ - if(msg->rep->an_numrrsets==0 && + * this is picked up as lame_referral by the + * sanitize step, so it can spot if there + * was data in the answer section before + * removal. If such data is then removed we + * do not want to turn that answer into lame. + * But if it was not there, it can be lame. */ + if(msg_lame_referral && + msg->rep->an_numrrsets==0 && !(msg->rep->flags&BIT_AA) && !rdset) - return RESPONSE_TYPE_THROWAWAY; + return RESPONSE_TYPE_LAME; return RESPONSE_TYPE_ANSWER; } /* If we are getting a referral upwards (or to Index: usr.sbin/unbound/iterator/iter_resptype.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_resptype.h,v diff -u -p -r1.1.1.3 iter_resptype.h --- usr.sbin/unbound/iterator/iter_resptype.h 12 Apr 2024 15:44:27 -0000 1.1.1.3 +++ usr.sbin/unbound/iterator/iter_resptype.h 21 Sep 2026 16:28:07 -0000 @@ -120,10 +120,14 @@ enum response_type response_type_from_ca * @param dp: The delegation point that was being queried * when the response was returned. * @param empty_nodata_found: flag to keep track of empty nodata detection. + * @param msg_lame_empty: The scrubber indicates that this empty message + * is lame, before it became empty. + * @param msg_lame_referral: returned true if the reply has a referral before + * scrub. * @return the response type (CNAME or ANSWER). */ enum response_type response_type_from_server(int rdset, struct dns_msg* msg, struct query_info* request, struct delegpt* dp, - int* empty_nodata_found); + int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral); #endif /* ITERATOR_ITER_RESPTYPE_H */ Index: usr.sbin/unbound/iterator/iter_scrub.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_scrub.c,v diff -u -p -r1.20 iter_scrub.c --- usr.sbin/unbound/iterator/iter_scrub.c 27 Nov 2025 14:50:38 -0000 1.20 +++ usr.sbin/unbound/iterator/iter_scrub.c 21 Sep 2026 16:28:07 -0000 @@ -285,6 +285,24 @@ synth_cname_rrset(uint8_t** sname, size_ return NULL; memmove(cn->rr_first->ttl_data, rrset->rr_first->ttl_data, sizeof(uint32_t)); /* RFC6672: synth CNAME TTL == DNAME TTL */ + /* Apply cache TTL policy so DNAME and synthesized CNAME stay equal + * and respect cache-min-ttl/cache-max-ttl (same as rdata_copy path). */ + if(!SERVE_ORIGINAL_TTL) { + uint32_t ttl = sldns_read_uint32(cn->rr_first->ttl_data); + time_t ttl_t = (time_t)ttl; + if(ttl_t < MIN_TTL) ttl_t = MIN_TTL; + if(ttl_t > MAX_TTL) ttl_t = MAX_TTL; + ttl = (uint32_t)ttl_t; + sldns_write_uint32(cn->rr_first->ttl_data, ttl); + /* Do NOT write the clamp back into the packet buffer: + * parse_packet already sized every name from the original + * bytes and rdata_copy re-walks them trusting those sizes; + * mutating packet bytes between the walks breaks that + * invariant (compression pointers can target these TTL + * bytes). The DNAME rrset receives the same clamp at store + * time in rdata_copy, so the DNAME and the synthesized + * CNAME still carry equal TTLs in the cache. */ + } sldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen); memmove(cn->rr_first->ttl_data+6, alias, aliaslen); cn->rr_first->size = sizeof(uint16_t)+aliaslen; @@ -305,6 +323,20 @@ synth_cname_rrset(uint8_t** sname, size_ return cn; } +/** Check if the packet has type NS in answer or authority section */ +static int +pkt_contains_ns(struct msg_parse* msg) +{ + struct rrset_parse* rrset; + for(rrset = msg->rrset_first; rrset; rrset = rrset->rrset_all_next) { + if(rrset->type == LDNS_RR_TYPE_NS && + (rrset->section == LDNS_SECTION_ANSWER || + rrset->section == LDNS_SECTION_AUTHORITY)) + return 1; + } + return 0; +} + /** check if DNAME applies to a name */ static int pkt_strict_sub(sldns_buffer* pkt, uint8_t* sname, uint8_t* dr) @@ -383,6 +415,8 @@ shorten_rrset(sldns_buffer* pkt, struct struct rr_parse* rr = rrset->rr_first, *prev = NULL; if(!rr) return; + if(count < 1) + return; /* cannot leave a still-linked rrset_parse with rr_count == 0 */ for(i=0; inext; @@ -408,6 +442,43 @@ shorten_rrset(sldns_buffer* pkt, struct else rrset->rr_first = NULL; } +/** Shorten RRSIGs list */ +static void +shorten_rrsig(sldns_buffer* pkt, struct rrset_parse* rrset, int count) +{ + /* The too large list of RRSIGs on the RRset is shortened. + * This is so that too large content does not overwhelm the cache. + * The validator does not validate more than a max number of + * RRSIGs as well. */ + int i; + struct rr_parse* rr = rrset->rrsig_first, *prev = NULL; + if(!rr) + return; + for(i=0; inext; + if(!rr) + return; /* The RRSIG list is already short. */ + } + if(verbosity >= VERB_QUERY + && rrset->dname_len <= LDNS_MAX_DOMAINLEN) { + uint8_t buf[LDNS_MAX_DOMAINLEN+1]; + dname_pkt_copy(pkt, buf, rrset->dname); + log_nametypeclass(VERB_QUERY, "normalize: shorten RRSIGs:", + buf, rrset->type, ntohs(rrset->rrset_class)); + } + /* remove further rrsigs */ + rrset->rrsig_last = prev; + rrset->rrsig_count = count; + while(rr) { + rrset->size -= rr->size; + rr = rr->next; + } + if(rrset->rrsig_last) + rrset->rrsig_last->next = NULL; + else rrset->rrsig_first = NULL; +} + /** * This routine normalizes a response. This includes removing "irrelevant" * records from the answer and additional sections and (re)synthesizing @@ -430,6 +501,7 @@ scrub_normalize(sldns_buffer* pkt, struc size_t snamelen = qinfo->qname_len; struct rrset_parse* rrset, *prev, *nsset=NULL; int cname_length = 0; /* number of CNAMEs, or DNAMEs */ + int has_answer = 0; /* if answer section contains nonCNAME,nonDNAME */ if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR && FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN && @@ -445,6 +517,8 @@ scrub_normalize(sldns_buffer* pkt, struc prev = NULL; rrset = msg->rrset_first; while(rrset && rrset->section == LDNS_SECTION_ANSWER) { + if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig) + shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig); if(cname_length > env->cfg->iter_scrub_cname) { /* Too many CNAMEs, or DNAMEs, from the authority * server, scrub down the length to something @@ -455,8 +529,9 @@ scrub_normalize(sldns_buffer* pkt, struc pkt, msg, prev, &rrset); continue; } - if(rrset->type == LDNS_RR_TYPE_DNAME && - pkt_strict_sub(pkt, sname, rrset->dname)) { + if(rrset->type == LDNS_RR_TYPE_DNAME && + pkt_strict_sub(pkt, sname, rrset->dname) && + pkt_sub(pkt, rrset->dname, zonename)) { /* check if next rrset is correct CNAME. else, * synthesize a CNAME */ struct rrset_parse* nx = rrset->rrset_all_next; @@ -468,6 +543,11 @@ scrub_normalize(sldns_buffer* pkt, struc (unsigned)rrset->rr_count); return 0; } + if(has_answer) { + remove_rrset("normalize: removing DNAME redirection after answer:", + pkt, msg, prev, &rrset); + continue; + } if(!synth_cname(sname, snamelen, rrset, alias, &aliaslen, pkt)) { verbose(VERB_ALGO, "synthesized CNAME " @@ -502,8 +582,6 @@ scrub_normalize(sldns_buffer* pkt, struc log_err("out of memory synthesizing CNAME"); return 0; } - /* FIXME: resolve the conflict between synthesized - * CNAME ttls and the cache. */ rrset = nx; continue; @@ -520,12 +598,18 @@ scrub_normalize(sldns_buffer* pkt, struc if(rrset->type == LDNS_RR_TYPE_CNAME) { struct rrset_parse* nx = rrset->rrset_all_next; uint8_t* oldsname = sname; + if(has_answer) { + remove_rrset("normalize: removing redirection after answer:", + pkt, msg, prev, &rrset); + continue; + } cname_length++; /* see if the next one is a DNAME, if so, swap them */ if(nx && nx->section == LDNS_SECTION_ANSWER && nx->type == LDNS_RR_TYPE_DNAME && nx->rr_count == 1 && - pkt_strict_sub(pkt, sname, nx->dname)) { + pkt_strict_sub(pkt, sname, nx->dname) && + pkt_sub(pkt, nx->dname, zonename)) { /* there is a DNAME after this CNAME, it * is in the ANSWER section, and the DNAME * applies to the name we cover */ @@ -571,6 +655,9 @@ scrub_normalize(sldns_buffer* pkt, struc if(rrset->type == LDNS_RR_TYPE_NS && rrset->rr_count > env->cfg->iter_scrub_ns) { shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); + } else if(rrset->type == LDNS_RR_TYPE_DS && + rrset->rr_count > env->cfg->iter_scrub_ns) { + shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); } prev = rrset; rrset = rrset->rrset_all_next; @@ -590,6 +677,9 @@ scrub_normalize(sldns_buffer* pkt, struc if(rrset->type == LDNS_RR_TYPE_NS && rrset->rr_count > env->cfg->iter_scrub_ns) { shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); + } else if(rrset->type == LDNS_RR_TYPE_DS && + rrset->rr_count > env->cfg->iter_scrub_ns) { + shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); } /* Mark the additional names from relevant rrset as OK. */ @@ -597,6 +687,7 @@ scrub_normalize(sldns_buffer* pkt, struc * will be removed by sanitize, so no additional for them */ if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) == 0) mark_additional_rrset(pkt, msg, rrset); + has_answer = 1; prev = rrset; rrset = rrset->rrset_all_next; @@ -620,6 +711,8 @@ scrub_normalize(sldns_buffer* pkt, struc "RRset:", pkt, msg, prev, &rrset); continue; } + if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig) + shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig); /* only one NS set allowed in authority section */ if(rrset->type==LDNS_RR_TYPE_NS) { /* NS set must be pertinent to the query */ @@ -680,6 +773,11 @@ scrub_normalize(sldns_buffer* pkt, struc "RRset:", pkt, msg, prev, &rrset); continue; } + if(ntohs(rrset->rrset_class) != qinfo->qclass) { + remove_rrset("normalize: removing other class " + "RRset:", pkt, msg, prev, &rrset); + continue; + } if(nsset == NULL) { nsset = rrset; } else { @@ -706,6 +804,11 @@ scrub_normalize(sldns_buffer* pkt, struc shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns); } } + } else if(rrset->type==LDNS_RR_TYPE_DS) { + if(rrset->rr_count > env->cfg->iter_scrub_ns) { + shorten_rrset(pkt, rrset, + env->cfg->iter_scrub_ns); + } } /* if this is type DS and we query for type DS we just got * a referral answer for our type DS query, fix packet */ @@ -725,7 +828,13 @@ scrub_normalize(sldns_buffer* pkt, struc rrset->rrset_all_next = NULL; return 1; } - mark_additional_rrset(pkt, msg, rrset); + /* Only mark glue as allowed for type NS in the authority + * section. Other RR types do not get glue for them, it + * is allowed from the answer section, but not authority + * so that a message can not have address records cached + * as a side effect to the query. */ + if(rrset->type==LDNS_RR_TYPE_NS) + mark_additional_rrset(pkt, msg, rrset); prev = rrset; rrset = rrset->rrset_all_next; } @@ -762,6 +871,8 @@ scrub_normalize(sldns_buffer* pkt, struc "RRset:", pkt, msg, prev, &rrset); continue; } + if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig) + shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig); prev = rrset; rrset = rrset->rrset_all_next; } @@ -908,12 +1019,20 @@ scrub_sanitize_rr_length(sldns_buffer* p * @param env: module environment with config and cache. * @param ie: iterator environment with private address data. * @param qstate: for setting errinf for EDE error messages. + * @param pkt_before_NS: if the packet had type NS before scrub. If that + * is removed now, that indicates this may have been lame. + * @param msg_lame_empty: returned true if the empty packet is lame. + * @param msg_lame_referral: returned true if the reply has a referral before + * scrub. + * @param rdset: if RD bit was sent in query sent by unbound. * @return 0 on error. */ static int scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg, struct query_info* qinfo, uint8_t* zonename, struct module_env* env, - struct iter_env* ie, struct module_qstate* qstate) + struct iter_env* ie, struct module_qstate* qstate, + int pkt_before_NS, int* msg_lame_empty, int* msg_lame_referral, + int rdset) { int del_addi = 0; /* if additional-holding rrsets are deleted, we do not trust the normalized additional-A-AAAA any more */ @@ -972,8 +1091,10 @@ scrub_sanitize(sldns_buffer* pkt, struct } /* remove private addresses */ - if( (rrset->type == LDNS_RR_TYPE_A || - rrset->type == LDNS_RR_TYPE_AAAA)) { + if(rrset->type == LDNS_RR_TYPE_A || + rrset->type == LDNS_RR_TYPE_AAAA || + rrset->type == LDNS_RR_TYPE_SVCB || + rrset->type == LDNS_RR_TYPE_HTTPS) { /* do not set servfail since this leads to too * many drops of other people using rfc1918 space */ @@ -1068,6 +1189,21 @@ scrub_sanitize(sldns_buffer* pkt, struct prev = rrset; rrset = rrset->rrset_all_next; } + + /* If the packet is empty now, but it was not before. And there + * was type NS in authority, then that indicates the answer is lame. */ + if(msg->rrset_first == NULL && pkt_before_NS) { + *msg_lame_empty = 1; + verbose(VERB_ALGO, "sanitize: empty message had referral to NS before, marked as lame"); + } else if(pkt_before_NS && msg->an_rrsets==0 && + !(msg->flags&BIT_AA) && !rdset) { + /* If the packet is now a referral, not really a nodata, + * then if it was also with an empty answer section before, + * it is also lame. */ + *msg_lame_referral = 1; + verbose(VERB_ALGO, "sanitize: message has referral not answer, marked as lame"); + } + return 1; } @@ -1075,11 +1211,15 @@ int scrub_message(sldns_buffer* pkt, struct msg_parse* msg, struct query_info* qinfo, uint8_t* zonename, struct regional* region, struct module_env* env, struct module_qstate* qstate, - struct iter_env* ie) + struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral, + int rdset) { + int pkt_before_NS; /* basic sanity checks */ log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS, qinfo->qclass); + *msg_lame_empty = 0; + *msg_lame_referral = 0; if(msg->qdcount > 1) return 0; if( !(msg->flags&BIT_QR) ) @@ -1104,11 +1244,21 @@ scrub_message(sldns_buffer* pkt, struct return 0; } + /* If the packet contains type NS in authority before scrub, + * like a self referral. With the answer section empty, it + * was not AA, the query was not sent with RD, with NS in auth, + * and no SOA in auth. For a negative answer, type SOA is present. + * This detects certain lameness if after has removed that. */ + pkt_before_NS = msg->an_rrsets == 0 && + !(msg->flags&BIT_AA) && !rdset && + pkt_contains_ns(msg) && !soa_in_auth(msg); + /* normalize the response, this cleans up the additional. */ if(!scrub_normalize(pkt, msg, qinfo, region, env, zonename)) return 0; /* delete all out-of-zone information */ - if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate)) + if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate, + pkt_before_NS, msg_lame_empty, msg_lame_referral, rdset)) return 0; return 1; } Index: usr.sbin/unbound/iterator/iter_scrub.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_scrub.h,v diff -u -p -r1.1.1.3 iter_scrub.h --- usr.sbin/unbound/iterator/iter_scrub.h 12 Apr 2024 15:44:27 -0000 1.1.1.3 +++ usr.sbin/unbound/iterator/iter_scrub.h 21 Sep 2026 16:28:07 -0000 @@ -62,11 +62,16 @@ struct module_qstate; * @param env: module environment with config settings and cache. * @param qstate: for setting errinf for EDE error messages. * @param ie: iterator module environment data. + * @param msg_lame_empty: returned true if the empty packet is lame. + * @param msg_lame_referral: returned true if the reply has a referral before + * scrub. + * @param rdset: if RD bit was sent in query sent by unbound. * @return: false if the message is total waste. true if scrubbed with success. */ int scrub_message(struct sldns_buffer* pkt, struct msg_parse* msg, struct query_info* qinfo, uint8_t* zonename, struct regional* regional, struct module_env* env, struct module_qstate* qstate, - struct iter_env* ie); + struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral, + int rdset); #endif /* ITERATOR_ITER_SCRUB_H */ Index: usr.sbin/unbound/iterator/iter_utils.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_utils.c,v diff -u -p -r1.25 iter_utils.c --- usr.sbin/unbound/iterator/iter_utils.c 31 Aug 2025 21:41:09 -0000 1.25 +++ usr.sbin/unbound/iterator/iter_utils.c 21 Sep 2026 16:28:07 -0000 @@ -253,7 +253,9 @@ iter_apply_cfg(struct iter_env* iter_env return 1; } -/** filter out unsuitable targets +/** filter out unsuitable targets. + * Applies NAT64 if needed as well by replacing the IPv4 with the synthesized + * IPv6 address. * @param iter_env: iterator environment with ipv6-support flag. * @param env: module environment with infra cache. * @param name: zone name @@ -306,9 +308,30 @@ iter_filter_unsuitable(struct iter_env* if(a->bogus) return -1; /* address of server is bogus */ if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) { - log_addr(VERB_ALGO, "skip addr on the donotquery list", - &a->addr, a->addrlen); - return -1; /* server is on the donotquery list */ + if(iter_env->nat64.use_nat64 && + addr_is_ip6(&a->addr, a->addrlen) && + a->addrlen == iter_env->nat64.nat64_prefix_addrlen && + addr_in_common(&a->addr, 128, + &iter_env->nat64.nat64_prefix_addr, + iter_env->nat64.nat64_prefix_net, + iter_env->nat64.nat64_prefix_addrlen) == + iter_env->nat64.nat64_prefix_net) { + /* The NAT64 is enabled, and address is IPv6, it is + * in the NAT64 prefix. It is allowed. + * So that in an IPv6-only cluster without internet + * access, that makes the NAT64 translation continue + * to work. The NAT64 prefix is allowed. */ + /* Otherwise, after a timeout, the already NAT64 + * translated address would be treated differently, + * and that causes confusion. */ + log_addr(VERB_ALGO, "the addr is on the donotquery " + "list, but allowed because it is NAT64", + &a->addr, a->addrlen); + } else { + log_addr(VERB_ALGO, "skip addr on the donotquery list", + &a->addr, a->addrlen); + return -1; /* server is on the donotquery list */ + } } if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) { return -1; /* there is no ip6 available */ @@ -317,6 +340,20 @@ iter_filter_unsuitable(struct iter_env* !addr_is_ip6(&a->addr, a->addrlen)) { return -1; /* there is no ip4 available */ } + if(iter_env->nat64.use_nat64 && !addr_is_ip6(&a->addr, a->addrlen)) { + struct sockaddr_storage real_addr; + socklen_t real_addrlen; + addr_to_nat64(&a->addr, &iter_env->nat64.nat64_prefix_addr, + iter_env->nat64.nat64_prefix_addrlen, + iter_env->nat64.nat64_prefix_net, + &real_addr, &real_addrlen); + log_name_addr(VERB_QUERY, "NAT64 apply: from: ", + name, &a->addr, a->addrlen); + log_name_addr(VERB_QUERY, "NAT64 apply: to: ", + name, &real_addr, real_addrlen); + a->addr = real_addr; + a->addrlen = real_addrlen; + } /* check lameness - need zone , class info */ if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen, name, namelen, qtype, &lame, &dnsseclame, &reclame, @@ -1276,7 +1313,8 @@ iter_lookup_parent_NS_from_cache(struct log_rrset_key(VERB_ALGO, "found parent-side NS in cache", akey); dp->has_parent_side_NS = 1; /* and mark the new names as lame */ - if(!delegpt_rrset_add_ns(dp, region, akey, 1)) { + if(!delegpt_rrset_add_ns(dp, region, akey, 1, + deleg_port_number(env))) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -1511,6 +1549,11 @@ iter_stub_fwd_no_cache(struct module_qst struct delegpt *dp; int nolock = 1; + log_assert((retdpname && retdpnamelen + && dpname_storage && dpname_storage_len > 0) || + (retdpname == NULL && retdpnamelen == NULL + && dpname_storage == NULL && dpname_storage_len == 0)); + /* Check for stub. */ /* Lock both forwards and hints for atomic read. */ lock_rw_rdlock(&qstate->env->fwds->lock); @@ -1660,4 +1703,12 @@ iter_make_minimal(struct reply_info* rep rep->ns_numrrsets = 0; rep->ar_numrrsets = 0; rep->rrset_count -= rem; +} + +int +deleg_port_number(struct module_env* env) +{ + if(env->cfg->ssl_upstream) + return env->cfg->ssl_port; + return -1; } Index: usr.sbin/unbound/iterator/iter_utils.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iter_utils.h,v diff -u -p -r1.18 iter_utils.h --- usr.sbin/unbound/iterator/iter_utils.h 31 Aug 2025 21:41:09 -0000 1.18 +++ usr.sbin/unbound/iterator/iter_utils.h 21 Sep 2026 16:28:07 -0000 @@ -84,6 +84,7 @@ int iter_apply_cfg(struct iter_env* iter /** * Select a valid, nice target to send query to. * Sorting and removing unsuitable targets is combined. + * Adds records to the infra cache if not already there. * * @param iter_env: iterator module global state, with ip6 enabled and * do-not-query-addresses. @@ -481,5 +482,8 @@ void limit_nsec_ttl(struct dns_msg* msg) * @param rep: reply to modify. */ void iter_make_minimal(struct reply_info* rep); + +/** See if we need a different port number */ +int deleg_port_number(struct module_env* env); #endif /* ITERATOR_ITER_UTILS_H */ Index: usr.sbin/unbound/iterator/iterator.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iterator.c,v diff -u -p -r1.41 iterator.c --- usr.sbin/unbound/iterator/iterator.c 26 Sep 2025 07:32:37 -0000 1.41 +++ usr.sbin/unbound/iterator/iterator.c 21 Sep 2026 16:28:07 -0000 @@ -81,7 +81,8 @@ int BLACKLIST_PENALTY = (120000*4); /** Timeout when only a single probe query per IP is allowed. */ int PROBE_MAXRTO = PROBE_MAXRTO_DEFAULT; /* in msec */ -static void target_count_increase_nx(struct iter_qstate* iq, int num); +static void target_count_increase_nx(struct module_qstate* qstate, + struct iter_qstate* iq, int num); int iter_init(struct module_env* env, int id) @@ -250,7 +251,7 @@ error_supers(struct module_qstate* qstat if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) && (dpns->got6 == 2 || !ie->supports_ipv6)) { dpns->resolved = 1; /* mark as failed */ - target_count_increase_nx(super_iq, 1); + target_count_increase_nx(super, super_iq, 1); } } if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) { @@ -297,6 +298,7 @@ error_response_cache(struct module_qstat struct reply_info err; struct msgreply_entry* msg; if(qstate->no_cache_store) { + qstate->error_response_cache = 1; return error_response(qstate, id, rcode); } if(qstate->prefetch_leeway > NORR_TTL) { @@ -733,7 +735,7 @@ is_caps_whitelisted(struct iter_env* ie, * created for the parent query. */ static void -target_count_create(struct iter_qstate* iq) +target_count_create(struct module_qstate* qstate, struct iter_qstate* iq) { if(!iq->target_count) { iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int)); @@ -741,33 +743,57 @@ target_count_create(struct iter_qstate* if(iq->target_count) { iq->target_count[TARGET_COUNT_REF] = 1; iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*)); + /* continue global quota from where it was. */ + if(qstate->global_quota_reached > + iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]) + iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] = + qstate->global_quota_reached; } } } static void -target_count_increase(struct iter_qstate* iq, int num) +target_count_store(struct module_qstate* qstate, struct iter_qstate* iq) { - target_count_create(iq); + if(iq->target_count) { + /* By storing the global quota counter, it stays + * there to be picked up if the module is restarted, + * eg. due to a validator retry, and then the + * target_count_create routine picks it up. */ + if(iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] > + qstate->global_quota_reached) + qstate->global_quota_reached = + iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]; + } +} + +static void +target_count_increase(struct module_qstate* qstate, + struct iter_qstate* iq, int num) +{ + target_count_create(qstate, iq); if(iq->target_count) iq->target_count[TARGET_COUNT_QUERIES] += num; iq->dp_target_count++; } static void -target_count_increase_nx(struct iter_qstate* iq, int num) +target_count_increase_nx(struct module_qstate* qstate, + struct iter_qstate* iq, int num) { - target_count_create(iq); + target_count_create(qstate, iq); if(iq->target_count) iq->target_count[TARGET_COUNT_NX] += num; } static void -target_count_increase_global_quota(struct iter_qstate* iq, int num) +target_count_increase_global_quota(struct module_qstate* qstate, + struct iter_qstate* iq, int num) { - target_count_create(iq); + target_count_create(qstate, iq); if(iq->target_count) iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num; + target_count_store(qstate, iq); } /** @@ -829,7 +855,7 @@ generate_sub_request(uint8_t* qname, siz struct mesh_state* sub = NULL; fptr_ok(fptr_whitelist_modenv_add_sub( qstate->env->add_sub)); - if(!(*qstate->env->add_sub)(qstate, &qinf, + if(!(*qstate->env->add_sub)(qstate, &qinf, NULL, qflags, prime, valrec, &subq, &sub)){ return 0; } @@ -838,8 +864,8 @@ generate_sub_request(uint8_t* qname, siz /* attach subquery, lookup existing or make a new one */ fptr_ok(fptr_whitelist_modenv_attach_sub( qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, - valrec, &subq)) { + if(!(*qstate->env->attach_sub)(qstate, &qinf, NULL, qflags, + prime, valrec, &subq)) { return 0; } } @@ -860,7 +886,7 @@ generate_sub_request(uint8_t* qname, siz subiq = (struct iter_qstate*)subq->minfo[id]; memset(subiq, 0, sizeof(*subiq)); subiq->num_target_queries = 0; - target_count_create(iq); + target_count_create(qstate, iq); subiq->target_count = iq->target_count; if(iq->target_count) { iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */ @@ -1485,6 +1511,7 @@ processInitRequest(struct module_qstate* verbose(VERB_ALGO, "no-cache set, going to the network"); qstate->no_cache_lookup = 1; qstate->no_cache_store = 1; + qstate->fwd_stub_no_cache = 1; msg = NULL; } else if(qstate->blacklist) { /* if cache, or anything else, was blacklisted then @@ -1504,7 +1531,7 @@ processInitRequest(struct module_qstate* msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase, qstate->region, qstate->env->rrset_cache, qstate->env->scratch_buffer, - *qstate->env->now, 1/*add SOA*/, NULL, + *qstate->env->now, 1/*add SOA*/, dpname, qstate->env->cfg); } /* item taken from cache does not match our query name, thus @@ -2082,7 +2109,7 @@ query_for_targets(struct module_qstate* ns->resolved = 1; } break; - } + } } /* Send the A request. */ if((ie->supports_ipv4 || ie->nat64.use_nat64) && @@ -2104,7 +2131,7 @@ query_for_targets(struct module_qstate* * a missing target. */ ns->resolved = 1; break; - } + } } /* mark this target as in progress. */ @@ -2229,11 +2256,11 @@ processLastResort(struct module_qstate* errinf(qstate, "could not fetch nameserver"); errinf_dname(qstate, "at zone", iq->dp->name); if(ret == 1) - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += qs; - target_count_increase(iq, qs); + target_count_increase(qstate, iq, qs); if(qs != 0) { qstate->ext_state[id] = module_wait_subquery; return 0; /* and wait for them */ @@ -2289,7 +2316,7 @@ processLastResort(struct module_qstate* * lookups at a time. */ verbose(VERB_ALGO, "try parent-side glue lookup"); iq->num_target_queries += query_count; - target_count_increase(iq, query_count); + target_count_increase(qstate, iq, query_count); qstate->ext_state[id] = module_wait_subquery; return 0; } @@ -2309,7 +2336,7 @@ processLastResort(struct module_qstate* if(query_count != 0) { /* suspend to await results */ verbose(VERB_ALGO, "try parent-side glue lookup"); iq->num_target_queries += query_count; - target_count_increase(iq, query_count); + target_count_increase(qstate, iq, query_count); qstate->ext_state[id] = module_wait_subquery; return 0; } @@ -2365,6 +2392,12 @@ processDSNSFind(struct module_qstate* qs /* go up one (more) step, until we hit the dp, if so, end */ dname_remove_label(&iq->dsns_point, &iq->dsns_point_len); + if(++iq->dsns_count > MAX_DSNS_FIND_COUNT) { + verbose(VERB_QUERY, "DS NS search exceeded %d labels", + MAX_DSNS_FIND_COUNT); + errinf(qstate, "DS NS search exceeded label limit"); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); + } if(query_dname_compare(iq->dsns_point, iq->dp->name) == 0) { /* there was no inbetween nameserver, use the old delegation * point again. And this time, because dsns_point is nonNULL @@ -2436,8 +2469,6 @@ processQueryTargets(struct module_qstate int tf_policy; struct delegpt_addr* target; struct outbound_entry* outq; - struct sockaddr_storage real_addr; - socklen_t real_addrlen; int auth_fallback = 0; uint8_t* qout_orig = NULL; size_t qout_orig_len = 0; @@ -2785,11 +2816,11 @@ processQueryTargets(struct module_qstate if((ret=query_for_targets(qstate, iq, ie, id, -1, &extra))!=0) { errinf(qstate, "could not fetch nameservers for 0x20 fallback"); if(ret == 1) - return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += extra; - target_count_increase(iq, extra); + target_count_increase(qstate, iq, extra); if(iq->num_target_queries > 0) { /* wait to get all targets, we want to try em */ verbose(VERB_ALGO, "wait for all targets for fallback"); @@ -2840,7 +2871,7 @@ processQueryTargets(struct module_qstate /* errors ignored, these targets are not strictly necessary for * this result, we do not have to reply with SERVFAIL */ iq->num_target_queries += extra; - target_count_increase(iq, extra); + target_count_increase(qstate, iq, extra); } /* Add the current set of unused targets to our queue. */ @@ -2937,8 +2968,8 @@ processQueryTargets(struct module_qstate errinf(qstate, "could not fetch nameserver"); errinf_dname(qstate, "at zone", iq->dp->name); if(ret == 1) - return error_response(qstate, id, - LDNS_RCODE_SERVFAIL); + return error_response(qstate, id, + LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -2963,7 +2994,7 @@ processQueryTargets(struct module_qstate LDNS_RCODE_SERVFAIL); } iq->num_target_queries += qs; - target_count_increase(iq, qs); + target_count_increase(qstate, iq, qs); } /* Since a target query might have been made, we * need to check again. */ @@ -3023,7 +3054,7 @@ processQueryTargets(struct module_qstate * this result, we do not have to reply with SERVFAIL */ if(extra > 0) { iq->num_target_queries += extra; - target_count_increase(iq, extra); + target_count_increase(qstate, iq, extra); check_waiting_queries(iq, qstate, id); /* undo qname minimise step because we'll get back here * to do it again */ @@ -3036,7 +3067,7 @@ processQueryTargets(struct module_qstate } } - target_count_increase_global_quota(iq, 1); + target_count_increase_global_quota(qstate, iq, 1); if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] > MAX_GLOBAL_QUOTA) { char s[LDNS_MAX_DOMAINLEN]; @@ -3049,7 +3080,9 @@ processQueryTargets(struct module_qstate /* Do not check ratelimit for forwarding queries or if we already got a * pass. */ - sq_check_ratelimit = (!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok); + sq_check_ratelimit = ((!(iq->chase_flags & BIT_RD) && + !iq->ratelimit_ok)); + iq->ratelimit_incremented = 0; /* We have a valid target. */ if(verbosity >= VERB_QUERY) { log_query_info(VERB_QUERY, "sending query:", &iq->qinfo_out); @@ -3060,17 +3093,6 @@ processQueryTargets(struct module_qstate iq->dnssec_lame_query?" but lame_query anyway": ""); } - real_addr = target->addr; - real_addrlen = target->addrlen; - - if(ie->nat64.use_nat64 && target->addr.ss_family == AF_INET) { - addr_to_nat64(&target->addr, &ie->nat64.nat64_prefix_addr, - ie->nat64.nat64_prefix_addrlen, ie->nat64.nat64_prefix_net, - &real_addr, &real_addrlen); - log_name_addr(VERB_QUERY, "applied NAT64:", - iq->dp->name, &real_addr, real_addrlen); - } - fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query)); outq = (*qstate->env->send_query)(&iq->qinfo_out, iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), @@ -3082,11 +3104,12 @@ processQueryTargets(struct module_qstate !qstate->blacklist&&(!iter_qname_indicates_dnssec(qstate->env, &iq->qinfo_out)||target->attempts==1)?0:BIT_CD), iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted( - ie, iq), sq_check_ratelimit, &real_addr, real_addrlen, + ie, iq), sq_check_ratelimit, &target->addr, target->addrlen, iq->dp->name, iq->dp->namelen, (iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream), (iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream), - target->tls_auth_name, qstate, &sq_was_ratelimited); + target->tls_auth_name, qstate, &sq_was_ratelimited, + &iq->ratelimit_incremented); if(!outq) { if(sq_was_ratelimited) { lock_basic_lock(&ie->queries_ratelimit_lock); @@ -3099,7 +3122,7 @@ processQueryTargets(struct module_qstate return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } log_addr(VERB_QUERY, "error sending query to auth server", - &real_addr, real_addrlen); + &target->addr, target->addrlen); if(qstate->env->cfg->qname_minimisation) iq->minimisation_state = SKIP_MINIMISE_STATE; return next_state(iq, QUERYTARGETS_STATE); @@ -3124,7 +3147,6 @@ find_NS(struct reply_info* rep, size_t f return NULL; } - /** * Process the query response. All queries end up at this state first. This * process generally consists of analyzing the response and routing the @@ -3166,7 +3188,8 @@ processQueryResponse(struct module_qstat orig_empty_nodata_found = iq->empty_nodata_found; type = response_type_from_server( (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd), - iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found); + iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found, + iq->msg_lame_empty, iq->msg_lame_referral); iq->chase_to_rd = 0; /* remove TC flag, if this is erroneously set by TCP upstream */ iq->response->rep->flags &= ~BIT_TC; @@ -3236,8 +3259,19 @@ processQueryResponse(struct module_qstat } else iter_scrub_ds(iq->response, NULL, NULL); if(type == RESPONSE_TYPE_THROWAWAY && FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) { - /* YXDOMAIN is a permanent error, no need to retry */ - type = RESPONSE_TYPE_ANSWER; + /* YXDOMAIN is a permanent error for DNAME expansion overflow + * (RFC 6672 Section 2.2). Only accept if the response + * contains a DNAME record in the answer section; otherwise + * treat as invalid, to make sure the authoritative answer + * make sense. */ + size_t i; + for(i=0; iresponse->rep->an_numrrsets; i++) { + if(ntohs(iq->response->rep->rrsets[i]->rk.type) + == LDNS_RR_TYPE_DNAME) { + type = RESPONSE_TYPE_ANSWER; + break; + } + } } if(type == RESPONSE_TYPE_CNAME) origtypecname = 1; @@ -3433,7 +3467,14 @@ processQueryResponse(struct module_qstat iq->deleg_msg = iq->response; /* Keep current delegation point for label comparison */ old_dp = iq->dp; - iq->dp = delegpt_from_message(iq->response, qstate->region); + /* A referral reply is "pleasant", refund the + * parent dp's rate charge before descending to the child. */ + if(iq->ratelimit_incremented) + infra_ratelimit_dec(qstate->env->infra_cache, + old_dp->name, old_dp->namelen, + *qstate->env->now); + iq->dp = delegpt_from_message(iq->response, qstate->region, + deleg_port_number(qstate->env)); if (qstate->env->cfg->qname_minimisation) iq->minimisation_state = INIT_MINIMISE_STATE; if(!iq->dp) { @@ -3616,7 +3657,7 @@ processQueryResponse(struct module_qstat return next_state(iq, INIT_REQUEST_STATE); } else if(type == RESPONSE_TYPE_LAME) { /* Cache the LAMEness. */ - verbose(VERB_DETAIL, "query response was %sLAME", + verbose(VERB_DETAIL, "query response was categorized as %sLAME", dnsseclame?"DNSSEC ":""); if(!dname_subdomain_c(iq->qchase.qname, iq->dp->name)) { log_err("mark lame: mismatch in qname and dpname"); @@ -3655,7 +3696,7 @@ processQueryResponse(struct module_qstat * In this case, the event is just sent directly back to * the QUERYTARGETS_STATE without resetting anything, * because, clearly, the next target must be tried. */ - verbose(VERB_DETAIL, "query response was THROWAWAY"); + verbose(VERB_DETAIL, "query response was categorized as THROWAWAY"); } else { log_warn("A query response came back with an unknown type: %d", (int)type); @@ -3710,7 +3751,8 @@ prime_supers(struct module_qstate* qstat log_assert(qstate->is_priming || foriq->wait_priming_stub); log_assert(qstate->return_rcode == LDNS_RCODE_NOERROR); /* Convert our response to a delegation point */ - dp = delegpt_from_message(qstate->return_msg, forq->region); + dp = delegpt_from_message(qstate->return_msg, forq->region, + deleg_port_number(forq->env)); if(!dp) { /* if there is no convertible delegation point, then * the ANSWER type was (presumably) a negative answer. */ @@ -3761,7 +3803,8 @@ processPrimeResponse(struct module_qstat iq->response->rep->flags &= ~(BIT_RD|BIT_RA); /* ignore rec-lame */ type = response_type_from_server( (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd), - iq->response, &iq->qchase, iq->dp, NULL); + iq->response, &iq->qchase, iq->dp, NULL, iq->msg_lame_empty, + iq->msg_lame_referral); if(type == RESPONSE_TYPE_ANSWER) { qstate->return_rcode = LDNS_RCODE_NOERROR; qstate->return_msg = iq->response; @@ -3880,7 +3923,7 @@ processTargetResponse(struct module_qsta /* no new addresses, increase the nxns counter, like * this could be a list of wildcards with no new * addresses */ - target_count_increase_nx(foriq, 1); + target_count_increase_nx(qstate, foriq, 1); } verbose(VERB_ALGO, "added target response"); delegpt_log(VERB_ALGO, foriq->dp); @@ -3892,7 +3935,7 @@ processTargetResponse(struct module_qsta dpns->resolved = 1; /* fail the target */ /* do not count cached answers */ if(qstate->reply_origin && qstate->reply_origin->len != 0) { - target_count_increase_nx(foriq, 1); + target_count_increase_nx(qstate, foriq, 1); } } } @@ -3925,7 +3968,8 @@ processDSNSResponse(struct module_qstate /* else, store as DP and continue at querytargets */ foriq->state = QUERYTARGETS_STATE; - foriq->dp = delegpt_from_message(qstate->return_msg, forq->region); + foriq->dp = delegpt_from_message(qstate->return_msg, forq->region, + deleg_port_number(forq->env)); if(!foriq->dp) { log_err("out of memory in dsns dp alloc"); errinf(qstate, "malloc failure, in DS search"); @@ -3974,7 +4018,7 @@ processClassResponse(struct module_qstat /* if there are records, copy RCODE */ /* lower sec_state if this message is lower */ if(from->rep->rrset_count != 0) { - size_t n = from->rep->rrset_count+to->rep->rrset_count; + size_t i, n = from->rep->rrset_count+to->rep->rrset_count; struct ub_packed_rrset_key** dest, **d; /* copy appropriate rcode */ to->rep->flags = from->rep->flags; @@ -3996,24 +4040,49 @@ processClassResponse(struct module_qstat memcpy(dest, to->rep->rrsets, to->rep->an_numrrsets * sizeof(dest[0])); dest += to->rep->an_numrrsets; - memcpy(dest, from->rep->rrsets, from->rep->an_numrrsets - * sizeof(dest[0])); + for(i=0; irep->an_numrrsets; i++) { + dest[i] = packed_rrset_copy_region( + from->rep->rrsets[i], forq->region, 0); + if(!dest[i]) { + log_err("malloc failed in collect ANY"); + foriq->state = FINISHED_STATE; + return; + } + } dest += from->rep->an_numrrsets; /* copy NS */ memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets, to->rep->ns_numrrsets * sizeof(dest[0])); dest += to->rep->ns_numrrsets; - memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets, - from->rep->ns_numrrsets * sizeof(dest[0])); + for(i=0; irep->ns_numrrsets; i++) { + dest[i] = packed_rrset_copy_region( + from->rep->rrsets[ + from->rep->an_numrrsets+i], + forq->region, 0); + if(!dest[i]) { + log_err("malloc failed in collect ANY"); + foriq->state = FINISHED_STATE; + return; + } + } dest += from->rep->ns_numrrsets; /* copy AR */ memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets+ to->rep->ns_numrrsets, to->rep->ar_numrrsets * sizeof(dest[0])); dest += to->rep->ar_numrrsets; - memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets+ - from->rep->ns_numrrsets, - from->rep->ar_numrrsets * sizeof(dest[0])); + for(i=0; irep->ar_numrrsets; i++) { + dest[i] = packed_rrset_copy_region( + from->rep->rrsets[ + from->rep->an_numrrsets+ + from->rep->ns_numrrsets+i], + forq->region, 0); + if(!dest[i]) { + log_err("malloc failed in collect ANY"); + foriq->state = FINISHED_STATE; + return; + } + } /* update counts */ to->rep->rrsets = d; to->rep->an_numrrsets += from->rep->an_numrrsets; @@ -4117,6 +4186,7 @@ processFinished(struct module_qstate* qs iter_store_parentside_neg(qstate->env, &qstate->qinfo, iq->deleg_msg?iq->deleg_msg->rep: (iq->response?iq->response->rep:NULL)); + target_count_store(qstate, iq); if(!iq->response) { verbose(VERB_ALGO, "No response is set, servfail"); errinf(qstate, "(no response found at query finish)"); @@ -4370,7 +4440,10 @@ process_response(struct module_qstate* q /* normalize and sanitize: easy to delete items from linked lists */ if(!scrub_message(pkt, prs, &iq->qinfo_out, iq->dp->name, - qstate->env->scratch, qstate->env, qstate, ie)) { + qstate->env->scratch, qstate->env, qstate, ie, + &iq->msg_lame_empty, &iq->msg_lame_referral, + (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd) + )) { /* if 0x20 enabled, start fallback, but we have no message */ if(event == module_event_capsfail && !iq->caps_fallback) { iq->caps_fallback = 1; @@ -4532,6 +4605,7 @@ iter_clear(struct module_qstate* qstate, iq = (struct iter_qstate*)qstate->minfo[id]; if(iq) { outbound_list_clear(&iq->outlist); + target_count_store(qstate, iq); if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) { free(iq->target_count); if(*iq->nxns_dp) free(*iq->nxns_dp); Index: usr.sbin/unbound/iterator/iterator.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/iterator/iterator.h,v diff -u -p -r1.24 iterator.h --- usr.sbin/unbound/iterator/iterator.h 31 Aug 2025 21:41:09 -0000 1.24 +++ usr.sbin/unbound/iterator/iterator.h 21 Sep 2026 16:28:07 -0000 @@ -104,6 +104,11 @@ extern int BLACKLIST_PENALTY; #define RTT_BAND 400 /** Number of retries for empty nodata packets before it is accepted. */ #define EMPTY_NODATA_RETRY_COUNT 2 +/** max label-strip iterations in DSNS_FIND_STATE (RFC 4035 4.2 parent-NS + * search) before giving up; bounds upstream NS sends per client DS. + * Means the max number of labels in grandchild to the grandparent zone that + * are co-hosted. */ +#define MAX_DSNS_FIND_COUNT 20 /** * Iterator global state for nat64. @@ -375,6 +380,10 @@ struct iter_qstate { /** if true, already tested for ratelimiting and passed the test */ int ratelimit_ok; + /** If the last query, that may be a referral, incremented the + * ratelimit counter. */ + int ratelimit_incremented; + /** * The query must store NS records from referrals as parentside RRs * Enabled once it hits resolution problems, to throttle retries. @@ -399,6 +408,8 @@ struct iter_qstate { uint8_t* dsns_point; /** length of the dname in dsns_point */ size_t dsns_point_len; + /** number of label-strip iterations performed in DSNS_FIND_STATE */ + int dsns_count; /** * expected dnssec information for this iteration step. @@ -433,6 +444,13 @@ struct iter_qstate { * This flag detects that a completely empty nodata was received, * already so that it is accepted later. */ int empty_nodata_found; + + /** Store if the answer was empty, but lame, before it became empty.*/ + int msg_lame_empty; + + /** Store if the answer was a referral, to self, before scrub. So the + * it is not some sort of answer. */ + int msg_lame_referral; /** list of pending queries to authoritative servers. */ struct outbound_list outlist; Index: usr.sbin/unbound/libunbound/context.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/libunbound/context.h,v diff -u -p -r1.9 context.h --- usr.sbin/unbound/libunbound/context.h 5 Sep 2023 11:12:10 -0000 1.9 +++ usr.sbin/unbound/libunbound/context.h 21 Sep 2026 16:28:07 -0000 @@ -167,6 +167,8 @@ struct ctx_query { ub_event_callback_type cb_event; /** for async query, the callback user arg */ void* cb_arg; + /** for async query the unique info */ + void* unique_info; /** answer message, result from resolver lookup. */ uint8_t* msg; Index: usr.sbin/unbound/libunbound/libunbound.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/libunbound/libunbound.c,v diff -u -p -r1.22 libunbound.c --- usr.sbin/unbound/libunbound/libunbound.c 4 Sep 2024 09:36:40 -0000 1.22 +++ usr.sbin/unbound/libunbound/libunbound.c 21 Sep 2026 16:28:07 -0000 @@ -571,6 +571,8 @@ ub_ctx_async(struct ub_ctx* ctx, int dot int ub_poll(struct ub_ctx* ctx) { + if(!ctx || ctx->event_base) + return UB_INITFAIL; /* no need to hold lock while testing for readability. */ return tube_poll(ctx->rr_pipe); } @@ -578,6 +580,8 @@ ub_poll(struct ub_ctx* ctx) int ub_fd(struct ub_ctx* ctx) { + if(!ctx || ctx->event_base) + return -1; return tube_read_fd(ctx->rr_pipe); } @@ -672,6 +676,8 @@ ub_process(struct ub_ctx* ctx) int r; uint8_t* msg; uint32_t len; + if(!ctx || ctx->event_base) + return UB_INITFAIL; while(1) { msg = NULL; lock_basic_lock(&ctx->rrpipe_lock); @@ -700,6 +706,8 @@ ub_wait(struct ub_ctx* ctx) int r; uint8_t* msg; uint32_t len; + if(!ctx || ctx->event_base) + return UB_INITFAIL; /* this is basically the same loop as _process(), but with changes. * holds the rrpipe lock and waits with tube_wait */ while(1) { @@ -837,6 +845,8 @@ ub_resolve_async(struct ub_ctx* ctx, con struct ctx_query* q; uint8_t* msg = NULL; uint32_t len = 0; + if(!ctx || ctx->event_base) + return UB_INITFAIL; if(async_id) *async_id = 0; @@ -1467,8 +1477,15 @@ ub_ctx_set_event(struct ub_ctx* ctx, str lock_basic_lock(&ctx->cfglock); /* destroy the current worker - safe to pass in NULL */ + + /* Unlock the cfglock during libworker_delete_event, since it + * calls context_release_alloc, that wants to lock cfglock again. + * Since the event base is used from one thread, the one that + * called this function, it is safe to do so. */ + lock_basic_unlock(&ctx->cfglock); libworker_delete_event(ctx->event_worker); ctx->event_worker = NULL; + lock_basic_lock(&ctx->cfglock); new_base = ub_libevent_event_base(base); if (new_base) ctx->event_base = new_base; Index: usr.sbin/unbound/libunbound/libworker.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/libunbound/libworker.c,v diff -u -p -r1.36 libworker.c --- usr.sbin/unbound/libunbound/libworker.c 26 Sep 2025 07:32:37 -0000 1.36 +++ usr.sbin/unbound/libunbound/libworker.c 21 Sep 2026 16:28:07 -0000 @@ -105,6 +105,7 @@ libworker_delete_env(struct libworker* w SSL_CTX_free(w->sslctx); #endif outside_network_delete(w->back); + shared_ports_delete(w->shared_ports); } /** delete libworker struct */ @@ -219,17 +220,25 @@ libworker_setup(struct ub_ctx* ctx, int libworker_delete(w); return NULL; } + if(!(w->shared_ports = shared_ports_create(cfg->out_ifs, + cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, ports, numports))) { + if(!w->is_bg || w->is_bg_thread) { + lock_basic_unlock(&ctx->cfglock); + } + libworker_delete(w); + return NULL; + } w->back = outside_network_create(w->base, cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, - ports, numports, cfg->unwanted_threshold, + cfg->unwanted_threshold, cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w, cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx, cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect, cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout, - cfg->tcp_auth_query_timeout); + cfg->tcp_auth_query_timeout, w->shared_ports); w->env->outnet = w->back; if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); @@ -642,7 +651,8 @@ int libworker_fg(struct ub_ctx* ctx, str } /* process new query */ if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, - w->back->udp_buff, qid, libworker_fg_done_cb, q, 0)) { + w->back->udp_buff, qid, libworker_fg_done_cb, q, 0, + &q->unique_info)) { free(qinfo.qname); return UB_NOMEM; } @@ -723,7 +733,8 @@ int libworker_attach_mesh(struct ub_ctx* if(async_id) *async_id = q->querynum; if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, - w->back->udp_buff, qid, libworker_event_done_cb, q, 0)) { + w->back->udp_buff, qid, libworker_event_done_cb, q, 0, + &q->unique_info)) { free(qinfo.qname); return UB_NOMEM; } @@ -861,7 +872,8 @@ handle_newq(struct libworker* w, uint8_t q->w = w; /* process new query */ if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, - w->back->udp_buff, qid, libworker_bg_done_cb, q, 0)) { + w->back->udp_buff, qid, libworker_bg_done_cb, q, 0, + &q->unique_info)) { add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0); } free(qinfo.qname); @@ -879,7 +891,8 @@ struct outbound_entry* libworker_send_qu int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, - struct module_qstate* q, int* was_ratelimited) + struct module_qstate* q, int* was_ratelimited, + int* ratelimit_incremented) { struct libworker* w = (struct libworker*)q->env->worker; struct outbound_entry* e = (struct outbound_entry*)regional_alloc( @@ -891,7 +904,7 @@ struct outbound_entry* libworker_send_qu want_dnssec, nocaps, check_ratelimit, tcp_upstream, ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q, libworker_handle_service_reply, e, w->back->udp_buff, q->env, - was_ratelimited); + was_ratelimited, ratelimit_incremented); if(!e->qsent) { return NULL; } @@ -976,7 +989,8 @@ struct outbound_entry* worker_send_query struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), - struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) + struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited), + int* ATTR_UNUSED(ratelimit_incremented)) { log_assert(0); return 0; Index: usr.sbin/unbound/libunbound/libworker.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/libunbound/libworker.h,v diff -u -p -r1.4 libworker.h --- usr.sbin/unbound/libunbound/libworker.h 17 Sep 2018 09:46:12 -0000 1.4 +++ usr.sbin/unbound/libunbound/libworker.h 21 Sep 2026 16:28:07 -0000 @@ -60,6 +60,7 @@ struct tube; struct sldns_buffer; struct ub_event_base; struct query_info; +struct shared_ports; /** * The library-worker status structure @@ -84,6 +85,8 @@ struct libworker { struct comm_base* base; /** the backside outside network interface to the auth servers */ struct outside_network* back; + /** shared ports structure */ + struct shared_ports* shared_ports; /** random() table for this worker. */ struct ub_randstate* rndstate; /** sslcontext for SSL wrapped DNS over TCP queries */ Index: usr.sbin/unbound/libunbound/unbound.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/libunbound/unbound.h,v diff -u -p -r1.18 unbound.h --- usr.sbin/unbound/libunbound/unbound.h 26 Sep 2025 07:32:37 -0000 1.18 +++ usr.sbin/unbound/libunbound/unbound.h 21 Sep 2026 16:28:07 -0000 @@ -853,6 +853,8 @@ struct ub_server_stats { long long qquic; /** number of queries removed due to discard-timeout */ long long num_queries_discard_timeout; + /** number of queries removed due to replyaddr limit */ + long long num_queries_replyaddr_limit; /** number of queries removed due to wait-limit */ long long num_queries_wait_limit; /** number of dns error reports generated */ @@ -872,6 +874,8 @@ struct ub_stats_info { long long mesh_num_states; /** mesh stats: current number of reply (user) states */ long long mesh_num_reply_states; + /** mesh stats: current number of reply entries */ + long long mesh_num_reply_addrs; /** mesh stats: number of reply states overwritten with a new one */ long long mesh_jostled; /** mesh stats: number of incoming queries dropped */ Index: usr.sbin/unbound/libunbound/worker.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/libunbound/worker.h,v diff -u -p -r1.7 worker.h --- usr.sbin/unbound/libunbound/worker.h 23 Feb 2022 12:04:05 -0000 1.7 +++ usr.sbin/unbound/libunbound/worker.h 21 Sep 2026 16:28:07 -0000 @@ -70,6 +70,8 @@ struct query_info; * @param q: which query state to reactivate upon return. * @param was_ratelimited: it will signal back if the query failed to pass the * ratelimit check. + * @param ratelimit_incremented: set to true if the ratelimit counter + * was increased. * @return: false on failure (memory or socket related). no query was * sent. */ @@ -78,7 +80,8 @@ struct outbound_entry* libworker_send_qu int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, - struct module_qstate* q, int* was_ratelimited); + struct module_qstate* q, int* was_ratelimited, + int* ratelimit_incremented); /** process incoming serviced query replies from the network */ int libworker_handle_service_reply(struct comm_point* c, void* arg, int error, @@ -126,6 +129,8 @@ void worker_sighandler(int sig, void* ar * @param q: which query state to reactivate upon return. * @param was_ratelimited: it will signal back if the query failed to pass the * ratelimit check. + * @param ratelimit_incremented: set to true if the ratelimit counter + * was increased. * @return: false on failure (memory or socket related). no query was * sent. */ @@ -134,7 +139,8 @@ struct outbound_entry* worker_send_query int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, - struct module_qstate* q, int* was_ratelimited); + struct module_qstate* q, int* was_ratelimited, + int* ratelimit_incremented); /** * process control messages from the main thread. Frees the control @@ -170,14 +176,5 @@ void worker_start_accept(void* arg); /** stop accept callback handler */ void worker_stop_accept(void* arg); - -/** handle remote control accept callbacks */ -int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*); - -/** handle remote control data callbacks */ -int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*); - -/** routine to printout option values over SSL */ -void remote_get_opt_ssl(char* line, void* arg); #endif /* LIBUNBOUND_WORKER_H */ Index: usr.sbin/unbound/respip/respip.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/respip/respip.c,v diff -u -p -r1.17 respip.c --- usr.sbin/unbound/respip/respip.c 31 Aug 2025 21:41:09 -0000 1.17 +++ usr.sbin/unbound/respip/respip.c 21 Sep 2026 16:28:07 -0000 @@ -899,27 +899,34 @@ respip_rewrite_reply(const struct query_ int rpz_cname_override = 0; char* log_name = NULL; - if(!cinfo) - goto done; - ctaglist = cinfo->taglist; - ctaglen = cinfo->taglen; - tag_actions = cinfo->tag_actions; - tag_actions_size = cinfo->tag_actions_size; - tag_datas = cinfo->tag_datas; - tag_datas_size = cinfo->tag_datas_size; - if(cinfo->view) { - view = cinfo->view; - lock_rw_rdlock(&view->lock); - } else if(cinfo->view_name) { - view = views_find_view(views, cinfo->view_name, 0); - if(!view) { - /* If the view no longer exists, the rewrite can not - * be processed further. */ - verbose(VERB_ALGO, "respip: failed because view %s no " - "longer exists", cinfo->view_name); - return 0; + if(!cinfo) { + /* Internal mesh sub-query (e.g. dns64 A lookup): no + * per-client view/tags, but global response-ip and RPZ + * rpz-ip must still apply. */ + ctaglist = NULL; ctaglen = 0; + tag_actions = NULL; tag_actions_size = 0; + tag_datas = NULL; tag_datas_size = 0; + } else { + ctaglist = cinfo->taglist; + ctaglen = cinfo->taglen; + tag_actions = cinfo->tag_actions; + tag_actions_size = cinfo->tag_actions_size; + tag_datas = cinfo->tag_datas; + tag_datas_size = cinfo->tag_datas_size; + if(cinfo->view) { + view = cinfo->view; + lock_rw_rdlock(&view->lock); + } else if(cinfo->view_name) { + view = views_find_view(views, cinfo->view_name, 0); + if(!view) { + /* If the view no longer exists, the rewrite can not + * be processed further. */ + verbose(VERB_ALGO, "respip: failed because view %s no " + "longer exists", cinfo->view_name); + return 0; + } + /* The view is rdlocked by views_find_view. */ } - /* The view is rdlocked by views_find_view. */ } log_assert(ipset); @@ -973,6 +980,9 @@ respip_rewrite_reply(const struct query_ lock_rw_unlock(&raddr->lock); lock_rw_unlock(&a->lock); lock_rw_unlock(&az->rpz_lock); + if(view) { + lock_rw_unlock(&view->lock); + } return 0; } if(rpz_used) { @@ -1074,7 +1084,8 @@ generate_cname_request(struct module_qst subqi.qtype = qstate->qinfo.qtype; subqi.qclass = qstate->qinfo.qclass; fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); - return (*qstate->env->attach_sub)(qstate, &subqi, BIT_RD, 0, 0, &subq); + return (*qstate->env->attach_sub)(qstate, &subqi, + qstate->client_info, BIT_RD, 0, 0, &subq); } void @@ -1110,7 +1121,13 @@ respip_operate(struct module_qstate* qst if((qstate->qinfo.qtype == LDNS_RR_TYPE_A || qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA || qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) && - qstate->return_msg && qstate->return_msg->rep) { + qstate->return_msg && qstate->return_msg->rep && + !(qstate->env->need_to_validate && + (!(qstate->query_flags & BIT_CD) + || qstate->env->cfg->ignore_cd) && + (qstate->return_msg->rep->security <= sec_status_bogus + || qstate->return_msg->rep->security == + sec_status_secure_sentinel_fail))) { struct reply_info* new_rep = qstate->return_msg->rep; struct ub_packed_rrset_key* alias_rrset = NULL; struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; @@ -1147,8 +1164,10 @@ respip_operate(struct module_qstate* qst * clients. */ qstate->is_drop = 1; } else if(alias_rrset) { - if(!generate_cname_request(qstate, alias_rrset)) + if(!generate_cname_request(qstate, alias_rrset)) { + errinf(qstate, "Could not generate CNAME request"); goto servfail; + } next_state = module_wait_subquery; } qstate->return_msg->rep = new_rep; @@ -1162,6 +1181,7 @@ respip_operate(struct module_qstate* qst servfail: qstate->return_rcode = LDNS_RCODE_SERVFAIL; qstate->return_msg = NULL; + qstate->ext_state[id] = module_finished; } int @@ -1233,7 +1253,8 @@ respip_inform_super(struct module_qstate struct respip_qstate* rq = (struct respip_qstate*)super->minfo[id]; struct reply_info* new_rep = NULL; - rq->state = RESPIP_SUBQUERY_FINISHED; + if(rq) + rq->state = RESPIP_SUBQUERY_FINISHED; /* respip subquery should have always been created with a valid reply * in super. */ @@ -1257,6 +1278,7 @@ respip_inform_super(struct module_qstate return; fail: + errinf(super, "CNAME lookup failed"); super->return_rcode = LDNS_RCODE_SERVFAIL; super->return_msg = NULL; return; Index: usr.sbin/unbound/services/authzone.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/authzone.c,v diff -u -p -r1.31 authzone.c --- usr.sbin/unbound/services/authzone.c 26 Sep 2025 07:32:37 -0000 1.31 +++ usr.sbin/unbound/services/authzone.c 21 Sep 2026 16:28:07 -0000 @@ -55,6 +55,7 @@ #include "util/log.h" #include "util/module.h" #include "util/random.h" +#include "util/timeval_func.h" #include "services/cache/dns.h" #include "services/outside_network.h" #include "services/listen_dnsport.h" @@ -95,6 +96,8 @@ /** number of timeouts before we fallback from IXFR to AXFR, * because some versions of servers (eg. dnsmasq) drop IXFR packets. */ #define NUM_TIMEOUTS_FALLBACK_IXFR 3 +/** number of IXFRs before an AXFR is performed, to consolidate RPZ memory. */ +#define NUM_IXFR_BEFORE_AXFR 5 /** pick up nextprobe task to start waiting to perform transfer actions */ static void xfr_set_timeout(struct auth_xfer* xfr, struct module_env* env, @@ -106,6 +109,9 @@ static void xfr_probe_send_or_end(struct * or transfer task if nothing to probe, or false if already in progress */ static int xfr_start_probe(struct auth_xfer* xfr, struct module_env* env, struct auth_master* spec); +/** copy the master addresses from the task_probe lookups to the allow_notify + * list of masters */ +static void probe_copy_masters_for_allow_notify(struct auth_xfer* xfr); /** delete xfer structure (not its tree entry) */ void auth_xfer_delete(struct auth_xfer* xfr); @@ -171,7 +177,7 @@ get_rrset_ttl(struct ub_packed_rrset_key /** Copy rrset into region from domain-datanode and packet rrset */ static struct ub_packed_rrset_key* auth_packed_rrset_copy_region(struct auth_zone* z, struct auth_data* node, - struct auth_rrset* rrset, struct regional* region, time_t adjust) + struct auth_rrset* rrset, struct regional* region) { struct ub_packed_rrset_key key; memset(&key, 0, sizeof(key)); @@ -182,7 +188,7 @@ auth_packed_rrset_copy_region(struct aut key.rk.type = htons(rrset->type); key.rk.rrset_class = htons(z->dclass); key.entry.hash = rrset_key_hash(&key.rk); - return packed_rrset_copy_region(&key, region, adjust); + return packed_rrset_copy_region(&key, region, 0); } /** fix up msg->rep TTL and prefetch ttl */ @@ -236,7 +242,7 @@ msg_add_rrset_an(struct auth_zone* z, st return 0; /* copy it */ if(!(msg->rep->rrsets[msg->rep->rrset_count] = - auth_packed_rrset_copy_region(z, node, rrset, region, 0))) + auth_packed_rrset_copy_region(z, node, rrset, region))) return 0; msg->rep->rrset_count++; msg->rep->an_numrrsets++; @@ -260,7 +266,7 @@ msg_add_rrset_ns(struct auth_zone* z, st return 0; /* copy it */ if(!(msg->rep->rrsets[msg->rep->rrset_count] = - auth_packed_rrset_copy_region(z, node, rrset, region, 0))) + auth_packed_rrset_copy_region(z, node, rrset, region))) return 0; msg->rep->rrset_count++; msg->rep->ns_numrrsets++; @@ -283,7 +289,7 @@ msg_add_rrset_ar(struct auth_zone* z, st return 0; /* copy it */ if(!(msg->rep->rrsets[msg->rep->rrset_count] = - auth_packed_rrset_copy_region(z, node, rrset, region, 0))) + auth_packed_rrset_copy_region(z, node, rrset, region))) return 0; msg->rep->rrset_count++; msg->rep->ar_numrrsets++; @@ -386,6 +392,20 @@ auth_data_del(rbnode_type* n, void* ATTR auth_data_delete(z); } +/** delete chunklist */ +static void +auth_chunk_list_delete(struct auth_chunk* first) +{ + struct auth_chunk* c, *cn; + c = first; + while(c) { + cn = c->next; + free(c->data); + free(c); + c = cn; + } +} + /** delete an auth zone structure (tree remove must be done elsewhere) */ static void auth_zone_delete(struct auth_zone* z, struct auth_zones* az) @@ -407,6 +427,7 @@ auth_zone_delete(struct auth_zone* z, st } if(z->rpz) rpz_delete(z->rpz); + auth_chunk_list_delete(z->perform_write_chunk_list); free(z->name); free(z->zonefile); free(z); @@ -432,7 +453,12 @@ auth_zone_create(struct auth_zones* az, rbtree_init(&z->data, &auth_data_cmp); lock_rw_init(&z->lock); lock_protect(&z->lock, &z->name, sizeof(*z)-sizeof(rbnode_type)- - sizeof(&z->rpz_az_next)-sizeof(&z->rpz_az_prev)); + sizeof(z->rpz_az_next)-sizeof(z->rpz_az_prev)- + sizeof(z->max_transfer_size)-sizeof(z->max_transfer_size)); + lock_protect(&z->lock, &z->max_transfer_size, + sizeof(z->max_transfer_size)); + lock_protect(&z->lock, &z->max_transfer_time, + sizeof(z->max_transfer_time)); lock_rw_wrlock(&z->lock); /* z lock protects all, except rbtree itself and the rpz linked list * pointers, which are protected using az->lock */ @@ -1175,6 +1201,22 @@ az_insert_rr(struct auth_zone* z, uint8_ log_err("wrong class for RR"); return 0; } + if(rr_type == LDNS_RR_TYPE_A && rdatalen != 6 /* 2 + 4 */) { + log_err("malformed A record"); + return 0; + } else if(rr_type == LDNS_RR_TYPE_AAAA && rdatalen != 18 /* 2 + 16 */) { + log_err("malformed AAAA record"); + return 0; + } + if(!dname_subdomain_c(dname, z->name)) { + char nm[LDNS_MAX_DOMAINLEN], zn[LDNS_MAX_DOMAINLEN]; + dname_str(dname, nm); + dname_str(z->name, zn); + verbose(VERB_ALGO, "auth-zone %s: dropping out-of-zone RR " + "%s", zn, nm); + if(duplicate) *duplicate=1; /* treat as bad insert */ + return 1; + } if(!(node=az_domain_find_or_create(z, dname, dname_len))) { log_err("cannot create domain"); return 0; @@ -1182,6 +1224,10 @@ az_insert_rr(struct auth_zone* z, uint8_ if(!az_domain_add_rr(node, rr_type, rr_ttl, rdata, rdatalen, duplicate)) { log_err("cannot add RR to domain"); + if(node->rrsets == NULL) { + (void)rbtree_delete(&z->data, node); + auth_data_delete(node); + } return 0; } if(z->rpz) { @@ -1369,6 +1415,10 @@ decompress_rr_into_buffer(struct sldns_b uncompressed_len = pkt_dname_len(&pktbuf); if(!uncompressed_len) return 0; /* parse error in dname */ + compressed_len = sldns_buffer_position( + &pktbuf) - oldpos; + if(compressed_len > rdlen) + return 0; /* dname exceeds rdata */ if(!sldns_buffer_available(buf, uncompressed_len)) /* dname too long for buffer */ @@ -1376,14 +1426,15 @@ decompress_rr_into_buffer(struct sldns_b dname_pkt_copy(&pktbuf, sldns_buffer_current(buf), rd); sldns_buffer_skip(buf, (ssize_t)uncompressed_len); - compressed_len = sldns_buffer_position( - &pktbuf) - oldpos; rd += compressed_len; rdlen -= compressed_len; count--; len = 0; break; case LDNS_RDF_TYPE_STR: + /* Check rdlen for resilience, because it is + * checked above, that rdlen > 0 */ + if(rdlen < 1) return 0; /* malformed */ len = rd[0] + 1; break; default: @@ -1391,6 +1442,8 @@ decompress_rr_into_buffer(struct sldns_b break; } if(len) { + if(len > rdlen) + return 0; /* malformed */ if(!sldns_buffer_available(buf, len)) return 0; /* too long for buffer */ sldns_buffer_write(buf, rd, len); @@ -1498,6 +1551,11 @@ az_parse_file(struct auth_zone* z, FILE* "exceeded", fname, state->lineno); return 0; } + /* A $INCLUDE is not expected for a secondary zone. */ + if(z->zone_is_slave) { + log_err("%s:%d $INCLUDE not allowed for secondary zone", fname, state->lineno); + return 0; + } /* skip spaces */ while(*incfile == ' ' || *incfile == '\t') incfile++; @@ -1563,6 +1621,16 @@ az_parse_file(struct auth_zone* z, FILE* return 1; } +void auth_zone_clear_data(struct auth_zone* z) +{ + /* clear the data tree */ + traverse_postorder(&z->data, auth_data_del, NULL); + rbtree_init(&z->data, &auth_data_cmp); + /* clear the RPZ policies */ + if(z->rpz) + rpz_clear(z->rpz); +} + int auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg) { @@ -1585,10 +1653,16 @@ auth_zone_read_zonefile(struct auth_zone in = fopen(zfilename, "r"); if(!in) { char* n = sldns_wire2str_dname(z->name, z->namelen); - if(z->zone_is_slave && errno == ENOENT) { - /* we fetch the zone contents later, no file yet */ - verbose(VERB_ALGO, "no zonefile %s for %s", - zfilename, n?n:"error"); + if(errno == ENOENT) { + /* For a secondary, fetch the zone contents later, no + * file yet. For a primary, no way to fetch the zone, + * so warn. */ + if(z->zone_is_slave) + verbose(VERB_ALGO, "no zonefile %s for %s", + zfilename, n?n:"error"); + else + log_warn("no zonefile %s for %s", + zfilename, n?n:"error"); free(n); return 1; } @@ -1791,9 +1865,11 @@ auth_zones_read_zones(struct auth_zones* RBTREE_FOR(z, struct auth_zone*, &az->ztree) { lock_rw_wrlock(&z->lock); if(!auth_zone_read_zonefile(z, cfg)) { + /* For both secondary and primary zones, not fatal. + * This keeps the server up. */ + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); - lock_rw_unlock(&az->lock); - return 0; + continue; } if(z->zonefile && z->zonefile[0]!=0 && env) zonemd_offline_verify(z, env, mods); @@ -1998,12 +2074,21 @@ auth_zone_get_serial(struct auth_zone* z struct auth_data* apex; struct auth_rrset* soa; struct packed_rrset_data* d; + size_t primlen, mboxlen; apex = az_find_name(z, z->name, z->namelen); if(!apex) return 0; soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA); if(!soa || soa->data->count==0) return 0; /* no RRset or no RRs in rrset */ if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */ + if((primlen = dname_valid(soa->data->rr_data[0]+2, + soa->data->rr_len[0]-2)) == 0) + return 0; /* primary dname malformed */ + if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen, + soa->data->rr_len[0]-2-primlen)) == 0) + return 0; /* mailbox dname malformed */ + if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0]) + return 0; /* rdata malformed */ d = soa->data; *serial = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-20)); return 1; @@ -2016,12 +2101,21 @@ xfr_find_soa(struct auth_zone* z, struct struct auth_data* apex; struct auth_rrset* soa; struct packed_rrset_data* d; + size_t primlen, mboxlen; apex = az_find_name(z, z->name, z->namelen); if(!apex) return 0; soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA); if(!soa || soa->data->count==0) return 0; /* no RRset or no RRs in rrset */ if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */ + if((primlen = dname_valid(soa->data->rr_data[0]+2, + soa->data->rr_len[0]-2)) == 0) + return 0; /* primary dname malformed */ + if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen, + soa->data->rr_len[0]-2-primlen)) == 0) + return 0; /* mailbox dname malformed */ + if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0]) + return 0; /* rdata malformed */ /* SOA record ends with serial, refresh, retry, expiry, minimum, * as 4 byte fields */ d = soa->data; @@ -2051,6 +2145,7 @@ auth_xfer_setup(struct auth_zone* z, str if(!xfr_find_soa(z, x)) { return 1; } + x->is_rpz = (z->rpz!=NULL); /* nothing for probe, nextprobe and transfer tasks */ return 1; } @@ -2110,6 +2205,9 @@ auth_zones_cfg(struct auth_zones* az, st } return 0; } + /* Populate the xfer related options early since we may create one now */ + z->max_transfer_size = c->max_transfer_size; + z->max_transfer_time = c->max_transfer_time; if(c->masters || c->urls) { if(!(x=auth_zones_find_or_add_xfer(az, z))) { lock_rw_unlock(&az->lock); @@ -2143,7 +2241,12 @@ auth_zones_cfg(struct auth_zones* az, st z->zonemd_reject_absence = c->zonemd_reject_absence; if(c->isrpz && !z->rpz){ if(!(z->rpz = rpz_create(c))){ - fatal_exit("Could not setup RPZ zones"); + log_err("Could not setup RPZ zones"); + if(x) { + lock_basic_unlock(&x->lock); + } + lock_rw_unlock(&z->lock); + lock_rw_unlock(&az->rpz_lock); return 0; } lock_protect(&z->lock, &z->rpz->local_zones, sizeof(*z->rpz)); @@ -2181,6 +2284,10 @@ auth_zones_cfg(struct auth_zones* az, st lock_rw_unlock(&z->lock); return 0; } + /* Pick up allow notify entries, early. This works for + * addresses and netblocks. */ + if(!x->allow_notify_list) + probe_copy_masters_for_allow_notify(x); lock_basic_unlock(&x->lock); } @@ -2277,17 +2384,11 @@ static void auth_chunks_delete(struct auth_transfer* at) { if(at->chunks_first) { - struct auth_chunk* c, *cn; - c = at->chunks_first; - while(c) { - cn = c->next; - free(c->data); - free(c); - c = cn; - } + auth_chunk_list_delete(at->chunks_first); } at->chunks_first = NULL; at->chunks_last = NULL; + at->chunks_total = 0; } /** free master addr list */ @@ -2619,7 +2720,7 @@ az_empty_nonterminal(struct auth_zone* z while(next && (rbnode_type*)next != RBTREE_NULL && next->rrsets == NULL) { /* the next name has empty rrsets, is an empty nonterminal * itself, see if there exists something below it */ - next = (struct auth_data*)rbtree_next(&node->node); + next = (struct auth_data*)rbtree_next(&next->node); } if((rbnode_type*)next == RBTREE_NULL || !next) { /* there is no next node, so something below it cannot @@ -3500,7 +3601,13 @@ int auth_zones_lookup(struct auth_zones* *fallback = 1; return 0; } - if(z->zone_expired) { + if(z->zone_expired || (z->zonemd_check && z->zonemd_callback_env)) { + /* Do not serve from a zonemd-check zone while its ZONEMD + * verification is still pending: the content is not yet known + * to pass the configured check. The pending marker + * (zonemd_callback_env) is set under z->lock when the async + * lookup is spawned and cleared by the callback under z->lock, + * so this test is race-free. */ *fallback = z->fallback_enabled; lock_rw_unlock(&z->lock); return 0; @@ -3602,7 +3709,10 @@ int auth_zones_downstream_answer(struct lock_rw_unlock(&z->lock); return 0; } - if(z->zone_expired) { + if(z->zone_expired || (z->zonemd_check && z->zonemd_callback_env)) { + /* see auth_zones_lookup: a pending ZONEMD verification is + * treated like expiry - the zone content is not yet known + * to pass the configured check. */ if(z->fallback_enabled) { lock_rw_unlock(&z->lock); return 0; @@ -3990,6 +4100,22 @@ auth_master_copy(struct auth_master* o) return m; } +/** append the master to the copied list. */ +static int +auth_master_copy_and_append(struct auth_master* p, struct auth_master** list, + struct auth_master** last) +{ + struct auth_master* m = auth_master_copy(p); + if(!m) { + return 0; + } + m->next = NULL; + if(*last) (*last)->next = m; + if(!*list) *list = m; + *last = m; + return 1; +} + /** copy the master addresses from the task_probe lookups to the allow_notify * list of masters */ static void @@ -3998,17 +4124,27 @@ probe_copy_masters_for_allow_notify(stru struct auth_master* list = NULL, *last = NULL; struct auth_master* p; /* build up new list with copies */ + /* The list in task probe has been looked up before the list in + * task transfer. */ + for(p = xfr->task_probe->masters; p; p=p->next) { + if(!auth_master_copy_and_append(p, &list, &last)) { + auth_free_masters(list); + /* failed because of malloc failure, use old list */ + return; + } + } + /* The list in task transfer also contains the http entries. */ for(p = xfr->task_transfer->masters; p; p=p->next) { - struct auth_master* m = auth_master_copy(p); - if(!m) { + /* Copy the http entries from this lookup. The allow_notify + * entries are not looked up from this list. The other + * ones are already in from the probe lookups. */ + if(!p->http) + continue; + if(!auth_master_copy_and_append(p, &list, &last)) { auth_free_masters(list); /* failed because of malloc failure, use old list */ return; } - m->next = NULL; - if(last) last->next = m; - if(!list) list = m; - last = m; } /* success, replace list */ auth_free_masters(xfr->allow_notify_list); @@ -4247,7 +4383,7 @@ xfr_create_ixfr_packet(struct auth_xfer* { struct query_info qinfo; uint32_t serial; - int have_zone; + int have_zone, get_full = 0; have_zone = xfr->have_zone; serial = xfr->serial; @@ -4260,7 +4396,18 @@ xfr_create_ixfr_packet(struct auth_xfer* xfr->task_transfer->on_ixfr_is_axfr = 0; xfr->task_transfer->on_ixfr = 1; qinfo.qtype = LDNS_RR_TYPE_IXFR; - if(!have_zone || xfr->task_transfer->ixfr_fail || !master->ixfr) { + if(xfr->num_ixfrs >= NUM_IXFR_BEFORE_AXFR && xfr->is_rpz) { + /* For the RPZ, an IXFR is going to grow regions, and a + * full transfer, zonefile read, AXFR and HTTP clear the + * region, but IXFR does not. That memory keeps growing, + * and getting a full transfer with AXFR here resets that. + * The rpz->client_set->region, rpz->ns_set->region and + * rpz->respip_set->region need to be reset, they are for + * rpz-client-ip, rpz-nsip and rpz-ip. */ + get_full = 1; + } + if(!have_zone || xfr->task_transfer->ixfr_fail || !master->ixfr + || get_full) { qinfo.qtype = LDNS_RR_TYPE_AXFR; xfr->task_transfer->ixfr_fail = 0; xfr->task_transfer->on_ixfr = 0; @@ -4411,29 +4558,31 @@ chunkline_get_line(struct auth_chunk** c } /** count number of open and closed parenthesis in a chunkline */ -static int +int chunkline_count_parens(sldns_buffer* buf, size_t start) { size_t end = sldns_buffer_position(buf); size_t i; int count = 0; - int squote = 0, dquote = 0; + int dquote = 0; + char prev_c = 0; for(i=start; inum_ixfrs++; + /* start RR iterator over chunklist of packets */ chunk_rrlist_start(xfr, &rr_chunk, &rr_num, &rr_pos); while(!chunk_rrlist_end(rr_chunk, rr_num)) { @@ -5015,16 +5169,11 @@ apply_axfr(struct auth_xfer* xfr, struct size_t rr_counter = 0; int have_end_soa = 0; - /* clear the data tree */ - traverse_postorder(&z->data, auth_data_del, NULL); - rbtree_init(&z->data, &auth_data_cmp); - /* clear the RPZ policies */ - if(z->rpz) - rpz_clear(z->rpz); - + auth_zone_clear_data(z); xfr->have_zone = 0; xfr->serial = 0; xfr->soa_zone_acquired = 0; + xfr->num_ixfrs = 0; /* insert all RRs in to the zone */ /* insert the SOA only once, skip the last one */ @@ -5117,16 +5266,11 @@ apply_http(struct auth_xfer* xfr, struct return 0; } - /* clear the data tree */ - traverse_postorder(&z->data, auth_data_del, NULL); - rbtree_init(&z->data, &auth_data_cmp); - /* clear the RPZ policies */ - if(z->rpz) - rpz_clear(z->rpz); - + auth_zone_clear_data(z); xfr->have_zone = 0; xfr->serial = 0; xfr->soa_zone_acquired = 0; + xfr->num_ixfrs = 0; chunk = xfr->task_transfer->chunks_first; chunk_pos = 0; @@ -5172,7 +5316,7 @@ apply_http(struct auth_xfer* xfr, struct /** write http chunks to zonefile to create downloaded file */ static int -auth_zone_write_chunks(struct auth_xfer* xfr, const char* fname) +auth_zone_write_chunks(struct auth_chunk* chunk_list, const char* fname) { FILE* out; struct auth_chunk* p; @@ -5181,7 +5325,7 @@ auth_zone_write_chunks(struct auth_xfer* log_err("could not open %s: %s", fname, strerror(errno)); return 0; } - for(p = xfr->task_transfer->chunks_first; p ; p = p->next) { + for(p = chunk_list; p ; p = p->next) { if(!write_out(out, (char*)p->data, p->len)) { log_err("could not write http download to %s", fname); fclose(out); @@ -5192,34 +5336,18 @@ auth_zone_write_chunks(struct auth_xfer* return 1; } -/** write to zonefile after zone has been updated */ +/** write to zonefile after zone has been updated, z has rdlock by caller. */ static void -xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env) +zone_write_after_update(struct auth_zone* z, struct module_env* env, + struct auth_chunk* chunk_list) { struct config_file* cfg = env->cfg; - struct auth_zone* z; char tmpfile[1024]; char* zfilename; - lock_basic_unlock(&xfr->lock); - - /* get lock again, so it is a readlock and concurrently queries - * can be answered */ - lock_rw_rdlock(&env->auth_zones->lock); - z = auth_zone_find(env->auth_zones, xfr->name, xfr->namelen, - xfr->dclass); - if(!z) { - lock_rw_unlock(&env->auth_zones->lock); - /* the zone is gone, ignore xfr results */ - lock_basic_lock(&xfr->lock); - return; - } - lock_rw_rdlock(&z->lock); - lock_basic_lock(&xfr->lock); - lock_rw_unlock(&env->auth_zones->lock); if(z->zonefile == NULL || z->zonefile[0] == 0) { - lock_rw_unlock(&z->lock); /* no write needed, no zonefile set */ + auth_chunk_list_delete(chunk_list); return; } zfilename = z->zonefile; @@ -5236,21 +5364,21 @@ xfr_write_after_update(struct auth_xfer* if((size_t)strlen(zfilename) + 16 > sizeof(tmpfile)) { verbose(VERB_ALGO, "tmpfilename too long, cannot update " " zonefile %s", zfilename); - lock_rw_unlock(&z->lock); + auth_chunk_list_delete(chunk_list); return; } snprintf(tmpfile, sizeof(tmpfile), "%s.tmp%u", zfilename, (unsigned)getpid()); - if(xfr->task_transfer->master->http) { + if(chunk_list) { /* use the stored chunk list to write them */ - if(!auth_zone_write_chunks(xfr, tmpfile)) { + if(!auth_zone_write_chunks(chunk_list, tmpfile)) { unlink(tmpfile); - lock_rw_unlock(&z->lock); + auth_chunk_list_delete(chunk_list); return; } + auth_chunk_list_delete(chunk_list); } else if(!auth_zone_write_file(z, tmpfile)) { unlink(tmpfile); - lock_rw_unlock(&z->lock); return; } #ifdef UB_ON_WINDOWS @@ -5260,9 +5388,57 @@ xfr_write_after_update(struct auth_xfer* log_err("could not rename(%s, %s): %s", tmpfile, zfilename, strerror(errno)); unlink(tmpfile); - lock_rw_unlock(&z->lock); return; } +} + +/** write to zonefile after zone has updated, reacquires z readlock. */ +static void +zone_write_after_update_reacq(uint8_t* bakname, size_t baknamelen, + uint16_t bakdclass, struct module_env* env, + struct auth_chunk* chunk_list) +{ + struct auth_zone* z; + /* get lock again, so it is a readlock and concurrently queries + * can be answered */ + lock_rw_rdlock(&env->auth_zones->lock); + z = auth_zone_find(env->auth_zones, bakname, baknamelen, bakdclass); + if(!z) { + lock_rw_unlock(&env->auth_zones->lock); + /* the zone is gone, ignore xfr results */ + return; + } + lock_rw_rdlock(&z->lock); + lock_rw_unlock(&env->auth_zones->lock); + + zone_write_after_update(z, env, chunk_list); + lock_rw_unlock(&z->lock); +} + +/** write to zonefile after zone has been updated */ +static void +xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env, + struct auth_chunk* chunk_list) +{ + struct auth_zone* z; + lock_basic_unlock(&xfr->lock); + + /* get lock again, so it is a readlock and concurrently queries + * can be answered */ + lock_rw_rdlock(&env->auth_zones->lock); + z = auth_zone_find(env->auth_zones, xfr->name, xfr->namelen, + xfr->dclass); + if(!z) { + lock_rw_unlock(&env->auth_zones->lock); + /* the zone is gone, ignore xfr results */ + lock_basic_lock(&xfr->lock); + return; + } + lock_rw_rdlock(&z->lock); + lock_basic_lock(&xfr->lock); + lock_rw_unlock(&env->auth_zones->lock); + + zone_write_after_update(z, env, chunk_list); lock_rw_unlock(&z->lock); } @@ -5295,6 +5471,8 @@ xfr_process_chunk_list(struct auth_xfer* int* ixfr_fail) { struct auth_zone* z; + int zonemd_in_progress; + struct auth_chunk* current_chunk_list = NULL; /* obtain locks and structures */ lock_basic_unlock(&xfr->lock); @@ -5307,6 +5485,7 @@ xfr_process_chunk_list(struct auth_xfer* /* apply data */ if(xfr->task_transfer->master->http) { if(!apply_http(xfr, z, env->scratch_buffer)) { + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); verbose(VERB_ALGO, "http from %s: could not store data", xfr->task_transfer->master->host); @@ -5315,6 +5494,7 @@ xfr_process_chunk_list(struct auth_xfer* } else if(xfr->task_transfer->on_ixfr && !xfr->task_transfer->on_ixfr_is_axfr) { if(!apply_ixfr(xfr, z, env->scratch_buffer)) { + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); verbose(VERB_ALGO, "xfr from %s: could not store IXFR" " data", xfr->task_transfer->master->host); @@ -5323,6 +5503,7 @@ xfr_process_chunk_list(struct auth_xfer* } } else { if(!apply_axfr(xfr, z, env->scratch_buffer)) { + auth_zone_clear_data(z); lock_rw_unlock(&z->lock); verbose(VERB_ALGO, "xfr from %s: could not store AXFR" " data", xfr->task_transfer->master->host); @@ -5339,6 +5520,7 @@ xfr_process_chunk_list(struct auth_xfer* } z->soa_zone_acquired = *env->now; xfr->soa_zone_acquired = *env->now; + xfr->is_rpz = (z->rpz!=NULL); /* release xfr lock while verifying zonemd because it may have * to spawn lookups in the state machines */ @@ -5374,6 +5556,25 @@ xfr_process_chunk_list(struct auth_xfer* if(z->rpz) rpz_finish_config(z->rpz); + if(z->zonemd_check && z->zonemd_callback_env) { + zonemd_in_progress = 1; + z->zonemd_callback_perform_write = 1; + auth_chunk_list_delete(z->perform_write_chunk_list); + z->perform_write_chunk_list = NULL; + if(xfr->task_transfer->master->http) { + z->perform_write_chunk_list = xfr->task_transfer->chunks_first; + xfr->task_transfer->chunks_first = NULL; + auth_chunks_delete(xfr->task_transfer); + } + } else { + zonemd_in_progress = 0; + z->zonemd_callback_perform_write = 0; + if(xfr->task_transfer->master->http) { + current_chunk_list = xfr->task_transfer->chunks_first; + xfr->task_transfer->chunks_first = NULL; + auth_chunks_delete(xfr->task_transfer); + } + } /* unlock */ lock_rw_unlock(&z->lock); @@ -5384,20 +5585,56 @@ xfr_process_chunk_list(struct auth_xfer* (unsigned)xfr->serial); } /* see if we need to write to a zonefile */ - xfr_write_after_update(xfr, env); + if(!zonemd_in_progress) { + xfr_write_after_update(xfr, env, current_chunk_list); + } return 1; } +/** Stop lookup using callback */ +static void +xfr_stop_lookup(struct auth_master** lookup_target, void* lookup_unique_info, + int lookup_aaaa, uint16_t dclass, struct mesh_area* mesh, + mesh_cb_func_type cb, void* cb_arg) +{ + struct query_info qinfo; + uint8_t dname[LDNS_MAX_DOMAINLEN+1]; + if(!*lookup_target) return; + qinfo.qname_len = sizeof(dname); + if(sldns_str2wire_dname_buf((*lookup_target)->host, dname, + &qinfo.qname_len) != 0) { + *lookup_target = NULL; + return; + } + qinfo.qname = dname; + qinfo.qclass = dclass; + qinfo.qtype = lookup_aaaa ? LDNS_RR_TYPE_AAAA : LDNS_RR_TYPE_A; + qinfo.local_alias = NULL; + log_query_info(VERB_ALGO, "removing xfr callback", &qinfo); + + mesh_remove_callback(mesh, &qinfo, BIT_RD, cb, cb_arg, + lookup_unique_info); + *lookup_target = NULL; +} + /** disown task_transfer. caller must hold xfr.lock */ static void xfr_transfer_disown(struct auth_xfer* xfr) { + /* remove data chunks */ + auth_chunks_delete(xfr->task_transfer); /* remove timer (from this worker's event base) */ comm_timer_delete(xfr->task_transfer->timer); xfr->task_transfer->timer = NULL; /* remove the commpoint */ comm_point_delete(xfr->task_transfer->cp); xfr->task_transfer->cp = NULL; + if(xfr->task_transfer->env) + xfr_stop_lookup(&xfr->task_transfer->lookup_target, + xfr->task_transfer->lookup_unique_info, + xfr->task_transfer->lookup_aaaa, xfr->dclass, + xfr->task_transfer->env->mesh, + &auth_xfer_transfer_lookup_callback, xfr); /* we don't own this item anymore */ xfr->task_transfer->worker = NULL; xfr->task_transfer->env = NULL; @@ -5464,7 +5701,8 @@ xfr_transfer_lookup_host(struct auth_xfe * called straight away */ lock_basic_unlock(&xfr->lock); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, - &auth_xfer_transfer_lookup_callback, xfr, 0)) { + &auth_xfer_transfer_lookup_callback, xfr, 0, + &xfr->task_transfer->lookup_unique_info)) { lock_basic_lock(&xfr->lock); log_err("out of memory lookup up master %s", master->host); return 0; @@ -5522,6 +5760,7 @@ xfr_transfer_init_fetch(struct auth_xfer t.tv_sec = timeout/1000; t.tv_usec = (timeout%1000)*1000; #endif + xfr->task_transfer->start_time = *env->now_tv; if(master->http) { /* perform http fetch */ @@ -5691,10 +5930,34 @@ xfr_master_add_addrs(struct auth_master* } } +/** check if the lookup target name equals the found answer name. */ +static int +xfer_target_equals_answer_name(struct auth_master* lookup_target, + struct ub_packed_rrset_key* answer, struct query_info* rq, + struct reply_info* rep) +{ + uint8_t qname[LDNS_MAX_DOMAINLEN+1]; + size_t qname_len; + if(!lookup_target) return 0; + if(!answer) return 0; + qname_len = sizeof(qname); + if(sldns_str2wire_dname_buf(lookup_target->host, qname, &qname_len) + != 0) { + verbose(VERB_ALGO, "xfer_target_equals_answer_name: could not parse auth host name"); + return 0; + } + if(query_dname_compare(answer->rk.dname, qname) == 0) + return 1; + /* It could be a CNAME. */ + if(reply_find_rrset_section_an(rep, qname, qname_len, + LDNS_RR_TYPE_CNAME, rq->qclass)) + return 1; + return 0; +} + /** callback for task_transfer lookup of host name, of A or AAAA */ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), - int ATTR_UNUSED(was_ratelimited)) + enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited)) { struct auth_xfer* xfr = (struct auth_xfer*)arg; struct module_env* env; @@ -5707,7 +5970,16 @@ void auth_xfer_transfer_lookup_callback( } /* process result */ - if(rcode == LDNS_RCODE_NOERROR) { + if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) { + if(verbosity >= VERB_OPS) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_OPS, "auth zone %s: primary %s address lookup is DNSSEC bogus: %s", + zname, xfr->task_transfer->lookup_target->host, + (why_bogus?why_bogus:"")); + } + /* fall through to next-lookup / next-master */ + } else if(rcode == LDNS_RCODE_NOERROR) { uint16_t wanted_qtype = LDNS_RR_TYPE_A; struct regional* temp = env->scratch; struct query_info rq; @@ -5721,21 +5993,29 @@ void auth_xfer_transfer_lookup_callback( /* parsed successfully */ struct ub_packed_rrset_key* answer = reply_find_answer_rrset(&rq, rep); - if(answer) { + if(answer && xfer_target_equals_answer_name( + xfr->task_transfer->lookup_target, answer, + &rq, rep)) { xfr_master_add_addrs(xfr->task_transfer-> lookup_target, answer, wanted_qtype); + } else if(answer) { + if(verbosity >= VERB_ALGO) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has mismatch in answer name", zname, ((xfr->task_transfer->lookup_target && xfr->task_transfer->lookup_target->host) ? xfr->task_transfer->lookup_target->host : "null"), (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); + } } else { if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has nodata", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has nodata", zname, ((xfr->task_transfer->lookup_target && xfr->task_transfer->lookup_target->host) ? xfr->task_transfer->lookup_target->host : "null"), (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); } } } else { if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has no answer", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has no answer", zname, ((xfr->task_transfer->lookup_target && xfr->task_transfer->lookup_target->host) ? xfr->task_transfer->lookup_target->host : "null"), (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); } } regional_free_all(temp); @@ -5743,10 +6023,11 @@ void auth_xfer_transfer_lookup_callback( if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup failed", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup failed", zname, ((xfr->task_transfer->lookup_target && xfr->task_transfer->lookup_target->host) ? xfr->task_transfer->lookup_target->host : "null"), (xfr->task_transfer->lookup_aaaa?"AAAA":"A")); } } - if(xfr->task_transfer->lookup_target->list && + if(xfr->task_transfer->lookup_target && + xfr->task_transfer->lookup_target->list && xfr->task_transfer->lookup_target == xfr_transfer_current_master(xfr)) xfr->task_transfer->scan_addr = xfr->task_transfer->lookup_target->list; @@ -6076,6 +6357,7 @@ xfer_link_data(sldns_buffer* pkt, struct if(xfr->task_transfer->chunks_last) xfr->task_transfer->chunks_last->next = e; xfr->task_transfer->chunks_last = e; + xfr->task_transfer->chunks_total += e->len; return 1; } @@ -6171,6 +6453,15 @@ auth_xfer_transfer_timer_callback(void* xfr_transfer_nexttarget_or_end(xfr, env); } +/** return the time taken by the transfer */ +static int +auth_xfer_transfer_time_taken(struct auth_xfer* xfr, struct module_env* env) +{ + struct timeval delta; + timeval_subtract(&delta, env->now_tv, &xfr->task_transfer->start_time); + return ((int)delta.tv_sec)*1000 + ((int)delta.tv_usec)/1000; +} + /** callback for task_transfer tcp connections */ int auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err, @@ -6237,6 +6528,15 @@ auth_xfer_transfer_tcp_callback(struct c xfr->task_transfer->master->host); goto failed; } + if(xfr->max_transfer_size > 0 && + xfr->task_transfer->chunks_total > xfr->max_transfer_size) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + log_err("auth zone %s transfer from %s exceeded %u bytes, aborting", + zname, xfr->task_transfer->master->host, + (unsigned)xfr->max_transfer_size); + goto failed; + } /* if the transfer is done now, disconnect and process the list */ if(transferdone) { comm_point_delete(xfr->task_transfer->cp); @@ -6245,6 +6545,16 @@ auth_xfer_transfer_tcp_callback(struct c return 0; } + if(xfr->max_transfer_time > 0 && + auth_xfer_transfer_time_taken(xfr, env) > xfr->max_transfer_time) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + log_err("auth zone %s transfer from %s exceeded %u msec total running time, aborting", + zname, xfr->task_transfer->master->host, + (unsigned)xfr->max_transfer_time); + goto failed; + } + /* if we want to read more messages, setup the commpoint to read * a DNS packet, and the timeout */ lock_basic_unlock(&xfr->lock); @@ -6300,6 +6610,16 @@ auth_xfer_transfer_http_callback(struct xfr->task_transfer->master->host); goto failed; } + if(xfr->max_transfer_size > 0 && + xfr->task_transfer->chunks_total > xfr->max_transfer_size) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + log_err("auth zone %s http %s/%s exceeded %u bytes, aborting", + zname, xfr->task_transfer->master->host, + xfr->task_transfer->master->file, + (unsigned)xfr->max_transfer_size); + goto failed; + } } /* if the transfer is done now, disconnect and process the list */ if(err == NETEVENT_DONE) { @@ -6311,6 +6631,17 @@ auth_xfer_transfer_http_callback(struct return 0; } + if(xfr->max_transfer_time > 0 && + auth_xfer_transfer_time_taken(xfr, env) > xfr->max_transfer_time) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + log_err("auth zone %s transfer http %s/%s exceeded %u msec total running time, aborting", + zname, xfr->task_transfer->master->host, + xfr->task_transfer->master->file, + (unsigned)xfr->max_transfer_time); + goto failed; + } + /* if we want to read more messages, setup the commpoint to read * a DNS packet, and the timeout */ lock_basic_unlock(&xfr->lock); @@ -6353,6 +6684,12 @@ xfr_probe_disown(struct auth_xfer* xfr) /* remove the commpoint */ comm_point_delete(xfr->task_probe->cp); xfr->task_probe->cp = NULL; + if(xfr->task_probe->env) + xfr_stop_lookup(&xfr->task_probe->lookup_target, + xfr->task_probe->lookup_unique_info, + xfr->task_probe->lookup_aaaa, xfr->dclass, + xfr->task_probe->env->mesh, + &auth_xfer_probe_lookup_callback, xfr); /* we don't own this item anymore */ xfr->task_probe->worker = NULL; xfr->task_probe->env = NULL; @@ -6659,7 +6996,8 @@ xfr_probe_lookup_host(struct auth_xfer* * called straight away */ lock_basic_unlock(&xfr->lock); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, - &auth_xfer_probe_lookup_callback, xfr, 0)) { + &auth_xfer_probe_lookup_callback, xfr, 0, + &xfr->task_probe->lookup_unique_info)) { lock_basic_lock(&xfr->lock); log_err("out of memory lookup up master %s", master->host); return 0; @@ -6668,6 +7006,18 @@ xfr_probe_lookup_host(struct auth_xfer* return 1; } +/** return true if there are probe (SOA UDP query) targets in the master list*/ +static int +have_probe_targets(struct auth_master* list) +{ + struct auth_master* p; + for(p=list; p; p = p->next) { + if(!p->allow_notify && p->host) + return 1; + } + return 0; +} + /** move to sending the probe packets, next if fails. task_probe */ static void xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) @@ -6707,6 +7057,16 @@ xfr_probe_send_or_end(struct auth_xfer* verbose(VERB_ALGO, "auth zone %s probe: finished only_lookup", zname); } xfr_probe_disown(xfr); + if(!have_probe_targets(xfr->task_probe->masters)) { + /* If there are no masters to probe, go to transfer. */ + if(xfr->task_transfer->worker == NULL) { + xfr_start_transfer(xfr, env, NULL); + return; + } + /* The transfer is already in progress. */ + lock_basic_unlock(&xfr->lock); + return; + } if(xfr->task_nextprobe->worker == NULL) xfr_set_timeout(xfr, env, 0, 0); lock_basic_unlock(&xfr->lock); @@ -6756,8 +7116,7 @@ xfr_probe_send_or_end(struct auth_xfer* /** callback for task_probe lookup of host name, of A or AAAA */ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), - int ATTR_UNUSED(was_ratelimited)) + enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited)) { struct auth_xfer* xfr = (struct auth_xfer*)arg; struct module_env* env; @@ -6770,7 +7129,16 @@ void auth_xfer_probe_lookup_callback(voi } /* process result */ - if(rcode == LDNS_RCODE_NOERROR) { + if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) { + if(verbosity >= VERB_OPS) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_OPS, "auth zone %s: primary %s address probe lookup is DNSSEC bogus: %s", + zname, xfr->task_probe->lookup_target->host, + (why_bogus?why_bogus:"")); + } + /* fall through to next-lookup / next-master */ + } else if(rcode == LDNS_RCODE_NOERROR) { uint16_t wanted_qtype = LDNS_RR_TYPE_A; struct regional* temp = env->scratch; struct query_info rq; @@ -6784,21 +7152,29 @@ void auth_xfer_probe_lookup_callback(voi /* parsed successfully */ struct ub_packed_rrset_key* answer = reply_find_answer_rrset(&rq, rep); - if(answer) { + if(answer && xfer_target_equals_answer_name( + xfr->task_probe->lookup_target, answer, + &rq, rep)) { xfr_master_add_addrs(xfr->task_probe-> lookup_target, answer, wanted_qtype); + } else if(answer) { + if(verbosity >= VERB_ALGO) { + char zname[LDNS_MAX_DOMAINLEN]; + dname_str(xfr->name, zname); + verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has mismatch in answer name", zname, ((xfr->task_probe->lookup_target && xfr->task_probe->lookup_target->host) ? xfr->task_probe->lookup_target->host : "null"), (xfr->task_probe->lookup_aaaa?"AAAA":"A")); + } } else { if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has nodata", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has nodata", zname, ((xfr->task_probe->lookup_target && xfr->task_probe->lookup_target->host) ? xfr->task_probe->lookup_target->host : "null"), (xfr->task_probe->lookup_aaaa?"AAAA":"A")); } } } else { if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has no address", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has no address", zname, ((xfr->task_probe->lookup_target && xfr->task_probe->lookup_target->host) ? xfr->task_probe->lookup_target->host : "null"), (xfr->task_probe->lookup_aaaa?"AAAA":"A")); } } regional_free_all(temp); @@ -6806,10 +7182,11 @@ void auth_xfer_probe_lookup_callback(voi if(verbosity >= VERB_ALGO) { char zname[LDNS_MAX_DOMAINLEN]; dname_str(xfr->name, zname); - verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup failed", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A")); + verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup failed", zname, ((xfr->task_probe->lookup_target && xfr->task_probe->lookup_target->host) ? xfr->task_probe->lookup_target->host : "null"), (xfr->task_probe->lookup_aaaa?"AAAA":"A")); } } - if(xfr->task_probe->lookup_target->list && + if(xfr->task_probe->lookup_target && + xfr->task_probe->lookup_target->list && xfr->task_probe->lookup_target == xfr_probe_current_master(xfr)) xfr->task_probe->scan_addr = xfr->task_probe->lookup_target->list; @@ -6863,18 +7240,6 @@ auth_xfer_timer(void* arg) } } -/** return true if there are probe (SOA UDP query) targets in the master list*/ -static int -have_probe_targets(struct auth_master* list) -{ - struct auth_master* p; - for(p=list; p; p = p->next) { - if(!p->allow_notify && p->host) - return 1; - } - return 0; -} - /** start task_probe if possible, if no masters for probe start task_transfer * returns true if task has been started, and false if the task is already * in progress. */ @@ -6886,8 +7251,10 @@ xfr_start_probe(struct auth_xfer* xfr, s * progress (due to notify)) */ if(xfr->task_probe->worker == NULL) { if(!have_probe_targets(xfr->task_probe->masters) && - !(xfr->task_probe->only_lookup && - xfr->task_probe->masters != NULL)) { + xfr->task_probe->masters != NULL) + xfr->task_probe->only_lookup = 1; + if(!xfr->task_probe->only_lookup && + !have_probe_targets(xfr->task_probe->masters)) { /* useless to pick up task_probe, no masters to * probe. Instead attempt to pick up task transfer */ if(xfr->task_transfer->worker == NULL) { @@ -7090,6 +7457,8 @@ auth_xfer_new(struct auth_zone* z) xfr->namelen = z->namelen; xfr->namelabs = z->namelabs; xfr->dclass = z->dclass; + xfr->max_transfer_size = z->max_transfer_size; + xfr->max_transfer_time = z->max_transfer_time; xfr->task_nextprobe = (struct auth_nextprobe*)calloc(1, sizeof(struct auth_nextprobe)); @@ -7299,35 +7668,48 @@ xfer_set_masters(struct auth_master** li { struct auth_master* m; struct config_strlist* p; + struct auth_master** tail; /* list points to the first, or next pointer for the new element */ while(*list) { list = &( (*list)->next ); } if(with_http) for(p = c->urls; p; p = p->next) { + tail = list; m = auth_master_new(&list); if(!m) return 0; m->http = 1; - if(!parse_url(p->str, &m->host, &m->file, &m->port, &m->ssl)) + if(!parse_url(p->str, &m->host, &m->file, &m->port, &m->ssl)) { + free(m->host); + free(m->file); + free(m); + *tail = NULL; return 0; + } } for(p = c->masters; p; p = p->next) { + tail = list; m = auth_master_new(&list); if(!m) return 0; m->ixfr = 1; /* this flag is not configurable */ m->host = strdup(p->str); if(!m->host) { log_err("malloc failure"); + free(m); + *tail = NULL; return 0; } } for(p = c->allow_notify; p; p = p->next) { + tail = list; m = auth_master_new(&list); if(!m) return 0; m->allow_notify = 1; m->host = strdup(p->str); if(!m->host) { log_err("malloc failure"); + free(m); + *tail = NULL; return 0; } } @@ -7852,7 +8234,8 @@ static int zonemd_dnssec_verify_rrset(st "zonemd: verify %s RRset with DNSKEY", typestr); } sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL, - LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, reasonlen); + LDNS_SECTION_ANSWER, NULL, NULL, &verified, reasonbuf, + reasonlen); if(sec == sec_status_secure) { return 1; } @@ -8201,8 +8584,8 @@ zonemd_get_dnskey_from_anchor(struct aut auth_zone_log(z->name, VERB_QUERY, "zonemd: verify DNSKEY RRset with trust anchor"); sec = val_verify_DNSKEY_with_TA(env, ve, keystorage, anchor->ds_rrset, - anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, reasonbuf, - reasonlen); + anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, NULL, + reasonbuf, reasonlen); regional_free_all(env->scratch); if(sec == sec_status_secure) { /* success */ @@ -8262,7 +8645,7 @@ auth_zone_verify_zonemd_key_with_ds(stru keystorage->rk.rrset_class = htons(z->dclass); auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS"); sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg, - why_bogus, NULL, NULL, reasonbuf, reasonlen); + why_bogus, NULL, NULL, NULL, reasonbuf, reasonlen); regional_free_all(env->scratch); if(sec == sec_status_secure) { /* success */ @@ -8291,9 +8674,13 @@ void auth_zonemd_dnskey_lookup_callback( char reasonbuf[256]; char* reason = NULL, *ds_bogus = NULL, *typestr="DNSKEY"; struct ub_packed_rrset_key* dnskey = NULL, *ds = NULL; - int is_insecure = 0, downprot; + int is_insecure = 0, downprot, perform_write = 0; struct ub_packed_rrset_key keystorage; uint8_t sigalg[ALGO_NEEDS_MAX+1]; + uint8_t bakname[LDNS_MAX_DOMAINLEN]; + size_t baknamelen; + uint16_t bakdclass; + struct auth_chunk* chunk_list = NULL; lock_rw_wrlock(&z->lock); env = z->zonemd_callback_env; @@ -8416,7 +8803,37 @@ void auth_zonemd_dnskey_lookup_callback( auth_zone_verify_zonemd_with_key(z, env, &env->mesh->mods, dnskey, is_insecure, NULL, downprot?sigalg:NULL); regional_free_all(env->scratch); + + if(z->zonemd_callback_perform_write) { + if(!z->zone_expired) { + /* Write to zonefile if the ZONEMD is okay. */ + perform_write = 1; + /* copy the key to lookup the z structure. + * The new lookup is readonly so concurrent + * queries can continue. */ + if(z->namelen > sizeof(bakname)) { + perform_write = 0; + auth_chunk_list_delete(z->perform_write_chunk_list); + z->perform_write_chunk_list = NULL; + } else { + memcpy(bakname, z->name, z->namelen); + baknamelen = z->namelen; + bakdclass = z->dclass; + chunk_list = z->perform_write_chunk_list; + z->perform_write_chunk_list = NULL; + } + } else { + auth_chunk_list_delete(z->perform_write_chunk_list); + z->perform_write_chunk_list = NULL; + } + z->zonemd_callback_perform_write = 0; + } lock_rw_unlock(&z->lock); + + if(perform_write) { + zone_write_after_update_reacq(bakname, baknamelen, bakdclass, + env, chunk_list); + } } /** lookup DNSKEY for ZONEMD verification */ @@ -8481,8 +8898,12 @@ zonemd_lookup_dnskey(struct auth_zone* z /* the callback can be called straight away */ lock_rw_unlock(&z->lock); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, - &auth_zonemd_dnskey_lookup_callback, z, 0)) { + &auth_zonemd_dnskey_lookup_callback, z, 0, + &z->zonemd_callback_unique_info)) { lock_rw_wrlock(&z->lock); + /* no callback will run; do not leave the pending + * marker set */ + z->zonemd_callback_env = NULL; log_err("out of memory lookup of %s for zonemd", (fetch_ds?"DS":"DNSKEY")); return 0; Index: usr.sbin/unbound/services/authzone.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/authzone.h,v diff -u -p -r1.15 authzone.h --- usr.sbin/unbound/services/authzone.h 26 Sep 2025 07:32:37 -0000 1.15 +++ usr.sbin/unbound/services/authzone.h 21 Sep 2026 16:28:07 -0000 @@ -144,6 +144,12 @@ struct auth_zone { struct module_env* zonemd_callback_env; /** for the zonemd callback, the type of data looked up */ uint16_t zonemd_callback_qtype; + /** for the zonemd callback, the unique info */ + void* zonemd_callback_unique_info; + /** if the zonemd callback should write to file */ + int zonemd_callback_perform_write; + /** chunklist to write for chunked transfer. */ + struct auth_chunk* perform_write_chunk_list; /** zone has been deleted */ int zone_deleted; /** deletelist pointer, unused normally except during delete */ @@ -153,6 +159,10 @@ struct auth_zone { struct auth_zone* rpz_az_next; /** previous auth zone containing RPZ data, or NULL */ struct auth_zone* rpz_az_prev; + /** The maximum auth zone transfer size, in bytes. */ + size_t max_transfer_size; + /** The maximum auth zone transfer time taken, in msec. */ + int max_transfer_time; }; /** @@ -283,6 +293,15 @@ struct auth_xfer { * this is renewed every SOA probe and transfer. On zone load * from zonefile it is also set (with probe set soon to check) */ time_t lease_time; + + /** The maximum auth zone transfer size, in bytes. */ + size_t max_transfer_size; + /** The maximum auth zone transfer time taken, in msec. */ + int max_transfer_time; + /** the zone is an rpz zone */ + int is_rpz; + /** the number of IXFRs since the last full transfer. */ + int num_ixfrs; }; /** @@ -331,6 +350,8 @@ struct auth_probe { /** for the hostname lookups, which master is current */ struct auth_master* lookup_target; + /** for the lookup, the callback unique info */ + void* lookup_unique_info; /** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */ int lookup_aaaa; /** we only want to do lookups for making config work (for notify), @@ -379,12 +400,18 @@ struct auth_transfer { struct auth_chunk* chunks_first; /** last element in chunks list (to append new data at the end) */ struct auth_chunk* chunks_last; + /** running total of bytes held in chunks_first..chunks_last */ + size_t chunks_total; + /** start time of the transfer */ + struct timeval start_time; /** list of upstream masters for this zone, from config */ struct auth_master* masters; /** for the hostname lookups, which master is current */ struct auth_master* lookup_target; + /** for the lookup, the callback unique info */ + void* lookup_unique_info; /** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */ int lookup_aaaa; @@ -827,5 +854,11 @@ void auth_xfer_delete(struct auth_xfer* * @param worker: the worker for which to stop tasks. */ void xfr_disown_tasks(struct auth_xfer* xfr, struct worker* worker); + +/** count number of open and closed parenthesis in a chunkline */ +int chunkline_count_parens(struct sldns_buffer* buf, size_t start); + +/** Clear data in auth zone */ +void auth_zone_clear_data(struct auth_zone* z); #endif /* SERVICES_AUTHZONE_H */ Index: usr.sbin/unbound/services/listen_dnsport.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/listen_dnsport.c,v diff -u -p -r1.40 listen_dnsport.c --- usr.sbin/unbound/services/listen_dnsport.c 26 Sep 2025 07:32:37 -0000 1.40 +++ usr.sbin/unbound/services/listen_dnsport.c 21 Sep 2026 16:28:07 -0000 @@ -42,7 +42,6 @@ #ifdef HAVE_SYS_TYPES_H # include #endif -#include #include #ifdef USE_TCP_FASTOPEN #include @@ -1126,7 +1125,7 @@ make_sock_port(int stype, const char* if int use_systemd, int dscp, struct unbound_socket* ub_sock, const char* additional) { - char* s = strchr(ifname, '@'); + const char* s = strchr(ifname, '@'); if(s) { /* override port with ifspec@port */ int port; @@ -1564,7 +1563,7 @@ listen_create(struct comm_base* base, st cp = comm_point_create_udp(base, ports->fd, front->udp_buff, ports->pp2_enabled, cb, cb_arg, ports->socket); - } else if(ports->ftype == listen_type_doq) { + } else if(ports->ftype == listen_type_doq && doq_table) { #ifndef HAVE_NGTCP2 log_warn("Unbound is not compiled with " "ngtcp2. This is required to use DNS " @@ -2134,7 +2133,7 @@ void listen_start_accept(struct listen_d } struct tcp_req_info* -tcp_req_info_create(struct sldns_buffer* spoolbuf) +tcp_req_info_create(struct comm_base* base, struct sldns_buffer* spoolbuf) { struct tcp_req_info* req = (struct tcp_req_info*)malloc(sizeof(*req)); if(!req) { @@ -2142,6 +2141,12 @@ tcp_req_info_create(struct sldns_buffer* return NULL; } memset(req, 0, sizeof(*req)); + req->read_again_timer = comm_timer_create(base, tcp_read_again_cb, req); + if(!req->read_again_timer) { + log_err("malloc failure"); + free(req); + return NULL; + } req->spool_buffer = spoolbuf; return req; } @@ -2151,6 +2156,7 @@ tcp_req_info_delete(struct tcp_req_info* { if(!req) return; tcp_req_info_clear(req); + comm_timer_delete(req->read_again_timer); /* cp is pointer back to commpoint that owns this struct and * called delete on us */ /* spool_buffer is shared udp buffer, not deleted here */ @@ -2167,7 +2173,8 @@ void tcp_req_info_clear(struct tcp_req_i open = req->open_req_list; while(open) { nopen = open->next; - mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp); + mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp, + NULL, NULL); free(open); open = nopen; } @@ -2189,6 +2196,9 @@ void tcp_req_info_clear(struct tcp_req_i req->done_req_list = NULL; req->num_done_req = 0; req->read_is_closed = 0; + + if(comm_timer_is_set(req->read_again_timer)) + comm_timer_disable(req->read_again_timer); } void @@ -2300,21 +2310,8 @@ int tcp_req_info_handle_read_close(struct tcp_req_info* req) { verbose(VERB_ALGO, "tcp channel read side closed %d", req->cp->fd); - /* reset byte count for (potential) partial read */ - req->cp->tcp_byte_count = 0; - /* if we still have results to write, pick up next and write it */ - if(req->num_done_req != 0) { - tcp_req_pickup_next_result(req); - tcp_req_info_setup_listen(req); - return 1; - } - /* if nothing to do, this closes the connection */ - if(req->num_open_req == 0 && req->num_done_req == 0) - return 0; - /* otherwise, we must be waiting for dns resolve, wait with timeout */ - req->read_is_closed = 1; - tcp_req_info_setup_listen(req); - return 1; + /* RFC 7766 6.2.4 says to drop pending replies when client closes. */ + return 0; /* drop connection */ } void @@ -2884,6 +2881,7 @@ submit_http_error: sldns_buffer_flip(h2_stream->qbuffer); h2_session->postpone_drop = 1; query_read_done = http2_query_read_done(h2_session, h2_stream); + h2_session->postpone_drop = 0; if(query_read_done < 0) return NGHTTP2_ERR_CALLBACK_FAILURE; else if(!query_read_done) { @@ -2893,11 +2891,9 @@ submit_http_error: * failure will result in reclaiming (and closing) * of comm point. */ verbose(VERB_QUERY, "http2 query dropped in worker cb"); - h2_session->postpone_drop = 0; return NGHTTP2_ERR_CALLBACK_FAILURE; } /* nothing to submit right now, query added to mesh. */ - h2_session->postpone_drop = 0; return 0; } if(!http2_submit_dns_response(h2_session)) { @@ -3275,14 +3271,18 @@ nghttp2_session_callbacks* http2_req_cal struct doq_table* doq_table_create(struct config_file* cfg, struct ub_randstate* rnd) { - struct doq_table* table = calloc(1, sizeof(*table)); + struct doq_table* table; + + if (!cfg->quic_port) + return NULL; + table = calloc(1, sizeof(*table)); if(!table) return NULL; #ifdef USE_NGTCP2_CRYPTO_OSSL /* Initialize the ossl crypto, it is harmless to call twice, * and this is before use of doq connections. */ if(ngtcp2_crypto_ossl_init() != 0) { - log_err("ngtcp2_crypto_oss_init failed"); + log_err("ngtcp2_crypto_ossl_init failed"); free(table); return NULL; } @@ -3354,7 +3354,7 @@ conn_tree_del(rbnode_type* node, void* a { struct doq_table* table = (struct doq_table*)arg; struct doq_conn* conn; - if(!node) + if(!node || !table) return; conn = (struct doq_conn*)node->key; if(conn->timer.timer_in_list) { @@ -3409,13 +3409,13 @@ doq_table_delete(struct doq_table* table } struct doq_timer* -doq_timer_find_time(struct doq_table* table, struct timeval* tv) +doq_timer_find_time(struct doq_table* table, ngtcp2_tstamp ts) { struct doq_timer key; struct rbnode_type* node; + log_assert(table != NULL); memset(&key, 0, sizeof(key)); - key.time.tv_sec = tv->tv_sec; - key.time.tv_usec = tv->tv_usec; + key.time_mono = ts; node = rbtree_search(table->timer_tree, &key); if(node) return (struct doq_timer*)node->key; @@ -3463,7 +3463,7 @@ doq_timer_list_remove(struct doq_table* if(!timer->timer_in_list) return; /* The item in the rbtree has the list start and end. */ - rb_timer = doq_timer_find_time(table, &timer->time); + rb_timer = doq_timer_find_time(table, timer->time_mono); if(rb_timer) { if(timer->setlist_prev) timer->setlist_prev->setlist_next = timer->setlist_next; @@ -3509,7 +3509,8 @@ doq_timer_unset(struct doq_table* table, } void doq_timer_set(struct doq_table* table, struct doq_timer* timer, - struct doq_server_socket* worker_doq_socket, struct timeval* tv) + struct doq_server_socket* worker_doq_socket, struct timeval* tv, + ngtcp2_tstamp ts) { struct doq_timer* rb_timer; if(verbosity >= VERB_ALGO && timer->conn) { @@ -3523,14 +3524,14 @@ void doq_timer_set(struct doq_table* tab (int)rel.tv_sec, (int)rel.tv_usec); } if(timer->timer_in_tree || timer->timer_in_list) { - if(timer->time.tv_sec == tv->tv_sec && - timer->time.tv_usec == tv->tv_usec) + if(timer->time_mono == ts) return; /* already set on that time */ doq_timer_unset(table, timer); } - timer->time.tv_sec = tv->tv_sec; - timer->time.tv_usec = tv->tv_usec; - rb_timer = doq_timer_find_time(table, tv); + timer->time_real.tv_sec = tv->tv_sec; + timer->time_real.tv_usec = tv->tv_usec; + timer->time_mono = ts; + rb_timer = doq_timer_find_time(table, ts); if(rb_timer) { /* There is a timeout already with this value. Timer is * added to the setlist. */ @@ -3606,15 +3607,29 @@ doq_conn_create(struct comm_point* c, st return conn; } +/** The arguments for doq stream tree del. */ +struct doq_stream_tree_del_args { + /** The doq table. */ + struct doq_table* table; + /** The doq connection for the stream. */ + struct doq_conn* conn; +}; + /** delete stream tree node */ static void stream_tree_del(rbnode_type* node, void* arg) { - struct doq_table* table = (struct doq_table*)arg; + struct doq_stream_tree_del_args* args = (struct doq_stream_tree_del_args*)arg; + struct doq_table* table = args->table; struct doq_stream* stream; if(!node) return; stream = (struct doq_stream*)node; + if(stream->mesh_state) { + mesh_state_remove_reply(stream->mesh, stream->mesh_state, + args->conn->doq_socket->cp, NULL, stream); + stream->mesh_state = NULL; + } if(stream->in) doq_table_quic_size_subtract(table, stream->inlen); if(stream->out) @@ -3634,9 +3649,14 @@ doq_conn_delete(struct doq_conn* conn, s lock_rw_unlock(&conn->table->conid_lock); /* Remove the app data from ngtcp2 before SSL_free of conn->ssl, * because the ngtcp2 conn is deleted. */ - SSL_set_app_data(conn->ssl, NULL); + if(conn->ssl) + SSL_set_app_data(conn->ssl, NULL); if(conn->stream_tree.count != 0) { - traverse_postorder(&conn->stream_tree, stream_tree_del, table); + struct doq_stream_tree_del_args args; + memset(&args, 0, sizeof(args)); + args.table = table; + args.conn = conn; + traverse_postorder(&conn->stream_tree, stream_tree_del, &args); } free(conn->key.dcid); SSL_free(conn->ssl); @@ -3709,13 +3729,9 @@ int doq_timer_cmp(const void* key1, cons { struct doq_timer* e = (struct doq_timer*)key1; struct doq_timer* f = (struct doq_timer*)key2; - if(e->time.tv_sec < f->time.tv_sec) - return -1; - if(e->time.tv_sec > f->time.tv_sec) - return 1; - if(e->time.tv_usec < f->time.tv_usec) + if(e->time_mono < f->time_mono) return -1; - if(e->time.tv_usec > f->time.tv_usec) + if(e->time_mono > f->time_mono) return 1; return 0; } @@ -3776,7 +3792,7 @@ doq_repinfo_retrieve_localaddr(struct co memset(sa6, 0, *localaddrlen); sa6->sin6_family = AF_INET6; memmove(&sa6->sin6_addr, &repinfo->pktinfo.v6info.ipi6_addr, - *localaddrlen); + sizeof(struct in6_addr)); sa6->sin6_port = repinfo->doq_srcport; #endif } else { @@ -3786,7 +3802,7 @@ doq_repinfo_retrieve_localaddr(struct co memset(sa, 0, *localaddrlen); sa->sin_family = AF_INET; memmove(&sa->sin_addr, &repinfo->pktinfo.v4info.ipi_addr, - *localaddrlen); + sizeof(struct in_addr)); sa->sin_port = repinfo->doq_srcport; #elif defined(IP_RECVDSTADDR) struct sockaddr_in* sa = (struct sockaddr_in*)localaddr; @@ -3949,6 +3965,11 @@ doq_stream_close(struct doq_conn* conn, if(stream->is_closed) return 1; stream->is_closed = 1; + if(stream->mesh_state) { + mesh_state_remove_reply(stream->mesh, stream->mesh_state, + conn->doq_socket->cp, NULL, stream); + stream->mesh_state = NULL; + } doq_stream_off_write_list(conn, stream); if(send_shutdown) { verbose(VERB_ALGO, "doq: shutdown stream_id %d with app_error_code %d", @@ -3978,7 +3999,8 @@ doq_stream_close(struct doq_conn* conn, /** doq stream pick up answer data from buffer */ static int -doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf) +doq_stream_pickup_answer(struct doq_conn* conn, struct doq_stream* stream, + struct sldns_buffer* buf) { stream->is_answer_available = 1; if(stream->out) { @@ -3988,6 +4010,11 @@ doq_stream_pickup_answer(struct doq_stre } stream->nwrite = 0; stream->outlen = sldns_buffer_limit(buf); + if(!doq_table_quic_size_available(conn->doq_socket->table, + conn->doq_socket->cfg, stream->outlen)) { + verbose(VERB_ALGO, "doq stream: no space for reply length"); + return 0; + } /* For quic the output bytes have to stay allocated and available, * for potential resends, until the remote end has acknowledged them. * This includes the tcplen start uint16_t, in outlen_wire. */ @@ -4014,24 +4041,56 @@ doq_stream_send_reply(struct doq_conn* c if(stream->out) doq_table_quic_size_subtract(conn->doq_socket->table, stream->outlen); - if(!doq_stream_pickup_answer(stream, buf)) + if(!doq_stream_pickup_answer(conn, stream, buf)) return 0; doq_table_quic_size_add(conn->doq_socket->table, stream->outlen); doq_stream_on_write_list(conn, stream); doq_conn_write_enable(conn); return 1; } +#endif /* HAVE_NGTCP2 */ + +void +doq_stream_add_meshstate(struct doq_stream* stream, + struct mesh_area* mesh, struct mesh_state* m) +{ +#ifdef HAVE_NGTCP2 + stream->mesh = mesh; + stream->mesh_state = m; +#else + (void)stream; (void)mesh; (void)m; +#endif +} + +void +doq_stream_remove_mesh_state(struct doq_stream* stream) +{ +#ifdef HAVE_NGTCP2 + if(!stream) + return; + stream->mesh_state = NULL; +#else + (void)stream; +#endif +} +#ifdef HAVE_NGTCP2 /** doq stream data length has completed, allocations can be done. False on * allocation failure. */ static int -doq_stream_datalen_complete(struct doq_stream* stream, struct doq_table* table) +doq_stream_datalen_complete(struct doq_conn* conn, struct doq_stream* stream, + struct doq_table* table) { if(stream->inlen > 1024*1024) { log_err("doq stream in length too large %d", (int)stream->inlen); return 0; } + if(!doq_table_quic_size_available(table, conn->doq_socket->cfg, + stream->inlen)) { + verbose(VERB_ALGO, "doq stream: no space for query length"); + return 0; + } stream->in = calloc(1, stream->inlen); if(!stream->in) { log_err("doq could not read stream, calloc failed: " @@ -4076,6 +4135,7 @@ doq_stream_data_complete(struct doq_conn return 0; } c->repinfo.doq_streamid = stream->stream_id; + c->repinfo.doq_stream = stream; conn->doq_socket->current_conn = conn; fptr_ok(fptr_whitelist_comm_point(c->callback)); if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo)) { @@ -4092,8 +4152,9 @@ doq_stream_data_complete(struct doq_conn /** doq receive data for a stream, more bytes of the incoming data */ static int -doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data, - size_t datalen, int* recv_done, struct doq_table* table) +doq_stream_recv_data(struct doq_conn* conn, struct doq_stream* stream, + const uint8_t* data, size_t datalen, int* recv_done, + struct doq_table* table) { int got_data = 0; /* read the tcplength uint16_t at the start */ @@ -4114,7 +4175,7 @@ doq_stream_recv_data(struct doq_stream* if(stream->nread == 2) { /* the initial length value is completed */ stream->inlen = ntohs(tcplen); - if(!doq_stream_datalen_complete(stream, table)) + if(!doq_stream_datalen_complete(conn, stream, table)) return 0; } else { /* store for later */ @@ -4263,12 +4324,11 @@ doq_submit_new_token(struct doq_conn* co ngtcp2_ssize tokenlen; int ret; const ngtcp2_path* path = ngtcp2_conn_get_path(conn->conn); - ngtcp2_tstamp ts = doq_get_timestamp_nanosec(); tokenlen = ngtcp2_crypto_generate_regular_token(token, conn->doq_socket->static_secret, conn->doq_socket->static_secret_len, path->remote.addr, - path->remote.addrlen, ts); + path->remote.addrlen, doq_get_timestamp_nanosec()); if(tokenlen < 0) { log_err("doq ngtcp2_crypto_generate_regular_token failed"); return 1; @@ -4331,8 +4391,7 @@ doq_stream_open_cb(ngtcp2_conn* ATTR_UNU verbose(VERB_ALGO, "doq: stream with this id already exists"); return 0; } - if(stream_id != 0 && stream_id != 4 && /* allow one stream on a new connection */ - !doq_table_quic_size_available(doq_conn->doq_socket->table, + if(!doq_table_quic_size_available(doq_conn->doq_socket->table, doq_conn->doq_socket->cfg, sizeof(*stream) + 100 /* estimated query in */ + 512 /* estimated response out */ @@ -4390,8 +4449,8 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATT return 0; } if(datalen != 0) { - if(!doq_stream_recv_data(stream, data, datalen, &recv_done, - doq_conn->doq_socket->table)) + if(!doq_stream_recv_data(doq_conn, stream, data, datalen, + &recv_done, doq_conn->doq_socket->table)) return NGTCP2_ERR_CALLBACK_FAILURE; } if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) { @@ -4455,11 +4514,34 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UN "unknown stream %d", (int)stream_id); return 0; } - if(!doq_stream_close(doq_conn, stream, 0)) + if(!doq_stream_close(doq_conn, stream, 1)) return NGTCP2_ERR_CALLBACK_FAILURE; return 0; } +/** ngtcp2 extend_max_stream_data function */ +int doq_extend_max_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), + int64_t stream_id, uint64_t max_data, void* user_data, + void* ATTR_UNUSED(stream_user_data)) +{ + struct doq_conn* doq_conn = (struct doq_conn*)user_data; + struct doq_stream* stream; + verbose(VERB_ALGO, "doq extend_max_stream_data stream id %d " + "max_data %d ", (int)stream_id, (int)max_data); + if(max_data == 0) + return 0; + stream = doq_stream_find(doq_conn, stream_id); + if(!stream) { + verbose(VERB_ALGO, "doq: unknown stream %d", (int)stream_id); + return 0; + } + if(!stream->is_answer_available) + return 0; + doq_stream_on_write_list(doq_conn, stream); + doq_conn_write_enable(doq_conn); + return 0; +} + /** ngtcp2 acked_stream_data_offset callback function */ static int doq_acked_stream_data_offset_cb(ngtcp2_conn* ATTR_UNUSED(conn), @@ -4780,7 +4862,7 @@ doq_ssl_server_setup(SSL_CTX* ctx, struc SSL_set_app_data(ssl, conn); #endif SSL_set_accept_state(ssl); -#ifdef USE_NGTCP2_CRYPTO_OSSL +#ifdef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED SSL_set_quic_tls_early_data_enabled(ssl, 1); #else SSL_set_quic_early_data_enabled(ssl, 1); @@ -4834,6 +4916,7 @@ doq_conn_setup(struct doq_conn* conn, ui callbacks.stream_open = doq_stream_open_cb; callbacks.stream_close = doq_stream_close_cb; callbacks.stream_reset = doq_stream_reset_cb; + callbacks.extend_max_stream_data = doq_extend_max_stream_data_cb; callbacks.acked_stream_data_offset = doq_acked_stream_data_offset_cb; callbacks.recv_stream_data = doq_recv_stream_data_cb; @@ -4888,6 +4971,7 @@ doq_conn_setup(struct doq_conn* conn, ui rv = ngtcp2_conn_server_new(&conn->conn, &scid_cid, &sv_scid, &path, conn->version, &callbacks, &settings, ¶ms, NULL, conn); if(rv != 0) { + conn->conn = NULL; lock_rw_unlock(&conn->table->conid_lock); log_err("ngtcp2_conn_server_new failed: %s", ngtcp2_strerror(rv)); @@ -4922,6 +5006,7 @@ doq_conid_find(struct doq_table* table, key.node.key = &key; key.cid = (void*)data; key.cidlen = datalen; + log_assert(table != NULL); node = rbtree_search(table->conid_tree, &key); if(node) return (struct doq_conid*)node->key; @@ -5109,23 +5194,30 @@ doq_conn_clear_conids(struct doq_conn* c ngtcp2_tstamp doq_get_timestamp_nanosec(void) { -#ifdef CLOCK_REALTIME struct timespec tp; memset(&tp, 0, sizeof(tp)); - /* Get a nanosecond time, that can be compared with the event base. */ - if(clock_gettime(CLOCK_REALTIME, &tp) == -1) { - log_err("clock_gettime failed: %s", strerror(errno)); +#ifdef CLOCK_BOOTTIME + if(clock_gettime(CLOCK_BOOTTIME, &tp) == -1) { +#endif + if(clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { + log_err("clock_gettime failed: %s", strerror(errno)); + } +#ifdef CLOCK_BOOTTIME } +#endif return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) + ((uint64_t)tp.tv_nsec); -#else +} + +static struct timeval doq_get_timevalue(void) +{ struct timeval tv; + memset(&tv, 0, sizeof(tv)); if(gettimeofday(&tv, NULL) < 0) { log_err("gettimeofday failed: %s", strerror(errno)); + memset(&tv, 0, sizeof(tv)); } - return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) + - ((uint64_t)tv.tv_usec)*((uint64_t)1000); -#endif /* CLOCK_REALTIME */ + return tv; } /** doq start the closing period for the connection. */ @@ -5248,18 +5340,17 @@ doq_conn_recv(struct comm_point* c, stru int* err_drop) { int ret; - ngtcp2_tstamp ts; struct ngtcp2_path path; memset(&path, 0, sizeof(path)); path.remote.addr = (struct sockaddr*)&paddr->addr; path.remote.addrlen = paddr->addrlen; path.local.addr = (struct sockaddr*)&paddr->localaddr; path.local.addrlen = paddr->localaddrlen; - ts = doq_get_timestamp_nanosec(); ret = ngtcp2_conn_read_pkt(conn->conn, &path, pi, sldns_buffer_begin(c->doq_socket->pkt_buf), - sldns_buffer_limit(c->doq_socket->pkt_buf), ts); + sldns_buffer_limit(c->doq_socket->pkt_buf), + doq_get_timestamp_nanosec()); if(ret != 0) { if(err_retry) *err_retry = 0; @@ -5347,7 +5438,6 @@ doq_conn_write_streams(struct comm_point { struct doq_stream* stream = conn->stream_write_first; ngtcp2_path_storage ps; - ngtcp2_tstamp ts = doq_get_timestamp_nanosec(); size_t num_packets = 0, max_packets = 65535; ngtcp2_path_storage_zero(&ps); @@ -5400,7 +5490,8 @@ doq_conn_write_streams(struct comm_point ret = ngtcp2_conn_writev_stream(conn->conn, &ps.path, &pi, sldns_buffer_begin(c->doq_socket->pkt_buf), sldns_buffer_remaining(c->doq_socket->pkt_buf), - &ndatalen, flags, stream_id, datav, datav_count, ts); + &ndatalen, flags, stream_id, datav, datav_count, + doq_get_timestamp_nanosec()); if(ret < 0) { if(ret == NGTCP2_ERR_WRITE_MORE) { verbose(VERB_ALGO, "doq: write more, ndatalen %d", (int)ndatalen); @@ -5415,26 +5506,20 @@ doq_conn_write_streams(struct comm_point continue; } else if(ret == NGTCP2_ERR_STREAM_DATA_BLOCKED) { verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_DATA_BLOCKED"); -#ifdef HAVE_NGTCP2_CCERR_DEFAULT - ngtcp2_ccerr_set_application_error( - &conn->ccerr, -1, NULL, 0); -#else - ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0); -#endif - if(err_drop) - *err_drop = 0; - if(!doq_conn_close_error(c, conn)) { - if(err_drop) - *err_drop = 1; + if(stream) { + doq_stream_off_write_list(conn, stream); + stream = stream->write_next; + continue; + } else { + break; } - return 0; } else if(ret == NGTCP2_ERR_STREAM_SHUT_WR) { verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_SHUT_WR"); #ifdef HAVE_NGTCP2_CCERR_DEFAULT ngtcp2_ccerr_set_application_error( - &conn->ccerr, -1, NULL, 0); + &conn->ccerr, DOQ_APP_ERROR_CODE, NULL, 0); #else - ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0); + ngtcp2_connection_close_error_set_application_error(&conn->last_error, DOQ_APP_ERROR_CODE, NULL, 0); #endif if(err_drop) *err_drop = 0; @@ -5472,7 +5557,8 @@ doq_conn_write_streams(struct comm_point if(ret == 0) { /* congestion limited */ doq_conn_write_disable(conn); - ngtcp2_conn_update_pkt_tx_time(conn->conn, ts); + ngtcp2_conn_update_pkt_tx_time(conn->conn, + doq_get_timestamp_nanosec()); return 1; } sldns_buffer_set_position(c->doq_socket->pkt_buf, ret); @@ -5486,7 +5572,7 @@ doq_conn_write_streams(struct comm_point if(stream) stream = stream->write_next; } - ngtcp2_conn_update_pkt_tx_time(conn->conn, ts); + ngtcp2_conn_update_pkt_tx_time(conn->conn, doq_get_timestamp_nanosec()); return 1; } @@ -5563,32 +5649,35 @@ doq_table_pop_first(struct doq_table* ta } int -doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv) +doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, ngtcp2_tstamp* ts) { - ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(conn->conn); - ngtcp2_tstamp now = doq_get_timestamp_nanosec(); + ngtcp2_tstamp doq_expiry = ngtcp2_conn_get_expiry(conn->conn); + ngtcp2_tstamp doq_now = doq_get_timestamp_nanosec(); ngtcp2_tstamp t; + struct timeval now = doq_get_timevalue(); - if(expiry <= now) { + if(doq_expiry <= doq_now || doq_expiry == UINT64_MAX) { + /* UINT64_MAX means there is no next expiry. */ /* The timer has already expired, add with zero timeout. * This should call the callback straight away. Calling it * from the event callbacks is cleaner than calling it here, * because then it is always called with the same locks and * so on. This routine only has the conn.lock. */ - t = now; + t = doq_now; + memcpy(tv, &now, sizeof(*tv)); } else { - t = expiry; + t = doq_expiry; + memset(tv, 0, sizeof(*tv)); + tv->tv_sec = (doq_expiry - doq_now) / NGTCP2_SECONDS; + tv->tv_usec = ((doq_expiry - doq_now) / NGTCP2_MICROSECONDS)%1000000; + timeval_add(tv, &now); } - /* convert to timeval */ - memset(tv, 0, sizeof(*tv)); - tv->tv_sec = t / NGTCP2_SECONDS; - tv->tv_usec = (t / NGTCP2_MICROSECONDS)%1000000; + *ts = t; /* If we already have a timer, is it the right value? */ if(conn->timer.timer_in_tree || conn->timer.timer_in_list) { - if(conn->timer.time.tv_sec == tv->tv_sec && - conn->timer.time.tv_usec == tv->tv_usec) + if(conn->timer.time_mono == *ts) return 0; } return 1; @@ -5609,13 +5698,12 @@ doq_conn_log_line(struct doq_conn* conn, int doq_conn_handle_timeout(struct doq_conn* conn) { - ngtcp2_tstamp now = doq_get_timestamp_nanosec(); int rv; if(verbosity >= VERB_ALGO) doq_conn_log_line(conn, "timeout"); - rv = ngtcp2_conn_handle_expiry(conn->conn, now); + rv = ngtcp2_conn_handle_expiry(conn->conn, doq_get_timestamp_nanosec()); if(rv != 0) { verbose(VERB_ALGO, "ngtcp2_conn_handle_expiry failed: %s", ngtcp2_strerror(rv)); @@ -5662,6 +5750,8 @@ doq_table_quic_size_available(struct doq struct config_file* cfg, size_t mem) { size_t cur; + if (!table) + return 0; lock_basic_lock(&table->size_lock); cur = table->current_size; lock_basic_unlock(&table->size_lock); Index: usr.sbin/unbound/services/listen_dnsport.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/listen_dnsport.h,v diff -u -p -r1.23 listen_dnsport.h --- usr.sbin/unbound/services/listen_dnsport.h 26 Sep 2025 07:32:37 -0000 1.23 +++ usr.sbin/unbound/services/listen_dnsport.h 21 Sep 2026 16:28:07 -0000 @@ -61,6 +61,8 @@ struct config_file; struct addrinfo; struct sldns_buffer; struct tcl_list; +struct mesh_area; +struct mesh_state; /** * Listening for queries structure. @@ -345,6 +347,10 @@ struct tcp_req_info { int num_done_req; /** list of pending writable result packets, malloced one at a time */ struct tcp_req_done_item* done_req_list; + /** the read again timer, when the number of pipelined TCP queries + * is large, it waits, zero time, for a new event loop to service + * the remainder of the TCP traffic on the fd. */ + struct comm_timer* read_again_timer; }; /** @@ -375,10 +381,12 @@ struct tcp_req_done_item { * Create tcp request info structure that keeps track of open * requests on the TCP channel that are resolved at the same time, * and the pending results that have to get written back to that client. + * @param base: comm base for read again timer. * @param spoolbuf: shared buffer * @return new structure or NULL on alloc failure. */ -struct tcp_req_info* tcp_req_info_create(struct sldns_buffer* spoolbuf); +struct tcp_req_info* tcp_req_info_create(struct comm_base* base, + struct sldns_buffer* spoolbuf); /** * Delete tcp request structure. Called by owning commpoint. @@ -538,8 +546,11 @@ void doq_table_delete(struct doq_table* struct doq_timer { /** The rbnode in the tree sorted by timeout value. Key this struct. */ struct rbnode_type node; + /** The timeout value. Monotonic value used with ngtcp2. + * This time value is used for the tree operations. */ + ngtcp2_tstamp time_mono; /** The timeout value. Absolute time value. */ - struct timeval time; + struct timeval time_real; /** If the timer is in the time tree, with the node. */ int timer_in_tree; /** If there are more timers with the exact same timeout value, @@ -689,6 +700,11 @@ struct doq_stream { uint8_t* out; /** if the stream is on the write list */ uint8_t on_write_list; + /** The mesh area and mesh state, set when this stream's query was + * dispatched into the mesh; used to detach the reply on stream close */ + struct mesh_area* mesh; + /** the mesh state for the query, is nonNULL when there is one. */ + struct mesh_state* mesh_state; /** the prev and next on the write list, if on the list */ struct doq_stream* write_prev, *write_next; }; @@ -791,7 +807,16 @@ int doq_stream_close(struct doq_conn* co /** send reply for a connection */ int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream, struct sldns_buffer* buf); +#endif /* HAVE_NGTCP2 */ +/** add mesh state to doq stream */ +void doq_stream_add_meshstate(struct doq_stream* stream, + struct mesh_area* mesh, struct mesh_state* m); + +/** remove mesh state from doq stream */ +void doq_stream_remove_mesh_state(struct doq_stream* stream); + +#ifdef HAVE_NGTCP2 /** the connection has write interest, wants to write packets */ void doq_conn_write_enable(struct doq_conn* conn); @@ -813,10 +838,12 @@ struct doq_conn* doq_table_pop_first(str * doq check if the timer for the conn needs to be changed. * @param conn: connection, caller must hold lock on it. * @param tv: time value, absolute time, returned. + * @param ts: time stamp, absolute time, returned. * @return true if timer needs to be set to tv, false if no change is needed * to the timer. The timer is already set to the right time in that case. */ -int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv); +int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, + ngtcp2_tstamp* ts); /** doq remove timer from tree */ void doq_timer_tree_remove(struct doq_table* table, struct doq_timer* timer); @@ -829,11 +856,12 @@ void doq_timer_unset(struct doq_table* t /** doq set the timer and add it. */ void doq_timer_set(struct doq_table* table, struct doq_timer* timer, - struct doq_server_socket* worker_doq_socket, struct timeval* tv); + struct doq_server_socket* worker_doq_socket, struct timeval* tv, + ngtcp2_tstamp ts); /** doq find a timeout in the timer tree */ struct doq_timer* doq_timer_find_time(struct doq_table* table, - struct timeval* tv); + ngtcp2_tstamp ts); /** doq handle timeout for a connection. Pass conn locked. Returns false for * deletion. */ @@ -851,6 +879,9 @@ int doq_table_quic_size_available(struct /** doq get the quic size value */ size_t doq_table_quic_size_get(struct doq_table* table); + +/** get a timestamp in nanoseconds */ +ngtcp2_tstamp doq_get_timestamp_nanosec(void); #endif /* HAVE_NGTCP2 */ char* set_ip_dscp(int socket, int addrfamily, int ds); @@ -866,8 +897,4 @@ void doq_client_event_cb(int fd, short e /** timer event callback for testcode/doqclient */ void doq_client_timer_cb(int fd, short event, void* arg); -#ifdef HAVE_NGTCP2 -/** get a timestamp in nanoseconds */ -ngtcp2_tstamp doq_get_timestamp_nanosec(void); -#endif #endif /* LISTEN_DNSPORT_H */ Index: usr.sbin/unbound/services/localzone.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/localzone.c,v diff -u -p -r1.24 localzone.c --- usr.sbin/unbound/services/localzone.c 31 Aug 2025 21:41:09 -0000 1.24 +++ usr.sbin/unbound/services/localzone.c 21 Sep 2026 16:28:08 -0000 @@ -56,6 +56,24 @@ * with 16 bytes for an A record, a 64K packet has about 4000 max */ #define LOCALZONE_RRSET_COUNT_MAX 4096 +static const char* default_zones_reverse_array[] = { + "127.in-addr.arpa.", /* reverse ip4 zone */ + "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", /* reverse ip6 zone */ + 0 +}; +const char** local_zones_default_reverse = default_zones_reverse_array; + +static const char* default_zones_special_array[] = { + "test.", /* RFC 6761 */ + "invalid.", /* RFC 6761 */ + "onion.", /* RFC 7686 */ + "home.arpa.", /* RFC 8375 */ + "resolver.arpa.", /* RFC 9462 */ + "service.arpa.", /* RFC 9665 */ + 0 +}; +const char** local_zones_default_special = default_zones_special_array; + /** print all RRsets in local zone */ static void local_zone_out(struct local_zone* z) @@ -368,8 +386,6 @@ new_local_rrset(struct regional* region, log_err("out of memory"); return NULL; } - rrset->next = node->rrsets; - node->rrsets = rrset; rrset->rrset = (struct ub_packed_rrset_key*) regional_alloc_zero(region, sizeof(*rrset->rrset)); if(!rrset->rrset) { @@ -390,6 +406,8 @@ new_local_rrset(struct regional* region, rrset->rrset->rk.dname_len = node->namelen; rrset->rrset->rk.type = htons(rrtype); rrset->rrset->rk.rrset_class = htons(rrclass); + rrset->next = node->rrsets; + node->rrsets = rrset; return rrset; } @@ -413,6 +431,10 @@ rrset_insert_rr(struct regional* region, pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count); pd->rr_data = regional_alloc(region, sizeof(*pd->rr_data)*pd->count); if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) { + pd->count--; + pd->rr_len = oldlen; + pd->rr_ttl = oldttl; + pd->rr_data = olddata; log_err("out of memory"); return 0; } @@ -428,6 +450,10 @@ rrset_insert_rr(struct regional* region, pd->rr_ttl[0] = ttl; pd->rr_data[0] = regional_alloc_init(region, rdata, rdata_len); if(!pd->rr_data[0]) { + pd->count--; + pd->rr_len = oldlen; + pd->rr_ttl = oldttl; + pd->rr_data = olddata; log_err("out of memory"); return 0; } @@ -650,10 +676,12 @@ lz_enter_rr_str(struct local_zones* zone } labs = dname_count_size_labels(rr_name, &len); lock_rw_rdlock(&zones->lock); - z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type); + z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type, 1); if(!z) { lock_rw_unlock(&zones->lock); - fatal_exit("internal error: no zone for rr %s", rr); + log_err("internal error: no zone for rr %s", rr); + free(rr_name); + return 0; } lock_rw_wrlock(&z->lock); lock_rw_unlock(&zones->lock); @@ -834,7 +862,7 @@ lz_nodefault(struct config_file* cfg, co for(p = cfg->local_zones_nodefault; p; p = p->next) { /* compare zone name, lowercase, compare without ending . */ - if(strncasecmp(p->str, name, len) == 0 && + if(strncasecmp(p->str, name, len) == 0 && (strlen(p->str) == len || (strlen(p->str)==len+1 && p->str[len] == '.'))) return 1; @@ -842,6 +870,45 @@ lz_nodefault(struct config_file* cfg, co return 0; } +/** enter reverse default zone */ +static int +add_reverse_default(struct local_zones* zones, struct config_file* cfg, + const char* name) +{ + struct local_zone* z; + char str[1024]; /* known long enough */ + if(lz_exists(zones, name) || lz_nodefault(cfg, name)) + return 1; /* do not enter default content */ + if(!(z=lz_enter_zone(zones, name, "static", LDNS_RR_CLASS_IN))) + return 0; + snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. " + "nobody.invalid. 1 3600 1200 604800 10800", name); + if(!lz_enter_rr_into_zone(z, str)) { + lock_rw_unlock(&z->lock); + return 0; + } + snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name); + if(!lz_enter_rr_into_zone(z, str)) { + lock_rw_unlock(&z->lock); + return 0; + } + if(strncasecmp("127.in-addr.arpa.", name, 17) == 0) { + if(!lz_enter_rr_into_zone(z, + "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) { + lock_rw_unlock(&z->lock); + return 0; + } + } else if(strncasecmp("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", name, 73) == 0) { + snprintf(str, sizeof(str), "%s 10800 IN PTR localhost.", name); + if(!lz_enter_rr_into_zone(z, str)) { + lock_rw_unlock(&z->lock); + return 0; + } + } + lock_rw_unlock(&z->lock); + return 1; +} + /** enter (AS112) empty default zone */ static int add_empty_default(struct local_zones* zones, struct config_file* cfg, @@ -902,72 +969,23 @@ int local_zone_enter_defaults(struct loc } lock_rw_unlock(&z->lock); } - /* reverse ip4 zone */ - if(!lz_exists(zones, "127.in-addr.arpa.") && - !lz_nodefault(cfg, "127.in-addr.arpa.")) { - if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static", - LDNS_RR_CLASS_IN)) || - !lz_enter_rr_into_zone(z, - "127.in-addr.arpa. 10800 IN NS localhost.") || - !lz_enter_rr_into_zone(z, - "127.in-addr.arpa. 10800 IN SOA localhost. " - "nobody.invalid. 1 3600 1200 604800 10800") || - !lz_enter_rr_into_zone(z, - "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) { + + /* ip4 and ip6 reverse */ + for(zstr = local_zones_default_reverse; *zstr; zstr++) { + if(!add_reverse_default(zones, cfg, *zstr)) { log_err("out of memory adding default zone"); - if(z) { lock_rw_unlock(&z->lock); } return 0; } - lock_rw_unlock(&z->lock); } - /* reverse ip6 zone */ - if(!lz_exists(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") && - !lz_nodefault(cfg, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.")) { - if(!(z=lz_enter_zone(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", "static", - LDNS_RR_CLASS_IN)) || - !lz_enter_rr_into_zone(z, - "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN NS localhost.") || - !lz_enter_rr_into_zone(z, - "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN SOA localhost. " - "nobody.invalid. 1 3600 1200 604800 10800") || - !lz_enter_rr_into_zone(z, - "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN PTR localhost.")) { + + /* special-use zones */ + for(zstr = local_zones_default_special; *zstr; zstr++) { + if(!add_empty_default(zones, cfg, *zstr)) { log_err("out of memory adding default zone"); - if(z) { lock_rw_unlock(&z->lock); } return 0; } - lock_rw_unlock(&z->lock); - } - /* home.arpa. zone (RFC 8375) */ - if(!add_empty_default(zones, cfg, "home.arpa.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* resolver.arpa. zone (RFC 9462) */ - if(!add_empty_default(zones, cfg, "resolver.arpa.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* service.arpa. zone (draft-ietf-dnssd-srp-25) */ - if(!add_empty_default(zones, cfg, "service.arpa.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* onion. zone (RFC 7686) */ - if(!add_empty_default(zones, cfg, "onion.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* test. zone (RFC 6761) */ - if(!add_empty_default(zones, cfg, "test.")) { - log_err("out of memory adding default zone"); - return 0; - } - /* invalid. zone (RFC 6761) */ - if(!add_empty_default(zones, cfg, "invalid.")) { - log_err("out of memory adding default zone"); - return 0; } + /* block AS112 zones, unless asked not to */ if(!cfg->unblock_lan_zones) { for(zstr = as112_zones; *zstr; zstr++) { @@ -998,23 +1016,23 @@ static struct local_zone* find_closest_p struct local_zone* prev) { struct local_zone* p; - int m; + int m; if(!prev || prev->dclass != curr->dclass) return NULL; (void)dname_lab_cmp(prev->name, prev->namelabs, curr->name, curr->namelabs, &m); /* we know prev is smaller */ - /* sort order like: . com. bla.com. zwb.com. net. */ - /* find the previous, or parent-parent-parent */ + /* sort order like: . com. bla.com. zwb.com. net. */ + /* find the previous, or parent-parent-parent */ for(p = prev; p; p = p->parent) { - /* looking for name with few labels, a parent */ - if(p->namelabs <= m) { - /* ==: since prev matched m, this is closest*/ - /* <: prev matches more, but is not a parent, - * this one is a (grand)parent */ + /* looking for name with few labels, a parent */ + if(p->namelabs <= m) { + /* ==: since prev matched m, this is closest*/ + /* <: prev matches more, but is not a parent, + * this one is a (grand)parent */ return p; } } return NULL; - } +} /** setup parent pointers, so that a lookup can be done for closest match */ void @@ -1029,7 +1047,7 @@ lz_init_parents(struct local_zones* zone if(node->override_tree) addr_tree_init_parents(node->override_tree); lock_rw_unlock(&node->lock); - } + } lock_rw_unlock(&zones->lock); } @@ -1062,14 +1080,15 @@ lz_setup_implicit(struct local_zones* zo labs = dname_count_size_labels(rr_name, &len); lock_rw_rdlock(&zones->lock); if(!local_zones_lookup(zones, rr_name, len, labs, rr_class, - rr_type)) { + rr_type, 1)) { /* Check if there is a zone that this could go * under but for different class; created zones are * always for LDNS_RR_CLASS_IN. Create the zone with * a different class but the same configured * local_zone_type. */ struct local_zone* z = local_zones_lookup(zones, - rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type); + rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type, + 1); if(z) { uint8_t* name = memdup(z->name, z->namelen); size_t znamelen = z->namelen; @@ -1231,28 +1250,48 @@ local_zones_apply_cfg(struct local_zones struct local_zone* local_zones_lookup(struct local_zones* zones, - uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype) + uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype, + int foradd) { return local_zones_tags_lookup(zones, name, len, labs, - dclass, dtype, NULL, 0, 1); + dclass, dtype, NULL, 0, 1, foradd); } struct local_zone* local_zones_tags_lookup(struct local_zones* zones, uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype, - uint8_t* taglist, size_t taglen, int ignoretags) + uint8_t* taglist, size_t taglen, int ignoretags, int foradd) { rbnode_type* res = NULL; struct local_zone *result; struct local_zone key; int m; + key.node.key = &key; + key.dclass = dclass; /* for type DS use a zone higher when on a zonecut */ if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) { - dname_remove_label(&name, &len); - labs--; + /* If this is at a zone cut, of a local-zone, and it is + * of type always_refuse. Then also refuse the type DS + * for it. That could make it DNSSEC bogus, but it is + * REFUSED anyway. It stops CNAME type answers in the + * type DS lookup. */ + key.name = name; + key.namelen = len; + key.namelabs = labs; + /* For additions and removals, use the ordinary rule, + * to remove a label for type DS to locate the parent zone. + * That is where the DS RR needs to be put. */ + if(!foradd && + (result=(struct local_zone*)rbtree_search( + &zones->ztree, &key)) != NULL && + result->type == local_zone_always_refuse) { + /* The type DS does not go up one label. */ + return result; + } else { + dname_remove_label(&name, &len); + labs--; + } } - key.node.key = &key; - key.dclass = dclass; key.name = name; key.namelen = len; key.namelabs = labs; @@ -1471,8 +1510,10 @@ find_tag_datas(struct query_info* qinfo, return 0; /* out of memory */ qinfo->local_alias->rrset = regional_alloc_init(temp, r, sizeof(*r)); - if(!qinfo->local_alias->rrset) + if(!qinfo->local_alias->rrset) { + qinfo->local_alias = NULL; return 0; /* out of memory */ + } } return result; } @@ -1538,13 +1579,17 @@ local_data_answer(struct local_zone* z, return 0; /* out of memory */ qinfo->local_alias->rrset = regional_alloc_init( temp, lr->rrset, sizeof(*lr->rrset)); - if(!qinfo->local_alias->rrset) + if(!qinfo->local_alias->rrset) { + qinfo->local_alias = NULL; return 0; /* out of memory */ + } qinfo->local_alias->rrset->rk.dname = qinfo->qname; qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len; get_cname_target(lr->rrset, &ctarget, &ctargetlen); - if(!ctargetlen) + if(!ctargetlen) { + qinfo->local_alias = NULL; return 0; /* invalid cname */ + } if(dname_is_wild(ctarget)) { /* synthesize cname target */ struct packed_rrset_data* d, *lr_d; @@ -1573,8 +1618,10 @@ local_data_answer(struct local_zone* z, sizeof(struct packed_rrset_data) + sizeof(size_t) + sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t) + newtargetlen); - if(!d) + if(!d) { + qinfo->local_alias = NULL; return 0; /* out of memory */ + } lr_d = (struct packed_rrset_data*)lr->rrset->entry.data; qinfo->local_alias->rrset->entry.data = d; d->ttl = lr_d->rr_ttl[0]; /* RFC6672-like behavior: @@ -1621,7 +1668,7 @@ local_zone_does_not_cover(struct local_z struct local_data key; struct local_data* ld = NULL; struct local_rrset* lr = NULL; - if(z->type == local_zone_always_transparent || z->type == local_zone_block_a) + if(z->type == local_zone_always_transparent || z->type == local_zone_block_a || z->type == local_zone_block_aaaa) return 1; if(z->type != local_zone_transparent && z->type != local_zone_typetransparent @@ -1632,7 +1679,9 @@ local_zone_does_not_cover(struct local_z key.namelen = qinfo->qname_len; key.namelabs = labs; ld = (struct local_data*)rbtree_search(&z->data, &key.node); - if(z->type == local_zone_transparent || z->type == local_zone_inform) + if(z->type == local_zone_transparent || z->type == local_zone_inform + || z->type == local_zone_block_a_wdata + || z->type == local_zone_block_aaaa_wdata) return (ld == NULL); if(ld) lr = local_data_find_type(ld, qinfo->qtype, 1); @@ -1698,7 +1747,8 @@ local_zones_zone_answer(struct local_zon || lz_type == local_zone_always_transparent) { /* no NODATA or NXDOMAINS for this zone type */ return 0; - } else if(lz_type == local_zone_block_a) { + } else if(lz_type == local_zone_block_a || + lz_type == local_zone_block_a_wdata) { /* Return NODATA for all A queries */ if(qinfo->qtype == LDNS_RR_TYPE_A) { local_error_encode(qinfo, env, edns, repinfo, buf, temp, @@ -1708,6 +1758,17 @@ local_zones_zone_answer(struct local_zon } return 0; + } else if(lz_type == local_zone_block_aaaa || + lz_type == local_zone_block_aaaa_wdata) { + /* Return NODATA for all AAAA queries */ + if(qinfo->qtype == LDNS_RR_TYPE_AAAA) { + local_error_encode(qinfo, env, edns, repinfo, buf, temp, + LDNS_RCODE_NOERROR, (LDNS_RCODE_NOERROR|BIT_AA), + LDNS_EDE_NONE, NULL); + return 1; + } + + return 0; } else if(lz_type == local_zone_always_null) { /* 0.0.0.0 or ::0 or noerror/nodata for this zone type, * used for blocklists. */ @@ -1863,7 +1924,7 @@ local_zones_answer(struct local_zones* z if(view->local_zones && (z = local_zones_lookup(view->local_zones, qinfo->qname, qinfo->qname_len, labs, - qinfo->qclass, qinfo->qtype))) { + qinfo->qclass, qinfo->qtype, 0))) { lock_rw_rdlock(&z->lock); lzt = z->type; } @@ -1875,7 +1936,10 @@ local_zones_answer(struct local_zones* z lzt == local_zone_typetransparent || lzt == local_zone_inform || lzt == local_zone_always_transparent || - lzt == local_zone_block_a) && + lzt == local_zone_block_a || + lzt == local_zone_block_aaaa || + lzt == local_zone_block_a_wdata || + lzt == local_zone_block_aaaa_wdata) && local_zone_does_not_cover(z, qinfo, labs)) { lock_rw_unlock(&z->lock); z = NULL; @@ -1897,7 +1961,7 @@ local_zones_answer(struct local_zones* z lock_rw_rdlock(&zones->lock); if(!(z = local_zones_tags_lookup(zones, qinfo->qname, qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype, - taglist, taglen, 0))) { + taglist, taglen, 0, 0))) { lock_rw_unlock(&zones->lock); return 0; } @@ -1924,6 +1988,7 @@ local_zones_answer(struct local_zones* z if(lzt != local_zone_always_refuse && lzt != local_zone_always_transparent && lzt != local_zone_block_a + && lzt != local_zone_block_aaaa && lzt != local_zone_always_nxdomain && lzt != local_zone_always_nodata && lzt != local_zone_always_deny @@ -1955,6 +2020,9 @@ const char* local_zone_type2str(enum loc case local_zone_inform_redirect: return "inform_redirect"; case local_zone_always_transparent: return "always_transparent"; case local_zone_block_a: return "block_a"; + case local_zone_block_aaaa: return "block_aaaa"; + case local_zone_block_a_wdata: return "block_a_wdata"; + case local_zone_block_aaaa_wdata: return "block_aaaa_wdata"; case local_zone_always_refuse: return "always_refuse"; case local_zone_always_nxdomain: return "always_nxdomain"; case local_zone_always_nodata: return "always_nodata"; @@ -1991,6 +2059,12 @@ int local_zone_str2type(const char* type *t = local_zone_always_transparent; else if(strcmp(type, "block_a") == 0) *t = local_zone_block_a; + else if(strcmp(type, "block_aaaa") == 0) + *t = local_zone_block_aaaa; + else if(strcmp(type, "block_a_wdata") == 0) + *t = local_zone_block_a_wdata; + else if(strcmp(type, "block_aaaa_wdata") == 0) + *t = local_zone_block_aaaa_wdata; else if(strcmp(type, "always_refuse") == 0) *t = local_zone_always_refuse; else if(strcmp(type, "always_nxdomain") == 0) @@ -2102,7 +2176,8 @@ local_zones_add_RR(struct local_zones* z /* could first try readlock then get writelock if zone does not exist, * but we do not add enough RRs (from multiple threads) to optimize */ lock_rw_wrlock(&zones->lock); - z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type); + z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type, + 1); if(!z) { z = local_zones_add_zone(zones, rr_name, len, labs, rr_class, local_zone_transparent); @@ -2180,7 +2255,8 @@ void local_zones_del_data(struct local_z /* remove DS */ lock_rw_rdlock(&zones->lock); - z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS); + z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS, + 1); if(z) { lock_rw_wrlock(&z->lock); d = local_zone_find_data(z, name, len, labs); @@ -2194,7 +2270,7 @@ void local_zones_del_data(struct local_z /* remove other types */ lock_rw_rdlock(&zones->lock); - z = local_zones_lookup(zones, name, len, labs, dclass, 0); + z = local_zones_lookup(zones, name, len, labs, dclass, 0, 1); if(!z) { /* no such zone, we're done */ lock_rw_unlock(&zones->lock); Index: usr.sbin/unbound/services/localzone.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/localzone.h,v diff -u -p -r1.14 localzone.h --- usr.sbin/unbound/services/localzone.h 31 Aug 2025 21:41:09 -0000 1.14 +++ usr.sbin/unbound/services/localzone.h 21 Sep 2026 16:28:08 -0000 @@ -57,6 +57,9 @@ struct sldns_buffer; struct comm_reply; struct config_strlist; +extern const char** local_zones_default_special; +extern const char** local_zones_default_reverse; + /** * Local zone type * This type determines processing for queries that did not match @@ -90,6 +93,12 @@ enum localzone_type { local_zone_always_transparent, /** resolve normally, even when there is local data but return NODATA for A queries */ local_zone_block_a, + /** resolve normally, even when there is local data, but return NODATA for AAAA queries */ + local_zone_block_aaaa, + /** resolve normally, use local data, else return NODATA for A queries */ + local_zone_block_a_wdata, + /** resolve normally, use local data, else return NODATA for AAAA queries */ + local_zone_block_aaaa_wdata, /** answer with error, even when there is local data */ local_zone_always_refuse, /** answer with nxdomain, even when there is local data */ @@ -262,11 +271,13 @@ void local_zone_delete(struct local_zone * @param taglen: length of taglist. * @param ignoretags: lookup zone by name and class, regardless the * local-zone's tags. + * @param foradd: if the lookup is for addition or removal of the type. + * Used for type DS. The lookup for answers turns this off. * @return closest local_zone or NULL if no covering zone is found. */ struct local_zone* local_zones_tags_lookup(struct local_zones* zones, uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype, - uint8_t* taglist, size_t taglen, int ignoretags); + uint8_t* taglist, size_t taglen, int ignoretags, int foradd); /** * Lookup zone that contains the given name, class. @@ -278,10 +289,13 @@ struct local_zone* local_zones_tags_look * @param dclass: class to lookup. * @param dtype: type of the record, if type DS then a zone higher up is found * pass 0 to just plain find a zone for a name. + * @param foradd: if the lookup is for addition or removal of the type. + * Used for type DS. The lookup for answers turns this off. * @return closest local_zone or NULL if no covering zone is found. */ struct local_zone* local_zones_lookup(struct local_zones* zones, - uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype); + uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype, + int foradd); /** * Debug helper. Print all zones @@ -565,7 +579,7 @@ enum respip_action { respip_always_nxdomain = local_zone_always_nxdomain, /** answer with nodata response */ respip_always_nodata = local_zone_always_nodata, - /** answer with nodata response */ + /** drop query */ respip_always_deny = local_zone_always_deny, /** RPZ: truncate answer in order to force switch to tcp */ respip_truncate = local_zone_truncate, Index: usr.sbin/unbound/services/mesh.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/mesh.c,v diff -u -p -r1.33 mesh.c --- usr.sbin/unbound/services/mesh.c 26 Sep 2025 07:32:37 -0000 1.33 +++ usr.sbin/unbound/services/mesh.c 21 Sep 2026 16:28:08 -0000 @@ -231,6 +231,7 @@ mesh_create(struct module_stack* stack, mesh->ans_expired = 0; mesh->ans_cachedb = 0; mesh->num_queries_discard_timeout = 0; + mesh->num_queries_replyaddr_limit = 0; mesh->num_queries_wait_limit = 0; mesh->num_dns_error_reports = 0; mesh->max_reply_states = env->cfg->num_queries_per_thread; @@ -296,12 +297,14 @@ int mesh_make_new_space(struct mesh_area if(mesh->num_reply_states < mesh->max_reply_states) return 1; /* try to kick out a jostle-list item */ - if(m && m->reply_list && m->list_select == mesh_jostle_list) { + if(m && m->list_select == mesh_jostle_list) { /* how old is it? */ struct timeval age; - timeval_subtract(&age, mesh->env->now_tv, - &m->reply_list->start_time); - if(timeval_smaller(&mesh->jostle_max, &age)) { + if(m->has_first_reply_time) + timeval_subtract(&age, mesh->env->now_tv, + &m->first_reply_time); + if(!m->has_first_reply_time || + timeval_smaller(&mesh->jostle_max, &age)) { /* its a goner */ log_nametypeclass(VERB_ALGO, "query jostled out to " "make space for a new one", @@ -348,7 +351,7 @@ mesh_serve_expired_lookup(struct module_ key = (struct msgreply_entry*)e->key; data = (struct reply_info*)e->data; - if(data->ttl < timenow) *is_expired = 1; + if(TTL_IS_EXPIRED(data->ttl, timenow)) *is_expired = 1; msg = tomsg(qstate->env, &key->key, data, qstate->region, timenow, qstate->env->cfg->serve_expired, qstate->env->scratch); if(!msg) @@ -370,7 +373,7 @@ mesh_serve_expired_lookup(struct module_ "validation"); goto bail_out; /* need to validate cache entry first */ } else if(msg->rep->security == sec_status_secure && - !reply_all_rrsets_secure(msg->rep) && must_validate) { + !reply_an_ns_rrsets_secure(msg->rep) && must_validate) { verbose(VERB_ALGO, "Serve expired: secure entry" " changed status"); goto bail_out; /* rrset changed, re-verify */ @@ -421,6 +424,44 @@ mesh_serve_expired_init(struct mesh_stat return 1; } +/** remove a reply without accounting, rollback the add reply. */ +static void +mesh_remove_reply_without_accounting(struct mesh_state* s, + struct mesh_reply* todel) +{ + struct mesh_reply* r, *prev = NULL; + for(r = s->reply_list; r; r = r->next) { + if(r == todel) { + if(prev) + prev->next = r->next; + else s->reply_list = r->next; + r->next = NULL; + /* todel is allocated in region */ + return; + } + prev = r; + } +} + +/** remove a callback without accounting, rollback the add reply. */ +static void +mesh_remove_callback_without_accounting(struct mesh_state* s, + struct mesh_cb* todel) +{ + struct mesh_cb* r, *prev = NULL; + for(r = s->cb_list; r; r = r->next) { + if(r == todel) { + if(prev) + prev->next = r->next; + else s->cb_list = r->next; + r->next = NULL; + /* todel is allocated in region */ + return; + } + prev = r; + } +} + void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, struct respip_client_info* cinfo, uint16_t qflags, struct edns_data* edns, struct comm_reply* rep, uint16_t qid, @@ -430,7 +471,8 @@ void mesh_new_client(struct mesh_area* m int unique = unique_mesh_state(edns->opt_list_in, mesh->env); int was_detached = 0; int was_noreply = 0; - int added = 0; + int added = 0, added_reply_without_accounting = 0, added_tcp = 0; + struct mesh_reply* repadded = NULL; int timeout = mesh->env->cfg->serve_expired? mesh->env->cfg->serve_expired_client_timeout:0; struct sldns_buffer* r_buffer = rep->c->buffer; @@ -441,9 +483,18 @@ void mesh_new_client(struct mesh_area* m if(!infra_wait_limit_allowed(mesh->env->infra_cache, rep, edns->cookie_valid, mesh->env->cfg)) { verbose(VERB_ALGO, "Too many queries waiting from the IP. " - "dropping incoming query."); - comm_point_drop_reply(rep); + "servfail incoming query."); mesh->num_queries_wait_limit++; + edns_opt_list_append_ede(&edns->opt_list_out, + mesh->env->scratch, LDNS_EDE_OTHER, + "Too many queries queued up and waiting from the IP"); + if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL, + LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) + edns->opt_list_inplace_cb_out = NULL; + error_encode(r_buffer, LDNS_RCODE_SERVFAIL, + qinfo, qid, qflags, edns); + regional_free_all(mesh->env->scratch); + comm_point_send_reply(rep); return; } if(!unique) @@ -453,6 +504,10 @@ void mesh_new_client(struct mesh_area* m if(!mesh_make_new_space(mesh, rep->c->buffer)) { verbose(VERB_ALGO, "Too many queries. dropping " "incoming query."); + if(rep->c->use_h2) + http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_drop_reply(rep); mesh->stats_dropped++; return; @@ -464,8 +519,12 @@ void mesh_new_client(struct mesh_area* m if(mesh->num_reply_addrs > mesh->max_reply_states*16) { verbose(VERB_ALGO, "Too many requests queued. " "dropping incoming query."); + if(rep->c->use_h2) + http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_drop_reply(rep); - mesh->stats_dropped++; + mesh->num_queries_replyaddr_limit++; return; } } @@ -524,18 +583,22 @@ void mesh_new_client(struct mesh_area* m } } /* add reply to s */ - if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) { + if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo, &repadded)) { log_err("mesh_new_client: out of memory; SERVFAIL"); goto servfail_mem; } + added_reply_without_accounting = 1; if(rep->c->tcp_req_info) { if(!tcp_req_info_add_meshstate(rep->c->tcp_req_info, mesh, s)) { log_err("mesh_new_client: out of memory add tcpreqinfo"); goto servfail_mem; } } + added_tcp = 1; if(rep->c->use_h2) { http2_stream_add_meshstate(rep->c->h2_stream, mesh, s); + } else if(rep->c->type == comm_doq && rep->doq_stream) { + doq_stream_add_meshstate(rep->doq_stream, mesh, s); } /* add serve expired timer if required and not already there */ if(timeout && !mesh_serve_expired_init(s, timeout)) { @@ -553,6 +616,8 @@ void mesh_new_client(struct mesh_area* m } } #endif + /* Since the acccounting now happens, + * added_reply_without_accounting = 0; but that is not used. */ infra_wait_limit_inc(mesh->env->infra_cache, rep, *mesh->env->now, mesh->env->cfg); /* update statistics */ @@ -589,7 +654,14 @@ servfail_mem: qinfo, qid, qflags, edns); if(rep->c->use_h2) http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_send_reply(rep); + if(added_reply_without_accounting) { + mesh_remove_reply_without_accounting(s, repadded); + if(added_tcp && rep->c->tcp_req_info) + tcp_req_info_remove_mesh_state(rep->c->tcp_req_info, s); + } if(added) mesh_state_delete(&s->s); return; @@ -598,7 +670,8 @@ servfail_mem: int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, struct edns_data* edns, sldns_buffer* buf, - uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru) + uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru, + void** unique_info) { struct mesh_state* s = NULL; int unique = unique_mesh_state(edns->opt_list_in, mesh->env); @@ -607,6 +680,7 @@ mesh_new_callback(struct mesh_area* mesh int was_detached = 0; int was_noreply = 0; int added = 0; + struct mesh_cb* add_cb = NULL; uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD); if(!unique) s = mesh_area_find(mesh, NULL, qinfo, mesh_flags, 0, 0); @@ -652,13 +726,14 @@ mesh_new_callback(struct mesh_area* mesh } } /* add reply to s */ - if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) { + if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags, &add_cb)) { if(added) mesh_state_delete(&s->s); return 0; } /* add serve expired timer if not already there */ if(timeout && !mesh_serve_expired_init(s, timeout)) { + mesh_remove_callback_without_accounting(s, add_cb); if(added) mesh_state_delete(&s->s); return 0; @@ -669,6 +744,7 @@ mesh_new_callback(struct mesh_area* mesh (mesh->env->cachedb_enabled && mesh->env->cfg->cachedb_check_when_serve_expired)) { if(!mesh_serve_expired_init(s, -1)) { + mesh_remove_callback_without_accounting(s, add_cb); if(added) mesh_state_delete(&s->s); return 0; @@ -684,6 +760,8 @@ mesh_new_callback(struct mesh_area* mesh mesh->num_reply_states ++; } mesh->num_reply_addrs++; + if(unique_info) + *unique_info = s->unique; if(added) mesh_run(mesh, s, module_event_new, NULL); return 1; @@ -887,33 +965,9 @@ void mesh_report_reply(struct mesh_area* mesh_run(mesh, e->qstate->mesh_info, event, e); } -/** copy strlist to region */ -static struct config_strlist* -cfg_region_strlist_copy(struct regional* region, struct config_strlist* list) -{ - struct config_strlist* result = NULL, *last = NULL, *s = list; - while(s) { - struct config_strlist* n = regional_alloc_zero(region, - sizeof(*n)); - if(!n) - return NULL; - n->str = regional_strdup(region, s->str); - if(!n->str) - return NULL; - if(last) - last->next = n; - else result = n; - last = n; - s = s->next; - } - return result; -} - -/** Copy the client info to the query region. */ -static struct respip_client_info* +struct respip_client_info* mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo) { - size_t i; struct respip_client_info* client_info; client_info = regional_alloc_init(region, cinfo, sizeof(*cinfo)); if(!client_info) @@ -932,20 +986,13 @@ mesh_copy_client_info(struct regional* r if(!client_info->tag_actions) return NULL; } - if(cinfo->tag_datas) { - client_info->tag_datas = regional_alloc_zero(region, - sizeof(struct config_strlist*)*cinfo->tag_datas_size); - if(!client_info->tag_datas) - return NULL; - for(i=0; itag_datas_size; i++) { - if(cinfo->tag_datas[i]) { - client_info->tag_datas[i] = cfg_region_strlist_copy( - region, cinfo->tag_datas[i]); - if(!client_info->tag_datas[i]) - return NULL; - } - } - } + /* tag_datas is owned by the matched acl_addr in config_file; its + * lifetime is until config reload, which tears down all mesh states + * first. Keep the original pointer so client_info_compare() + * can recognise two states from the same ACL entry. */ + /* fast reload insists on dropping the queries when interface-tag-data + * or access-control-tag-data are changed. */ + /* client_info->tag_datas already copied by regional_alloc_init above */ if(cinfo->view) { /* Do not copy the view pointer but store a name instead. * The name is looked up later when done, this means that @@ -955,6 +1002,11 @@ mesh_copy_client_info(struct regional* r cinfo->view->name); if(!client_info->view_name) return NULL; + } else if(cinfo->view_name) { + client_info->view_name = regional_strdup(region, + cinfo->view_name); + if(!client_info->view_name) + return NULL; } return client_info; } @@ -1022,6 +1074,7 @@ mesh_state_create(struct module_env* env mstate->s.no_cache_store = 0; mstate->s.need_refetch = 0; mstate->s.was_ratelimited = 0; + mstate->s.error_response_cache = 0; mstate->s.qstarttime = *env->now; /* init modules */ @@ -1044,6 +1097,18 @@ mesh_state_make_unique(struct mesh_state mstate->unique = mstate; } +/** pop a reply from the reply list, if there are any. */ +static struct mesh_reply* +mesh_reply_list_pop_first(struct mesh_state* mstate) +{ + if(mstate->reply_list) { + struct mesh_reply* r = mstate->reply_list; + mstate->reply_list = r->next; + return r; + } + return NULL; +} + void mesh_state_cleanup(struct mesh_state* mstate) { @@ -1059,17 +1124,30 @@ mesh_state_cleanup(struct mesh_state* ms } /* drop unsent replies */ if(!mstate->replies_sent) { - struct mesh_reply* rep = mstate->reply_list; + struct mesh_reply* rep; struct mesh_cb* cb; - /* in tcp_req_info, the mstates linked are removed, but - * the reply_list is now NULL, so the remove-from-empty-list - * takes no time and also it does not do the mesh accounting */ - mstate->reply_list = NULL; - for(; rep; rep=rep->next) { + /* Pop items from the list, that means there is no iterator. + * And then items can be removed from the reply list, from + * like comm_point_drop_reply and comm_point_close calls. + * As the tcp_req_info and http2 code drops the entire + * connection. That could delete mesh_reply items previous and + * after the current state. The previous items are already + * popped. And the next items can be altered, like to when a + * connection has more replies on the reply list. + * The current item is also popped so the code needs to + * remove its references. */ + while((rep = mesh_reply_list_pop_first(mstate)) != NULL) { infra_wait_limit_dec(mesh->env->infra_cache, &rep->query_reply, mesh->env->cfg); - if(rep->query_reply.c->use_h2) + if(rep->query_reply.c->tcp_req_info) + tcp_req_info_remove_mesh_state( + rep->query_reply.c->tcp_req_info, + mstate); + else if(rep->query_reply.c->use_h2) http2_stream_remove_mesh_state(rep->h2_stream); + else if(rep->query_reply.doq_stream) + doq_stream_remove_mesh_state( + rep->query_reply.doq_stream); comm_point_drop_reply(&rep->query_reply); log_assert(mesh->num_reply_addrs > 0); mesh->num_reply_addrs--; @@ -1152,8 +1230,7 @@ mesh_detect_cycle_found(struct module_qs { struct mesh_state* cyc_m = qstate->mesh_info; size_t counter = 0; - if(!dep_m) - return 0; + log_assert(dep_m); if(dep_m == cyc_m || find_in_subsub(dep_m, cyc_m, &counter)) { if(counter > MESH_MAX_SUBSUB) return 2; @@ -1190,28 +1267,26 @@ void mesh_detach_subs(struct module_qsta } int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq, - struct mesh_state** sub) + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq, struct mesh_state** sub) { /* find it, if not, create it */ struct mesh_area* mesh = qstate->env->mesh; - *sub = mesh_area_find(mesh, NULL, qinfo, qflags, - prime, valrec); - if(mesh_detect_cycle_found(qstate, *sub)) { - verbose(VERB_ALGO, "attach failed, cycle detected"); - return 0; - } + *sub = mesh_area_find(mesh, cinfo, qinfo, qflags, prime, valrec); if(!*sub) { #ifdef UNBOUND_DEBUG struct rbnode_type* n; #endif /* create a new one */ - *sub = mesh_state_create(qstate->env, qinfo, NULL, qflags, prime, - valrec); + *sub = mesh_state_create(qstate->env, qinfo, cinfo, qflags, + prime, valrec); if(!*sub) { log_err("mesh_attach_sub: out of memory"); return 0; } + /* inherit RPZ passthru from the parent so respip on the sub + * sees the same client-IP/qname PASSTHRU decision */ + (*sub)->s.rpz_passthru = qstate->rpz_passthru; #ifdef UNBOUND_DEBUG n = #else @@ -1230,18 +1305,25 @@ int mesh_add_sub(struct module_qstate* q rbtree_insert(&mesh->run, &(*sub)->run_node); log_assert(n != NULL); *newq = &(*sub)->s; - } else + } else { *newq = NULL; + if(mesh_detect_cycle_found(qstate, *sub)) { + verbose(VERB_ALGO, "attach failed, cycle detected"); + return 0; + } + } return 1; } int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq) + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq) { struct mesh_area* mesh = qstate->env->mesh; struct mesh_state* sub = NULL; int was_detached; - if(!mesh_add_sub(qstate, qinfo, qflags, prime, valrec, newq, &sub)) + if(!mesh_add_sub(qstate, qinfo, cinfo, qflags, prime, valrec, newq, + &sub)) return 0; was_detached = (sub->super_set.count == 0); if(!mesh_state_attachment(qstate->mesh_info, sub)) @@ -1429,12 +1511,6 @@ mesh_send_reply(struct mesh_state* m, in struct timeval end_time; struct timeval duration; int secure; - /* briefly set the replylist to null in case the - * meshsendreply calls tcpreqinfo sendreply that - * comm_point_drops because of size, and then the - * null stops the mesh state remove and thus - * reply_list modification and accounting */ - struct mesh_reply* rlist = m->reply_list; /* rpz: apply actions */ rcode = mesh_is_udp(r) && mesh_is_rpz_respip_tcponly_action(m) @@ -1460,6 +1536,10 @@ mesh_send_reply(struct mesh_state* m, in * for HTTP/2 stream to refer to mesh state, in case * connection gets cleanup before HTTP/2 stream close. */ r->h2_stream->mesh_state = NULL; +#ifdef HAVE_NGTCP2 + } else if(r->query_reply.doq_stream) { + r->query_reply.doq_stream->mesh_state = NULL; +#endif } /* send the reply */ /* We don't reuse the encoded answer if: @@ -1487,9 +1567,7 @@ mesh_send_reply(struct mesh_state* m, in sldns_buffer_write_at(r_buffer, 0, &r->qid, sizeof(uint16_t)); sldns_buffer_write_at(r_buffer, 12, r->qname, m->s.qinfo.qname_len); - m->reply_list = NULL; comm_point_send_reply(&r->query_reply); - m->reply_list = rlist; } else if(rcode) { m->s.qinfo.qname = r->qname; m->s.qinfo.local_alias = r->local_alias; @@ -1511,9 +1589,7 @@ mesh_send_reply(struct mesh_state* m, in } error_encode(r_buffer, rcode, &m->s.qinfo, r->qid, r->qflags, &r->edns); - m->reply_list = NULL; comm_point_send_reply(&r->query_reply); - m->reply_list = rlist; } else { size_t udp_size = r->edns.udp_size; r->edns.edns_version = EDNS_ADVERTISED_VERSION; @@ -1549,9 +1625,7 @@ mesh_send_reply(struct mesh_state* m, in error_encode(r_buffer, LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, r->qflags, &r->edns); } - m->reply_list = NULL; comm_point_send_reply(&r->query_reply); - m->reply_list = rlist; } infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply, m->s.env->cfg); @@ -1614,9 +1688,9 @@ static void dns_error_reporting(struct m opt = edns_opt_list_find(qstate->edns_opts_back_in, LDNS_EDNS_REPORT_CHANNEL); if(!opt) return; - agent_domain_len = opt->opt_len; agent_domain = opt->opt_data; - if(dname_valid(agent_domain, agent_domain_len) < 3) { + agent_domain_len = dname_valid(agent_domain, opt->opt_len); + if(agent_domain_len < 3) { /* The agent domain needs to be a valid dname that is not the * root; from RFC9567. */ return; @@ -1684,7 +1758,7 @@ static void dns_error_reporting(struct m log_query_info(VERB_ALGO, "DNS Error Reporting: generating report " "query for", &qinfo); - if(mesh_add_sub(qstate, &qinfo, BIT_RD, 0, 0, &newq, &sub)) { + if(mesh_add_sub(qstate, &qinfo, NULL, BIT_RD, 0, 0, &newq, &sub)) { qstate->env->mesh->num_dns_error_reports++; } return; @@ -1703,6 +1777,7 @@ void mesh_query_done(struct mesh_state* struct reply_info* rep = (mstate->s.return_msg? mstate->s.return_msg->rep:NULL); struct timeval tv = {0, 0}; + struct mesh_area* mesh = mstate->s.env->mesh; int i = 0; /* No need for the serve expired timer anymore; we are going to reply. */ if(mstate->s.serve_expired_data) { @@ -1723,32 +1798,53 @@ void mesh_query_done(struct mesh_state* } } - if(mstate->reply_list && mstate->s.env->cfg->dns_error_reporting) + if(mstate->reply_list && mstate->s.env->cfg->dns_error_reporting + && (!rep || rep->security != sec_status_secure)) dns_error_reporting(&mstate->s, rep); - for(r = mstate->reply_list; r; r = r->next) { - struct timeval old; - timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); - if(mstate->s.env->cfg->discard_timeout != 0 && - ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > - mstate->s.env->cfg->discard_timeout) { - /* Drop the reply, it is too old */ - /* briefly set the reply_list to NULL, so that the - * tcp req info cleanup routine that calls the mesh - * to deregister the meshstate for it is not done - * because the list is NULL and also accounting is not - * done there, but instead we do that here. */ - struct mesh_reply* reply_list = mstate->reply_list; - verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); - infra_wait_limit_dec(mstate->s.env->infra_cache, - &r->query_reply, mstate->s.env->cfg); - mstate->reply_list = NULL; - if(r->query_reply.c->use_h2) - http2_stream_remove_mesh_state(r->h2_stream); - comm_point_drop_reply(&r->query_reply); - mstate->reply_list = reply_list; - mstate->s.env->mesh->num_queries_discard_timeout++; - continue; + while((r = mesh_reply_list_pop_first(mstate)) != NULL) { + + /* it was not detached (because it had a reply list), could be now */ + if(!mstate->reply_list && !mstate->cb_list + && mstate->super_set.count == 0) { + mesh->num_detached_states++; + } + /* if not replies any more in mstate, it is no longer a reply_state */ + if(!mstate->reply_list && !mstate->cb_list) { + log_assert(mesh->num_reply_states > 0); + mesh->num_reply_states--; + } + if(mesh_is_udp(r)) { + /* For UDP queries, the old replies are discarded. + * This stops a large volume of old replies from + * building up. + * The stream replies, are not discarded. The + * stream is open, the other side is waiting. + * Some answer is needed, even if servfail, but the + * real reply is ready to go, so that is given. */ + struct timeval old; + timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); + if(mstate->s.env->cfg->discard_timeout != 0 && + ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > + mstate->s.env->cfg->discard_timeout) { + /* Drop the reply, it is too old */ + verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); + infra_wait_limit_dec(mstate->s.env->infra_cache, + &r->query_reply, mstate->s.env->cfg); + if(r->query_reply.c->tcp_req_info) + tcp_req_info_remove_mesh_state( + r->query_reply.c->tcp_req_info, + mstate); + else if(r->query_reply.c->use_h2) + http2_stream_remove_mesh_state(r->h2_stream); + else if(r->query_reply.doq_stream) + doq_stream_remove_mesh_state(r->query_reply.doq_stream); + comm_point_drop_reply(&r->query_reply); + log_assert(mstate->s.env->mesh->num_reply_addrs > 0); + mstate->s.env->mesh->num_reply_addrs--; + mstate->s.env->mesh->num_queries_discard_timeout++; + continue; + } } i++; @@ -1768,20 +1864,19 @@ void mesh_query_done(struct mesh_state* /* if this query is determined to be dropped during the * mesh processing, this is the point to take that action. */ if(mstate->s.is_drop) { - /* briefly set the reply_list to NULL, so that the - * tcp req info cleanup routine that calls the mesh - * to deregister the meshstate for it is not done - * because the list is NULL and also accounting is not - * done there, but instead we do that here. */ - struct mesh_reply* reply_list = mstate->reply_list; infra_wait_limit_dec(mstate->s.env->infra_cache, &r->query_reply, mstate->s.env->cfg); - mstate->reply_list = NULL; - if(r->query_reply.c->use_h2) { + if(r->query_reply.c->tcp_req_info) { + tcp_req_info_remove_mesh_state( + r->query_reply.c->tcp_req_info, mstate); + } else if(r->query_reply.c->use_h2) { http2_stream_remove_mesh_state(r->h2_stream); + } else if(r->query_reply.doq_stream) { + doq_stream_remove_mesh_state(r->query_reply.doq_stream); } comm_point_drop_reply(&r->query_reply); - mstate->reply_list = reply_list; + log_assert(mstate->s.env->mesh->num_reply_addrs > 0); + mstate->s.env->mesh->num_reply_addrs--; } else { struct sldns_buffer* r_buffer = r->query_reply.c->buffer; if(r->query_reply.c->tcp_req_info) { @@ -1820,18 +1915,6 @@ void mesh_query_done(struct mesh_state* } } - /* Mesh area accounting */ - if(mstate->reply_list) { - mstate->reply_list = NULL; - if(!mstate->reply_list && !mstate->cb_list) { - /* was a reply state, not anymore */ - log_assert(mstate->s.env->mesh->num_reply_states > 0); - mstate->s.env->mesh->num_reply_states--; - } - if(!mstate->reply_list && !mstate->cb_list && - mstate->super_set.count == 0) - mstate->s.env->mesh->num_detached_states++; - } mstate->replies_sent = 1; while((c = mstate->cb_list) != NULL) { @@ -1889,6 +1972,25 @@ struct mesh_state* mesh_area_find(struct return result; } +struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh, + struct respip_client_info* cinfo, struct query_info* qinfo, + uint16_t qflags, int prime, int valrec, void* unique_info) +{ + struct mesh_state key; + struct mesh_state* result; + + key.node.key = &key; + key.s.is_priming = prime; + key.s.is_valrec = valrec; + key.s.qinfo = *qinfo; + key.s.query_flags = qflags; + key.unique = (struct mesh_state*)unique_info; + key.s.client_info = cinfo; + + result = (struct mesh_state*)rbtree_search(&mesh->all, &key); + return result; +} + /** remove mesh state callback */ int mesh_state_del_cb(struct mesh_state* s, mesh_cb_func_type cb, void* cb_arg) { @@ -1910,7 +2012,7 @@ int mesh_state_del_cb(struct mesh_state* int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg, - uint16_t qid, uint16_t qflags) + uint16_t qid, uint16_t qflags, struct mesh_cb** result) { struct mesh_cb* r = regional_alloc(s->s.region, sizeof(struct mesh_cb)); @@ -1934,13 +2036,14 @@ int mesh_state_add_cb(struct mesh_state* r->qflags = qflags; r->next = s->cb_list; s->cb_list = r; + *result = r; return 1; } int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, struct comm_reply* rep, uint16_t qid, uint16_t qflags, - const struct query_info* qinfo) + const struct query_info* qinfo, struct mesh_reply** result) { struct mesh_reply* r = regional_alloc(s->s.region, sizeof(struct mesh_reply)); @@ -1960,6 +2063,10 @@ int mesh_state_add_reply(struct mesh_sta r->qid = qid; r->qflags = qflags; r->start_time = *s->s.env->now_tv; + if(s->reply_list == NULL && !s->has_first_reply_time) { + s->first_reply_time = r->start_time; + s->has_first_reply_time = 1; + } r->next = s->reply_list; r->qname = regional_alloc_init(s->s.region, qinfo->qname, s->s.qinfo.qname_len); @@ -1968,6 +2075,8 @@ int mesh_state_add_reply(struct mesh_sta if(rep->c->use_h2) r->h2_stream = rep->c->h2_stream; else r->h2_stream = NULL; + if(rep->c->type != comm_doq) + r->query_reply.doq_stream = NULL; /* Data related to local alias stored in 'qinfo' (if any) is ephemeral * and can be different for different original queries (even if the @@ -2015,6 +2124,7 @@ int mesh_state_add_reply(struct mesh_sta r->local_alias = NULL; s->reply_list = r; + *result = r; return 1; } @@ -2172,8 +2282,29 @@ void mesh_run(struct mesh_area* mesh, st enum module_ev ev, struct outbound_entry* e) { enum module_ext_state s; + int numrun = 0; verbose(VERB_ALGO, "mesh_run: start"); while(mstate) { + if(numrun++ > MESH_MAX_RUN_ITER) { + /* These modules are too much to activate, stop them.*/ + log_err("Too many module run iterations, deleting"); + while(mstate) { + /* notify supers */ + if(mstate->super_set.count > 0) { + verbose(VERB_ALGO, "notify supers of failure"); + mstate->s.return_msg = NULL; + mstate->s.return_rcode = LDNS_RCODE_SERVFAIL; + mesh_walk_supers(mesh, mstate); + } + mesh_state_delete(&mstate->s); + if(mesh->run.count > 0) { + /* pop random element off the runnable tree */ + mstate = (struct mesh_state*)mesh->run.root->key; + (void)rbtree_delete(&mesh->run, mstate); + } else mstate = NULL; + } + break; + } /* run the module */ fptr_ok(fptr_whitelist_mod_operate( mesh->mods.mod[mstate->s.curmod]->operate)); @@ -2272,6 +2403,7 @@ mesh_stats_clear(struct mesh_area* mesh) memset(&mesh->rpz_action[0], 0, sizeof(size_t)*UB_STATS_RPZ_ACTION_NUM); mesh->ans_nodata = 0; mesh->num_queries_discard_timeout = 0; + mesh->num_queries_replyaddr_limit = 0; mesh->num_queries_wait_limit = 0; mesh->num_dns_error_reports = 0; } @@ -2297,7 +2429,7 @@ mesh_detect_cycle(struct module_qstate* struct mesh_area* mesh = qstate->env->mesh; struct mesh_state* dep_m = NULL; dep_m = mesh_area_find(mesh, NULL, qinfo, flags, prime, valrec); - return mesh_detect_cycle_found(qstate, dep_m); + return dep_m?mesh_detect_cycle_found(qstate, dep_m):0; } void mesh_list_insert(struct mesh_state* m, struct mesh_state** fp, @@ -2324,7 +2456,8 @@ void mesh_list_remove(struct mesh_state* } void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, - struct comm_point* cp) + struct comm_point* cp, struct http2_stream* h2_stream, + struct doq_stream* doq_stream) { struct mesh_reply* n, *prev = NULL; n = m->reply_list; @@ -2332,7 +2465,9 @@ void mesh_state_remove_reply(struct mesh * there is no accounting twice */ if(!n) return; /* nothing to remove, also no accounting needed */ while(n) { - if(n->query_reply.c == cp) { + if(n->query_reply.c == cp + && (!h2_stream || n->h2_stream == h2_stream) + && (!doq_stream || n->query_reply.doq_stream == doq_stream)) { /* unlink it */ if(prev) prev->next = n->next; else m->reply_list = n->next; @@ -2341,6 +2476,14 @@ void mesh_state_remove_reply(struct mesh mesh->num_reply_addrs--; infra_wait_limit_dec(mesh->env->infra_cache, &n->query_reply, mesh->env->cfg); + /* We may be removing more than one http2 stream (they + * share the same comm_point); make sure the streams + * don't point back. */ + if(n->h2_stream) n->h2_stream->mesh_state = NULL; +#ifdef HAVE_NGTCP2 + if(n->query_reply.doq_stream) + n->query_reply.doq_stream->mesh_state = NULL; +#endif /* prev = prev; */ n = n->next; @@ -2361,7 +2504,6 @@ void mesh_state_remove_reply(struct mesh } } - static int apply_respip_action(struct module_qstate* qstate, const struct query_info* qinfo, struct respip_client_info* cinfo, @@ -2381,9 +2523,10 @@ apply_respip_action(struct module_qstate /* xxx_deny actions mean dropping the reply, unless the original reply * was redirected to response-ip data. */ - if((actinfo->action == respip_deny || + if(actinfo->action == respip_always_deny || + ((actinfo->action == respip_deny || actinfo->action == respip_inform_deny) && - *encode_repp == rep) + *encode_repp == rep)) *encode_repp = NULL; return 1; @@ -2448,12 +2591,15 @@ mesh_serve_expired_callback(void* arg) qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep, qstate->env->auth_zones)) { return; - } else if(partial_rep && - !respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep, + } else if(partial_rep) { + if(!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep, qstate->client_info, must_validate, &encode_rep, qstate->region, qstate->env->auth_zones, qstate->env->views, qstate->env->respip_set)) { - return; + return; + } + /* merge succeeded; final reply, no further alias pass */ + partial_rep = NULL; } if(!encode_rep || alias_rrset) { if(!encode_rep) { @@ -2464,6 +2610,7 @@ mesh_serve_expired_callback(void* arg) partial_rep = encode_rep; } } + msg->rep = encode_rep; /* We've found a partial reply ending with an * alias. Replace the lookup qinfo for the * alias target and lookup the cache again to @@ -2489,29 +2636,41 @@ mesh_serve_expired_callback(void* arg) if(verbosity >= VERB_ALGO) log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep); - for(r = mstate->reply_list; r; r = r->next) { - struct timeval old; - timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); - if(mstate->s.env->cfg->discard_timeout != 0 && + while((r = mesh_reply_list_pop_first(mstate)) != NULL) { + + /* it was not detached (because it had a reply list), could be now */ + if(!mstate->reply_list && !mstate->cb_list + && mstate->super_set.count == 0) { + mesh->num_detached_states++; + } + /* if not replies any more in mstate, it is no longer a reply_state */ + if(!mstate->reply_list && !mstate->cb_list) { + log_assert(mesh->num_reply_states > 0); + mesh->num_reply_states--; + } + if(mesh_is_udp(r)) { + struct timeval old; + timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); + if(mstate->s.env->cfg->discard_timeout != 0 && ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > mstate->s.env->cfg->discard_timeout) { /* Drop the reply, it is too old */ - /* briefly set the reply_list to NULL, so that the - * tcp req info cleanup routine that calls the mesh - * to deregister the meshstate for it is not done - * because the list is NULL and also accounting is not - * done there, but instead we do that here. */ - struct mesh_reply* reply_list = mstate->reply_list; verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); infra_wait_limit_dec(mstate->s.env->infra_cache, &r->query_reply, mstate->s.env->cfg); - mstate->reply_list = NULL; - if(r->query_reply.c->use_h2) + if(r->query_reply.c->tcp_req_info) + tcp_req_info_remove_mesh_state( + r->query_reply.c->tcp_req_info, mstate); + else if(r->query_reply.c->use_h2) http2_stream_remove_mesh_state(r->h2_stream); + else if(r->query_reply.doq_stream) + doq_stream_remove_mesh_state(r->query_reply.doq_stream); comm_point_drop_reply(&r->query_reply); - mstate->reply_list = reply_list; + log_assert(mstate->s.env->mesh->num_reply_addrs > 0); + mstate->s.env->mesh->num_reply_addrs--; mstate->s.env->mesh->num_queries_discard_timeout++; continue; + } } i++; @@ -2544,8 +2703,7 @@ mesh_serve_expired_callback(void* arg) if(r->query_reply.c->tcp_req_info) tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); /* mesh_send_reply removed mesh state from http2_stream. */ - infra_wait_limit_dec(mstate->s.env->infra_cache, - &r->query_reply, mstate->s.env->cfg); + /* mesh_send_reply decremented wait_limit. */ prev = r; prev_buffer = r_buffer; } @@ -2564,18 +2722,6 @@ mesh_serve_expired_callback(void* arg) } } - /* Mesh area accounting */ - if(mstate->reply_list) { - mstate->reply_list = NULL; - if(!mstate->reply_list && !mstate->cb_list) { - log_assert(mesh->num_reply_states > 0); - mesh->num_reply_states--; - if(mstate->super_set.count == 0) { - mesh->num_detached_states++; - } - } - } - while((c = mstate->cb_list) != NULL) { /* take this cb off the list; so that the list can be * changed, eg. by adds from the callback routine */ @@ -2608,13 +2754,30 @@ int mesh_jostle_exceeded(struct mesh_are } void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo, - uint16_t qflags, mesh_cb_func_type cb, void* cb_arg) + uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info) { struct mesh_state* s = NULL; s = mesh_area_find(mesh, NULL, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); - if(!s) return; - if(!mesh_state_del_cb(s, cb, cb_arg)) return; + if(s && mesh_state_del_cb(s, cb, cb_arg)) + goto removed; + if(unique_info) { + s = mesh_area_find_unique(mesh, NULL, qinfo, + qflags&(BIT_RD|BIT_CD), 0, 0, unique_info); + if(s && mesh_state_del_cb(s, cb, cb_arg)) + goto removed; + } + /* mesh_area_find builds key.unique=NULL and cannot match a state + * created with mesh_state_make_unique (e.g. subnetcache sets + * env->unique_mesh). Fall back to a linear scan; cb+cb_arg is an + * exact key (mesh_state_del_cb compares both). + * This works for both lookups for zonemd and for hostname authzone. */ + RBTREE_FOR(s, struct mesh_state*, &mesh->all) { + if(s->cb_list && mesh_state_del_cb(s, cb, cb_arg)) + goto removed; + } + return; +removed: /* It was in the list and removed. */ log_assert(mesh->num_reply_addrs > 0); mesh->num_reply_addrs--; Index: usr.sbin/unbound/services/mesh.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/mesh.h,v diff -u -p -r1.15 mesh.h --- usr.sbin/unbound/services/mesh.h 26 Sep 2025 07:32:37 -0000 1.15 +++ usr.sbin/unbound/services/mesh.h 21 Sep 2026 16:28:08 -0000 @@ -70,6 +70,13 @@ struct respip_client_info; #define MESH_MAX_ACTIVATION 10000 /** + * Maximum number of mesh state run items. These are different modules + * activated during a mesh run. Any more is likely an infinite loop + * in the module. It is then terminated, and states are deleted. + */ +#define MESH_MAX_RUN_ITER 10000 + +/** * Max number of references-to-references-to-references.. search size. * Any more is treated like 'too large', and the creation of a new * dependency is failed (so that no loops can be created). @@ -141,6 +148,8 @@ struct mesh_area { size_t rpz_action[UB_STATS_RPZ_ACTION_NUM]; /** stats, number of queries removed due to discard-timeout */ size_t num_queries_discard_timeout; + /** stats, number of queries removed due to replyaddr limit */ + size_t num_queries_replyaddr_limit; /** stats, number of queries removed due to wait-limit */ size_t num_queries_wait_limit; /** stats, number of dns error reports generated */ @@ -189,6 +198,12 @@ struct mesh_state { struct module_qstate s; /** the list of replies to clients for the results */ struct mesh_reply* reply_list; + /** if it has a first reply time */ + int has_first_reply_time; + /** wall-clock time the first client reply was attached; + * used by mesh_make_new_space() so duplicate retransmits + * cannot reset jostle aging. */ + struct timeval first_reply_time; /** the list of callbacks for the results */ struct mesh_cb* cb_list; /** set of superstates (that want this state's result) @@ -334,11 +349,14 @@ void mesh_new_client(struct mesh_area* m * @param cb_arg: callback user arg. * @param rpz_passthru: if true, the rpz passthru was previously found and * further rpz processing is stopped. + * @param unique_info: if nonnull, unique info is passed back to be used + * for the callback remove call. It does not need to be deallocated. * @return 0 on error. */ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, struct edns_data* edns, struct sldns_buffer* buf, - uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru); + uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru, + void** unique_info); /** * New prefetch message. Create new query state if needed. @@ -399,6 +417,8 @@ void mesh_detach_subs(struct module_qsta * @param qstate: the state to find mesh state, and that wants to receive * the results from the new subquery. * @param qinfo: what to query for (copied). + * @param cinfo: if non-NULL client specific info that may affect IP-based + * actions that apply to the query result. It is copied. * @param qflags: what flags to use (RD / CD flag or not). * @param prime: if it is a (stub) priming query. * @param valrec: if it is a validation recursion query (lookup of key, DS). @@ -407,7 +427,8 @@ void mesh_detach_subs(struct module_qsta * @return: false on error, true if success (and init may be needed). */ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq); + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq); /** * Add detached query. @@ -426,6 +447,8 @@ int mesh_attach_sub(struct module_qstate * @param qstate: the state to find mesh state, and that wants to receive * the results from the new subquery. * @param qinfo: what to query for (copied). + * @param cinfo: if non-NULL client specific info that may affect IP-based + * actions that apply to the query result. It is copied. * @param qflags: what flags to use (RD / CD flag or not). * @param prime: if it is a (stub) priming query. * @param valrec: if it is a validation recursion query (lookup of key, DS). @@ -435,8 +458,8 @@ int mesh_attach_sub(struct module_qstate * @return: false on error, true if success (and init may be needed). */ int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq, - struct mesh_state** sub); + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq, struct mesh_state** sub); /** * Query state is done, send messages to reply entries. @@ -531,6 +554,23 @@ struct mesh_state* mesh_area_find(struct uint16_t qflags, int prime, int valrec); /** + * Find a unique mesh state in the mesh area. Pass relevant flags. + * + * @param mesh: the mesh area to look in. + * @param cinfo: if non-NULL client specific info that may affect IP-based + * actions that apply to the query result. + * @param qinfo: what query + * @param qflags: if RD / CD bit is set or not. + * @param prime: if it is a priming query. + * @param valrec: if it is a validation-recursion query. + * @param unique_info: the unique info for the state. NULL can be passed. + * @return: mesh state or NULL if not found. + */ +struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh, + struct respip_client_info* cinfo, struct query_info* qinfo, + uint16_t qflags, int prime, int valrec, void* unique_info); + +/** * Setup attachment super/sub relation between super and sub mesh state. * The relation must not be present when calling the function. * Does not update stat items in mesh_area. @@ -549,11 +589,12 @@ int mesh_state_attachment(struct mesh_st * @param qid: ID of reply. * @param qflags: original query flags. * @param qinfo: original query info. + * @param result: the allocated reply structure, for rollback. * @return: 0 on alloc error. */ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, struct comm_reply* rep, uint16_t qid, uint16_t qflags, - const struct query_info* qinfo); + const struct query_info* qinfo, struct mesh_reply** result); /** * Create new callback structure and attach it to a mesh state. @@ -565,11 +606,12 @@ int mesh_state_add_reply(struct mesh_sta * @param cb_arg: callback user arg. * @param qid: ID of reply. * @param qflags: original query flags. + * @param result: the allocated callback structure, for rollback. * @return: 0 on alloc error. */ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, struct sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg, - uint16_t qid, uint16_t qflags); + uint16_t qid, uint16_t qflags, struct mesh_cb** result); /** * Run the mesh. Run all runnable mesh states. Which can create new @@ -670,9 +712,14 @@ void mesh_list_remove(struct mesh_state* * @param mesh: to update the counters. * @param m: the mesh state. * @param cp: the comm_point to remove from the list. + * @param h2_stream: if not NULL, it specifies the h2_stream to match + * for the delete. + * @param doq_stream: if not NULL, it specifies the doq_stream to match + * for the delete. */ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, - struct comm_point* cp); + struct comm_point* cp, struct http2_stream* h2_stream, + struct doq_stream* doq_stream); /** Callback for when the serve expired client timer has run out. Tries to * find an expired answer in the cache and reply that to the client. @@ -719,8 +766,13 @@ void mesh_respond_serve_expired(struct m * @param qflags: flags from client query. * @param cb: callback function. * @param cb_arg: callback user arg. + * @param unique_info: if not NULL, used to find a unique state for removal. */ void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo, - uint16_t qflags, mesh_cb_func_type cb, void* cb_arg); + uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info); + +/** Copy the client info to the query region. */ +struct respip_client_info* mesh_copy_client_info(struct regional* region, + struct respip_client_info* cinfo); #endif /* SERVICES_MESH_H */ Index: usr.sbin/unbound/services/modstack.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/modstack.c,v diff -u -p -r1.11 modstack.c --- usr.sbin/unbound/services/modstack.c 26 Sep 2025 07:32:37 -0000 1.11 +++ usr.sbin/unbound/services/modstack.c 21 Sep 2026 16:28:08 -0000 @@ -232,7 +232,7 @@ module_func_block* module_factory(const return NULL; } -int +int modstack_call_startup(struct module_stack* stack, const char* module_conf, struct module_env* env) { @@ -262,6 +262,7 @@ int modstack_call_init(struct module_stack* stack, const char* module_conf, struct module_env* env) { + const char* orig_module_conf = module_conf; int i, changed = 0; env->need_to_validate = 0; /* set by module init below */ for(i=0; inum; i++) { @@ -276,11 +277,13 @@ modstack_call_init(struct module_stack* changed = 1; } } - module_conf += strlen(stack->mod[i]->name); + /* Skip this module name in module_conf. */ + while(*module_conf && !isspace((unsigned char)*module_conf)) + module_conf++; } if(changed) { modstack_free(stack); - if(!modstack_config(stack, module_conf)) { + if(!modstack_config(stack, orig_module_conf)) { return 0; } } @@ -298,7 +301,7 @@ modstack_call_init(struct module_stack* return 1; } -void +void modstack_call_deinit(struct module_stack* stack, struct module_env* env) { int i; @@ -320,7 +323,7 @@ modstack_call_destartup(struct module_st } } -int +int modstack_find(struct module_stack* stack, const char* name) { int i; Index: usr.sbin/unbound/services/outside_network.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/outside_network.c,v diff -u -p -r1.33 outside_network.c --- usr.sbin/unbound/services/outside_network.c 26 Sep 2025 07:32:37 -0000 1.33 +++ usr.sbin/unbound/services/outside_network.c 21 Sep 2026 16:28:08 -0000 @@ -160,6 +160,19 @@ reuse_cmp_addrportssl(const void* key1, return 1; if(!r1->is_ssl && r2->is_ssl) return -1; + + /* compare tls_auth_name if SSL-enabled */ + if(r1->is_ssl) { + if(r1->tls_auth_name && !r2->tls_auth_name) + return 1; + if(!r1->tls_auth_name && r2->tls_auth_name) + return -1; + if(r1->tls_auth_name && r2->tls_auth_name) { + r = strcmp(r1->tls_auth_name, r2->tls_auth_name); + if(r != 0) + return r; + } + } return 0; } @@ -195,6 +208,7 @@ static void waiting_tcp_delete(struct waiting_tcp* w) { if(!w) return; + free(w->tls_auth_name); if(w->timer) comm_timer_delete(w->timer); free(w); @@ -531,7 +545,7 @@ reuse_tcp_insert(struct outside_network* /** find reuse tcp stream to destination for query, or NULL if none */ static struct reuse_tcp* reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr, - socklen_t addrlen, int use_ssl) + socklen_t addrlen, int use_ssl, char* tls_auth_name) { struct waiting_tcp key_w; struct pending_tcp key_p; @@ -545,8 +559,10 @@ reuse_tcp_find(struct outside_network* o key_p.c = &c; key_p.reuse.pending = &key_p; key_p.reuse.node.key = &key_p.reuse; - if(use_ssl) + if(use_ssl) { key_p.reuse.is_ssl = 1; + key_p.reuse.tls_auth_name = tls_auth_name; + } if(addrlen > (socklen_t)sizeof(key_p.reuse.addr)) return NULL; memmove(&key_p.reuse.addr, addr, addrlen); @@ -646,6 +662,7 @@ static int outnet_tcp_take_into_use(struct waiting_tcp* w) { struct pending_tcp* pend = w->outnet->tcp_free; + char* tls_auth_name = NULL; int s; log_assert(pend); log_assert(w->pkt); @@ -746,7 +763,22 @@ outnet_tcp_take_into_use(struct waiting_ comm_point_tcp_win_bio_cb(pend->c, pend->c->ssl); #endif pend->c->ssl_shake_state = comm_ssl_shake_write; - if(!set_auth_name_on_ssl(pend->c->ssl, w->tls_auth_name, + if(w->tls_auth_name) { + /* strdup the auth name, while not linked the list yet, + * in case of failure, easy cleanup. */ + tls_auth_name = strdup(w->tls_auth_name); + if(!tls_auth_name) { + log_err("out of memory: alloc tls auth name"); + pend->c->fd = s; +#ifdef HAVE_SSL + SSL_free(pend->c->ssl); +#endif + pend->c->ssl = NULL; + comm_point_close(pend->c); + return 0; + } + } + if(!set_auth_name_on_ssl(pend->c->ssl, tls_auth_name, w->outnet->tls_use_sni)) { pend->c->fd = s; #ifdef HAVE_SSL @@ -754,6 +786,7 @@ outnet_tcp_take_into_use(struct waiting_ #endif pend->c->ssl = NULL; comm_point_close(pend->c); + free(tls_auth_name); return 0; } } @@ -778,9 +811,20 @@ outnet_tcp_take_into_use(struct waiting_ if(pend->reuse.node.key) reuse_tcp_remove_tree_list(w->outnet, &pend->reuse); - if(pend->c->ssl) + if(pend->c->ssl) { pend->reuse.is_ssl = 1; - else pend->reuse.is_ssl = 0; + if(pend->reuse.tls_auth_name) + free(pend->reuse.tls_auth_name); + pend->reuse.tls_auth_name = tls_auth_name; + tls_auth_name = NULL; + } else { + pend->reuse.is_ssl = 0; + if(pend->reuse.tls_auth_name) + free(pend->reuse.tls_auth_name); + pend->reuse.tls_auth_name = NULL; + } + /* free tls auth name if nonNULL */ + free(tls_auth_name); /* insert in reuse by address tree if not already inserted there */ (void)reuse_tcp_insert(w->outnet, pend); reuse_tree_by_id_insert(&pend->reuse, w); @@ -969,7 +1013,7 @@ use_free_buffer(struct outside_network* (!outnet->tcp_reuse_first && !outnet->tcp_reuse_last) || (outnet->tcp_reuse_first && outnet->tcp_reuse_last)); reuse = reuse_tcp_find(outnet, &w->addr, w->addrlen, - w->ssl_upstream); + w->ssl_upstream, w->tls_auth_name); /* re-select an ID when moving to a new TCP buffer */ w->id = tcp_select_id(outnet, reuse); LDNS_ID_SET(w->pkt, w->id); @@ -1198,6 +1242,10 @@ decommission_pending_tcp(struct outside_ /* needs unlink from the reuse tree to get deleted */ reuse_tcp_remove_tree_list(outnet, &pend->reuse); } + if(pend->reuse.tls_auth_name) { + free(pend->reuse.tls_auth_name); + pend->reuse.tls_auth_name = NULL; + } /* free SSL structure after remove from outnet tcp reuse tree, * because the c->ssl null or not is used for sorting in the tree */ if(pend->c->ssl) { @@ -1433,7 +1481,7 @@ portcomm_loweruse(struct outside_network pif = pc->pif; log_assert(pif->inuse > 0); #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pif->avail_ports[pif->avail_total - pif->inuse] = pc->number; + shared_ports_return_port(outnet->shared_ports, pif->shpif, pc->number); #endif pif->inuse--; pif->out[pc->index] = pif->out[pif->inuse]; @@ -1647,19 +1695,25 @@ create_pending_tcp(struct outside_networ } /** setup an outgoing interface, ready address */ -static int setup_if(struct port_if* pif, const char* addrstr, - int* avail, int numavail, size_t numfd) +static int setup_if(struct port_if* pif, const char* addrstr, size_t numfd, + struct shared_ports* shp) { -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pif->avail_total = numavail; - pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int)); - if(!pif->avail_ports) - return 0; -#endif if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) && !netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen, &pif->pfxlen)) return 0; +#ifdef INT_MAX + if(numfd > (size_t)INT_MAX) { + log_err("num_ports exceeds INT_MAX"); + return 0; + } +#endif +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + pif->shpif = shared_ports_find_if(shp, &pif->addr, pif->addrlen, + pif->pfxlen); +#else + (void)shp; +#endif pif->maxout = (int)numfd; pif->inuse = 0; pif->out = (struct port_comm**)calloc(numfd, @@ -1673,12 +1727,12 @@ struct outside_network* outside_network_create(struct comm_base *base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, - struct ub_randstate* rnd, int use_caps_for_id, int* availports, - int numavailports, size_t unwanted_threshold, int tcp_mss, + struct ub_randstate* rnd, int use_caps_for_id, + size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv, int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout, - int tcp_auth_query_timeout) + int tcp_auth_query_timeout, struct shared_ports* shared_ports) { struct outside_network* outnet = (struct outside_network*) calloc(1, sizeof(struct outside_network)); @@ -1713,6 +1767,7 @@ outside_network_create(struct comm_base outnet->do_udp = do_udp; outnet->tcp_mss = tcp_mss; outnet->ip_dscp = dscp; + outnet->shared_ports = shared_ports; #ifndef S_SPLINT_S if(delayclose) { outnet->delayclose = 1; @@ -1723,11 +1778,18 @@ outside_network_create(struct comm_base if(udp_connect) { outnet->udp_connect = 1; } - if(numavailports == 0 || num_ports == 0) { + if(num_ports == 0) { log_err("no outgoing ports available"); outside_network_delete(outnet); return NULL; } +#ifdef INT_MAX + if(num_ports > (size_t)INT_MAX) { + log_err("outgoing num_ports exceeds INT_MAX"); + outside_network_delete(outnet); + return NULL; + } +#endif #ifndef INET6 do_ip6 = 0; #endif @@ -1784,13 +1846,13 @@ outside_network_create(struct comm_base /* allocate interfaces */ if(num_ifs == 0) { if(do_ip4 && !setup_if(&outnet->ip4_ifs[0], "0.0.0.0", - availports, numavailports, num_ports)) { + num_ports, outnet->shared_ports)) { log_err("malloc failed"); outside_network_delete(outnet); return NULL; } if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::", - availports, numavailports, num_ports)) { + num_ports, outnet->shared_ports)) { log_err("malloc failed"); outside_network_delete(outnet); return NULL; @@ -1801,7 +1863,7 @@ outside_network_create(struct comm_base for(i=0; iip6_ifs[done_6], ifs[i], - availports, numavailports, num_ports)){ + num_ports, outnet->shared_ports)){ log_err("malloc failed"); outside_network_delete(outnet); return NULL; @@ -1810,7 +1872,7 @@ outside_network_create(struct comm_base } if(!str_is_ip6(ifs[i]) && do_ip4) { if(!setup_if(&outnet->ip4_ifs[done_4], ifs[i], - availports, numavailports, num_ports)){ + num_ports, outnet->shared_ports)){ log_err("malloc failed"); outside_network_delete(outnet); return NULL; @@ -1888,9 +1950,6 @@ outside_network_delete(struct outside_ne comm_point_delete(pc->cp); free(pc); } -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - free(outnet->ip4_ifs[i].avail_ports); -#endif free(outnet->ip4_ifs[i].out); } free(outnet->ip4_ifs); @@ -1904,9 +1963,6 @@ outside_network_delete(struct outside_ne comm_point_delete(pc->cp); free(pc); } -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - free(outnet->ip6_ifs[i].avail_ports); -#endif free(outnet->ip6_ifs[i].out); } free(outnet->ip6_ifs); @@ -1922,6 +1978,10 @@ outside_network_delete(struct outside_ne * the tcp conn is working on */ decommission_pending_tcp(outnet, pend); } + if(pend->reuse.tls_auth_name) { + free(pend->reuse.tls_auth_name); + pend->reuse.tls_auth_name = NULL; + } comm_point_delete(outnet->tcp_conns[i]->c); free(outnet->tcp_conns[i]); outnet->tcp_conns[i] = NULL; @@ -2112,7 +2172,10 @@ static int select_ifport(struct outside_network* outnet, struct pending* pend, int num_if, struct port_if* ifs) { - int my_if, my_port, fd, portno, inuse, tries=0; + int my_if, fd, portno, inuse, tries=0; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int reused; +#endif struct port_if* pif; /* randomly select interface and port */ if(num_if == 0) { @@ -2126,37 +2189,35 @@ select_ifport(struct outside_network* ou my_if = ub_random_max(outnet->rnd, num_if); pif = &ifs[my_if]; #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - if(outnet->udp_connect) { - /* if we connect() we cannot reuse fds for a port */ - if(pif->inuse >= pif->avail_total) { - tries++; - if(tries < MAX_PORT_RETRY) - continue; - log_err("failed to find an open port, drop msg"); - return 0; - } - my_port = pif->inuse + ub_random_max(outnet->rnd, - pif->avail_total - pif->inuse); - } else { - my_port = ub_random_max(outnet->rnd, pif->avail_total); - if(my_port < pif->inuse) { - /* port already open */ - pend->pc = pif->out[my_port]; - verbose(VERB_ALGO, "using UDP if=%d port=%d", - my_if, pend->pc->number); - break; - } + if(!shared_ports_fetch_random(outnet->shared_ports, + pif->shpif, outnet->rnd, outnet->udp_connect, + pif->inuse, &portno, &reused)) { + tries++; + if(tries < MAX_PORT_RETRY) + continue; + log_err("failed to find an open port, drop msg"); + return 0; + } + if(reused) { + /* port already open */ + log_assert(portno < pif->inuse); + pend->pc = pif->out[portno]; + verbose(VERB_ALGO, "using UDP if=%d port=%d", + my_if, pend->pc->number); + break; } - /* try to open new port, if fails, loop to try again */ - log_assert(pif->inuse < pif->maxout); - portno = pif->avail_ports[my_port - pif->inuse]; #else - my_port = portno = 0; + portno = 0; #endif + /* try to open new port, if fails, loop to try again */ fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen, portno, &inuse, outnet->rnd, outnet->ip_dscp); if(fd == -1 && !inuse) { /* nonrecoverable error making socket */ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + shared_ports_return_port(outnet->shared_ports, + pif->shpif, portno); +#endif return 0; } if(fd != -1) { @@ -2173,6 +2234,11 @@ select_ifport(struct outside_network* ou pend->addrlen); } sock_close(fd); +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + shared_ports_return_port( + outnet->shared_ports, + pif->shpif, portno); +#endif return 0; } } @@ -2190,14 +2256,14 @@ select_ifport(struct outside_network* ou /* grab port in interface */ pif->out[pif->inuse] = pend->pc; -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pif->avail_ports[my_port - pif->inuse] = - pif->avail_ports[pif->avail_total-pif->inuse-1]; -#endif pif->inuse++; break; } /* failed, already in use */ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + shared_ports_return_port(outnet->shared_ports, pif->shpif, + portno); +#endif verbose(VERB_QUERY, "port %d in use, trying another", portno); tries++; if(tries == MAX_PORT_RETRY) { @@ -2447,7 +2513,7 @@ pending_tcp_query(struct serviced_query* /* find out if a reused stream to the target exists */ /* if so, take it into use */ reuse = reuse_tcp_find(sq->outnet, &sq->addr, sq->addrlen, - sq->ssl_upstream); + sq->ssl_upstream, sq->tls_auth_name); if(reuse) { log_reuse_tcp(VERB_CLIENT, "pending_tcp_query: found reuse", reuse); log_assert(reuse->pending); @@ -2489,7 +2555,16 @@ pending_tcp_query(struct serviced_query* w->cb = callback; w->cb_arg = callback_arg; w->ssl_upstream = sq->ssl_upstream; - w->tls_auth_name = sq->tls_auth_name; + if(sq->tls_auth_name) { + w->tls_auth_name = strdup(sq->tls_auth_name); + if(!w->tls_auth_name) { + comm_timer_delete(w->timer); + free(w); + return NULL; + } + } else { + w->tls_auth_name = NULL; + } w->timeout = timeout; w->id_node.key = NULL; w->write_wait_prev = NULL; @@ -3287,9 +3362,9 @@ serviced_udp_callback(struct comm_point* if(error == NETEVENT_TIMEOUT) { if(sq->status == serviced_query_UDP_EDNS && sq->last_rtt < 5000 && (serviced_query_udp_size(sq, serviced_query_UDP_EDNS_FRAG) < serviced_query_udp_size(sq, serviced_query_UDP_EDNS))) { - /* fallback to 1480/1280 */ + /* fallback to 1472/1232 */ sq->status = serviced_query_UDP_EDNS_FRAG; - log_name_addr(VERB_ALGO, "try edns1xx0", sq->qbuf+10, + log_name_addr(VERB_ALGO, "try edns1xx2", sq->qbuf+10, &sq->addr, sq->addrlen); if(!serviced_udp_send(sq, c->buffer)) { serviced_callbacks(sq, NETEVENT_CLOSED, c, rep); @@ -3426,7 +3501,8 @@ outnet_serviced_query(struct outside_net char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, struct module_qstate* qstate, comm_point_callback_type* callback, void* callback_arg, - sldns_buffer* buff, struct module_env* env, int* was_ratelimited) + sldns_buffer* buff, struct module_env* env, int* was_ratelimited, + int* ratelimit_incremented) { struct serviced_query* sq; struct service_callback* cb; @@ -3498,6 +3574,7 @@ outnet_serviced_query(struct outside_net "delegation point", zone, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN); } + *ratelimit_incremented = 1; } /* make new serviced query entry */ sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps, @@ -3579,13 +3656,16 @@ fd_for_dest(struct outside_network* outn { struct sockaddr_storage* addr; socklen_t addrlen; - int i, try, pnum, dscp; + int i, try, dscp; struct port_if* pif; /* create fd */ dscp = outnet->ip_dscp; for(try = 0; try<1000; try++) { int port = 0; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int reused = 0; +#endif int freebind = 0; int noproto = 0; int inuse = 0; @@ -3614,16 +3694,18 @@ fd_for_dest(struct outside_network* outn addr = &pif->addr; addrlen = pif->addrlen; #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - pnum = ub_random_max(outnet->rnd, pif->avail_total); - if(pnum < pif->inuse) { - /* port already open */ - port = pif->out[pnum]->number; - } else { - /* unused ports in start part of array */ - port = pif->avail_ports[pnum - pif->inuse]; + if(!shared_ports_fetch_random(outnet->shared_ports, + pif->shpif, outnet->rnd, 0, pif->inuse, + &port, &reused)) { + /* try again, perhaps another interface. */ + continue; + } + if(reused) { + log_assert(port < pif->inuse); + port = pif->out[port]->number; } #else - pnum = port = 0; + port = 0; #endif if(addr_is_ip6(to_addr, to_addrlen)) { struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; @@ -3638,6 +3720,14 @@ fd_for_dest(struct outside_network* outn (struct sockaddr*)addr, addrlen, 1, &inuse, &noproto, 0, 0, 0, NULL, 0, freebind, 0, dscp); } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + if(!reused) { + /* Return the port to the pool, since the caller does + * not keep track of it, also have done fd, and bind. */ + shared_ports_return_port(outnet->shared_ports, + pif->shpif, port); + } +#endif if(fd != -1) { return fd; } @@ -3690,7 +3780,33 @@ setup_comm_ssl(struct comm_point* cp, st (void)SSL_set_tlsext_host_name(cp->ssl, host); } #endif -#ifdef HAVE_SSL_SET1_HOST +#ifdef HAVE_SSL_SET1_DNSNAME + if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) { + /* because we set SSL_VERIFY_PEER, in netevent in + * ssl_handshake, it'll check if the certificate + * verification has succeeded */ + /* SSL_VERIFY_PEER is set on the sslctx */ + /* and the certificates to verify with are loaded into + * it with SSL_load_verify_locations or + * SSL_CTX_set_default_verify_paths */ + /* setting the hostname makes openssl verify the + * host name in the x509 certificate in the + * SSL connection*/ + struct sockaddr_storage tmpaddr; + socklen_t tmpaddrlen = (socklen_t)sizeof(tmpaddr); + if(ipstrtoaddr(host, UNBOUND_DNS_PORT, &tmpaddr, &tmpaddrlen)) { + if(!SSL_set1_ipaddr(cp->ssl, host)) { + log_err("SSL_set1_ipaddr failed"); + return 0; + } + } else { + if(!SSL_set1_dnsname(cp->ssl, host)) { + log_err("SSL_set1_dnsname failed"); + return 0; + } + } + } +#elif defined(HAVE_SSL_SET1_HOST) if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) { /* because we set SSL_VERIFY_PEER, in netevent in * ssl_handshake, it'll check if the certificate @@ -3819,7 +3935,8 @@ outnet_comm_point_for_http(struct outsid /* outnet_tcp_connect has closed fd on error for us */ return 0; } - cp = comm_point_create_http_out(outnet->base, 65552, cb, cb_arg, + cp = comm_point_create_http_out(outnet->base, + sldns_buffer_capacity(outnet->udp_buff), cb, cb_arg, outnet->udp_buff); if(!cp) { log_err("malloc failure"); @@ -3868,11 +3985,7 @@ if_get_mem(struct port_if* pif) { size_t s; int i; - s = sizeof(*pif) + -#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - sizeof(int)*pif->avail_total + -#endif - sizeof(struct port_comm*)*pif->maxout; + s = sizeof(*pif) + sizeof(struct port_comm*)*pif->maxout; for(i=0; iinuse; i++) s += sizeof(*pif->out[i]) + comm_point_get_mem(pif->out[i]->cp); @@ -3960,3 +4073,250 @@ serviced_get_mem(struct serviced_query* return s; } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION +/** Setup shared port interface */ +static int shared_ports_setup_if(struct shared_ports_if* shpif, char* str, + int* availports, int numavailports) +{ + shpif->avail_ports = (int*)memdup(availports, + (size_t)numavailports*sizeof(int)); + if(!shpif->avail_ports) + return 0; + shpif->avail_total = numavailports; + shpif->inuse = 0; + shpif->pfxlen = 0; + if(!ipstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, &shpif->addrlen) && + !netblockstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, + &shpif->addrlen, &shpif->pfxlen)) + return 0; + return 1; +} +#endif + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION +/** Allocate shared ports interfaces */ +static int shared_ports_alloc_ifs(struct shared_ports* shp, char** ifs, + int num_ifs, int do_ip4, int do_ip6, int* availports, + int numavailports) +{ +#ifndef INET6 + do_ip6 = 0; +#endif + calc_num46(ifs, num_ifs, do_ip4, do_ip6, + &shp->num_ip4, &shp->num_ip6); + if(shp->num_ip4 != 0) { + if(!(shp->ip4_ifs = (struct shared_ports_if*)calloc( + (size_t)shp->num_ip4, + sizeof(struct shared_ports_if)))) + return 0; + } + if(shp->num_ip6 != 0) { + if(!(shp->ip6_ifs = (struct shared_ports_if*)calloc( + (size_t)shp->num_ip6, + sizeof(struct shared_ports_if)))) + return 0; + } + if(num_ifs == 0) { + if(do_ip4 && !shared_ports_setup_if(&shp->ip4_ifs[0], + "0.0.0.0", availports, numavailports)) + return 0; + if(do_ip6 && !shared_ports_setup_if(&shp->ip6_ifs[0], + "::", availports, numavailports)) + return 0; + } else { + size_t done_4 = 0, done_6 = 0; + int i; + for(i=0; inum_ip6) { + if(!shared_ports_setup_if(&shp->ip6_ifs[done_6], + ifs[i], availports, numavailports)) + return 0; + done_6++; + } + if(!str_is_ip6(ifs[i]) && do_ip4 && + (int)done_4 < shp->num_ip4) { + if(!shared_ports_setup_if(&shp->ip4_ifs[done_4], + ifs[i], availports, numavailports)) + return 0; + done_4++; + } + } + } + return 1; +} +#endif + +struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4, + int do_ip6, int* availports, int numavailports) +{ + struct shared_ports* shp = calloc(1, sizeof(*shp)); + if(!shp) { + log_err("malloc failed"); + return NULL; + } + lock_basic_init(&shp->lock); + lock_protect(&shp->lock, &shp->ip4_ifs, sizeof(shp->ip4_ifs)); + lock_protect(&shp->lock, &shp->num_ip4, sizeof(shp->num_ip4)); + lock_protect(&shp->lock, &shp->ip6_ifs, sizeof(shp->ip6_ifs)); + lock_protect(&shp->lock, &shp->num_ip6, sizeof(shp->num_ip6)); + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + /* Allocate interfaces */ + lock_basic_lock(&shp->lock); + if(!shared_ports_alloc_ifs(shp, ifs, num_ifs, do_ip4, do_ip6, + availports, numavailports)) { + log_err("malloc failed"); + shared_ports_delete(shp); + return NULL; + } + lock_basic_unlock(&shp->lock); +#else + (void)ifs; (void)num_ifs; (void)do_ip4; (void)do_ip6; + (void)availports; (void)numavailports; +#endif + return shp; +} + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION +/** Delete shared ports interface structure */ +static void shared_ports_if_delete(struct shared_ports_if* shpif) +{ + if(!shpif) + return; + free(shpif->avail_ports); +} +#endif + +void shared_ports_delete(struct shared_ports* shp) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int i; +#endif + if(!shp) + return; + lock_basic_destroy(&shp->lock); +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + for(i=0; inum_ip4; i++) { + shared_ports_if_delete(&shp->ip4_ifs[i]); + } + free(shp->ip4_ifs); + for(i=0; inum_ip6; i++) { + shared_ports_if_delete(&shp->ip6_ifs[i]); + } + free(shp->ip6_ifs); +#endif + free(shp); +} + +struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp, + struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + struct shared_ports_if* ret, *ifs = NULL; + int i, num_ifs = 0; + lock_basic_lock(&shp->lock); + if(addr_is_ip6(addr, addrlen)) { + ifs = shp->ip6_ifs; + num_ifs = shp->num_ip6; + } else { + ifs = shp->ip4_ifs; + num_ifs = shp->num_ip4; + } + for(i=0; ilock); + return ret; + } + } + lock_basic_unlock(&shp->lock); + return NULL; +#else + (void)shp; (void)addr; (void)addrlen; (void)pfxlen; + return NULL; +#endif +} + +int shared_ports_fetch_random(struct shared_ports* shp, + struct shared_ports_if* shpif, struct ub_randstate* rnd, + int udp_connect, int reusenum, int* port, int* reused) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + int portno = 0, my_port = 0; + if(!shpif) + return 0; +# ifdef THREADS_DISABLED + (void)shp; +# endif + lock_basic_lock(&shp->lock); + if(udp_connect) { + /* if we connect() we cannot reuse fds for a port. */ + if(shpif->inuse >= shpif->avail_total) { + lock_basic_unlock(&shp->lock); + return 0; + } + my_port = ub_random_max(rnd, + shpif->avail_total - shpif->inuse); + } else { + /* select from free ports and open ports on this thread. */ + if(shpif->inuse >= shpif->avail_total) { + lock_basic_unlock(&shp->lock); + if(reusenum == 0) { + return 0; + } + my_port = ub_random_max(rnd, reusenum); + *port = my_port; + *reused = 1; + return 1; + } + my_port = ub_random_max(rnd, shpif->avail_total - shpif->inuse + + reusenum); + if(my_port < reusenum) { + /* port already open */ + lock_basic_unlock(&shp->lock); + *port = my_port; + *reused = 1; + return 1; + } + my_port -= reusenum; + } + log_assert(shpif->inuse < shpif->avail_total); + log_assert(my_port >= 0 && my_port < shpif->avail_total); + portno = shpif->avail_ports[my_port]; + shpif->avail_ports[my_port] = + shpif->avail_ports[shpif->avail_total-shpif->inuse-1]; + shpif->inuse++; + lock_basic_unlock(&shp->lock); + *port = portno; + *reused = 0; + return 1; +#else + (void)shp; (void)shpif; (void)rnd; (void)udp_connect; + (void)reusenum; + *port = 0; + *reused = 0; + return 1; +#endif +} + +void shared_ports_return_port(struct shared_ports* shp, + struct shared_ports_if* shpif, int port) +{ +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + if(!shpif) + return; +# ifdef THREADS_DISABLED + (void)shp; +# endif + lock_basic_lock(&shp->lock); + log_assert(shpif->inuse > 0); + shpif->avail_ports[shpif->avail_total - shpif->inuse] = port; + shpif->inuse--; + lock_basic_unlock(&shp->lock); +#else + (void)shp; (void)shpif; (void)port; +#endif +} Index: usr.sbin/unbound/services/outside_network.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/outside_network.h,v diff -u -p -r1.17 outside_network.h --- usr.sbin/unbound/services/outside_network.h 31 Aug 2025 21:41:09 -0000 1.17 +++ usr.sbin/unbound/services/outside_network.h 21 Sep 2026 16:28:08 -0000 @@ -48,6 +48,10 @@ #include "util/regional.h" #include "util/netevent.h" #include "dnstap/dnstap_config.h" +#ifdef __QNX__ +/* For struct timeval */ +#include +#endif /* __QNX__ */ struct pending; struct pending_timeout; struct ub_randstate; @@ -66,6 +70,8 @@ struct module_env; struct module_qstate; struct query_info; struct config_file; +struct shared_ports; +struct shared_ports_if; /** * Send queries to outside servers and wait for answers from servers. @@ -115,6 +121,9 @@ struct outside_network { int udp_connect; /** number of udp packets sent. */ size_t num_udp_outgoing; + /** the shared ports structure, with random ports numbers. + * This is a reference to the member in the daemon structure. */ + struct shared_ports* shared_ports; /** array of outgoing IP4 interfaces */ struct port_if* ip4_ifs; @@ -207,11 +216,8 @@ struct port_if { int pfxlen; #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION - /** the available ports array. These are unused. - * Only the first total-inuse part is filled. */ - int* avail_ports; - /** the total number of available ports (size of the array) */ - int avail_total; + /** the shared port numbers for this interface. */ + struct shared_ports_if* shpif; #endif /** array of the commpoints currently in use. @@ -242,6 +248,42 @@ struct port_comm { }; /** + * Shared ports, the list of ports shared across threads + */ +struct shared_ports { + /** mutex on the ports */ + lock_basic_type lock; + /** array of IP4 interfaces */ + struct shared_ports_if* ip4_ifs; + /** number of outgoing IP4 interfaces */ + int num_ip4; + /** array of IP6 interfaces */ + struct shared_ports_if* ip6_ifs; + /** number of outgoing IP6 interfaces */ + int num_ip6; +}; + +/** + * Shared ports for an interface. + */ +struct shared_ports_if { + /** address ready to allocate new socket (except port no). */ + struct sockaddr_storage addr; + /** length of addr field */ + socklen_t addrlen; + /** if a netblock, the prefix */ + int pfxlen; + + /** the available ports array. These are unused. + * Only the first total-inuse part is filled. */ + int* avail_ports; + /** the total number of available ports (size of the array) */ + int avail_total; + /** the number in use. */ + int inuse; +}; + +/** * Reuse TCP connection, still open can be used again. */ struct reuse_tcp { @@ -260,6 +302,9 @@ struct reuse_tcp { socklen_t addrlen; /** also key for tcp_reuse tree, if ssl is used */ int is_ssl; + /** If is_ssl is enabled, tls_auth_name is part of the key for + * tcp_reuse tree. If the string is NULL, it without a tls_auth_name */ + char* tls_auth_name; /** lru chain, so that the oldest can be removed to get a new * connection when all are in (re)use. oldest is last in list. * The lru only contains empty connections waiting for reuse, @@ -412,7 +457,7 @@ struct waiting_tcp { void* cb_arg; /** if it uses ssl upstream */ int ssl_upstream; - /** ref to the tls_auth_name from the serviced_query */ + /** owned copy of the tls_auth_name (malloced) */ char* tls_auth_name; /** the packet was involved in an error, to stop looping errors */ int error_count; @@ -493,7 +538,7 @@ struct serviced_query { serviced_query_UDP_EDNS_fallback, /** probe to test TCP noEDNS0 (EDNS gives FORMERRorNOTIMP) */ serviced_query_TCP_EDNS_fallback, - /** send UDP query with EDNS1480 (or 1280) */ + /** send UDP query with EDNS1472 (or 1232) */ serviced_query_UDP_EDNS_FRAG } /** variable with current status */ @@ -544,8 +589,6 @@ struct serviced_query { * @param infra: pointer to infra cached used for serviced queries. * @param rnd: stored to create random numbers for serviced queries. * @param use_caps_for_id: enable to use 0x20 bits to encode id randomness. - * @param availports: array of available ports. - * @param numavailports: number of available ports in array. * @param unwanted_threshold: when to take defensive action. * @param unwanted_action: the action to take. * @param unwanted_param: user parameter to action. @@ -560,17 +603,18 @@ struct serviced_query { * @param max_reuse_tcp_queries: max number of queries on a reuse connection. * @param tcp_reuse_timeout: timeout for REUSE entries in milliseconds. * @param tcp_auth_query_timeout: timeout in milliseconds for TCP queries to auth servers. + * @param shared_ports: the shared_ports structure. * @return: the new structure (with no pending answers) or NULL on error. */ struct outside_network* outside_network_create(struct comm_base* base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, - struct ub_randstate* rnd, int use_caps_for_id, int* availports, - int numavailports, size_t unwanted_threshold, int tcp_mss, + struct ub_randstate* rnd, int use_caps_for_id, + size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv, int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout, - int tcp_auth_query_timeout); + int tcp_auth_query_timeout, struct shared_ports* shared_ports); /** * Delete outside_network structure. @@ -653,6 +697,8 @@ void pending_delete(struct outside_netwo * @param env: the module environment. * @param was_ratelimited: it will signal back if the query failed to pass the * ratelimit check. + * @param ratelimit_incremented: set to true if the ratelimit counter + * was increased. * @return 0 on error, or pointer to serviced query that is used to answer * this serviced query may be shared with other callbacks as well. */ @@ -662,7 +708,8 @@ struct serviced_query* outnet_serviced_q char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, struct module_qstate* qstate, comm_point_callback_type* callback, void* callback_arg, - struct sldns_buffer* buff, struct module_env* env, int* was_ratelimited); + struct sldns_buffer* buff, struct module_env* env, int* was_ratelimited, + int* ratelimit_incremented); /** * Remove service query callback. @@ -811,6 +858,54 @@ struct comm_point* outnet_comm_point_for /** connect tcp connection to addr, 0 on failure */ int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen); + +/** + * Create new shared ports structure. + * @param ifs: interface names (or NULL for default interface). + * These interfaces must be able to access all authoritative servers. + * @param num_ifs: number of names in array ifs. + * @param do_ip4: service IP4. + * @param do_ip6: service IP6. + * @param availports: array of available ports. + * @param numavailports: number of available ports in array. + * @return new, or NULL on failure. + */ +struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4, + int do_ip6, int* availports, int numavailports); + +/** + * Delete shared ports structure. + * @param shp: shared ports structure. + */ +void shared_ports_delete(struct shared_ports* shp); + +/** Find interface in shared ports. */ +struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp, + struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen); + +/** + * Get a shared port from the list of random ports. + * @param shp: shared ports structure. + * @param shpif: the shared ports interface. + * @param rnd: used to make random numbers. + * @param udp_connect: set to true if no reuse is possible. + * @param reusenum: number of ports that can be reused (already open). + * @param port: the port number is returned. + * @param reused: if the port numer is reused, returned. + * @return false on failure. That can mean no more free ports to use. + */ +int shared_ports_fetch_random(struct shared_ports* shp, + struct shared_ports_if* shpif, struct ub_randstate* rnd, + int udp_connect, int reusenum, int* port, int* reused); + +/** + * Return a shared port to the list of random ports. + * @param shp: shared ports structure. + * @param shpif: the shared ports interface. + * @param port: port number to return to be used again. + */ +void shared_ports_return_port(struct shared_ports* shp, + struct shared_ports_if* shpif, int port); /** callback for incoming udp answers from the network */ int outnet_udp_cb(struct comm_point* c, void* arg, int error, Index: usr.sbin/unbound/services/rpz.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/rpz.c,v diff -u -p -r1.1.1.16 rpz.c --- usr.sbin/unbound/services/rpz.c 26 Sep 2025 07:30:47 -0000 1.1.1.16 +++ usr.sbin/unbound/services/rpz.c 21 Sep 2026 16:28:08 -0000 @@ -153,6 +153,7 @@ rpz_type_ignored(uint16_t rr_type) case LDNS_RR_TYPE_SOA: case LDNS_RR_TYPE_NS: case LDNS_RR_TYPE_DNAME: + case LDNS_RR_TYPE_ZONEMD: /* all DNSSEC-related RRs must be ignored */ case LDNS_RR_TYPE_DNSKEY: case LDNS_RR_TYPE_DS: @@ -720,13 +721,22 @@ rpz_insert_local_zones_trigger(struct lo char* rrstr = sldns_wire2str_rr(rr, rr_len); if(rrstr == NULL) { log_err("malloc error while inserting rpz nsdname trigger"); - free(dname); + if(!newzone) + free(dname); lock_rw_unlock(&lz->lock); return; } lock_rw_wrlock(&z->lock); - local_zone_enter_rr(z, dname, dnamelen, dnamelabs, rrtype, - rrclass, ttl, rdata, rdata_len, rrstr); + if(!local_zone_enter_rr(z, dname, dnamelen, dnamelabs, rrtype, + rrclass, ttl, rdata, rdata_len, rrstr)) { + log_err("rpz: could not enter local-data: %s", rrstr); + if(!newzone) + free(dname); + lock_rw_unlock(&z->lock); + lock_rw_unlock(&lz->lock); + free(rrstr); + return; + } lock_rw_unlock(&z->lock); free(rrstr); } @@ -804,8 +814,9 @@ rpz_insert_nsdname_trigger(struct rpz* r uint8_t* dname_stripped = NULL; size_t dnamelen_stripped = 0; - rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped, - &dnamelen_stripped); + if(!rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped, + &dnamelen_stripped)) + return; if(a == RPZ_INVALID_ACTION) { verbose(VERB_ALGO, "rpz: skipping invalid action"); free(dname_stripped); @@ -903,8 +914,8 @@ rpz_report_rrset_error(const char* msg, /* from localzone.c; difference is we don't have a dname */ static struct local_rrset* -rpz_clientip_new_rrset(struct regional* region, - struct clientip_synthesized_rr* raddr, uint16_t rrtype, uint16_t rrclass) +rpz_clientip_new_rrset(struct regional* region, uint16_t rrtype, + uint16_t rrclass) { struct packed_rrset_data* pd; struct local_rrset* rrset = (struct local_rrset*) @@ -913,8 +924,6 @@ rpz_clientip_new_rrset(struct regional* log_err("out of memory"); return NULL; } - rrset->next = raddr->data; - raddr->data = rrset; rrset->rrset = (struct ub_packed_rrset_key*) regional_alloc_zero(region, sizeof(*rrset->rrset)); if(rrset->rrset == NULL) { @@ -953,12 +962,18 @@ rpz_clientip_enter_rr(struct regional* r return 0; } - rrset = rpz_clientip_new_rrset(region, raddr, rrtype, rrclass); - if(raddr->data == NULL) { + rrset = rpz_clientip_new_rrset(region, rrtype, rrclass); + if(rrset == NULL) { return 0; } - return rrset_insert_rr(region, rrset->rrset->entry.data, rdata, rdata_len, ttl, ""); + if(!rrset_insert_rr(region, rrset->rrset->entry.data, rdata, rdata_len, ttl, "")) + return 0; + + /* Link in now that the allocations have succeeded. */ + rrset->next = raddr->data; + raddr->data = rrset; + return 1; } static int @@ -981,7 +996,6 @@ rpz_clientip_insert_trigger_rr(struct cl lock_rw_wrlock(&node->lock); lock_rw_unlock(&set->lock); - node->action = a; if(a == RPZ_LOCAL_DATA_ACTION) { if(!rpz_clientip_enter_rr(set->region, node, rrtype, rrclass, ttl, rdata, rdata_len)) { @@ -991,6 +1005,7 @@ rpz_clientip_insert_trigger_rr(struct cl } } + node->action = a; lock_rw_unlock(&node->lock); @@ -1976,8 +1991,9 @@ rpz_synthesize_nodata(struct rpz* ATTR_U 0, /* total */ sec_status_insecure, LDNS_EDE_NONE); - if(msg->rep) - msg->rep->authoritative = 1; + if(!msg->rep) + return NULL; + msg->rep->authoritative = 1; if(!rpz_add_soa(msg->rep, ms, az)) return NULL; return msg; @@ -2007,8 +2023,9 @@ rpz_synthesize_nxdomain(struct rpz* r, s 0, /* total */ sec_status_insecure, LDNS_EDE_NONE); - if(msg->rep) - msg->rep->authoritative = 1; + if(!msg->rep) + return NULL; + msg->rep->authoritative = 1; if(!rpz_add_soa(msg->rep, ms, az)) return NULL; return msg; @@ -2468,6 +2485,7 @@ rpz_callback_from_iterator_module(struct { struct auth_zones* az; struct auth_zone* a; + struct dns_msg* ret = NULL; struct clientip_synthesized_rr* raddr = NULL; struct rpz* r = NULL; struct local_zone* z = NULL; @@ -2511,13 +2529,11 @@ rpz_callback_from_iterator_module(struct z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones, is->qchase.qclass, &match); if(z != NULL) { - lock_rw_unlock(&a->lock); break; } raddr = rpz_delegation_point_ipbased_trigger_lookup(r, is); if(raddr != NULL) { - lock_rw_unlock(&a->lock); break; } lock_rw_unlock(&a->lock); @@ -2532,9 +2548,12 @@ rpz_callback_from_iterator_module(struct if(z) { lock_rw_unlock(&z->lock); } - return rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a); + ret = rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a); + } else { + ret = rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a); } - return rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a); + lock_rw_unlock(&a->lock); + return ret; } struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, Index: usr.sbin/unbound/services/cache/dns.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/cache/dns.c,v diff -u -p -r1.27 dns.c --- usr.sbin/unbound/services/cache/dns.c 31 Aug 2025 21:41:09 -0000 1.27 +++ usr.sbin/unbound/services/cache/dns.c 21 Sep 2026 16:28:08 -0000 @@ -43,6 +43,7 @@ #include "iterator/iter_utils.h" #include "validator/val_nsec.h" #include "validator/val_utils.h" +#include "iterator/iter_utils.h" #include "services/cache/dns.h" #include "services/cache/rrset.h" #include "util/data/msgparse.h" @@ -60,10 +61,10 @@ * @param rep: contains list of rrsets to store. * @param now: current time. * @param leeway: during prefetch how much leeway to update TTLs. - * This makes rrsets (other than type NS) timeout sooner so they get - * updated with a new full TTL. - * Type NS does not get this, because it must not be refreshed from the - * child domain, but keep counting down properly. + * This makes rrsets expire sooner so they get updated with a new full + * TTL. + * Child side type NS does get this but TTL checks are done using the time + * the query was created rather than the time the answer was received. * @param pside: if from parentside discovered NS, so that its NS is okay * in a prefetch situation to be updated (without becoming sticky). * @param qrep: update rrsets here if cache is better @@ -100,11 +101,20 @@ store_rrsets(struct module_env* env, str rep->ref[i].id != rep->ref[i].key->id) ck = NULL; else ck = packed_rrset_copy_region( - rep->ref[i].key, region, now); + rep->ref[i].key, region, + ((ntohs(rep->ref[i].key->rk.type)== + LDNS_RR_TYPE_NS && !pside)?qstarttime:now)); lock_rw_unlock(&rep->ref[i].key->entry.lock); if(ck) { /* use cached copy if memory allows */ qrep->rrsets[i] = ck; + ttl = ((struct packed_rrset_data*) + ck->entry.data)->ttl; + if(ttl < qrep->ttl) { + qrep->ttl = ttl; + qrep->prefetch_ttl = PREFETCH_TTL_CALC(qrep->ttl); + qrep->serve_expired_ttl = qrep->ttl + SERVE_EXPIRED_TTL; + } } } /* no break: also copy key item */ @@ -122,8 +132,8 @@ store_rrsets(struct module_env* env, str rep->ref[i].id == rep->ref[i].key->id) { ttl = ((struct packed_rrset_data*) rep->rrsets[i]->entry.data)->ttl; - if(ttl < min_ttl) min_ttl = ttl; - } + if(ttl < min_ttl) min_ttl = ttl; + } lock_rw_unlock(&rep->ref[i].key->entry.lock); } } @@ -169,10 +179,12 @@ dns_cache_store_msg(struct module_env* e /* there was a reply_info_sortref(rep) here but it seems to be * unnecessary, because the cache gets locked per rrset. */ - reply_info_set_ttls(rep, *env->now); + if((flags & DNSCACHE_STORE_EXPIRED_MSG_CACHEDB)) { + reply_info_absolute_ttls(rep, *env->now, *env->now - ttl); + } else reply_info_set_ttls(rep, *env->now); store_rrsets(env, rep, *env->now, leeway, pside, qrep, region, qstarttime); - if(ttl == 0 && !(flags & DNSCACHE_STORE_ZEROTTL)) { + if(ttl == 0) { /* we do not store the message, but we did store the RRs, * which could be useful for delegation information */ verbose(VERB_ALGO, "TTL 0: dropped msg from cache"); @@ -221,8 +233,15 @@ find_closest_of_type(struct module_env* /* snip off front part of qname until the type is found */ while(qnamelen > 0) { - if((rrset = rrset_cache_lookup(env->rrset_cache, qname, - qnamelen, searchtype, qclass, 0, now, 0))) { + rrset = rrset_cache_lookup(env->rrset_cache, qname, + qnamelen, searchtype, qclass, 0, now, 0); + if(!rrset && searchtype == LDNS_RR_TYPE_DNAME) + /* If not found, for type DNAME, try 0TTL stored, + * for its grace period. */ + rrset = rrset_cache_lookup(env->rrset_cache, qname, + qnamelen, searchtype, qclass, + PACKED_RRSET_UPSTREAM_0TTL, now, 0); + if(rrset) { uint8_t* origqname = qname; size_t origqnamelen = qnamelen; if(!noexpiredabove) @@ -259,6 +278,8 @@ find_closest_of_type(struct module_env* /* snip off front label */ lablen = *qname; + if(lablen == 0) + break; qname += lablen + 1; qnamelen -= lablen + 1; } @@ -272,8 +293,10 @@ addr_to_additional(struct ub_packed_rrse { if((msg->rep->rrsets[msg->rep->rrset_count] = packed_rrset_copy_region(rrset, region, now))) { + struct packed_rrset_data* d = rrset->entry.data; msg->rep->ar_numrrsets++; msg->rep->rrset_count++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); } } @@ -456,8 +479,10 @@ find_add_ds(struct module_env* env, stru /* add it to auth section. This is the second rrset. */ if((msg->rep->rrsets[msg->rep->rrset_count] = packed_rrset_copy_region(rrset, region, now))) { + struct packed_rrset_data* d = rrset->entry.data; msg->rep->ns_numrrsets++; msg->rep->rrset_count++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); } lock_rw_unlock(&rrset->entry.lock); } @@ -487,6 +512,8 @@ dns_msg_create(uint8_t* qname, size_t qn return NULL; /* integer overflow protection */ msg->rep->flags = BIT_QR; /* with QR, no AA */ msg->rep->qdcount = 1; + msg->rep->ttl = MAX_TTL; /* will be updated (brought down) while we add + * rrsets to the message */ msg->rep->reason_bogus = LDNS_EDE_NONE; msg->rep->rrsets = (struct ub_packed_rrset_key**) regional_alloc(region, @@ -497,24 +524,28 @@ dns_msg_create(uint8_t* qname, size_t qn } int -dns_msg_authadd(struct dns_msg* msg, struct regional* region, +dns_msg_authadd(struct dns_msg* msg, struct regional* region, struct ub_packed_rrset_key* rrset, time_t now) { - if(!(msg->rep->rrsets[msg->rep->rrset_count++] = + struct packed_rrset_data* d = rrset->entry.data; + if(!(msg->rep->rrsets[msg->rep->rrset_count++] = packed_rrset_copy_region(rrset, region, now))) return 0; msg->rep->ns_numrrsets++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); return 1; } int -dns_msg_ansadd(struct dns_msg* msg, struct regional* region, +dns_msg_ansadd(struct dns_msg* msg, struct regional* region, struct ub_packed_rrset_key* rrset, time_t now) { - if(!(msg->rep->rrsets[msg->rep->rrset_count++] = + struct packed_rrset_data* d = rrset->entry.data; + if(!(msg->rep->rrsets[msg->rep->rrset_count++] = packed_rrset_copy_region(rrset, region, now))) return 0; msg->rep->an_numrrsets++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); return 1; } @@ -556,8 +587,12 @@ dns_cache_find_delegation(struct module_ return NULL; } } - if(!delegpt_rrset_add_ns(dp, region, nskey, 0)) + if(!delegpt_rrset_add_ns(dp, region, nskey, 0, + deleg_port_number(env))) { + lock_rw_unlock(&nskey->entry.lock); log_err("find_delegation: addns out of memory"); + return NULL; + } lock_rw_unlock(&nskey->entry.lock); /* first unlock before next lookup*/ /* find and add DS/NSEC (if any) */ if(msg) @@ -585,6 +620,7 @@ gen_dns_msg(struct regional* region, str sizeof(struct reply_info) - sizeof(struct rrset_ref)); if(!msg->rep) return NULL; + msg->rep->ttl = MAX_TTL; msg->rep->reason_bogus = LDNS_EDE_NONE; msg->rep->reason_bogus_str = NULL; if(num > RR_COUNT_MAX) @@ -606,13 +642,13 @@ tomsg(struct module_env* env, struct que size_t i; int is_expired = 0; time_t now_control = now; - if(now > r->ttl) { + if(TTL_IS_EXPIRED(r->ttl, now)) { /* Check if we are allowed to serve expired */ if(!allow_expired || !reply_info_can_answer_expired(r, now)) return NULL; - /* Change the current time so we can pass the below TTL checks when - * serving expired data. */ - now_control = r->ttl - env->cfg->serve_expired_reply_ttl; + /* Change the current time so we can pass the below TTL checks + * when serving expired data. */ + now_control = 0; is_expired = 1; } @@ -620,15 +656,6 @@ tomsg(struct module_env* env, struct que if(!msg) return NULL; msg->rep->flags = r->flags; msg->rep->qdcount = r->qdcount; - msg->rep->ttl = is_expired - ?SERVE_EXPIRED_REPLY_TTL - :r->ttl - now; - if(r->prefetch_ttl > now) - msg->rep->prefetch_ttl = r->prefetch_ttl - now; - else - msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); - msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; - msg->rep->serve_expired_norec_ttl = 0; msg->rep->security = r->security; msg->rep->an_numrrsets = r->an_numrrsets; msg->rep->ns_numrrsets = r->ns_numrrsets; @@ -650,19 +677,36 @@ tomsg(struct module_env* env, struct que rrset_array_unlock(r->ref, r->rrset_count); return NULL; } - if(r->security == sec_status_secure && !reply_all_rrsets_secure(r)) { + if(r->security == sec_status_secure && !reply_an_ns_rrsets_secure(r)) { /* message rrsets have changed status, revalidate */ rrset_array_unlock(r->ref, r->rrset_count); return NULL; } for(i=0; irep->rrset_count; i++) { + struct packed_rrset_data* d; msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i], region, now); if(!msg->rep->rrsets[i]) { rrset_array_unlock(r->ref, r->rrset_count); return NULL; } + d = msg->rep->rrsets[i]->entry.data; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); + } + if(msg->rep->rrset_count < 1) { + msg->rep->ttl = is_expired + ?SERVE_EXPIRED_REPLY_TTL + :r->ttl - now; + if(r->prefetch_ttl > now) + msg->rep->prefetch_ttl = r->prefetch_ttl - now; + else + msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + } else { + /* msg->rep->ttl has been updated through the RRSets above */ + msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); } + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; + msg->rep->serve_expired_norec_ttl = 0; if(env) rrset_array_unlock_touch(env->rrset_cache, scratch, r->ref, r->rrset_count); @@ -675,10 +719,16 @@ struct dns_msg* dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region) { size_t i; + struct ub_packed_rrset_key** saved_rrsets; struct dns_msg* res = NULL; + size_t rep_alloc_size = sizeof(struct reply_info) + - sizeof(struct rrset_ref); /* this is the size of res->rep + allocated in gen_dns_msg() */ res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count); if(!res) return NULL; - *res->rep = *origin->rep; + saved_rrsets = res->rep->rrsets; /* save rrsets alloc by gen_dns_msg */ + memcpy(res->rep, origin->rep, rep_alloc_size); + res->rep->rrsets = saved_rrsets; if(origin->rep->reason_bogus_str) { res->rep->reason_bogus_str = regional_strdup(region, origin->rep->reason_bogus_str); @@ -701,7 +751,7 @@ rrset_msg(struct ub_packed_rrset_key* rr struct dns_msg* msg; struct packed_rrset_data* d = (struct packed_rrset_data*) rrset->entry.data; - if(now > d->ttl) + if(TTL_IS_EXPIRED(d->ttl, now)) return NULL; msg = gen_dns_msg(region, q, 1); /* only the CNAME (or other) RRset */ if(!msg) @@ -736,8 +786,20 @@ synth_dname_msg(struct ub_packed_rrset_k rrset->entry.data; uint8_t* newname, *dtarg = NULL; size_t newlen, dtarglen; - if(now > d->ttl) - return NULL; + time_t rr_ttl; + int graceperiod = 0; + if(TTL_IS_EXPIRED(d->ttl, now)) { + /* Allow TTL=0 DNAME from upstream within grace period */ + if(!(rrset->rk.flags & PACKED_RRSET_UPSTREAM_0TTL)) + return NULL; + rr_ttl = 0; + /* Since PACKED_RRSET_UPSTREAM_0TTL set the flag that + * the grace period has been applied, this stops the rrset + * from getting stored back into the cache with a bigger TTL.*/ + graceperiod = 1; + } else { + rr_ttl = d->ttl - now; + } /* only allow validated (with DNSSEC) DNAMEs used from cache * for insecure DNAMEs, query again. */ *sec_status = d->security; @@ -749,7 +811,7 @@ synth_dname_msg(struct ub_packed_rrset_k msg->rep->flags = BIT_QR; /* reply, no AA, no error */ msg->rep->authoritative = 0; /* reply stored in cache can't be authoritative */ msg->rep->qdcount = 1; - msg->rep->ttl = d->ttl - now; + msg->rep->ttl = rr_ttl; msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; msg->rep->serve_expired_norec_ttl = 0; @@ -762,6 +824,8 @@ synth_dname_msg(struct ub_packed_rrset_k msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now); if(!msg->rep->rrsets[0]) /* copy DNAME */ return NULL; + if(graceperiod) + msg->rep->rrsets[0]->rk.flags |= PACKED_RRSET_0TTL_GRACE; /* synth CNAME rrset */ get_cname_target(rrset, &dtarg, &dtarglen); if(!dtarg) @@ -801,7 +865,7 @@ synth_dname_msg(struct ub_packed_rrset_k if(!newd) return NULL; ck->entry.data = newd; - newd->ttl = d->ttl - now; /* RFC6672: synth CNAME TTL == DNAME TTL */ + newd->ttl = rr_ttl; /* RFC6672: synth CNAME TTL == DNAME TTL */ newd->count = 1; newd->rrsig_count = 0; newd->trust = rrset_trust_ans_noAA; @@ -844,6 +908,8 @@ fill_any(struct module_env* env, /* set NOTIMPL for RFC 8482 */ msg->rep->flags |= LDNS_RCODE_NOTIMPL; msg->rep->security = sec_status_indeterminate; + msg->rep->ttl = 1; /* empty NOTIMPL response will never be + * updated with rrsets, set TTL to 1 */ return msg; } @@ -1013,7 +1079,7 @@ dns_cache_lookup(struct module_env* env, if(env->cfg->harden_below_nxdomain) { while(!dname_is_root(k.qname)) { if(dpname && dpnamelen - && !dname_subdomain_c(k.qname, dpname)) + && !dname_strict_subdomain_c(k.qname, dpname)) break; /* no synth nxdomain above the stub */ dname_remove_label(&k.qname, &k.qname_len); h = query_info_hash(&k, flags); @@ -1069,7 +1135,7 @@ dns_cache_store(struct module_env* env, msgqinf->qclass, flags, 0, 1); if(e) { struct reply_info* cached = e->entry.data; - if(cached->ttl < *env->now + if(TTL_IS_EXPIRED(cached->ttl, *env->now) && reply_info_could_use_expired(cached, *env->now) /* If we are validating make sure only * validating modules can update such messages. Index: usr.sbin/unbound/services/cache/dns.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/cache/dns.h,v diff -u -p -r1.13 dns.h --- usr.sbin/unbound/services/cache/dns.h 31 Aug 2025 21:41:09 -0000 1.13 +++ usr.sbin/unbound/services/cache/dns.h 21 Sep 2026 16:28:08 -0000 @@ -53,7 +53,7 @@ struct delegpt; * Must be an unsigned 32-bit value larger than 0xffff */ /** Allow caching a DNS message with a zero TTL. */ -#define DNSCACHE_STORE_ZEROTTL 0x100000 +#define DNSCACHE_STORE_EXPIRED_MSG_CACHEDB 0x100000 /** * Region allocated message reply Index: usr.sbin/unbound/services/cache/infra.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/cache/infra.c,v diff -u -p -r1.18 infra.c --- usr.sbin/unbound/services/cache/infra.c 31 Aug 2025 21:41:09 -0000 1.18 +++ usr.sbin/unbound/services/cache/infra.c 21 Sep 2026 16:28:08 -0000 @@ -1269,7 +1269,8 @@ int infra_wait_limit_allowed(struct infr int cookie_valid, struct config_file* cfg) { struct lruhash_entry* entry; - if(cfg->wait_limit == 0) + if(cfg->wait_limit == 0 || + (cookie_valid && cfg->wait_limit_cookie == 0)) return 1; entry = infra_find_ip_ratedata(infra, &rep->client_addr, Index: usr.sbin/unbound/services/cache/rrset.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/services/cache/rrset.c,v diff -u -p -r1.10 rrset.c --- usr.sbin/unbound/services/cache/rrset.c 26 Sep 2025 07:32:37 -0000 1.10 +++ usr.sbin/unbound/services/cache/rrset.c 21 Sep 2026 16:28:08 -0000 @@ -50,6 +50,7 @@ #include "util/regional.h" #include "util/alloc.h" #include "util/net_help.h" +#include "validator/val_utils.h" void rrset_markdel(void* key) @@ -126,12 +127,13 @@ rrset_cache_touch(struct rrset_cache* r, /** see if rrset needs to be updated in the cache */ static int -need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) +need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns, + int a_aaaa) { struct packed_rrset_data* newd = (struct packed_rrset_data*)nd; struct packed_rrset_data* cached = (struct packed_rrset_data*)cd; /* o if new data is expired, cached data is better */ - if( newd->ttl < timenow && timenow <= cached->ttl) + if( TTL_IS_EXPIRED(newd->ttl, timenow) && !TTL_IS_EXPIRED(cached->ttl, timenow)) return 0; /* o store if rrset has been validated * everything better than bogus data @@ -146,13 +148,27 @@ need_to_update_rrset(void* nd, void* cd, if( newd->trust > cached->trust ) { /* if the cached rrset is bogus, and new is equal, * do not update the TTL - let it expire. */ - if(equal && cached->ttl >= timenow && + if(equal && !TTL_IS_EXPIRED(cached->ttl, timenow) && cached->security == sec_status_bogus) return 0; + /* ghost-domain: never let an NS overwrite extend lifetime + * past the entry it replaces, regardless of trust. */ + /* Also for A/AAAA and it is glue. */ + if((ns || + (a_aaaa && cached->trust==rrset_trust_add_noAA)) + && !TTL_IS_EXPIRED(cached->ttl, timenow) && + newd->ttl > cached->ttl) { + size_t i; + if(a_aaaa) newd->trust=rrset_trust_add_noAA; + newd->ttl = cached->ttl; + for(i=0; i<(newd->count+newd->rrsig_count); i++) + if(newd->rr_ttl[i] > newd->ttl) + newd->rr_ttl[i] = newd->ttl; + } return 1; } /* o item in cache has expired */ - if( cached->ttl < timenow ) + if( TTL_IS_EXPIRED(cached->ttl, timenow) ) return 1; /* o same trust, but different in data - insert it */ if( newd->trust == cached->trust && !equal ) { @@ -199,6 +215,13 @@ rrset_cache_update(struct rrset_cache* r int equal = 0; log_assert(ref->id != 0 && k->id != 0); log_assert(k->rk.dname != NULL); + if((k->rk.flags&PACKED_RRSET_0TTL_GRACE) !=0) { + log_nametypeclass(VERB_ALGO, "rrset store of PACKED_RRSET_0TTL_GRACE rrset skipped", k->rk.dname, rrset_type, ntohs(k->rk.rrset_class)); + ub_packed_rrset_parsedelete(k, alloc); + return 0; /* Do not store 0TTL items after apply of + the grace ttl amount. + This means the ref was not changed by the call. */ + } /* looks up item with a readlock - no editing! */ if((e=slabhash_lookup(&r->table, h, k, 0)) != 0) { /* return id and key as they will be used in the cache @@ -213,7 +236,8 @@ rrset_cache_update(struct rrset_cache* r equal = rrsetdata_equal((struct packed_rrset_data*)k->entry. data, (struct packed_rrset_data*)e->data); if(!need_to_update_rrset(k->entry.data, e->data, timenow, - equal, (rrset_type==LDNS_RR_TYPE_NS))) { + equal, (rrset_type==LDNS_RR_TYPE_NS), + (rrset_type==LDNS_RR_TYPE_A || rrset_type==LDNS_RR_TYPE_AAAA))) { /* cache is superior, return that value */ lock_rw_unlock(&e->lock); ub_packed_rrset_parsedelete(k, alloc); @@ -245,12 +269,45 @@ rrset_cache_update(struct rrset_cache* r return 0; } +/** See if the name is a within signer authority */ +static int +dname_subdomain_rrsig_signers(uint8_t* dname, + struct ub_packed_rrset_key* rrset) +{ + struct packed_rrset_data* d = (struct packed_rrset_data*) + rrset->entry.data; + size_t i; + if(!d || !d->rrsig_count) + return 0; + for(i=0; irrsig_count; i++) { + uint8_t* sname = NULL; + size_t slen = 0; + rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i], + &sname, &slen); + if(!sname || !slen) + return 0; /* malformed */ + if(!dname_subdomain_c(dname, sname)) + return 0; /* not a subdomain */ + } + return 1; +} + void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache, struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len, struct alloc_cache* alloc, time_t timenow) { struct rrset_ref ref; uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3]; + uint8_t* new_dname; + size_t new_dname_len; + + /* See if the RRSIG signer name allows this wildcard, + * the new rrset should fall within the zone of the RRSIG signer(s). */ + if(!dname_subdomain_rrsig_signers(ce, rrset)) { + verbose(VERB_ALGO, "wildcard canonical parent outside signer authority"); + return; + } + rrset = packed_rrset_copy_alloc(rrset, alloc, timenow); if(!rrset) { log_err("malloc failure in rrset_cache_update_wildcard"); @@ -262,14 +319,16 @@ void rrset_cache_update_wildcard(struct wc_dname[1] = (uint8_t)'*'; memmove(wc_dname+2, ce, ce_len); - free(rrset->rk.dname); - rrset->rk.dname_len = ce_len + 2; - rrset->rk.dname = (uint8_t*)memdup(wc_dname, rrset->rk.dname_len); - if(!rrset->rk.dname) { - alloc_special_release(alloc, rrset); + new_dname_len = ce_len + 2; + new_dname = (uint8_t*)memdup(wc_dname, new_dname_len); + if(!new_dname) { + ub_packed_rrset_parsedelete(rrset, alloc); log_err("memdup failure in rrset_cache_update_wildcard"); return; } + free(rrset->rk.dname); + rrset->rk.dname = new_dname; + rrset->rk.dname_len = new_dname_len; rrset->entry.hash = rrset_key_hash(&rrset->rk); ref.key = rrset; @@ -278,6 +337,10 @@ void rrset_cache_update_wildcard(struct (void)rrset_cache_update(rrset_cache, &ref, alloc, timenow); } +/** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache). + * Allows synthesis from cache within this window to reduce recursion load. */ +#define DNAME_TTL0_GRACE_SECONDS 1 + struct ub_packed_rrset_key* rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow, @@ -300,27 +363,36 @@ rrset_cache_lookup(struct rrset_cache* r /* check TTL */ struct packed_rrset_data* data = (struct packed_rrset_data*)e->data; - if(timenow > data->ttl) { - lock_rw_unlock(&e->lock); - return NULL; + struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key; + if(TTL_IS_EXPIRED(data->ttl, timenow)) { + /* Allow TTL=0 DNAME within grace period for synthesis */ + if(qtype == LDNS_RR_TYPE_DNAME && + (k->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) && + (timenow - data->ttl_add) <= DNAME_TTL0_GRACE_SECONDS) { + /* within grace: allow for synthesis */ + } else { + lock_rw_unlock(&e->lock); + return NULL; + } } /* we're done */ - return (struct ub_packed_rrset_key*)e->key; + return k; } return NULL; } -int +int rrset_array_lock(struct rrset_ref* ref, size_t count, time_t timenow) { size_t i; + struct packed_rrset_data* d; for(i=0; i0 && ref[i].key == ref[i-1].key) continue; /* only lock items once */ lock_rw_rdlock(&ref[i].key->entry.lock); - if(ref[i].id != ref[i].key->id || timenow > - ((struct packed_rrset_data*)(ref[i].key->entry.data)) - ->ttl) { + d = ref[i].key->entry.data; + if(ref[i].id != ref[i].key->id || + TTL_IS_EXPIRED(d->ttl, timenow)) { /* failure! rollback our readlocks */ rrset_array_unlock(ref, i+1); return 0; @@ -511,7 +583,7 @@ rrset_cache_expired_above(struct rrset_c *qnamelen, searchtype, qclass, 0, 0, 0))) { struct packed_rrset_data* data = (struct packed_rrset_data*)rrset->entry.data; - if(now > data->ttl) { + if(TTL_IS_EXPIRED(data->ttl, now)) { /* it is expired, this is not wanted */ lock_rw_unlock(&rrset->entry.lock); log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass); Index: usr.sbin/unbound/sldns/keyraw.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/sldns/keyraw.c,v diff -u -p -r1.11 keyraw.c --- usr.sbin/unbound/sldns/keyraw.c 26 Sep 2025 07:32:37 -0000 1.11 +++ usr.sbin/unbound/sldns/keyraw.c 21 Sep 2026 16:28:08 -0000 @@ -67,19 +67,28 @@ sldns_rr_dnskey_key_size_raw(const unsig case LDNS_RSASHA512: #endif if (len > 0) { + size_t nlen, offset; if (keydata[0] == 0) { /* big exponent */ if (len > 3) { memmove(&int16, keydata + 1, 2); exp = ntohs(int16); - return (len - exp - 3)*8; + offset = 3; } else { return 0; } } else { exp = keydata[0]; - return (len-exp-1)*8; + offset = 1; } + if(exp+offset > len) + return 0; + nlen = len - exp - offset; + /* prefixed zeroes mean a smaller value */ + while(nlen > 0 && + keydata[len-nlen] == 0) + nlen--; + return nlen*8; } else { return 0; } Index: usr.sbin/unbound/sldns/rrdef.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/sldns/rrdef.h,v diff -u -p -r1.15 rrdef.h --- usr.sbin/unbound/sldns/rrdef.h 31 Aug 2025 21:41:10 -0000 1.15 +++ usr.sbin/unbound/sldns/rrdef.h 21 Sep 2026 16:28:08 -0000 @@ -480,11 +480,13 @@ enum sldns_enum_ede_code LDNS_EDE_TOO_EARLY = 26, LDNS_EDE_UNSUPPORTED_NSEC3_ITERATIONS = 27, LDNS_EDE_BADPROXYPOLICY = 28, - LDNS_EDE_SYNTHESIZED = 29 + LDNS_EDE_SYNTHESIZED = 29, + LDNS_EDE_INVALID_QUERY_TYPE = 30 }; typedef enum sldns_enum_ede_code sldns_ede_code; #define LDNS_EDNS_MASK_DO_BIT 0x8000 +#define LDNS_EDNS_MASK_CO_BIT 0x4000 /** TSIG and TKEY extended rcodes (16bit), 0-15 are the normal rcodes. */ #define LDNS_TSIG_ERROR_NOERROR 0 Index: usr.sbin/unbound/sldns/str2wire.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/sldns/str2wire.c,v diff -u -p -r1.19 str2wire.c --- usr.sbin/unbound/sldns/str2wire.c 26 Sep 2025 07:32:37 -0000 1.19 +++ usr.sbin/unbound/sldns/str2wire.c 21 Sep 2026 16:28:08 -0000 @@ -842,7 +842,8 @@ rrinternal_parse_rdata(sldns_buffer* str sldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10)); *rr_len = rr_cur_len; /* SVCB/HTTPS handling */ - if (rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) { + if ((rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) + && !was_unknown_rr_format) { size_t rdata_len = rr_cur_len - dname_len - 10; uint8_t *rdata = rr+dname_len + 10; @@ -1201,7 +1202,7 @@ sldns_str2wire_svcbparam_ipv4hint(const { size_t count; char ip_str[INET_ADDRSTRLEN+1]; - char *next_ip_str; + const char *next_ip_str; size_t i; for (i = 0, count = 1; val[i]; i++) { @@ -1256,7 +1257,7 @@ sldns_str2wire_svcbparam_ipv6hint(const { size_t count; char ip_str[INET6_ADDRSTRLEN+1]; - char *next_ip_str; + const char *next_ip_str; size_t i; for (i = 0, count = 1; val[i]; i++) { @@ -1317,7 +1318,7 @@ static int sldns_str2wire_svcbparam_mandatory(const char* val, uint8_t* rd, size_t* rd_len) { size_t i, count, val_len; - char* next_key; + const char* next_key; val_len = strlen(val); @@ -1410,6 +1411,7 @@ sldns_str2wire_svcbparam_ech_value(const return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; sldns_write_uint16(rd, SVCB_KEY_ECH); sldns_write_uint16(rd + 2, 0); + *rd_len = 4; return LDNS_WIREPARSE_ERR_OK; } Index: usr.sbin/unbound/sldns/wire2str.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/sldns/wire2str.c,v diff -u -p -r1.18 wire2str.c --- usr.sbin/unbound/sldns/wire2str.c 31 Aug 2025 21:41:10 -0000 1.18 +++ usr.sbin/unbound/sldns/wire2str.c 21 Sep 2026 16:28:08 -0000 @@ -233,6 +233,7 @@ static sldns_lookup_table sldns_edns_ede { LDNS_EDE_UNSUPPORTED_NSEC3_ITERATIONS, "Unsupported NSEC3 Iterations Value" }, { LDNS_EDE_BADPROXYPOLICY, "Unable to Conform to Policy" }, { LDNS_EDE_SYNTHESIZED, "Synthesized Answer" }, + { LDNS_EDE_INVALID_QUERY_TYPE, "Invalid Query Type" }, { 0, NULL} }; sldns_lookup_table* sldns_edns_ede_codes = sldns_edns_ede_codes_data; @@ -2485,6 +2486,8 @@ int sldns_wire2str_edns_scan(uint8_t** d w += sldns_str_print(str, str_len, " flags:"); if((edns_bits & LDNS_EDNS_MASK_DO_BIT)) w += sldns_str_print(str, str_len, " do"); + if((edns_bits & LDNS_EDNS_MASK_CO_BIT)) + w += sldns_str_print(str, str_len, " co"); /* the extended rcode is the value set, shifted four bits, * and or'd with the original rcode */ if(ext_rcode) { Index: usr.sbin/unbound/smallapp/unbound-anchor.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/smallapp/unbound-anchor.c,v diff -u -p -r1.22 unbound-anchor.c --- usr.sbin/unbound/smallapp/unbound-anchor.c 26 Sep 2025 07:32:37 -0000 1.22 +++ usr.sbin/unbound/smallapp/unbound-anchor.c 21 Sep 2026 16:28:08 -0000 @@ -160,7 +160,7 @@ char* wsa_strerror(int err); #endif static const char ICANN_UPDATE_CA[] = - /* The ICANN CA fetched at 24 Sep 2010. Valid to 2028 */ + /* The ICANN CA fetched at 29 May 2026. Valid to 20 Mar 2045 */ "-----BEGIN CERTIFICATE-----\n" "MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n" "TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n" @@ -181,6 +181,40 @@ static const char ICANN_UPDATE_CA[] = "15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF\n" "0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n" "j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n" + "-----END CERTIFICATE-----\n" + "\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFsTCCA5mgAwIBAgIUQFsYkgroBoe69HKQPy8/DQuiLwgwDQYJKoZIhvcNAQEN\n" + "BQAwYDELMAkGA1UEBhMCVVMxDjAMBgNVBAoMBUlDQU5OMSYwJAYDVQQLDB1JQ0FO\n" + "TiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEZMBcGA1UEAwwQSUNBTk4gUm9vdCBD\n" + "QSB2MjAeFw0yNTAzMjAyMTA0MjZaFw00NTAzMjAyMTA0MjZaMGAxCzAJBgNVBAYT\n" + "AlVTMQ4wDAYDVQQKDAVJQ0FOTjEmMCQGA1UECwwdSUNBTk4gQ2VydGlmaWNhdGlv\n" + "biBBdXRob3JpdHkxGTAXBgNVBAMMEElDQU5OIFJvb3QgQ0EgdjIwggIiMA0GCSqG\n" + "SIb3DQEBAQUAA4ICDwAwggIKAoICAQCepDjrubjR7en/uZWo7MAnzFIIvUPYEc7b\n" + "+AlefdlEDQ1JEmpfrvt/4CX9lJ9ShIBR6zwrQeDvrj5XZ2kEjbJ8Nnc6sM/ojdyr\n" + "5jSLqcDPH9fJg7jCW02KF8CtqWsnqcW6jjTIZcCWkg9lEixdF8QAjIEgJtZte+Yh\n" + "XeyN0KD2EaO8U5Id0bLvMyphuO1OCGKzDtetcX8K7SvoshdJx3lPIlYzqXl0nVAY\n" + "iCeNdeDzTNjEOHYJOP6dYoZI8nKRJltMkZcCCjBE2vQuSMY2w4pOlWk1skHjMWXj\n" + "QsZzngXuNG56zialL0TPEDVWjWRjzOnruHUAs4KUY8Zs+Nt8JdSlXMi825PKoKpp\n" + "ESs7/ZG1mPjVOYp7Z7ntrRjJFgnUBjWzVPOx4yHiJj1ur+OpqP18oP5YfqY+tKmz\n" + "7vlfRGGOEd08a0XgZISDNKpMAovn5pRUHTWPCCjc28tns9ODPvr1cQi+QSwTv+v8\n" + "wnA5etGrsead88Rv/ieaq5ikMJTRDfW4d9SY2uPcMGvfU6VdQLRhQkzEVTQNAJ1R\n" + "i2lOoJbbjwnK+OU9OhST/OqdjJDJAhTAstdUnrr8WBU80xM75MIaaTjSBCvZ1wro\n" + "pAi2hYb0tedTH6WarSW3MH9HcEoGGzs2GD3hDB0a2eCp+TdAs8Up944SjY7UV4Jx\n" + "sOC7TxbmkQIDAQABo2MwYTAdBgNVHQ4EFgQU+1EuMRuOZ/ecsfYzNQ+yGZsxZrMw\n" + "HwYDVR0jBBgwFoAU+1EuMRuOZ/ecsfYzNQ+yGZsxZrMwDwYDVR0TAQH/BAUwAwEB\n" + "/zAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQENBQADggIBACz38SkKR1WsEZnX\n" + "x1BKaS5/oQPw+7quDQCKGoD2Vz7CR7yQh4zQn/Hh0173vKvRWcwN2io0iLJ1ysv5\n" + "jXBLeWZh3djiQlXP3iWp4s01SiUwmFssxi3SD1IT2jNosk1xcVWthle9zth7Y8Mp\n" + "iUJYnHobP7tX7H2g+I8Rqw2sEX/yPSYMYcdH5a1xRMPOLHTyOaCgevRBBBtXkiAJ\n" + "Ob9QKZTaFaXntPXBKNSGkVb2d+2qKyJMrwd0KNI+SVSoIgNDAxkNOdi9x6X6ETW2\n" + "4aYFsytohFVkNUXx2eFYRim4yjnD8PHIvDQSofLfSAC5TOERtwUFd+Mw3/di+HCm\n" + "50OJPyoxZLjWQCCfNUZzgZZOe+zT6lgBiV3KB0UuuAdq7jGUeH/328HJDi30BvNj\n" + "+TNb9Hmpm+ZDguM+f8p7GxapX8AVNu/xErtl4msYiVJrr1qqV+qLLEMwIz0raujG\n" + "FFDd6N43wgduffbU20pThry0Y7rku5+RZjUZe/T7ZL+NUKiqXAPufrkqVkjX/8T+\n" + "wyNZz8KkiQwkJthojpppa79FDxn/A2M8tt+FQqIONAUPR2m5nurVgftQH0z5ZtDB\n" + "YykUlkUiPOJNXoDOIkbpA7lW2wezeY4te+EiSeUZSE541N5QBwaItaonIZsIgn6C\n" + "pMnwChV9468oRE20bdqq9+Go7g4E\n" "-----END CERTIFICATE-----\n"; static const char DS_TRUST_ANCHOR[] = @@ -1678,18 +1712,116 @@ static unsigned long get_usage_of_ex(X509* cert) { unsigned long val = 0; +#ifdef HAVE_X509_GET_KEY_USAGE + val = X509_get_key_usage(cert); + if (val == UINT32_MAX) + return 0; +#else ASN1_BIT_STRING* s; if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) { - if(s->length > 0) { - val = s->data[0]; - if(s->length > 1) - val |= s->data[1] << 8; +# ifdef HAVE_ASN1_STRING_GET0_DATA + const unsigned char *data = ASN1_STRING_get0_data(s); +# else + const unsigned char *data = ASN1_STRING_data(s); +# endif + int len = ASN1_STRING_length(s); + if(len > 0) { + val = data[0]; + if(len > 1) + val |= data[1] << 8; } ASN1_BIT_STRING_free(s); } +#endif return val; } +#if !defined(HAVE_X509_NAME_GET_TEXT_BY_NID) || defined(DEPRECATED_X509_NAME_GET_TEXT_BY_NID) +/** print verbose output about name extension data. */ +static void +print_name_ext( +#if OPENSSL_VERSION_NUMBER >= 0x40000000 + const +#endif + X509_NAME* nm, int nid, const char* str) +{ + int lastpos = -1; + for(;;) { +#if OPENSSL_VERSION_NUMBER >= 0x40000000 + const +#endif + X509_NAME_ENTRY* ne; +#if OPENSSL_VERSION_NUMBER >= 0x40000000 + const +#endif + ASN1_STRING *asn; + const unsigned char *data; + char buf[1024]; + + lastpos = X509_NAME_get_index_by_NID(nm, nid, lastpos); + if(lastpos == -1 || lastpos == -2) + break; + ne = X509_NAME_get_entry(nm, lastpos); + if(!ne) continue; + asn = X509_NAME_ENTRY_get_data(ne); + if(!asn) continue; +# ifdef HAVE_ASN1_STRING_GET0_DATA + data = ASN1_STRING_get0_data(asn); +# else + data = ASN1_STRING_data(asn); +# endif + if(!data) continue; + if(ASN1_STRING_length(asn) > (int)sizeof(buf)-1) continue; + memcpy(buf, data, ASN1_STRING_length(asn)); + buf[ASN1_STRING_length(asn)]=0; + printf("%s: %s\n", str, buf); + } +} +#endif /* X509_NAME_GET_TEXT_BY_NID */ + +#if !defined(HAVE_X509_NAME_GET_TEXT_BY_NID) || defined(DEPRECATED_X509_NAME_GET_TEXT_BY_NID) +/** see if the valid emailaddr is present. */ +static int +has_valid_emailaddr( +#if OPENSSL_VERSION_NUMBER >= 0x40000000 + const +#endif + X509_NAME* nm, const char* p7signer) +{ + int lastpos = -1; + for(;;) { +#if OPENSSL_VERSION_NUMBER >= 0x40000000 + const +#endif + X509_NAME_ENTRY* ne; +#if OPENSSL_VERSION_NUMBER >= 0x40000000 + const +#endif + ASN1_STRING *asn; + const unsigned char *data; + + lastpos = X509_NAME_get_index_by_NID(nm, + NID_pkcs9_emailAddress, lastpos); + if(lastpos == -1 || lastpos == -2) + break; + ne = X509_NAME_get_entry(nm, lastpos); + if(!ne) continue; + asn = X509_NAME_ENTRY_get_data(ne); + if(!asn) continue; +# ifdef HAVE_ASN1_STRING_GET0_DATA + data = ASN1_STRING_get0_data(asn); +# else + data = ASN1_STRING_data(asn); +# endif + if(!data) continue; + if(ASN1_STRING_length(asn) == (int)strlen(p7signer) && + strncmp((char*)data, p7signer, strlen(p7signer)) == 0) + return 1; /* match */ + } + return 0; +} +#endif /* X509_NAME_GET_TEXT_BY_NID */ + /** get valid signers from the list of signers in the signature */ static STACK_OF(X509)* get_valid_signers(PKCS7* p7, const char* p7signer) @@ -1709,6 +1841,9 @@ get_valid_signers(PKCS7* p7, const char* return NULL; } for(i=0; i= 0x40000000 + const +#endif X509_NAME* nm = X509_get_subject_name( sk_X509_value(signers, i)); char buf[1024]; @@ -1721,17 +1856,29 @@ get_valid_signers(PKCS7* p7, const char* (int)sizeof(buf)); printf("signer %d: Subject: %s\n", i, nmline?nmline:"no subject"); +#if !defined(HAVE_X509_NAME_GET_TEXT_BY_NID) || defined(DEPRECATED_X509_NAME_GET_TEXT_BY_NID) + if(verb >= 3) { + print_name_ext(nm, NID_commonName, + "commonName"); + print_name_ext(nm, NID_pkcs9_emailAddress, + "emailAddress"); + } +#else if(verb >= 3 && X509_NAME_get_text_by_NID(nm, - NID_commonName, buf, (int)sizeof(buf))) + NID_commonName, buf, (int)sizeof(buf)) > 0) printf("commonName: %s\n", buf); if(verb >= 3 && X509_NAME_get_text_by_NID(nm, - NID_pkcs9_emailAddress, buf, (int)sizeof(buf))) + NID_pkcs9_emailAddress, buf, (int)sizeof(buf)) > 0) printf("emailAddress: %s\n", buf); +#endif } if(verb) { int ku_loc = X509_get_ext_by_NID( sk_X509_value(signers, i), NID_key_usage, -1); if(verb >= 3 && ku_loc >= 0) { +#if OPENSSL_VERSION_NUMBER >= 0x40000000 + const +#endif X509_EXTENSION *ex = X509_get_ext( sk_X509_value(signers, i), ku_loc); if(ex) { @@ -1745,16 +1892,23 @@ get_valid_signers(PKCS7* p7, const char* /* there is no name to check, return all records */ if(verb) printf("did not check commonName of signer\n"); } else { - if(!X509_NAME_get_text_by_NID(nm, +#if !defined(HAVE_X509_NAME_GET_TEXT_BY_NID) || defined(DEPRECATED_X509_NAME_GET_TEXT_BY_NID) + if(!has_valid_emailaddr(nm, p7signer)) { + if(verb) printf("removed cert with wrong emailaddress\n"); + continue; /* wrong name, skip it */ + } +#else + if(X509_NAME_get_text_by_NID(nm, NID_pkcs9_emailAddress, - buf, (int)sizeof(buf))) { - if(verb) printf("removed cert with no name\n"); + buf, (int)sizeof(buf)) <= 0) { + if(verb) printf("removed cert with no emailaddress\n"); continue; /* no name, no use */ } if(strcmp(buf, p7signer) != 0) { - if(verb) printf("removed cert with wrong name\n"); + if(verb) printf("removed cert with wrong emailaddress\n"); continue; /* wrong name, skip it */ } +#endif } /* check that the key usage allows digital signatures @@ -2436,12 +2590,20 @@ int main(int argc, char* argv[]) #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else - (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif if(dolist) do_list_builtin(); Index: usr.sbin/unbound/smallapp/unbound-checkconf.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/smallapp/unbound-checkconf.c,v diff -u -p -r1.27 unbound-checkconf.c --- usr.sbin/unbound/smallapp/unbound-checkconf.c 29 Sep 2025 15:00:44 -0000 1.27 +++ usr.sbin/unbound/smallapp/unbound-checkconf.c 21 Sep 2026 16:28:08 -0000 @@ -44,6 +44,7 @@ #include "config.h" #include +#include "util/as112.h" #include "util/log.h" #include "util/config_file.h" #include "util/module.h" @@ -72,6 +73,9 @@ #ifdef HAVE_GLOB_H #include #endif +#ifdef HAVE_FNMATCH_H +#include +#endif #ifdef WITH_PYTHONMODULE #include "pythonmod/pythonmod.h" #endif @@ -188,11 +192,56 @@ donotquerylocalhostcheck(struct config_f } } +static void +nodefaultzonescheck(struct config_file* cfg) +{ + struct config_strlist* d; + const char** zstr; + size_t len; + +#define COMPARE_ZONE_NAME(confname, builtname, len) \ + (strncasecmp(confname, builtname, (len)) == 0 && \ + (strlen(confname) == (len) || \ + (strlen(confname) == (len) + 1 \ + && confname[(len)] == '.'))) + + for(d = cfg->local_zones_nodefault; d; d = d->next) { + if(!cfg->unblock_lan_zones) { + for(zstr = as112_zones; *zstr; zstr++) { + len = strlen(*zstr) - 1; /* trailing '.' */ + if(COMPARE_ZONE_NAME(d->str, *zstr, len)) + goto default_continue; + } + } + for(zstr = local_zones_default_special; *zstr; zstr++) { + len = strlen(*zstr) - 1; /* trailing '.' */ + if(COMPARE_ZONE_NAME(d->str, *zstr, len)) + goto default_continue; + } + for(zstr = local_zones_default_reverse; *zstr; zstr++) { + len = strlen(*zstr) - 1; /* trailing '.' */ + if(COMPARE_ZONE_NAME(d->str, *zstr, len)) + goto default_continue; + } + if(COMPARE_ZONE_NAME(d->str, "localhost.", 10 - 1)) + goto default_continue; + fprintf(stderr, "unbound-checkconf: warning: local-zone: '%s' " + "is configured as 'nodefault' but there is no such " + "default local-zone. Check the unbound.conf " + "documentation for default configured local-zones.\n", + d->str); +default_continue: + ; /* statement to jump to, for older gcc. */ + } +#undef COMPARE_ZONE_NAME +} + /** check localzones */ static void localzonechecks(struct config_file* cfg) { struct local_zones* zs; + nodefaultzonescheck(cfg); if(!(zs = local_zones_create())) fatal_exit("out of memory"); if(!local_zones_apply_cfg(zs, cfg)) @@ -682,6 +731,122 @@ check_modules_exist(const char* module_c } } +#ifdef USE_IPSECMOD +/** Compare filename with string, true if it matches the name. */ +static int +file_string_matches(char* str, char* fname, struct config_file* cfg) +{ + char* f; + if(!str || str[0] == 0) + return 0; + /* compare name after chroot and working dir are applied */ + f = fname_after_chroot(str, cfg, 1); + if(!f) fatal_exit("out of memory"); + if(strcmp(fname, f) == 0) { + free(f); + return 1; + } + free(f); + return 0; +} +#endif /* USE_IPSECMOD */ + +/** Compare filename with list of files, true if list contains the name. */ +static int +file_list_contains(struct config_strlist* list, char* fname, + struct config_file* cfg) +{ + struct config_strlist* s; + char* f; + for(s = list; s; s = s->next) { + if(!s->str || s->str[0] == 0) + continue; /* skip if no file name */ + /* compare names after chroot and working dir are applied */ + f = fname_after_chroot(s->str, cfg, 1); + if(!f) fatal_exit("out of memory"); + if(strcmp(fname, f) == 0) { + free(f); + return 1; + } + free(f); + } + return 0; +} + +/** Compare filename with list of files, true if list contains the name, + * with glob compare. */ +static int +file_list_contains_wild(struct config_strlist* list, char* fname, + struct config_file* cfg) +{ + struct config_strlist* s; + char* f; + for(s = list; s; s = s->next) { + if(!s->str || s->str[0] == 0) + continue; /* skip if no file name */ + /* compare names after chroot and working dir are applied */ + f = fname_after_chroot(s->str, cfg, 1); + if(!f) fatal_exit("out of memory"); + if(strcmp(fname, f) == 0) { + free(f); + return 1; + } +#ifdef HAVE_FNMATCH + if(fnmatch(f, fname, 0) == 0) { + log_err("trusted-keys-file: \"%s\" matches zonefile '%s'", + s->str, fname); + free(f); + return 1; + } +#endif + free(f); + } + return 0; +} + +/** Check if the auth-zone/rpz zonefile: conflicts with other files, + * so it would overwrite that file. Refuse it aliasing any read-side bootstrap + * file. */ +static void +check_file_clobber(struct config_file* cfg) +{ + struct config_auth* p; + char* zfile, *sourceopt = NULL; + for(p = cfg->auths; p; p = p->next) { + if(!p->name || p->name[0] == 0) + continue; /* skip if no name */ + if(!p->zonefile || p->zonefile[0]==0) + continue; /* no zone file */ + zfile = fname_after_chroot(p->zonefile, cfg, 1); + if(!zfile) fatal_exit("out of memory"); + if(file_list_contains(cfg->auto_trust_anchor_file_list, zfile, + cfg)) + sourceopt = "auto-trust-anchor-file"; + else if(file_list_contains(cfg->trust_anchor_file_list, zfile, + cfg)) + sourceopt = "trust-anchor-file"; + else if(file_list_contains_wild(cfg->trusted_keys_file_list, + zfile, cfg)) + sourceopt = "trusted-keys-file"; + else if(file_list_contains(cfg->root_hints, zfile, cfg)) + sourceopt = "root-hints"; + else if(file_list_contains(cfg->tls_session_ticket_keys.first, + zfile, cfg)) + sourceopt = "tls-session-ticket-keys"; +#ifdef USE_IPSECMOD + if(cfg->ipsecmod_enabled && + file_string_matches(cfg->ipsecmod_hook, zfile, cfg)) + sourceopt = "ipsecmod-hook"; +#endif + if(sourceopt) + fatal_exit("auth-zone '%s': zonefile \"%s\" " + "is the same path as a %s option. " + "The auth-zone transfer would overwrite it.", + p->name, p->zonefile, sourceopt); + free(zfile); + } +} + /** check configuration for errors */ static void morechecks(struct config_file* cfg) @@ -776,6 +941,7 @@ morechecks(struct config_file* cfg) cfg->chrootdir, cfg); } #endif + check_file_clobber(cfg); /* remove chroot setting so that modules are not stripping pathnames */ free(cfg->chrootdir); cfg->chrootdir = NULL; @@ -783,7 +949,6 @@ morechecks(struct config_file* cfg) /* check that the modules listed in module_conf exist */ check_modules_exist(cfg->module_conf); - /* Respip is known to *not* work with dns64. */ if(strcmp(cfg->module_conf, "iterator") != 0 && strcmp(cfg->module_conf, "validator iterator") != 0 && strcmp(cfg->module_conf, "dns64 validator iterator") != 0 @@ -869,6 +1034,7 @@ morechecks(struct config_file* cfg) && strcmp(cfg->module_conf, "respip cachedb iterator") != 0 && strcmp(cfg->module_conf, "dns64 validator cachedb iterator") != 0 && strcmp(cfg->module_conf, "dns64 cachedb iterator") != 0 + && strcmp(cfg->module_conf, "respip dns64 validator cachedb iterator") != 0 #endif #if defined(WITH_PYTHONMODULE) && defined(USE_CACHEDB) && strcmp(cfg->module_conf, "python dns64 cachedb iterator") != 0 Index: usr.sbin/unbound/smallapp/unbound-control.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/smallapp/unbound-control.c,v diff -u -p -r1.31 unbound-control.c --- usr.sbin/unbound/smallapp/unbound-control.c 26 Sep 2025 07:32:37 -0000 1.31 +++ usr.sbin/unbound/smallapp/unbound-control.c 21 Sep 2026 16:28:08 -0000 @@ -236,6 +236,8 @@ static void pr_stats(const char* nm, str s->svr.num_queries_cookie_invalid); PR_UL_NM("num.queries_discard_timeout", s->svr.num_queries_discard_timeout); + PR_UL_NM("num.queries_replyaddr_limit", + s->svr.num_queries_replyaddr_limit); PR_UL_NM("num.queries_wait_limit", s->svr.num_queries_wait_limit); PR_UL_NM("num.cachehits", s->svr.num_queries - s->svr.num_queries_missed_cache); @@ -263,6 +265,7 @@ static void pr_stats(const char* nm, str PR_UL_NM("requestlist.exceeded", s->mesh_dropped); PR_UL_NM("requestlist.current.all", s->mesh_num_states); PR_UL_NM("requestlist.current.user", s->mesh_num_reply_states); + PR_UL_NM("requestlist.current.replies", s->mesh_num_reply_addrs); #ifndef S_SPLINT_S sumwait.tv_sec = s->mesh_replies_sum_wait_sec; sumwait.tv_usec = s->mesh_replies_sum_wait_usec; @@ -1049,12 +1052,20 @@ int main(int argc, char* argv[]) #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else - (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif if(!RAND_status()) { Index: usr.sbin/unbound/smallapp/unbound-host.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/smallapp/unbound-host.c,v diff -u -p -r1.9 unbound-host.c --- usr.sbin/unbound/smallapp/unbound-host.c 21 Feb 2025 13:20:40 -0000 1.9 +++ usr.sbin/unbound/smallapp/unbound-host.c 21 Sep 2026 16:28:09 -0000 @@ -521,12 +521,20 @@ int main(int argc, char* argv[]) #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else - (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #endif /* HAVE_SSL */ #ifdef HAVE_NSS Index: usr.sbin/unbound/smallapp/worker_cb.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/smallapp/worker_cb.c,v diff -u -p -r1.14 worker_cb.c --- usr.sbin/unbound/smallapp/worker_cb.c 31 Aug 2025 21:41:10 -0000 1.14 +++ usr.sbin/unbound/smallapp/worker_cb.c 21 Sep 2026 16:28:09 -0000 @@ -43,6 +43,26 @@ #include "config.h" #include "libunbound/context.h" #include "libunbound/worker.h" + +struct comm_reply; +struct comm_point; + +/** fast reload thread commands to remote service thread event callback */ +void fast_reload_service_cb(int fd, short bits, void* arg); + +/** fast reload callback for the remote control client connection */ +int fast_reload_client_callback(struct comm_point* c, void* arg, int err, + struct comm_reply* rep); + +/** handle remote control accept callbacks */ +int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*); + +/** handle remote control data callbacks */ +int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*); + +/** routine to printout option values over SSL */ +void remote_get_opt_ssl(char* line, void* arg); + #include "util/fptr_wlist.h" #include "util/log.h" #include "services/mesh.h" @@ -102,7 +122,7 @@ struct outbound_entry* worker_send_query socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q), - int* ATTR_UNUSED(was_ratelimited)) + int* ATTR_UNUSED(was_ratelimited), int* ATTR_UNUSED(ratelimit_incremented)) { log_assert(0); return 0; @@ -128,6 +148,12 @@ worker_alloc_cleanup(void* ATTR_UNUSED(a log_assert(0); } +void +libworker_alloc_cleanup(void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + struct outbound_entry* libworker_send_query( struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), @@ -136,7 +162,7 @@ struct outbound_entry* libworker_send_qu socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q), - int* ATTR_UNUSED(was_ratelimited)) + int* ATTR_UNUSED(was_ratelimited), int* ATTR_UNUSED(ratelimit_incremented)) { log_assert(0); return 0; Index: usr.sbin/unbound/testcode/asynclook.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/asynclook.c,v diff -u -p -r1.1.1.4 asynclook.c --- usr.sbin/unbound/testcode/asynclook.c 23 Feb 2022 11:57:27 -0000 1.1.1.4 +++ usr.sbin/unbound/testcode/asynclook.c 21 Sep 2026 16:28:09 -0000 @@ -488,12 +488,20 @@ int main(int argc, char** argv) #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else - (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #endif /* HAVE_SSL */ Index: usr.sbin/unbound/testcode/checklocks.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/checklocks.h,v diff -u -p -r1.1.1.2 checklocks.h --- usr.sbin/unbound/testcode/checklocks.h 21 Feb 2025 13:17:11 -0000 1.1.1.2 +++ usr.sbin/unbound/testcode/checklocks.h 21 Sep 2026 16:28:09 -0000 @@ -360,6 +360,7 @@ typedef pthread_key_t ub_thread_key_type #define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f)) #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v)) #define ub_thread_key_get(key) pthread_getspecific(key) +#define ub_thread_setname(thread, name) /* nop */ #endif /* USE_THREAD_DEBUG */ #endif /* TESTCODE_CHECK_LOCKS_H */ Index: usr.sbin/unbound/testcode/dohclient.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/dohclient.c,v diff -u -p -r1.1.1.8 dohclient.c --- usr.sbin/unbound/testcode/dohclient.c 26 Sep 2025 07:30:47 -0000 1.1.1.8 +++ usr.sbin/unbound/testcode/dohclient.c 21 Sep 2026 16:28:09 -0000 @@ -146,7 +146,9 @@ submit_query(struct http2_session* h2_se { int32_t stream_id; struct http2_stream* h2_stream; - nghttp2_nv headers[5]; + nghttp2_nv headers[6]; + size_t num_headers = 5; + char clen[16]; char* qb64; size_t qb64_size; size_t qb64_expected_size; @@ -194,9 +196,16 @@ submit_query(struct http2_session* h2_se headers[3].value = (uint8_t*)h2_session->authority; headers[4].name = (uint8_t*)"content-type"; headers[4].value = (uint8_t*)h2_session->content_type; + if(h2_session->post) { + snprintf(clen, sizeof(clen), "%u", + (unsigned)sldns_buffer_remaining(buf)); + headers[5].name = (uint8_t*)"content-length"; + headers[5].value = (uint8_t*)clen; + num_headers = 6; + } printf("Request headers\n"); - for(i=0; isession, NULL, headers, - sizeof(headers)/sizeof(headers[0]), + num_headers, (h2_session->post) ? &data_prd : NULL, h2_stream); if(stream_id < 0) { printf("Failed to submit nghttp2 request"); @@ -642,12 +651,20 @@ int main(int argc, char** argv) #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else - (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif } run(h2_session, port, no_tls, argc, argv); Index: usr.sbin/unbound/testcode/doqclient.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/doqclient.c,v diff -u -p -r1.1.1.3 doqclient.c --- usr.sbin/unbound/testcode/doqclient.c 26 Sep 2025 07:30:47 -0000 1.1.1.3 +++ usr.sbin/unbound/testcode/doqclient.c 21 Sep 2026 16:28:09 -0000 @@ -1137,8 +1137,11 @@ static struct ngtcp2_conn* conn_client_s client_chosen_version, &cbs, &settings, ¶ms, NULL, /* ngtcp2_mem allocator, use default */ data /* callback argument */); - if(!conn) fatal_exit("could not ngtcp2_conn_client_new: %s", - ngtcp2_strerror(rv)); + if(rv!=0) { + conn = NULL; + fatal_exit("could not ngtcp2_conn_client_new: %s", + ngtcp2_strerror(rv)); + } data->cc_algo = settings.cc_algo; return conn; } @@ -1519,9 +1522,9 @@ doq_client_send_pkt(struct doq_client_da } log_err("doq sendmsg: %s", strerror(errno)); #ifdef HAVE_NGTCP2_CCERR_DEFAULT - ngtcp2_ccerr_set_application_error(&data->ccerr, -1, NULL, 0); + ngtcp2_ccerr_set_application_error(&data->ccerr, 1, NULL, 0); #else - ngtcp2_connection_close_error_set_application_error(&data->last_error, -1, NULL, 0); + ngtcp2_connection_close_error_set_application_error(&data->last_error, 1, NULL, 0); #endif return 0; } @@ -2098,7 +2101,7 @@ early_data_setup_session(struct doq_clie SSL_SESSION_free(session); return 0; } -#ifdef USE_NGTCP2_CRYPTO_OSSL +#ifdef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED SSL_set_quic_tls_early_data_enabled(data->ssl, 1); #else SSL_set_quic_early_data_enabled(data->ssl, 1); @@ -2255,7 +2258,7 @@ create_doq_client_data(const char* svr, /* Initialize the ossl crypto, it is harmless to call twice, * and this is before use of doq connections. */ if(ngtcp2_crypto_ossl_init() != 0) - fatal_exit("ngtcp2_crypto_oss_init failed"); + fatal_exit("ngtcp2_crypto_ossl_init failed"); #elif defined(HAVE_NGTCP2_CRYPTO_QUICTLS_INIT) if(ngtcp2_crypto_quictls_init() != 0) fatal_exit("ngtcp2_crypto_quictls_init failed"); @@ -2595,7 +2598,8 @@ struct outbound_entry* worker_send_query socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), - struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) + struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited), + int* ATTR_UNUSED(ratelimit_incremented)) { log_assert(0); return 0; @@ -2629,7 +2633,8 @@ struct outbound_entry* libworker_send_qu socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), - struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) + struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited), + int* ATTR_UNUSED(ratelimit_incremented)) { log_assert(0); return 0; @@ -2667,6 +2672,11 @@ void libworker_bg_done_cb(void* ATTR_UNU void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) +{ + log_assert(0); +} + +void libworker_alloc_cleanup(void* ATTR_UNUSED(arg)) { log_assert(0); } Index: usr.sbin/unbound/testcode/fake_event.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/fake_event.c,v diff -u -p -r1.1.1.19 fake_event.c --- usr.sbin/unbound/testcode/fake_event.c 26 Sep 2025 07:30:48 -0000 1.1.1.19 +++ usr.sbin/unbound/testcode/fake_event.c 21 Sep 2026 16:28:09 -0000 @@ -1126,15 +1126,16 @@ outside_network_create(struct comm_base* int ATTR_UNUSED(dscp), struct infra_cache* infra, struct ub_randstate* ATTR_UNUSED(rnd), - int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports), - int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold), + int ATTR_UNUSED(use_caps_for_id), + size_t ATTR_UNUSED(unwanted_threshold), int ATTR_UNUSED(outgoing_tcp_mss), void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param), int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx), int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni), struct dt_env* ATTR_UNUSED(dtenv), int ATTR_UNUSED(udp_connect), int ATTR_UNUSED(max_reuse_tcp_queries), int ATTR_UNUSED(tcp_reuse_timeout), - int ATTR_UNUSED(tcp_auth_query_timeout)) + int ATTR_UNUSED(tcp_auth_query_timeout), + struct shared_ports* ATTR_UNUSED(shared_ports)) { struct replay_runtime* runtime = (struct replay_runtime*)base; struct outside_network* outnet = calloc(1, @@ -1275,7 +1276,8 @@ struct serviced_query* outnet_serviced_q socklen_t addrlen, uint8_t* zone, size_t zonelen, struct module_qstate* qstate, comm_point_callback_type* callback, void* callback_arg, sldns_buffer* ATTR_UNUSED(buff), - struct module_env* env, int* ATTR_UNUSED(was_ratelimited)) + struct module_env* env, int* ATTR_UNUSED(was_ratelimited), + int* ATTR_UNUSED(ratelimit_incremented)) { struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; struct fake_pending* pend = (struct fake_pending*)calloc(1, @@ -1980,6 +1982,20 @@ int outnet_tcp_connect(int ATTR_UNUSED(s return 0; } +struct shared_ports* shared_ports_create(char** ATTR_UNUSED(ifs), + int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4), + int ATTR_UNUSED(do_ip6), int* ATTR_UNUSED(availports), + int ATTR_UNUSED(numavailports)) +{ + return calloc(1, sizeof(struct shared_ports)); +} + +void shared_ports_delete(struct shared_ports* shp) +{ + if(!shp) return; + free(shp); +} + int tcp_req_info_add_meshstate(struct tcp_req_info* ATTR_UNUSED(req), struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m)) { @@ -2018,6 +2034,15 @@ void http2_stream_add_meshstate(struct h } void http2_stream_remove_mesh_state(struct http2_stream* ATTR_UNUSED(h2_stream)) +{ +} + +void doq_stream_add_meshstate(struct doq_stream* ATTR_UNUSED(stream), + struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m)) +{ +} + +void doq_stream_remove_mesh_state(struct doq_stream* ATTR_UNUSED(stream)) { } Index: usr.sbin/unbound/testcode/mini_tdir.sh =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/mini_tdir.sh,v diff -u -p -r1.1.1.6 mini_tdir.sh --- usr.sbin/unbound/testcode/mini_tdir.sh 4 Sep 2024 09:35:36 -0000 1.1.1.6 +++ usr.sbin/unbound/testcode/mini_tdir.sh 21 Sep 2026 16:28:09 -0000 @@ -141,6 +141,13 @@ if test -f $done; then exit 0 fi +# always clear the skip mark file in case something changed in the environment +# in between runs +if test -f $skip; then + echo "minitdir $skip exists; removing." + rm $skip +fi + # Copy if test $quiet = 0; then echo "minitdir copy $1 to $dir" Index: usr.sbin/unbound/testcode/petal.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/petal.c,v diff -u -p -r1.1.1.9 petal.c --- usr.sbin/unbound/testcode/petal.c 26 Sep 2025 07:30:47 -0000 1.1.1.9 +++ usr.sbin/unbound/testcode/petal.c 21 Sep 2026 16:28:09 -0000 @@ -160,11 +160,26 @@ read_ssl_line(SSL* ssl, char* buf, size_ return 0; } if((r = SSL_read(ssl, buf+n, 1)) <= 0) { - if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { + int e = SSL_get_error(ssl, r); + if(e == SSL_ERROR_ZERO_RETURN) { /* EOF */ break; + } else if(e == SSL_ERROR_WANT_READ) { + continue; + } else if(e == SSL_ERROR_WANT_WRITE) { + continue; + } else if(e == SSL_ERROR_SYSCALL) { + if(verb) printf("could not SSL_read %s\n", + strerror(errno)); + } else if(e == SSL_ERROR_SSL) { + int er = ERR_peek_error(); + if(er) + printf("could not SSL_read: %s\n", + ERR_reason_error_string(er)); + } else { + if(verb) printf("could not SSL_read " + "(SSL_get_error %d)\n", e); } - if(verb) printf("could not SSL_read\n"); return 0; } if(endnl && buf[n] == '\n') { @@ -222,7 +237,8 @@ read_http_headers(SSL* ssl, char* file, if(verb>=2) printf("read: %s\n", buf); if(buf[0] == 0) { int e = ERR_peek_error(); - printf("error string: %s\n", ERR_reason_error_string(e)); + if(e) + printf("error string: %s\n", ERR_reason_error_string(e)); return 1; } if(!process_one_header(buf, file, flen, host, hlen, vs)) @@ -246,7 +262,8 @@ setup_ctx(char* key, char* cert) #endif if(!SSL_CTX_use_certificate_chain_file(ctx, cert)) { int e = ERR_peek_error(); - printf("error string: %s\n", ERR_reason_error_string(e)); + if(e) + printf("error string: %s\n", ERR_reason_error_string(e)); print_exit("cannot read cert"); } if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) @@ -673,12 +690,20 @@ int main(int argc, char* argv[]) #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else - (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif do_service(addr, port, key, cert); Index: usr.sbin/unbound/testcode/pktview.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/pktview.c,v diff -u -p -r1.1.1.1 pktview.c --- usr.sbin/unbound/testcode/pktview.c 17 Sep 2018 09:43:45 -0000 1.1.1.1 +++ usr.sbin/unbound/testcode/pktview.c 21 Sep 2026 16:28:09 -0000 @@ -59,12 +59,16 @@ static void usage(char* argv[]) /** read hex input */ static void read_input(sldns_buffer* pkt, FILE* in) { - char buf[102400]; + /* Buffer for 64Kib packet, in hex, with spaces and comments. */ + char buf[1024000]; char* np = buf; while(fgets(np, (int)sizeof(buf) - (np-buf), in)) { if(buf[0] == ';') /* comment */ continue; np = &np[strlen(np)]; + if((size_t)(np-buf) >= sizeof(buf)-1) + fatal_exit("input too large (%lu bytes)", + (unsigned long)sizeof(buf)); } hex_to_buf(pkt, buf); } @@ -188,10 +192,16 @@ static void analyze(sldns_buffer* pkt) /** main program for pktview */ int main(int argc, char* argv[]) { - sldns_buffer* pkt = sldns_buffer_new(65553); + sldns_buffer* pkt; + + log_init(NULL, 0, NULL); + log_ident_set("pktview"); + if(argc != 1) { usage(argv); } + + pkt = sldns_buffer_new(65553); if(!pkt) fatal_exit("out of memory"); read_input(pkt, stdin); Index: usr.sbin/unbound/testcode/replay.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/replay.h,v diff -u -p -r1.1.1.5 replay.h --- usr.sbin/unbound/testcode/replay.h 13 Jun 2024 14:29:33 -0000 1.1.1.5 +++ usr.sbin/unbound/testcode/replay.h 21 Sep 2026 16:28:09 -0000 @@ -142,6 +142,10 @@ #include "util/netevent.h" #include "testcode/testpkts.h" #include "util/rbtree.h" +#ifdef __QNX__ +/* For struct timeval */ +#include +#endif /* __QNX__ */ struct replay_answer; struct replay_moment; struct replay_range; Index: usr.sbin/unbound/testcode/streamtcp.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/streamtcp.c,v diff -u -p -r1.1.1.12 streamtcp.c --- usr.sbin/unbound/testcode/streamtcp.c 4 Sep 2024 09:35:36 -0000 1.1.1.12 +++ usr.sbin/unbound/testcode/streamtcp.c 21 Sep 2026 16:28:09 -0000 @@ -652,12 +652,20 @@ int main(int argc, char** argv) #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else - (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS +# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS) + | OPENSSL_INIT_NO_LOAD_CONFIG +# endif + , NULL); #endif } send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv); Index: usr.sbin/unbound/testcode/testbound.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/testbound.c,v diff -u -p -r1.1.1.14 testbound.c --- usr.sbin/unbound/testcode/testbound.c 26 Sep 2025 07:30:48 -0000 1.1.1.14 +++ usr.sbin/unbound/testcode/testbound.c 21 Sep 2026 16:28:09 -0000 @@ -786,3 +786,13 @@ size_t doq_table_quic_size_get(struct do return 0; } #endif + +void tcp_read_again_cb(void* ATTR_UNUSED(arg)) +{ + /* nothing */ +} + +void tcp_more_read_again_cb(void* ATTR_UNUSED(arg)) +{ + /* nothing */ +} Index: usr.sbin/unbound/testcode/testpkts.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/testpkts.c,v diff -u -p -r1.1.1.10 testpkts.c --- usr.sbin/unbound/testcode/testpkts.c 26 Sep 2025 07:30:47 -0000 1.1.1.10 +++ usr.sbin/unbound/testcode/testpkts.c 21 Sep 2026 16:28:09 -0000 @@ -135,6 +135,8 @@ static void matchline(char* line, struct e->match_ttl = 1; } else if(str_keyword(&parse, "DO")) { e->match_do = 1; + } else if(str_keyword(&parse, "CO")) { + e->match_co = 1; } else if(str_keyword(&parse, "noedns")) { e->match_noedns = 1; } else if(str_keyword(&parse, "ednsdata")) { @@ -178,7 +180,7 @@ static void matchline(char* line, struct /** parse REPLY line */ static void replyline(char* line, uint8_t* reply, size_t reply_len, - int* do_flag) + int* do_flag, int* co_flag) { char* parse = line; if(reply_len < LDNS_HEADER_SIZE) error("packet too short for header"); @@ -236,6 +238,8 @@ static void replyline(char* line, uint8_ LDNS_AD_SET(reply); } else if(str_keyword(&parse, "DO")) { *do_flag = 1; + } else if(str_keyword(&parse, "CO")) { + *co_flag = 1; } else { error("could not parse REPLY: '%s'", parse); } @@ -289,6 +293,7 @@ static struct entry* new_entry(void) e->match_all_noedns = 0; e->match_ttl = 0; e->match_do = 0; + e->match_co = 0; e->match_noedns = 0; e->match_serial = 0; e->ixfr_soa_serial = 0; @@ -521,15 +526,17 @@ static void add_rr(char* rrstr, uint8_t* /* add EDNS 4096 opt record */ static void -add_edns(uint8_t* pktbuf, size_t pktsize, int do_flag, uint8_t *ednsdata, - uint16_t ednslen, size_t* pktlen) +add_edns(uint8_t* pktbuf, size_t pktsize, int do_flag, int co_flag, + uint8_t *ednsdata, uint16_t ednslen, size_t* pktlen) { uint8_t edns[] = {0x00, /* root label */ 0x00, LDNS_RR_TYPE_OPT, /* type */ 0x04, 0xD0, /* class is UDPSIZE 1232 */ 0x00, /* TTL[0] is ext rcode */ 0x00, /* TTL[1] is edns version */ - (uint8_t)(do_flag?0x80:0x00), 0x00, /* TTL[2-3] is edns flags, DO */ + (uint8_t)(do_flag?0x80:0x00) + | (uint8_t)(co_flag?0x40:0x00) + , 0x00, /* TTL[2-3] is edns flags, DO */ (uint8_t)((ednslen >> 8) & 0xff), (uint8_t)(ednslen & 0xff), /* rdatalength */ }; @@ -561,6 +568,7 @@ read_entry(FILE* in, const char* name, s uint8_t pktbuf[MAX_PACKETLEN]; size_t pktlen = LDNS_HEADER_SIZE; int do_flag = 0; /* DO flag in EDNS */ + int co_flag = 0; /* CO flag in EDNS */ memset(pktbuf, 0, pktlen); /* ID = 0, FLAGS="", and rr counts 0 */ while(fgets(line, (int)sizeof(line), in) != NULL) { @@ -598,7 +606,7 @@ read_entry(FILE* in, const char* name, s if(str_keyword(&parse, "MATCH")) { matchline(parse, current); } else if(str_keyword(&parse, "REPLY")) { - replyline(parse, pktbuf, pktlen, &do_flag); + replyline(parse, pktbuf, pktlen, &do_flag, &co_flag); } else if(str_keyword(&parse, "ADJUST")) { adjustline(parse, current, cur_reply); } else if(str_keyword(&parse, "EXTRA_PACKET")) { @@ -654,15 +662,16 @@ read_entry(FILE* in, const char* name, s if(hex_ednsdata_buffer) sldns_buffer_free(hex_ednsdata_buffer); if(pktlen != 0) { - if(do_flag || cur_reply->raw_ednsdata) { + if(do_flag || co_flag + || cur_reply->raw_ednsdata) { if(cur_reply->raw_ednsdata && sldns_buffer_limit(cur_reply->raw_ednsdata)) - add_edns(pktbuf, sizeof(pktbuf), do_flag, + add_edns(pktbuf, sizeof(pktbuf), do_flag, co_flag, sldns_buffer_begin(cur_reply->raw_ednsdata), (uint16_t)sldns_buffer_limit(cur_reply->raw_ednsdata), &pktlen); else - add_edns(pktbuf, sizeof(pktbuf), do_flag, + add_edns(pktbuf, sizeof(pktbuf), do_flag, co_flag, NULL, 0, &pktlen); } cur_reply->reply_pkt = memdup(pktbuf, pktlen); @@ -909,6 +918,22 @@ get_do_flag(uint8_t* pkt, size_t len) return (int)(edns_bits&LDNS_EDNS_MASK_DO_BIT); } +/** return true if the CO flag is set */ +static int +get_co_flag(uint8_t* pkt, size_t len) +{ + uint16_t edns_bits; + uint8_t* walk = pkt; + size_t walk_len = len; + if(!pkt_find_edns_opt(&walk, &walk_len)) { + return 0; + } + if(walk_len < 6) + return 0; /* malformed */ + edns_bits = sldns_read_uint16(walk+4); + return (int)(edns_bits&LDNS_EDNS_MASK_CO_BIT); +} + /** Snips the specified EDNS option out of the OPT record and puts it in the * provided buffer. The buffer should be able to hold any opt data ie 65535. * Returns the length of the option written, @@ -1654,6 +1679,10 @@ find_match(struct entry* entries, uint8_ verbose(3, "no DO bit set\n"); continue; } + if(p->match_co && !get_co_flag(query_pkt, len)) { + verbose(3, "no CO bit set\n"); + continue; + } if(p->match_noedns && get_has_edns(query_pkt, len)) { verbose(3, "bad; EDNS OPT present\n"); continue; @@ -1745,11 +1774,14 @@ adjust_packet(struct entry* match, uint8 memmove(res+LDNS_HEADER_SIZE+dlen+4, orig+LDNS_HEADER_SIZE+olen+4, reslen-(LDNS_HEADER_SIZE+dlen+4)); + } else if(origlen == 0) { + res = NULL; + reslen = 0; } else { res = memdup(orig, origlen); reslen = origlen; } - if(!res) { + if(!res && reslen > 0) { verbose(1, "out of memory; send without adjust\n"); return; } Index: usr.sbin/unbound/testcode/testpkts.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/testpkts.h,v diff -u -p -r1.1.1.4 testpkts.h --- usr.sbin/unbound/testcode/testpkts.h 5 Sep 2023 11:07:49 -0000 1.1.1.4 +++ usr.sbin/unbound/testcode/testpkts.h 21 Sep 2026 16:28:09 -0000 @@ -218,6 +218,8 @@ struct entry { uint8_t match_ttl; /** match DO bit */ uint8_t match_do; + /** match CO bit */ + uint8_t match_co; /** match absence of EDNS OPT record in query */ uint8_t match_noedns; /** match edns data field given in hex */ Index: usr.sbin/unbound/testcode/unitauth.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/unitauth.c,v diff -u -p -r1.1.1.7 unitauth.c --- usr.sbin/unbound/testcode/unitauth.c 26 Sep 2025 07:30:47 -0000 1.1.1.7 +++ usr.sbin/unbound/testcode/unitauth.c 21 Sep 2026 16:28:09 -0000 @@ -1027,6 +1027,38 @@ authzone_query_test(void) check_queries("example.com", zone_example_com, example_com_queries); } +/** Test chunkline_count_parens output */ +static void +authzone_chunkline_count_parens_test(void) +{ + sldns_buffer* buf; + if(vbmp) printf("Testing chunkline_count_parens\n"); + buf = sldns_buffer_new(1024); + if(!buf) fatal_exit("out of memory"); + + /* Check that escaped characters are handled, '\x', and in quotes. */ + sldns_buffer_printf(buf, "TXT \"x\" \\("); + unit_assert(chunkline_count_parens(buf, 0) == 0); + + sldns_buffer_clear(buf); + sldns_buffer_printf(buf, "TXT ';x' ("); + unit_assert(chunkline_count_parens(buf, 0) == 0); + + sldns_buffer_clear(buf); + sldns_buffer_printf(buf, "TXT \"a;b\" ("); + unit_assert(chunkline_count_parens(buf, 0) == 1); + + sldns_buffer_clear(buf); + sldns_buffer_printf(buf, "TXT \\) )"); + unit_assert(chunkline_count_parens(buf, 0) == -1); + + sldns_buffer_clear(buf); + sldns_buffer_printf(buf, "TXT \"a\\\\\" \"(\" "); + unit_assert(chunkline_count_parens(buf, 0) == 0); + + sldns_buffer_free(buf); +} + /** test authzone code */ void authzone_test(void) @@ -1036,4 +1068,5 @@ authzone_test(void) authzone_compare_serial(); authzone_read_test(); authzone_query_test(); + authzone_chunkline_count_parens_test(); } Index: usr.sbin/unbound/testcode/unitecs.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/unitecs.c,v diff -u -p -r1.1.1.3 unitecs.c --- usr.sbin/unbound/testcode/unitecs.c 20 Oct 2022 08:25:17 -0000 1.1.1.3 +++ usr.sbin/unbound/testcode/unitecs.c 21 Sep 2026 16:28:09 -0000 @@ -141,6 +141,7 @@ static addrlen_t randomkey(addrkey_t **k int bits = rand() % maxlen; int bytes = bits/8 + (bits%8>0); /*ceil*/ *k = (addrkey_t *) malloc(bytes * sizeof(addrkey_t)); + if(!*k) fatal_exit("out of memory"); for (byte = 0; byte < bytes; byte++) { (*k)[byte] = (addrkey_t)(rand() & 0xFF); } Index: usr.sbin/unbound/testcode/unitldns.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/unitldns.c,v diff -u -p -r1.1.1.6 unitldns.c --- usr.sbin/unbound/testcode/unitldns.c 31 Aug 2025 21:36:34 -0000 1.1.1.6 +++ usr.sbin/unbound/testcode/unitldns.c 21 Sep 2026 16:28:09 -0000 @@ -207,7 +207,11 @@ rr_test_file(const char* input, const ch #define xstr(s) str(s) #define str(s) #s +#ifndef __QNX__ #define SRCDIRSTR xstr(SRCDIR) +#else /* !__QNX__ */ +#define SRCDIRSTR "." +#endif /* __QNX__ */ /** read rrs to and from string, to and from wireformat */ static void @@ -275,10 +279,24 @@ b64_test(void) unit_assert(result == -1); } +/** test SVCB ech svcparam */ +static void +svcb_ech_test(void) +{ + uint8_t rr[LDNS_RR_BUF_SIZE]; + size_t rr_len = sizeof(rr), dname_len = 0; + int e = sldns_str2wire_rr_buf("x. 300 IN HTTPS 1 . ech=0", + rr, &rr_len, &dname_len, 300, NULL, 0, NULL, 0); + unit_assert(e == LDNS_WIREPARSE_ERR_OK); + unit_assert(rr_len == dname_len + 10 /* type,class,ttl,rdatalen */ + 7 /* rdata */); + unit_assert(sldns_read_uint16(rr + dname_len + 8 /* rdlen */) == 7); +} + void ldns_test(void) { unit_show_feature("sldns"); rr_tests(); b64_test(); + svcb_ech_test(); } Index: usr.sbin/unbound/testcode/unitmain.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/unitmain.c,v diff -u -p -r1.1.1.13 unitmain.c --- usr.sbin/unbound/testcode/unitmain.c 26 Sep 2025 07:30:47 -0000 1.1.1.13 +++ usr.sbin/unbound/testcode/unitmain.c 21 Sep 2026 16:28:09 -0000 @@ -283,7 +283,7 @@ net_test(void) unit_assert(strcmp(astr, "1.2.3.0") == 0); unit_assert(ntohs(((struct sockaddr_in*)&a)->sin_port)==53); - res = netblockstrtoaddr("2001:DB8:33:44::/64", 53, + res = netblockstrtoaddr("2001:db8:33:44::/64", 53, &a, &alen, &net); unit_assert(res!=0 && net == 64); addr_to_str(&a, alen, astr, sizeof(astr)); @@ -1092,7 +1092,7 @@ static void edns_ede_encode_notxt_fit_te { struct edns_data edns; sldns_buffer* pkt; - uint16_t edns_field_size, ede_txt_size; + size_t edns_field_size, ede_txt_size; int found_ede = 0, found_ede_other = 0, found_ede_txt = 0; int found_other_edns = 0; edns_ede_encode_setup(&edns, region); @@ -1123,7 +1123,7 @@ static void edns_ede_encode_no_fit_test( { struct edns_data edns; sldns_buffer* pkt; - uint16_t edns_field_size, ede_size, ede_txt_size; + size_t edns_field_size, ede_size, ede_txt_size; int found_ede = 0, found_ede_other = 0, found_ede_txt = 0; int found_other_edns = 0; edns_ede_encode_setup(&edns, region); @@ -1282,6 +1282,61 @@ static void localzone_test(void) localzone_parents_test(); } +#include "services/mesh.h" +/** mesh unit tests */ +static void mesh_test(void) +{ + struct regional* r2, *r3; + struct respip_client_info* c1, *c2, *c3; + unit_show_func("services/mesh.c", "mesh_copy_client_info"); + r2 = regional_create(); + r3 = regional_create(); + if(!r2 || !r3) fatal_exit("out of memory"); + + c1 = calloc(1, sizeof(*c1)); + if(!c1) fatal_exit("out of memory"); + c1->view = calloc(1, sizeof(*c1->view)); + if(!c1->view) fatal_exit("out of memory"); + c1->view->name = strdup("view1"); + if(!c1->view->name) fatal_exit("out of memory"); + + c2 = mesh_copy_client_info(r2, c1); + if(!c2) fatal_exit("out of memory"); + c3 = mesh_copy_client_info(r3, c2); + if(!c3) fatal_exit("out of memory"); + + unit_assert(strcmp(c1->view->name, c2->view_name) == 0); + unit_assert(strcmp(c1->view->name, c3->view_name) == 0); + + /* make sure that the c3 view_name is in the r3 region. */ + unit_assert(r3->next == NULL); /* only the first chunk present atm */ + if(strlen(c3->view_name) >= r3->large_object_size) { + char* a = r3->large_list; + int found = 0; + while(a) { + if(strcmp(c3->view_name, + a + /* ALIGNEMENT */ sizeof(uint64_t)) == 0) { + found = 1; + break; + } + a = *(char**)a; + } + unit_assert(found == 1); + } else { + /* The allocation is expected in the r3 region first chunk */ + unit_assert((uint8_t*)c3->view_name < ((uint8_t*)r3)+r3->first_size); + } + + regional_destroy(r2); + /* ASAN should complain for the freed access below */ + unit_assert(strcmp(c1->view->name, c3->view_name) == 0); + + regional_destroy(r3); + free(c1->view->name); + free(c1->view); + free(c1); +} + void unit_show_func(const char* file, const char* func) { printf("test %s:%s\n", file, func); @@ -1356,6 +1411,7 @@ main(int argc, char* argv[]) msgparse_test(); edns_ede_answer_encode_test(); localzone_test(); + mesh_test(); #ifdef CLIENT_SUBNET ecs_test(); #endif /* CLIENT_SUBNET */ @@ -1389,6 +1445,9 @@ main(int argc, char* argv[]) # ifdef HAVE_RAND_CLEANUP RAND_cleanup(); # endif +#ifdef HAVE_OPENSSL_CLEANUP + OPENSSL_cleanup(); +#endif #elif defined(HAVE_NSS) if(NSS_Shutdown() != SECSuccess) fatal_exit("could not shutdown NSS"); Index: usr.sbin/unbound/testcode/unitmsgparse.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/unitmsgparse.c,v diff -u -p -r1.1.1.4 unitmsgparse.c --- usr.sbin/unbound/testcode/unitmsgparse.c 7 Jun 2022 15:40:02 -0000 1.1.1.4 +++ usr.sbin/unbound/testcode/unitmsgparse.c 21 Sep 2026 16:28:09 -0000 @@ -498,7 +498,11 @@ testfromdrillfile(sldns_buffer* pkt, str #define xstr(s) str(s) #define str(s) #s +#ifndef __QNX__ #define SRCDIRSTR xstr(SRCDIR) +#else /* !__QNX__ */ +#define SRCDIRSTR "." +#endif /* __QNX__ */ void msgparse_test(void) { Index: usr.sbin/unbound/testcode/unittcpreuse.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/unittcpreuse.c,v diff -u -p -r1.1.1.2 unittcpreuse.c --- usr.sbin/unbound/testcode/unittcpreuse.c 20 Oct 2022 08:25:17 -0000 1.1.1.2 +++ usr.sbin/unbound/testcode/unittcpreuse.c 21 Sep 2026 16:28:09 -0000 @@ -41,6 +41,7 @@ #include "config.h" #include "testcode/unitmain.h" #include "util/log.h" +#include "util/net_help.h" #include "util/random.h" #include "services/outside_network.h" @@ -479,6 +480,278 @@ static void reuse_write_wait_test(void) check_reuse_write_wait_removal(1, &reuse, store, 0, 1); } +static void shared_port_test_ifs(void) +{ + struct shared_ports* shp; + struct shared_ports_if* shpif; + char* ifs[] = {"1.2.3.4", "1.2.3.5", "::1:2", "::1:3"}; + int availports[] = {1, 2, 3, 4}; + struct sockaddr_storage addr; + socklen_t addrlen; + + shp = shared_ports_create(ifs, 4, 1, 1, availports, 4); + unit_assert(shp); + + if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + if(!ipstrtoaddr("1.2.3.5", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + if(!ipstrtoaddr("::1:2", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + if(!ipstrtoaddr("::1:3", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + shared_ports_delete(shp); +} + +/** See if a port is on the shared_ports ports list */ +static int +pif_list_contains(struct shared_ports_if* shpif, int item) +{ + int i; + unit_assert(shpif->inuse >= 0 && shpif->inuse <= shpif->avail_total); + for(i=0; i< shpif->avail_total - shpif->inuse; i++) { + if(shpif->avail_ports[i] == item) + return 1; + } + return 0; +} + +/** See if a number of ports are on the shared_ports list */ +static int +pif_list_contains_items(struct shared_ports_if* shpif, int item1, + int item2, int item3, int item4) +{ + if(item1 != -1 && !pif_list_contains(shpif, item1)) + return 0; + if(item2 != -1 && !pif_list_contains(shpif, item2)) + return 0; + if(item3 != -1 && !pif_list_contains(shpif, item3)) + return 0; + if(item4 != -1 && !pif_list_contains(shpif, item4)) + return 0; + return 1; +} + +static void shared_port_test_port(void) +{ + struct shared_ports* shp; + struct shared_ports_if* shpif; + char* ifs[] = {"1.2.3.4", "1.2.3.5"}; + int availports[] = {1, 2, 3, 4}; + struct sockaddr_storage addr; + socklen_t addrlen; + int p1, p2, p3, reused; + struct ub_randstate* rnd; + + rnd = ub_initstate(NULL); + unit_assert(rnd); + + shp = shared_ports_create(ifs, 2, 1, 1, availports, 4); + unit_assert(shp); + + if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen)) + log_err("could not parse"); + shpif = shared_ports_find_if(shp, &addr, addrlen, 0); + unit_assert(shpif); + + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + unit_assert(!pif_list_contains(shpif, p1)); + if(p1 != 1) unit_assert(pif_list_contains(shpif, 1)); + if(p1 != 2) unit_assert(pif_list_contains(shpif, 2)); + if(p1 != 3) unit_assert(pif_list_contains(shpif, 3)); + if(p1 != 4) unit_assert(pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 1); + + shared_ports_return_port(shp, shpif, p1); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + /* pick up two items */ + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p2, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p2 != 0); + unit_assert(!pif_list_contains(shpif, p1)); + unit_assert(!pif_list_contains(shpif, p2)); + if(p1 != 1 && p2 != 1) unit_assert(pif_list_contains(shpif, 1)); + if(p1 != 2 && p2 != 2) unit_assert(pif_list_contains(shpif, 2)); + if(p1 != 3 && p2 != 3) unit_assert(pif_list_contains(shpif, 3)); + if(p1 != 4 && p2 != 4) unit_assert(pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 2); + + shared_ports_return_port(shp, shpif, p1); + unit_assert(pif_list_contains(shpif, p1)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 1); + + shared_ports_return_port(shp, shpif, p2); + unit_assert(pif_list_contains(shpif, p2)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + /* pick up three items */ + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p2, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p2 != 0); + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p3, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p3 != 0); + unit_assert(!pif_list_contains(shpif, p1)); + unit_assert(!pif_list_contains(shpif, p2)); + unit_assert(!pif_list_contains(shpif, p3)); + if(p1 != 1 && p2 != 1 && p3 != 1) + unit_assert(pif_list_contains(shpif, 1)); + if(p1 != 2 && p2 != 2 && p3 != 2) + unit_assert(pif_list_contains(shpif, 2)); + if(p1 != 3 && p2 != 3 && p3 != 3) + unit_assert(pif_list_contains(shpif, 3)); + if(p1 != 4 && p2 != 4 && p3 != 4) + unit_assert(pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 3); + + shared_ports_return_port(shp, shpif, p1); + unit_assert(pif_list_contains(shpif, p1)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 2); + + shared_ports_return_port(shp, shpif, p2); + unit_assert(pif_list_contains(shpif, p2)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 1); + + shared_ports_return_port(shp, shpif, p3); + unit_assert(pif_list_contains(shpif, p3)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + /* pick up all four items */ + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0, 0, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 0); + unit_assert(p1 != 0); + unit_assert(!pif_list_contains(shpif, 1)); + unit_assert(!pif_list_contains(shpif, 2)); + unit_assert(!pif_list_contains(shpif, 3)); + unit_assert(!pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 4); + + /* more fetches fail, it is fully inuse. */ + unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p2, + &reused)); + unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p3, + &reused)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 4); + + /* reuse is then always the case */ + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 1); + unit_assert(p1 >= 0 && p1 < 4 /* reusenum */); + + if(!shared_ports_fetch_random(shp, shpif, rnd, + 0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) { + unit_assert(0); /* should succeed */ + } + unit_assert(reused == 1); + unit_assert(p1 >= 0 && p1 < 4 /* reusenum */); + + /* return all the ports */ + shared_ports_return_port(shp, shpif, 1); + unit_assert(pif_list_contains(shpif, 1)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 3); + shared_ports_return_port(shp, shpif, 2); + unit_assert(pif_list_contains(shpif, 2)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 2); + shared_ports_return_port(shp, shpif, 3); + unit_assert(pif_list_contains(shpif, 3)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 1); + shared_ports_return_port(shp, shpif, 4); + unit_assert(pif_list_contains(shpif, 4)); + unit_assert(shpif->avail_total == 4); + unit_assert(shpif->inuse == 0); + unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4)); + + shared_ports_delete(shp); + ub_randfree(rnd); +} + void tcpreuse_test(void) { unit_show_feature("tcp_reuse"); @@ -486,4 +759,7 @@ void tcpreuse_test(void) tcp_reuse_tree_list_test(); waiting_tcp_list_test(); reuse_write_wait_test(); + unit_show_feature("shared_ports"); + shared_port_test_ifs(); + shared_port_test_port(); } Index: usr.sbin/unbound/testcode/unitverify.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/unitverify.c,v diff -u -p -r1.5 unitverify.c --- usr.sbin/unbound/testcode/unitverify.c 26 Sep 2025 07:32:37 -0000 1.5 +++ usr.sbin/unbound/testcode/unitverify.c 21 Sep 2026 16:28:09 -0000 @@ -196,7 +196,7 @@ verifytest_rrset(struct module_env* env, setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */ /* ok to give null as qstate here, won't be used for answer section. */ sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason, - NULL, LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, + NULL, LDNS_SECTION_ANSWER, NULL, NULL, &verified, reasonbuf, sizeof(reasonbuf)); if(vsig) { printf("verify outcome is: %s %s\n", sec_status_to_string(sec), @@ -510,11 +510,154 @@ nsec3_hash_test(const char* fname) sldns_buffer_free(buf); } +/** Test the rrset_canonicalize_to_buffer function to see if the + * size of canon_owner name is properly checked for. */ +static void +canon_owner_buf_test(void) +{ + struct regional* region; + sldns_buffer* buf; + struct ub_packed_rrset_key k; + struct packed_rrset_data d; + size_t rr_len[2]; + time_t rr_ttl[2]; + uint8_t* rr_data[2]; + int ret; + unit_show_func("validator/val_sigcrypt.c", + "rrset_canonicalize_to_buffer"); + region = regional_create(); + if(!region) + fatal_exit("out of memory"); + /* Purposefully a very small buffer, to overflow it */ + buf = sldns_buffer_new(28); + if(!buf) + fatal_exit("out of memory"); + + /* An RRset to canonicalize. The buffer is made smaller, so + * it can fail on bounds checks. */ + memset(&d, 0, sizeof(d)); + d.ttl = 3600; + d.count = 1; + d.rrsig_count = 1; + d.rr_len = rr_len; + d.rr_ttl = rr_ttl; + d.rr_data = rr_data; + rr_len[0] = 18; + rr_len[1] = 36; + rr_ttl[0] = 3600; + rr_ttl[1] = 3600; + rr_data[0] = (uint8_t*)"\x00\x10\x0Fzzaaaaaaaaaaaaa"; + rr_data[1] = (uint8_t*)"\x00\x24\x00\x06\x08\x3\x01\x02\x03\x04\x01\x02\x03\x04\x01\x02\x03\x04\x12\x34\x03zzz\x00zzaaaaaaaaaaa"; + + memset(&k, 0, sizeof(k)); + k.rk.dname = (uint8_t*) "\x0f" "aaaaaaaaaaaaaaa" "\x00"; + k.rk.dname_len = 17; + k.rk.type = htons(LDNS_RR_TYPE_TXT); + k.rk.rrset_class = htons(LDNS_RR_CLASS_IN); + k.entry.data = &d; + + /* There should be no buffer overflow, assertion failure, here */ + ret = rrset_canonicalize_to_buffer(region, buf, &k); + unit_assert(ret == 0); + + regional_destroy(region); + sldns_buffer_free(buf); +} + +/** Test if ds_digest_match_dnskey that calls ds_create_dnskey_digest, + * checks the buffer size. */ +static void +dnskey_ds_digest_test(void) +{ + struct regional* region; + sldns_buffer* buf; + struct module_env env; + struct ub_packed_rrset_key k1, k2; + struct packed_rrset_data d1, d2; + size_t rr_len1[1], rr_len2[1]; + time_t rr_ttl1[1], rr_ttl2[1]; + uint8_t* rr_rdata1[1], *rr_rdata2[1]; + int ret; + unit_show_func("validator/val_sigcrypt.c", "ds_digest_match_dnskey"); + region = regional_create(); + if(!region) + fatal_exit("out of memory"); + /* Purposefully a very small buffer, to overflow it */ + buf = sldns_buffer_new(28); + if(!buf) + fatal_exit("out of memory"); + memset(&env, 0, sizeof(env)); + env.scratch = region; + env.scratch_buffer = buf; + + /* A DNSKEY and DS RRset to match together. The buffer is made + * smaller, so it can fail on bounds checks. */ + memset(&d1, 0, sizeof(d1)); + d1.ttl = 3600; + d1.count = 1; + d1.rr_len = rr_len1; + d1.rr_ttl = rr_ttl1; + d1.rr_data = rr_rdata1; + rr_len1[0] = 38; + rr_ttl1[0] = 3600; + /* DS rdata has: keytag (2bytes), algorithm (1byte), + * digesttype (1byte), digest (remainder). */ + rr_rdata1[0] = (uint8_t*)"\x00\x24" + "\x12\x34" + "\x08" /* RSASHA256 */ + "\x02" /* SHA256 */ + "0123456789abcdef0123456789abcdef"; /* 32 bytes */ + ; + + memset(&k1, 0, sizeof(k1)); + k1.rk.dname = (uint8_t*) "\x03" "foo" "\x00"; + k1.rk.dname_len = 5; + k1.rk.type = htons(LDNS_RR_TYPE_DS); + k1.rk.rrset_class = htons(LDNS_RR_CLASS_IN); + k1.entry.data = &d1; + + memset(&d2, 0, sizeof(d2)); + d2.ttl = 3600; + d2.count = 1; + d2.rr_len = rr_len2; + d2.rr_ttl = rr_ttl2; + d2.rr_data = rr_rdata2; + rr_len2[0] = 38; + rr_ttl2[0] = 3600; + /* DNSKEY rdata has: flags (2bytes), protocol (1byte), + * algorithm (1byte), publickey (remainder). */ + rr_rdata2[0] = (uint8_t*)"\x00\x24" + "\x01\x01" /* KSK */ + "\x03" /* DNSSEC_KEYPROTO */ + "\x08" /* RSASHA256 */ + "0123456789abcdef0123456789abcdef"; /* 32 bytes of content */ + ; + + memset(&k2, 0, sizeof(k2)); + k2.rk.dname = (uint8_t*) "\x03" "foo" "\x00"; + k2.rk.dname_len = 5; + k2.rk.type = htons(LDNS_RR_TYPE_DNSKEY); + k2.rk.rrset_class = htons(LDNS_RR_CLASS_IN); + k2.entry.data = &d2; + /* 36 byte rdata length for DNSKEY (38-2), and dname length of 5, + * exceeds the (small) buffer size. */ + + /* There should be no buffer overflow, assertion failure, here */ + ret = ds_digest_match_dnskey(&env, &k2, 0, &k1, 0); + unit_assert(ret == 0); + + regional_destroy(region); + sldns_buffer_free(buf); +} + #define xstr(s) str(s) #define str(s) #s +#ifndef __QNX__ #define SRCDIRSTR xstr(SRCDIR) - +#else /* !__QNX__ */ +#define SRCDIRSTR "." +#endif /* __QNX__ */ #if defined(HAVE_SSL) && defined(USE_SHA1) /* Detect if openssl is configured to disable RSASHA1 signatures, * with the rh-allow-sha1-signatures disabled. */ @@ -631,6 +774,7 @@ rh_allow_sha1_signatures_disabled(void) void verify_test(void) { + int do_sha1 = 1; unit_show_feature("signature verify"); #if defined(HAVE_SSL) && defined(USE_SHA1) @@ -643,27 +787,40 @@ verify_test(void) #else _putenv("OPENSSL_ENABLE_SHA1_SIGNATURES=1"); #endif + do_sha1 = 1; } +#ifdef HAVE_EVP_DEFAULT_PROPERTIES_IS_FIPS_ENABLED + if (EVP_default_properties_is_fips_enabled(NULL)) + do_sha1 = 0; #endif +#endif /* HAVE_SSL and USE_SHA1 */ #ifdef USE_SHA1 - verifytest_file(SRCDIRSTR "/testdata/test_signatures.1", "20070818005004"); + if(do_sha1) { + verifytest_file(SRCDIRSTR "/testdata/test_signatures.1", "20070818005004"); + } #endif #if defined(USE_DSA) && defined(USE_SHA1) - verifytest_file(SRCDIRSTR "/testdata/test_signatures.2", "20080414005004"); - verifytest_file(SRCDIRSTR "/testdata/test_signatures.3", "20080416005004"); - verifytest_file(SRCDIRSTR "/testdata/test_signatures.4", "20080416005004"); - verifytest_file(SRCDIRSTR "/testdata/test_signatures.5", "20080416005004"); - verifytest_file(SRCDIRSTR "/testdata/test_signatures.6", "20080416005004"); - verifytest_file(SRCDIRSTR "/testdata/test_signatures.7", "20070829144150"); + if(do_sha1) { + verifytest_file(SRCDIRSTR "/testdata/test_signatures.2", "20080414005004"); + verifytest_file(SRCDIRSTR "/testdata/test_signatures.3", "20080416005004"); + verifytest_file(SRCDIRSTR "/testdata/test_signatures.4", "20080416005004"); + verifytest_file(SRCDIRSTR "/testdata/test_signatures.5", "20080416005004"); + verifytest_file(SRCDIRSTR "/testdata/test_signatures.6", "20080416005004"); + verifytest_file(SRCDIRSTR "/testdata/test_signatures.7", "20070829144150"); + } #endif /* USE_DSA */ #ifdef USE_SHA1 - verifytest_file(SRCDIRSTR "/testdata/test_signatures.8", "20070829144150"); + if(do_sha1) { + verifytest_file(SRCDIRSTR "/testdata/test_signatures.8", "20070829144150"); + } #endif #if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2) verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256", "20070829144150"); # ifdef USE_SHA1 - verifytest_file(SRCDIRSTR "/testdata/test_sigs.sha1_and_256", "20070829144150"); + if(do_sha1) { + verifytest_file(SRCDIRSTR "/testdata/test_sigs.sha1_and_256", "20070829144150"); + } # endif verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256_draft", "20090101000000"); #endif @@ -672,8 +829,10 @@ verify_test(void) verifytest_file(SRCDIRSTR "/testdata/test_signatures.9", "20171215000000"); #endif #ifdef USE_SHA1 - verifytest_file(SRCDIRSTR "/testdata/test_sigs.hinfo", "20090107100022"); - verifytest_file(SRCDIRSTR "/testdata/test_sigs.revoked", "20080414005004"); + if(do_sha1) { + verifytest_file(SRCDIRSTR "/testdata/test_sigs.hinfo", "20090107100022"); + verifytest_file(SRCDIRSTR "/testdata/test_sigs.revoked", "20080414005004"); + } #endif #ifdef USE_GOST if(sldns_key_EVP_load_gost_id()) @@ -699,8 +858,12 @@ verify_test(void) } #endif #ifdef USE_SHA1 - dstest_file(SRCDIRSTR "/testdata/test_ds.sha1"); + if(do_sha1) { + dstest_file(SRCDIRSTR "/testdata/test_ds.sha1"); + } #endif nsectest(); nsec3_hash_test(SRCDIRSTR "/testdata/test_nsec3_hash.1"); + dnskey_ds_digest_test(); + canon_owner_buf_test(); } Index: usr.sbin/unbound/testcode/unitzonemd.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/testcode/unitzonemd.c,v diff -u -p -r1.1.1.6 unitzonemd.c --- usr.sbin/unbound/testcode/unitzonemd.c 26 Sep 2025 07:30:47 -0000 1.1.1.6 +++ usr.sbin/unbound/testcode/unitzonemd.c 21 Sep 2026 16:28:09 -0000 @@ -50,7 +50,11 @@ #define xstr(s) str(s) #define str(s) #s +#ifndef __QNX__ #define SRCDIRSTR xstr(SRCDIR) +#else /* !__QNX__ */ +#define SRCDIRSTR "." +#endif /* __QNX__ */ /** Add zone from file for testing */ struct auth_zone* authtest_addzone(struct auth_zones* az, const char* name, Index: usr.sbin/unbound/util/alloc.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/alloc.c,v diff -u -p -r1.6 alloc.c --- usr.sbin/unbound/util/alloc.c 21 Feb 2025 13:20:40 -0000 1.6 +++ usr.sbin/unbound/util/alloc.c 21 Sep 2026 16:28:09 -0000 @@ -328,7 +328,7 @@ size_t alloc_get_mem(struct alloc_cache* struct regional* alloc_reg_obtain(struct alloc_cache* alloc) { - if(alloc->num_reg_blocks > 0) { + if(alloc->num_reg_blocks > 0 && alloc->reg_list) { struct regional* r = alloc->reg_list; alloc->reg_list = (struct regional*)r->next; r->next = NULL; Index: usr.sbin/unbound/util/config_file.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/config_file.c,v diff -u -p -r1.41 config_file.c --- usr.sbin/unbound/util/config_file.c 23 Oct 2025 12:50:29 -0000 1.41 +++ usr.sbin/unbound/util/config_file.c 21 Sep 2026 16:28:09 -0000 @@ -46,6 +46,7 @@ #ifdef HAVE_TIME_H #include #endif +#include #include "util/log.h" #include "util/configyyrename.h" #include "util/config_file.h" @@ -62,6 +63,9 @@ #include "sldns/wire2str.h" #include "sldns/parseutil.h" #include "iterator/iterator.h" +#ifdef HAVE_SYS_STAT_H +#include +#endif #ifdef HAVE_GLOB_H # include #endif @@ -90,7 +94,7 @@ struct config_parser_state* cfg_parser = static void init_outgoing_availports(int* array, int num); /** init cookie with random data */ -static void init_cookie_secret(uint8_t* cookie_secret, size_t cookie_secret_len); +static int init_cookie_secret(struct config_file* cfg); struct config_file* config_create(void) @@ -129,6 +133,7 @@ config_create(void) cfg->tls_cert_bundle = NULL; cfg->tls_win_cert = 0; cfg->tls_use_sni = 1; + if(!(cfg->tls_protocols = strdup("TLSv1.2 TLSv1.3"))) goto error_exit; cfg->https_port = UNBOUND_DNS_OVER_HTTPS_PORT; if(!(cfg->http_endpoint = strdup("/dns-query"))) goto error_exit; cfg->http_max_streams = 100; @@ -147,6 +152,7 @@ config_create(void) cfg->log_local_actions = 0; cfg->log_servfail = 0; cfg->log_destaddr = 0; + cfg->log_thread_id = 0; #ifndef USE_WINSOCK # ifdef USE_MINI_EVENT /* select max 1024 sockets */ @@ -272,7 +278,7 @@ config_create(void) cfg->val_sig_skew_min = 3600; /* at least daylight savings trouble */ cfg->val_sig_skew_max = 86400; /* at most timezone settings trouble */ cfg->val_max_restart = 5; - cfg->val_clean_additional = 1; + cfg->val_clean_additional = 0; /* off to protect against much data. */ cfg->val_log_level = 0; cfg->val_log_squelch = 0; cfg->val_permissive_mode = 0; @@ -384,8 +390,7 @@ config_create(void) #endif cfg->do_answer_cookie = 0; memset(cfg->cookie_secret, 0, sizeof(cfg->cookie_secret)); - cfg->cookie_secret_len = 16; - init_cookie_secret(cfg->cookie_secret, cfg->cookie_secret_len); + cfg->cookie_secret_len = 0; /* not set yet */ cfg->cookie_secret_file = NULL; #ifdef USE_CACHEDB if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit; @@ -421,8 +426,11 @@ config_create(void) cfg->dns_error_reporting = 0; cfg->iter_scrub_ns = 20; cfg->iter_scrub_cname = 11; + cfg->iter_scrub_rrsig = 8; cfg->iter_scrub_promiscuous = 1; cfg->max_global_quota = 200; + cfg->val_validation_attempts = 32; + cfg->val_hash_attempts = 32; return cfg; error_exit: config_delete(cfg); @@ -527,7 +535,11 @@ probe_maxrto(int useful_server_top_timeo int config_apply_max_rtt(int max_rtt) { USEFUL_SERVER_TOP_TIMEOUT = max_rtt; - BLACKLIST_PENALTY = max_rtt*4; + BLACKLIST_PENALTY = +#ifdef INT_MAX + (max_rtt > INT_MAX/4) ? INT_MAX : +#endif + max_rtt*4; PROBE_MAXRTO = probe_maxrto(max_rtt); return max_rtt; } @@ -629,6 +641,11 @@ int config_set_option(struct config_file else S_STR("tls-ciphers:", tls_ciphers) else S_STR("tls-ciphersuites:", tls_ciphersuites) else S_YNO("tls-use-sni:", tls_use_sni) + else if(strcmp(opt, "tls-protocols:") == 0) { + if(!cfg_tls_protocols_is_valid(val)) return 0; + free(cfg->tls_protocols); + return (cfg->tls_protocols = strdup(val)) != NULL; + } else S_NUMBER_NONZERO("https-port:", https_port) else S_STR("http-endpoint:", http_endpoint) else S_NUMBER_NONZERO("http-max-streams:", http_max_streams) @@ -746,6 +763,7 @@ int config_set_option(struct config_file else S_YNO("log-local-actions:", log_local_actions) else S_YNO("log-servfail:", log_servfail) else S_YNO("log-destaddr:", log_destaddr) + else S_YNO("log-thread-id:", log_thread_id) else S_YNO("val-permissive-mode:", val_permissive_mode) else S_YNO("aggressive-nsec:", aggressive_nsec) else S_YNO("ignore-cd-flag:", ignore_cd) @@ -764,10 +782,13 @@ int config_set_option(struct config_file else S_YNO("ede:", ede) else S_YNO("ede-serve-expired:", ede_serve_expired) else S_YNO("dns-error-reporting:", dns_error_reporting) - else S_NUMBER_OR_ZERO("iter-scrub-ns:", iter_scrub_ns) + else S_NUMBER_NONZERO("iter-scrub-ns:", iter_scrub_ns) else S_NUMBER_OR_ZERO("iter-scrub-cname:", iter_scrub_cname) + else S_NUMBER_OR_ZERO("iter-scrub-rrsig:", iter_scrub_rrsig) else S_YNO("iter-scrub-promiscuous:", iter_scrub_promiscuous) else S_NUMBER_OR_ZERO("max-global-quota:", max_global_quota) + else S_NUMBER_OR_ZERO("val-validation-attempts:", val_validation_attempts) + else S_NUMBER_OR_ZERO("val-hash-attempts:", val_hash_attempts) else S_YNO("serve-original-ttl:", serve_original_ttl) else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations) else S_YNO("zonemd-permissive-mode:", zonemd_permissive_mode) @@ -1181,6 +1202,7 @@ config_get_option(struct config_file* cf else O_STR(opt, "tls-ciphers", tls_ciphers) else O_STR(opt, "tls-ciphersuites", tls_ciphersuites) else O_YNO(opt, "tls-use-sni", tls_use_sni) + else O_STR(opt, "tls-protocols", tls_protocols) else O_DEC(opt, "https-port", https_port) else O_STR(opt, "http-endpoint", http_endpoint) else O_UNS(opt, "http-max-streams", http_max_streams) @@ -1202,6 +1224,7 @@ config_get_option(struct config_file* cf else O_YNO(opt, "log-local-actions", log_local_actions) else O_YNO(opt, "log-servfail", log_servfail) else O_YNO(opt, "log-destaddr", log_destaddr) + else O_YNO(opt, "log-thread-id", log_thread_id) else O_STR(opt, "pidfile", pidfile) else O_YNO(opt, "hide-identity", hide_identity) else O_YNO(opt, "hide-version", hide_version) @@ -1243,8 +1266,11 @@ config_get_option(struct config_file* cf else O_YNO(opt, "dns-error-reporting", dns_error_reporting) else O_DEC(opt, "iter-scrub-ns", iter_scrub_ns) else O_DEC(opt, "iter-scrub-cname", iter_scrub_cname) + else O_DEC(opt, "iter-scrub-rrsig", iter_scrub_rrsig) else O_YNO(opt, "iter-scrub-promiscuous", iter_scrub_promiscuous) else O_DEC(opt, "max-global-quota", max_global_quota) + else O_DEC(opt, "val-validation-attempts", val_validation_attempts) + else O_DEC(opt, "val-hash-attempts", val_hash_attempts) else O_YNO(opt, "serve-original-ttl", serve_original_ttl) else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations) else O_YNO(opt, "zonemd-permissive-mode", zonemd_permissive_mode) @@ -1556,6 +1582,8 @@ config_read(struct config_file* cfg, con } globfree(&g); config_auto_slab_values(cfg); + if(!init_cookie_secret(cfg)) + return 0; return 1; } #endif /* HAVE_GLOB */ @@ -1580,6 +1608,8 @@ config_read(struct config_file* cfg, con } config_auto_slab_values(cfg); + if(!init_cookie_secret(cfg)) + return 0; return 1; } @@ -1750,6 +1780,7 @@ config_delete(struct config_file* cfg) config_delstrlist(cfg->tls_session_ticket_keys.first); free(cfg->tls_ciphers); free(cfg->tls_ciphersuites); + free(cfg->tls_protocols); free(cfg->http_endpoint); if(cfg->log_identity) { log_ident_revert_to_default(); @@ -1853,18 +1884,33 @@ config_delete(struct config_file* cfg) free(cfg); } -static void -init_cookie_secret(uint8_t* cookie_secret, size_t cookie_secret_len) +static int +init_cookie_secret(struct config_file* cfg) { - struct ub_randstate *rand = ub_initstate(NULL); + struct ub_randstate* rand; + size_t cookie_secret_len; + uint8_t* cookie_secret; + if(!cfg->do_answer_cookie) + return 1; + if(cfg->cookie_secret_file && cfg->cookie_secret_file[0]) + return 1; + if(cfg->cookie_secret_len != 0) + return 1; - if (!rand) - fatal_exit("could not init random generator"); + rand = ub_initstate(NULL); + if(!rand) { + log_err("init_cookie_secret: could not init random generator"); + return 0; + } + cfg->cookie_secret_len = 16; + cookie_secret_len = cfg->cookie_secret_len; + cookie_secret = cfg->cookie_secret; while (cookie_secret_len) { *cookie_secret++ = (uint8_t)ub_random(rand); cookie_secret_len--; } ub_randfree(rand); + return 1; } static void @@ -1927,7 +1973,7 @@ extract_port_from_str(const char* str, i int cfg_mark_ports(const char* str, int allow, int* avail, int num) { - char* mid = strchr(str, '-'); + const char* mid = strchr(str, '-'); #ifdef DISABLE_EXPLICIT_PORT_RANDOMISATION log_warn("Explicit port randomisation disabled, ignoring " "outgoing-port-permit and outgoing-port-avoid configuration " @@ -1935,7 +1981,7 @@ cfg_mark_ports(const char* str, int allo #endif if(!mid) { int port = extract_port_from_str(str, num); - if(port < 0) { + if (port < 0) { log_err("Failed to parse the port number"); return 0; } @@ -1945,7 +1991,7 @@ cfg_mark_ports(const char* str, int allo char buf[16]; int i, low; int high = extract_port_from_str(mid+1, num); - if(high < 0) { + if (high < 0) { log_err("Failed to parse the port number"); return 0; } @@ -1959,7 +2005,7 @@ cfg_mark_ports(const char* str, int allo memcpy(buf, str, (size_t)(mid-str)); buf[mid-str] = 0; low = extract_port_from_str(buf, num); - if(low < 0) { + if (low < 0) { log_err("Failed to parse the port number"); return 0; } @@ -2630,10 +2676,10 @@ fname_after_chroot(const char* fname, st } /** return next space character in string */ -static char* next_space_pos(const char* str) +static const char* next_space_pos(const char* str) { - char* sp = strchr(str, ' '); - char* tab = strchr(str, '\t'); + const char* sp = strchr(str, ' '); + const char* tab = strchr(str, '\t'); if(!tab && !sp) return NULL; if(!sp) return tab; @@ -2642,10 +2688,10 @@ static char* next_space_pos(const char* } /** return last space character in string */ -static char* last_space_pos(const char* str) +static const char* last_space_pos(const char* str) { - char* sp = strrchr(str, ' '); - char* tab = strrchr(str, '\t'); + const char* sp = strrchr(str, ' '); + const char* tab = strrchr(str, '\t'); if(!tab && !sp) return NULL; if(!sp) return tab; @@ -2703,8 +2749,8 @@ cfg_parse_local_zone(struct config_file* char* cfg_ptr_reverse(char* str) { - char* ip, *ip_end; - char* name; + const char* ip, *ip_end; + const char* name; char* result; char buf[1024]; struct sockaddr_storage addr; @@ -2855,7 +2901,7 @@ if_listens_on(const char* ifname, int de struct config_strlist* additional_ports) { struct config_strlist* s; - char* p = strchr(ifname, '@'); + const char* p = strchr(ifname, '@'); int if_port; if(p) if_port = atoi(p+1); else if_port = default_port; @@ -2923,6 +2969,29 @@ if_is_quic(const char* ifname, int defau } int +cfg_ports_list_contains(char* ports, int p) +{ + char* now = ports, *after; + int extraport; + while(now && *now) { + while(isspace((unsigned char)*now)) + now++; + if(!now) + break; + after = now; + extraport = (int)strtol(now, &after, 10); + if(extraport < 0 || extraport > 65535) + continue; /* Out of range. */ + if(extraport == 0 && now == after) + return 0; /* Number could not be parsed. */ + now = after; + if(extraport == p) + return 1; + } + return 0; +} + +int cfg_has_https(struct config_file* cfg) { int i; @@ -2930,6 +2999,8 @@ cfg_has_https(struct config_file* cfg) if(if_is_https(cfg->ifs[i], cfg->port, cfg->https_port)) return 1; } + if(cfg_ports_list_contains(cfg->if_automatic_ports, cfg->https_port)) + return 1; return 0; } @@ -2942,9 +3013,83 @@ cfg_has_quic(struct config_file* cfg) if(if_is_quic(cfg->ifs[i], cfg->port, cfg->quic_port)) return 1; } + if(cfg_ports_list_contains(cfg->if_automatic_ports, cfg->quic_port)) + return 1; return 0; #else (void)cfg; return 0; #endif +} + +int +cfg_tls_protocols_is_valid(const char* tls_protocols) +{ + const char* s = tls_protocols; + while(*s && isspace((unsigned char)*s)) s++; + while(*s && !isspace((unsigned char)*s)) { + if(strncmp(s, "TLSv1.2", 7) == 0 || + strncmp(s, "TLSv1.3", 7) == 0) { + s += 7; + if(*s && !isspace((unsigned char)*s)) { + /* something is attached; fail */ + return 0; + } + while(*s && isspace((unsigned char)*s)) + s++; + continue; + } + return 0; + } + return 1; +} + +void +cfg_tls_protocols_allowed(const char* tls_protocols, int* allow12, int* allow13) +{ + const char* s = tls_protocols; + *allow12 = 0; + *allow13 = 0; + if(tls_protocols == NULL) return; + while(*s && isspace((unsigned char)*s)) s++; + while(*s && !isspace((unsigned char)*s)) { + if(strncmp(s, "TLSv1.2", 7) == 0) { + *allow12 = 1; + s += 7; + } else if(strncmp(s, "TLSv1.3", 7) == 0) { + *allow13 = 1; + s += 7; + } else { + /* Unknown word, this should never happen but skip to + * be safe */ + while(*s && !isspace((unsigned char)*s)) + s++; + } + while(*s && isspace((unsigned char)*s)) + s++; + } +} + +int +file_get_mtime(const char* file, time_t* mtime, long* ns, int* nonexist) +{ + struct stat s; + if(stat(file, &s) != 0) { + *mtime = 0; + *ns = 0; + if(nonexist) + *nonexist = (errno == ENOENT); + return 0; + } + if(nonexist) + *nonexist = 0; + *mtime = s.st_mtime; +#ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC + *ns = s.st_mtimensec; +#elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) + *ns = s.st_mtim.tv_nsec; +#else + *ns = 0; +#endif + return 1; } Index: usr.sbin/unbound/util/config_file.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/config_file.h,v diff -u -p -r1.38 config_file.h --- usr.sbin/unbound/util/config_file.h 23 Oct 2025 12:50:29 -0000 1.38 +++ usr.sbin/unbound/util/config_file.h 21 Sep 2026 16:28:09 -0000 @@ -148,6 +148,8 @@ struct config_file { char* tls_ciphersuites; /** if SNI is to be used */ int tls_use_sni; + /** TLS protocols */ + char* tls_protocols; /** port on which to provide DNS over HTTPS service */ int https_port; @@ -365,6 +367,8 @@ struct config_file { char* log_identity; /** log dest addr for log_replies */ int log_destaddr; + /** log linux thread ID */ + int log_thread_id; /** do not report identity (id.server, hostname.bind) */ int hide_identity; @@ -790,8 +794,14 @@ struct config_file { size_t iter_scrub_ns; /** limit on CNAME, DNAME RRs in answer for the iterator scrubber. */ int iter_scrub_cname; + /** limit on RRSIGs for an RRset for the iterator scrubber. */ + int iter_scrub_rrsig; /** limit on upstream queries for an incoming query and subqueries. */ int max_global_quota; + /** limit on validator validation attempts. */ + int val_validation_attempts; + /** limit on validator hash attempts. */ + int val_hash_attempts; /** Should the iterator scrub promiscuous NS rrsets, from positive * answers. */ int iter_scrub_promiscuous; @@ -878,6 +888,10 @@ struct config_auth { int zonemd_check; /** Reject absence of ZONEMD records, zone must have one */ int zonemd_reject_absence; + /** The maximum auth zone transfer size, in bytes. */ + size_t max_transfer_size; + /** The maximum auth zone transfer time taken, in msec. */ + int max_transfer_time; }; /** @@ -1480,5 +1494,31 @@ int cfg_has_quic(struct config_file* cfg /** get memory for string */ size_t getmem_str(char* str); + +/** + * See if the if_automatic_ports list contains the value. + * @param ports: String with port numbers. + * @param p: number looked for. + * @return true if found, false if not found or parse failure. + */ +int cfg_ports_list_contains(char* ports, int p); + +/** + * Check if the configured string contains supported TLS protocols. + * @param tls_protocols: String with TLS protocols. + * @return true if all options are valid, else false. + */ +int cfg_tls_protocols_is_valid(const char* tls_protocols); + +/** + * Based on the configured TLS protocols fill which ones are allowed. + * @param tls_protocols: String with TLS protocols. + * @param allow12: will be true if TLSv1.2 is configured. + * @param allow13: will be true if TLSv1.3 is configured. + */ +void cfg_tls_protocols_allowed(const char* tls_protocols, int* allow12, int* allow13); + +/** get the file mtime stat (or error, with errno and nonexist) */ +int file_get_mtime(const char* file, time_t* mtime, long* ns, int* nonexist); #endif /* UTIL_CONFIG_FILE_H */ Index: usr.sbin/unbound/util/configlexer.lex =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/configlexer.lex,v diff -u -p -r1.34 configlexer.lex --- usr.sbin/unbound/util/configlexer.lex 23 Oct 2025 12:50:29 -0000 1.34 +++ usr.sbin/unbound/util/configlexer.lex 21 Sep 2026 16:28:09 -0000 @@ -13,7 +13,6 @@ #pragma GCC diagnostic ignored "-Wsign-compare" #endif -#include #include #ifdef HAVE_GLOB_H # include @@ -262,6 +261,7 @@ tls-session-ticket-keys{COLON} { YDVAR(1 tls-ciphers{COLON} { YDVAR(1, VAR_TLS_CIPHERS) } tls-ciphersuites{COLON} { YDVAR(1, VAR_TLS_CIPHERSUITES) } tls-use-sni{COLON} { YDVAR(1, VAR_TLS_USE_SNI) } +tls-protocols{COLON} { YDVAR(1, VAR_TLS_PROTOCOLS) } https-port{COLON} { YDVAR(1, VAR_HTTPS_PORT) } http-endpoint{COLON} { YDVAR(1, VAR_HTTP_ENDPOINT) } http-max-streams{COLON} { YDVAR(1, VAR_HTTP_MAX_STREAMS) } @@ -440,6 +440,7 @@ log-tag-queryreply{COLON} { YDVAR(1, VAR log-local-actions{COLON} { YDVAR(1, VAR_LOG_LOCAL_ACTIONS) } log-servfail{COLON} { YDVAR(1, VAR_LOG_SERVFAIL) } log-destaddr{COLON} { YDVAR(1, VAR_LOG_DESTADDR) } +log-thread-id{COLON} { YDVAR(1, VAR_LOG_THREAD_ID) } local-zone{COLON} { YDVAR(2, VAR_LOCAL_ZONE) } local-data{COLON} { YDVAR(1, VAR_LOCAL_DATA) } local-data-ptr{COLON} { YDVAR(1, VAR_LOCAL_DATA_PTR) } @@ -605,7 +606,12 @@ dns-error-reporting{COLON} { YDVAR(1, VA proxy-protocol-port{COLON} { YDVAR(1, VAR_PROXY_PROTOCOL_PORT) } iter-scrub-ns{COLON} { YDVAR(1, VAR_ITER_SCRUB_NS) } iter-scrub-cname{COLON} { YDVAR(1, VAR_ITER_SCRUB_CNAME) } +iter-scrub-rrsig{COLON} { YDVAR(1, VAR_ITER_SCRUB_RRSIG) } max-global-quota{COLON} { YDVAR(1, VAR_MAX_GLOBAL_QUOTA) } +val-validation-attempts{COLON} { YDVAR(1, VAR_VAL_VALIDATION_ATTEMPTS) } +val-hash-attempts{COLON} { YDVAR(1, VAR_VAL_HASH_ATTEMPTS) } +max-transfer-size{COLON} { YDVAR(1, VAR_MAX_TRANSFER_SIZE) } +max-transfer-time{COLON} { YDVAR(1, VAR_MAX_TRANSFER_TIME) } iter-scrub-promiscuous{COLON} { YDVAR(1, VAR_ITER_SCRUB_PROMISCUOUS) } {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; } Index: usr.sbin/unbound/util/configparser.y =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/configparser.y,v diff -u -p -r1.36 configparser.y --- usr.sbin/unbound/util/configparser.y 23 Oct 2025 12:50:29 -0000 1.36 +++ usr.sbin/unbound/util/configparser.y 21 Sep 2026 16:28:10 -0000 @@ -199,6 +199,7 @@ extern struct config_parser_state* cfg_p %token VAR_DISCARD_TIMEOUT VAR_WAIT_LIMIT VAR_WAIT_LIMIT_COOKIE %token VAR_WAIT_LIMIT_NETBLOCK VAR_WAIT_LIMIT_COOKIE_NETBLOCK %token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES VAR_TLS_USE_SNI +%token VAR_TLS_PROTOCOLS %token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6 %token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE %token VAR_RPZ_CNAME_OVERRIDE VAR_RPZ_LOG VAR_RPZ_LOG_NAME @@ -214,8 +215,11 @@ extern struct config_parser_state* cfg_p %token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE %token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED %token VAR_COOKIE_SECRET_FILE VAR_ITER_SCRUB_NS VAR_ITER_SCRUB_CNAME +%token VAR_ITER_SCRUB_RRSIG +%token VAR_MAX_TRANSFER_SIZE VAR_MAX_TRANSFER_TIME %token VAR_MAX_GLOBAL_QUOTA VAR_HARDEN_UNVERIFIED_GLUE VAR_LOG_TIME_ISO -%token VAR_ITER_SCRUB_PROMISCUOUS +%token VAR_VAL_VALIDATION_ATTEMPTS VAR_VAL_HASH_ATTEMPTS +%token VAR_ITER_SCRUB_PROMISCUOUS VAR_LOG_THREAD_ID %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -287,7 +291,7 @@ content_server: server_num_threads | ser server_edns_buffer_size | server_prefetch | server_prefetch_key | server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag | server_log_queries | server_log_replies | server_tcp_upstream | server_ssl_upstream | - server_log_local_actions | + server_log_local_actions | server_log_thread_id | server_ssl_service_key | server_ssl_service_pem | server_ssl_port | server_https_port | server_http_endpoint | server_http_max_streams | server_http_query_buffer_size | server_http_response_buffer_size | @@ -346,7 +350,7 @@ content_server: server_num_threads | ser server_stream_wait_size | server_tls_ciphers | server_tls_ciphersuites | server_tls_session_ticket_keys | server_answer_cookie | server_cookie_secret | server_ip_ratelimit_cookie | - server_tls_use_sni | server_edns_client_string | + server_tls_use_sni | server_edns_client_string | server_tls_protocols | server_edns_client_string_opcode | server_nsid | server_zonemd_permissive_mode | server_max_reuse_tcp_queries | server_tcp_reuse_timeout | server_tcp_auth_query_timeout | @@ -357,6 +361,8 @@ content_server: server_num_threads | ser server_harden_unknown_additional | server_disable_edns_do | server_log_destaddr | server_cookie_secret_file | server_iter_scrub_ns | server_iter_scrub_cname | server_max_global_quota | + server_val_validation_attempts | + server_val_hash_attempts | server_iter_scrub_rrsig | server_harden_unverified_glue | server_log_time_iso | server_iter_scrub_promiscuous ; stub_clause: stubstart contents_stub @@ -456,6 +462,8 @@ authstart: VAR_AUTH_ZONE s->zonemd_check = 0; s->zonemd_reject_absence = 0; s->isrpz = 0; + s->max_transfer_size = 0; + s->max_transfer_time = 0; } else { yyerror("out of memory"); } @@ -465,7 +473,8 @@ contents_auth: contents_auth content_aut | ; content_auth: auth_name | auth_zonefile | auth_master | auth_url | auth_for_downstream | auth_for_upstream | auth_fallback_enabled | - auth_allow_notify | auth_zonemd_check | auth_zonemd_reject_absence + auth_allow_notify | auth_zonemd_check | auth_zonemd_reject_absence | + auth_max_transfer_size | auth_max_transfer_time ; rpz_tag: VAR_TAGS STRING_ARG @@ -553,6 +562,8 @@ rpzstart: VAR_RPZ s->for_upstream = 0; s->fallback_enabled = 0; s->isrpz = 1; + s->max_transfer_size = 0; + s->max_transfer_time = 0; } else { yyerror("out of memory"); } @@ -562,7 +573,8 @@ contents_rpz: contents_rpz content_rpz | ; content_rpz: auth_name | auth_zonefile | rpz_tag | auth_master | auth_url | auth_allow_notify | rpz_action_override | rpz_cname_override | - rpz_log | rpz_log_name | rpz_signal_nxdomain_ra | auth_for_downstream + rpz_log | rpz_log_name | rpz_signal_nxdomain_ra | auth_for_downstream | + auth_max_transfer_size | auth_max_transfer_time ; server_num_threads: VAR_NUM_THREADS STRING_ARG { @@ -654,7 +666,7 @@ server_send_client_subnet: VAR_SEND_CLIE #ifdef CLIENT_SUBNET OUTYY(("P(server_send_client_subnet:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->client_subnet, $2)) - fatal_exit("out of memory adding client-subnet"); + yyerror("out of memory"); #else OUTYY(("P(Compiled without edns subnet option, ignoring)\n")); free($2); @@ -667,7 +679,7 @@ server_client_subnet_zone: VAR_CLIENT_SU OUTYY(("P(server_client_subnet_zone:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->client_subnet_zone, $2)) - fatal_exit("out of memory adding client-subnet-zone"); + yyerror("out of memory"); #else OUTYY(("P(Compiled without edns subnet option, ignoring)\n")); free($2); @@ -1155,6 +1167,15 @@ server_tls_use_sni: VAR_TLS_USE_SNI STRI free($2); } ; +server_tls_protocols: VAR_TLS_PROTOCOLS STRING_ARG + { + OUTYY(("P(server_tls_protocols:%s)\n", $2)); + if(!cfg_tls_protocols_is_valid($2)) + yyerror("tls-protocols: valid values are 'TLSv1.2' and 'TLSv1.3'."); + free(cfg_parser->cfg->tls_protocols); + cfg_parser->cfg->tls_protocols = $2; + } + ; server_https_port: VAR_HTTPS_PORT STRING_ARG { OUTYY(("P(server_https_port:%s)\n", $2)); @@ -1224,14 +1245,17 @@ server_http_notls_downstream: VAR_HTTP_N server_quic_port: VAR_QUIC_PORT STRING_ARG { OUTYY(("P(server_quic_port:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2,"0")!=0) + yyerror("port number expected"); + else { + cfg_parser->cfg->quic_port = atoi($2); #ifndef HAVE_NGTCP2 - log_warn("%s:%d: Unbound is not compiled with " - "ngtcp2. This is required to use DNS " - "over QUIC.", cfg_parser->filename, cfg_parser->line); + if (cfg_parser->cfg->quic_port != 0) + log_warn("%s:%d: Unbound is not compiled with " + "ngtcp2. This is required to use DNS " + "over QUIC.", cfg_parser->filename, cfg_parser->line); #endif - if(atoi($2) == 0) - yyerror("port number expected"); - else cfg_parser->cfg->quic_port = atoi($2); + } free($2); }; server_quic_size: VAR_QUIC_SIZE STRING_ARG @@ -1336,6 +1360,15 @@ server_log_destaddr: VAR_LOG_DESTADDR ST free($2); } ; +server_log_thread_id: VAR_LOG_THREAD_ID STRING_ARG + { + OUTYY(("P(server_log_thread_id:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->log_thread_id = (strcmp($2, "yes")==0); + free($2); + } + ; server_log_local_actions: VAR_LOG_LOCAL_ACTIONS STRING_ARG { OUTYY(("P(server_log_local_actions:%s)\n", $2)); @@ -2005,7 +2038,7 @@ server_access_control: VAR_ACCESS_CONTRO OUTYY(("P(server_access_control:%s %s)\n", $2, $3)); validate_acl_action($3); if(!cfg_str2list_insert(&cfg_parser->cfg->acls, $2, $3)) - fatal_exit("out of memory adding acl"); + yyerror("out of memory"); } ; server_interface_action: VAR_INTERFACE_ACTION STRING_ARG STRING_ARG @@ -2014,7 +2047,7 @@ server_interface_action: VAR_INTERFACE_A validate_acl_action($3); if(!cfg_str2list_insert( &cfg_parser->cfg->interface_actions, $2, $3)) - fatal_exit("out of memory adding acl"); + yyerror("out of memory"); } ; server_module_conf: VAR_MODULE_CONF STRING_ARG @@ -2364,6 +2397,9 @@ server_local_zone: VAR_LOCAL_ZONE STRING && strcmp($3, "typetransparent")!=0 && strcmp($3, "always_transparent")!=0 && strcmp($3, "block_a")!=0 + && strcmp($3, "block_aaaa")!=0 + && strcmp($3, "block_a_wdata")!=0 + && strcmp($3, "block_aaaa_wdata")!=0 && strcmp($3, "always_refuse")!=0 && strcmp($3, "always_nxdomain")!=0 && strcmp($3, "always_nodata")!=0 @@ -2376,7 +2412,9 @@ server_local_zone: VAR_LOCAL_ZONE STRING yyerror("local-zone type: expected static, deny, " "refuse, redirect, transparent, " "typetransparent, inform, inform_deny, " - "inform_redirect, always_transparent, block_a," + "inform_redirect, always_transparent, " + "block_a, block_aaaa, " + "block_a_wdata, block_aaaa_wdata, " "always_refuse, always_nxdomain, " "always_nodata, always_deny, always_null, " "noview, nodefault or ipset"); @@ -2385,7 +2423,7 @@ server_local_zone: VAR_LOCAL_ZONE STRING } else if(strcmp($3, "nodefault")==0) { if(!cfg_strlist_insert(&cfg_parser->cfg-> local_zones_nodefault, $2)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); free($3); #ifdef USE_IPSET } else if(strcmp($3, "ipset")==0) { @@ -2393,21 +2431,24 @@ server_local_zone: VAR_LOCAL_ZONE STRING /* Make sure to add the trailing dot. * These are str compared to domain names. */ if($2[len-1] != '.') { + char* prev = $2; if(!($2 = realloc($2, len+2))) { - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); + free(prev); + } else { + $2[len] = '.'; + $2[len+1] = 0; } - $2[len] = '.'; - $2[len+1] = 0; } if(!cfg_strlist_insert(&cfg_parser->cfg-> local_zones_ipset, $2)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); free($3); #endif } else { if(!cfg_str2list_insert(&cfg_parser->cfg->local_zones, $2, $3)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); } } ; @@ -2415,7 +2456,7 @@ server_local_data: VAR_LOCAL_DATA STRING { OUTYY(("P(server_local_data:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->local_data, $2)) - fatal_exit("out of memory adding local-data"); + yyerror("out of memory"); } ; server_local_data_ptr: VAR_LOCAL_DATA_PTR STRING_ARG @@ -2427,7 +2468,7 @@ server_local_data_ptr: VAR_LOCAL_DATA_PT if(ptr) { if(!cfg_strlist_insert(&cfg_parser->cfg-> local_data, ptr)) - fatal_exit("out of memory adding local-data"); + yyerror("out of memory"); } else { yyerror("local-data-ptr could not be reversed"); } @@ -2491,8 +2532,7 @@ server_wait_limit_netblock: VAR_WAIT_LIM } else { if(!cfg_str2list_insert(&cfg_parser->cfg-> wait_limit_netblock, $2, $3)) - fatal_exit("out of memory adding " - "wait-limit-netblock"); + yyerror("out of memory"); } } ; @@ -2506,8 +2546,7 @@ server_wait_limit_cookie_netblock: VAR_W } else { if(!cfg_str2list_insert(&cfg_parser->cfg-> wait_limit_cookie_netblock, $2, $3)) - fatal_exit("out of memory adding " - "wait-limit-cookie-netblock"); + yyerror("out of memory"); } } ; @@ -2539,7 +2578,7 @@ server_dns64_ignore_aaaa: VAR_DNS64_IGNO OUTYY(("P(dns64_ignore_aaaa:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->dns64_ignore_aaaa, $2)) - fatal_exit("out of memory adding dns64-ignore-aaaa"); + yyerror("out of memory"); } ; server_nat64_prefix: VAR_NAT64_PREFIX STRING_ARG @@ -2804,8 +2843,7 @@ server_ratelimit_for_domain: VAR_RATELIM } else { if(!cfg_str2list_insert(&cfg_parser->cfg-> ratelimit_for_domain, $2, $3)) - fatal_exit("out of memory adding " - "ratelimit-for-domain"); + yyerror("out of memory"); } } ; @@ -2819,8 +2857,7 @@ server_ratelimit_below_domain: VAR_RATEL } else { if(!cfg_str2list_insert(&cfg_parser->cfg-> ratelimit_below_domain, $2, $3)) - fatal_exit("out of memory adding " - "ratelimit-below-domain"); + yyerror("out of memory"); } } ; @@ -3054,8 +3091,7 @@ server_edns_client_string: VAR_EDNS_CLIE OUTYY(("P(server_edns_client_string:%s %s)\n", $2, $3)); if(!cfg_str2list_insert( &cfg_parser->cfg->edns_client_strings, $2, $3)) - fatal_exit("out of memory adding " - "edns-client-string"); + yyerror("out of memory"); } ; server_edns_client_string_opcode: VAR_EDNS_CLIENT_STRING_OPCODE STRING_ARG @@ -3317,6 +3353,23 @@ auth_fallback_enabled: VAR_FALLBACK_ENAB free($2); } ; +auth_max_transfer_size: VAR_MAX_TRANSFER_SIZE STRING_ARG + { + OUTYY(("P(max-transfer-size:%s)\n", $2)); + if(!cfg_parse_memsize($2, &cfg_parser->cfg->auths->max_transfer_size)) + yyerror("memory size expected"); + free($2); + } + ; +auth_max_transfer_time: VAR_MAX_TRANSFER_TIME STRING_ARG + { + OUTYY(("P(max-transfer-time:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->auths->max_transfer_time = atoi($2); + free($2); + } + ; view_name: VAR_NAME STRING_ARG { OUTYY(("P(name:%s)\n", $2)); @@ -3356,7 +3409,7 @@ view_local_zone: VAR_LOCAL_ZONE STRING_A } else if(strcmp($3, "nodefault")==0) { if(!cfg_strlist_insert(&cfg_parser->cfg->views-> local_zones_nodefault, $2)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); free($3); #ifdef USE_IPSET } else if(strcmp($3, "ipset")==0) { @@ -3364,22 +3417,25 @@ view_local_zone: VAR_LOCAL_ZONE STRING_A /* Make sure to add the trailing dot. * These are str compared to domain names. */ if($2[len-1] != '.') { + char* prev = $2; if(!($2 = realloc($2, len+2))) { - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); + free(prev); + } else { + $2[len] = '.'; + $2[len+1] = 0; } - $2[len] = '.'; - $2[len+1] = 0; } if(!cfg_strlist_insert(&cfg_parser->cfg->views-> local_zones_ipset, $2)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); free($3); #endif } else { if(!cfg_str2list_insert( &cfg_parser->cfg->views->local_zones, $2, $3)) - fatal_exit("out of memory adding local-zone"); + yyerror("out of memory"); } } ; @@ -3389,8 +3445,7 @@ view_response_ip: VAR_RESPONSE_IP STRING validate_respip_action($3); if(!cfg_str2list_insert( &cfg_parser->cfg->views->respip_actions, $2, $3)) - fatal_exit("out of memory adding per-view " - "response-ip action"); + yyerror("out of memory"); } ; view_response_ip_data: VAR_RESPONSE_IP_DATA STRING_ARG STRING_ARG @@ -3398,14 +3453,14 @@ view_response_ip_data: VAR_RESPONSE_IP_D OUTYY(("P(view_response_ip_data:%s)\n", $2)); if(!cfg_str2list_insert( &cfg_parser->cfg->views->respip_data, $2, $3)) - fatal_exit("out of memory adding response-ip-data"); + yyerror("out of memory"); } ; view_local_data: VAR_LOCAL_DATA STRING_ARG { OUTYY(("P(view_local_data:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->views->local_data, $2)) { - fatal_exit("out of memory adding local-data"); + yyerror("out of memory"); } } ; @@ -3418,7 +3473,7 @@ view_local_data_ptr: VAR_LOCAL_DATA_PTR if(ptr) { if(!cfg_strlist_insert(&cfg_parser->cfg->views-> local_data, ptr)) - fatal_exit("out of memory adding local-data"); + yyerror("out of memory"); } else { yyerror("local-data-ptr could not be reversed"); } @@ -3758,7 +3813,7 @@ server_response_ip: VAR_RESPONSE_IP STRI validate_respip_action($3); if(!cfg_str2list_insert(&cfg_parser->cfg->respip_actions, $2, $3)) - fatal_exit("out of memory adding response-ip"); + yyerror("out of memory"); } ; server_response_ip_data: VAR_RESPONSE_IP_DATA STRING_ARG STRING_ARG @@ -3766,7 +3821,7 @@ server_response_ip_data: VAR_RESPONSE_IP OUTYY(("P(server_response_ip_data:%s)\n", $2)); if(!cfg_str2list_insert(&cfg_parser->cfg->respip_data, $2, $3)) - fatal_exit("out of memory adding response-ip-data"); + yyerror("out of memory"); } ; dnscstart: VAR_DNSCRYPT @@ -3814,26 +3869,30 @@ dnsc_dnscrypt_provider: VAR_DNSCRYPT_PRO dnsc_dnscrypt_provider_cert: VAR_DNSCRYPT_PROVIDER_CERT STRING_ARG { OUTYY(("P(dnsc_dnscrypt_provider_cert:%s)\n", $2)); - if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_provider_cert, $2)) + if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_provider_cert, $2)) { log_warn("dnscrypt-provider-cert %s is a duplicate", $2); - if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert, $2)) - fatal_exit("out of memory adding dnscrypt-provider-cert"); + free($2); + } else if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert, $2)) { + yyerror("out of memory"); + } } ; dnsc_dnscrypt_provider_cert_rotated: VAR_DNSCRYPT_PROVIDER_CERT_ROTATED STRING_ARG { OUTYY(("P(dnsc_dnscrypt_provider_cert_rotated:%s)\n", $2)); if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert_rotated, $2)) - fatal_exit("out of memory adding dnscrypt-provider-cert-rotated"); + yyerror("out of memory"); } ; dnsc_dnscrypt_secret_key: VAR_DNSCRYPT_SECRET_KEY STRING_ARG { OUTYY(("P(dnsc_dnscrypt_secret_key:%s)\n", $2)); - if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_secret_key, $2)) + if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_secret_key, $2)) { log_warn("dnscrypt-secret-key: %s is a duplicate", $2); - if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_secret_key, $2)) - fatal_exit("out of memory adding dnscrypt-secret-key"); + free($2); + } else if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_secret_key, $2)) { + yyerror("out of memory"); + } } ; dnsc_dnscrypt_shared_secret_cache_size: VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE STRING_ARG @@ -4178,7 +4237,7 @@ server_tcp_connection_limit: VAR_TCP_CON yyerror("positive number expected"); else { if(!cfg_str2list_insert(&cfg_parser->cfg->tcp_connection_limits, $2, $3)) - fatal_exit("out of memory adding tcp connection limit"); + yyerror("out of memory"); } } ; @@ -4217,8 +4276,8 @@ server_cookie_secret_file: VAR_COOKIE_SE server_iter_scrub_ns: VAR_ITER_SCRUB_NS STRING_ARG { OUTYY(("P(server_iter_scrub_ns:%s)\n", $2)); - if(atoi($2) == 0 && strcmp($2, "0") != 0) - yyerror("number expected"); + if(atoi($2) < 1) + yyerror("number >= 1 expected"); else cfg_parser->cfg->iter_scrub_ns = atoi($2); free($2); } @@ -4232,6 +4291,15 @@ server_iter_scrub_cname: VAR_ITER_SCRUB_ free($2); } ; +server_iter_scrub_rrsig: VAR_ITER_SCRUB_RRSIG STRING_ARG + { + OUTYY(("P(server_iter_scrub_rrsig:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->iter_scrub_rrsig = atoi($2); + free($2); + } + ; server_max_global_quota: VAR_MAX_GLOBAL_QUOTA STRING_ARG { OUTYY(("P(server_max_global_quota:%s)\n", $2)); @@ -4248,6 +4316,24 @@ server_iter_scrub_promiscuous: VAR_ITER_ yyerror("expected yes or no."); else cfg_parser->cfg->iter_scrub_promiscuous = (strcmp($2, "yes")==0); + free($2); + } + ; +server_val_validation_attempts: VAR_VAL_VALIDATION_ATTEMPTS STRING_ARG + { + OUTYY(("P(server_val_validation_attempts:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->val_validation_attempts = atoi($2); + free($2); + } + ; +server_val_hash_attempts: VAR_VAL_HASH_ATTEMPTS STRING_ARG + { + OUTYY(("P(server_val_hash_attempts:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->val_hash_attempts = atoi($2); free($2); } ; Index: usr.sbin/unbound/util/fptr_wlist.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/fptr_wlist.c,v diff -u -p -r1.29 fptr_wlist.c --- usr.sbin/unbound/util/fptr_wlist.c 31 Aug 2025 21:41:10 -0000 1.29 +++ usr.sbin/unbound/util/fptr_wlist.c 21 Sep 2026 16:28:10 -0000 @@ -141,6 +141,8 @@ fptr_whitelist_comm_timer(void (*fptr)(v #ifdef UB_ON_WINDOWS else if(fptr == &wsvc_cron_cb) return 1; #endif + else if(fptr == &tcp_read_again_cb) return 1; + else if(fptr == &tcp_more_read_again_cb) return 1; else if(fptr == &auth_xfer_timer) return 1; else if(fptr == &auth_xfer_probe_timer_callback) return 1; else if(fptr == &auth_xfer_transfer_timer_callback) return 1; @@ -362,7 +364,7 @@ fptr_whitelist_modenv_send_query(struct int nocaps, int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, struct module_qstate* q, - int* was_ratelimited)) + int* was_ratelimited, int* ratelimit_incremented)) { if(fptr == &worker_send_query) return 1; else if(fptr == &libworker_send_query) return 1; @@ -380,7 +382,8 @@ fptr_whitelist_modenv_detach_subs(void ( int fptr_whitelist_modenv_attach_sub(int (*fptr)( struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq)) + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq)) { if(fptr == &mesh_attach_sub) return 1; return 0; @@ -389,8 +392,8 @@ fptr_whitelist_modenv_attach_sub(int (*f int fptr_whitelist_modenv_add_sub(int (*fptr)( struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq, - struct mesh_state** sub)) + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq, struct mesh_state** sub)) { if(fptr == &mesh_add_sub) return 1; return 0; @@ -412,7 +415,7 @@ fptr_whitelist_modenv_detect_cycle(int ( return 0; } -int +int fptr_whitelist_mod_init(int (*fptr)(struct module_env* env, int id)) { if(fptr == &iter_init) return 1; @@ -440,7 +443,7 @@ fptr_whitelist_mod_init(int (*fptr)(stru return 0; } -int +int fptr_whitelist_mod_deinit(void (*fptr)(struct module_env* env, int id)) { if(fptr == &iter_deinit) return 1; @@ -609,6 +612,7 @@ int fptr_whitelist_alloc_cleanup(void (*fptr)(void*)) { if(fptr == &worker_alloc_cleanup) return 1; + else if(fptr == &libworker_alloc_cleanup) return 1; return 0; } Index: usr.sbin/unbound/util/fptr_wlist.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/fptr_wlist.h,v diff -u -p -r1.12 fptr_wlist.h --- usr.sbin/unbound/util/fptr_wlist.h 4 Sep 2024 09:36:41 -0000 1.12 +++ usr.sbin/unbound/util/fptr_wlist.h 21 Sep 2026 16:28:10 -0000 @@ -214,7 +214,7 @@ int fptr_whitelist_modenv_send_query(str int nocaps, int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, struct module_qstate* q, - int* was_ratelimited)); + int* was_ratelimited, int* ratelimit_incremented)); /** * Check function pointer whitelist for module_env detach_subs callback values. @@ -233,7 +233,8 @@ int fptr_whitelist_modenv_detach_subs(vo */ int fptr_whitelist_modenv_attach_sub(int (*fptr)( struct module_qstate* qstate, struct query_info* qinfo, - uint16_t qflags, int prime, int valrec, struct module_qstate** newq)); + struct respip_client_info* cinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq)); /** * Check function pointer whitelist for module_env add_sub callback values. @@ -242,8 +243,9 @@ int fptr_whitelist_modenv_attach_sub(int * @return false if not in whitelist. */ int fptr_whitelist_modenv_add_sub(int (*fptr)(struct module_qstate* qstate, - struct query_info* qinfo, uint16_t qflags, int prime, int valrec, - struct module_qstate** newq, struct mesh_state** sub)); + struct query_info* qinfo, struct respip_client_info* cinfo, + uint16_t qflags, int prime, int valrec, struct module_qstate** newq, + struct mesh_state** sub)); /** * Check function pointer whitelist for module_env kill_sub callback values. * Index: usr.sbin/unbound/util/iana_ports.inc =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/iana_ports.inc,v diff -u -p -r1.30 iana_ports.inc --- usr.sbin/unbound/util/iana_ports.inc 26 Sep 2025 07:32:37 -0000 1.30 +++ usr.sbin/unbound/util/iana_ports.inc 21 Sep 2026 16:28:10 -0000 @@ -649,9 +649,6 @@ 828, 829, 830, -831, -832, -833, 847, 848, 853, @@ -3869,6 +3866,7 @@ 4456, 4457, 4458, +4480, 4484, 4486, 4488, @@ -3981,6 +3979,7 @@ 4791, 4792, 4793, +4794, 4800, 4801, 4802, @@ -4173,6 +4172,7 @@ 5313, 5314, 5315, +5319, 5343, 5344, 5349, @@ -4507,6 +4507,7 @@ 6581, 6582, 6583, +6610, 6619, 6620, 6621, @@ -4609,6 +4610,7 @@ 7101, 7107, 7121, +7123, 7128, 7129, 7161, @@ -4950,6 +4952,7 @@ 9162, 9163, 9164, +9183, 9191, 9200, 9201, @@ -5343,6 +5346,7 @@ 24465, 24554, 24577, +24601, 24676, 24677, 24678, @@ -5392,6 +5396,7 @@ 30004, 30260, 30832, +30939, 30999, 31016, 31029, @@ -5433,6 +5438,8 @@ 34962, 34963, 34964, +34965, +34966, 34980, 35001, 35004, Index: usr.sbin/unbound/util/locks.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/locks.h,v diff -u -p -r1.3 locks.h --- usr.sbin/unbound/util/locks.h 21 Feb 2025 13:20:40 -0000 1.3 +++ usr.sbin/unbound/util/locks.h 21 Sep 2026 16:28:10 -0000 @@ -178,6 +178,30 @@ typedef pthread_key_t ub_thread_key_type #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v)) #define ub_thread_key_get(key) pthread_getspecific(key) +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#if defined(HAVE_PTHREAD_SET_NAME_NP) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_set_name_np(thread, name);\ + } while(0) +#elif defined(HAVE_PTHREAD_SETNAME_NP1) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_setname_np(name); \ + } while(0) +#elif defined(HAVE_PTHREAD_SETNAME_NP3) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_setname_np(thread, name, NULL); \ + } while(0) +#elif defined(HAVE_PTHREAD_SETNAME_NP) + #define ub_thread_setname(thread, name) do { \ + (void)pthread_setname_np(thread, name); \ + } while(0) +#else + #define ub_thread_setname(thread, name) /* nop */ +#endif /* HAVE_PTHREAD_SET_NAME_NP */ + + #else /* we do not HAVE_PTHREAD */ #ifdef HAVE_SOLARIS_THREADS @@ -215,6 +239,7 @@ typedef thread_key_t ub_thread_key_type; #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f)) #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v)) void* ub_thread_key_get(ub_thread_key_type key); +#define ub_thread_setname(thread, name) /* nop */ #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */ @@ -253,6 +278,7 @@ typedef DWORD ub_thread_key_type; void ub_thread_key_create(ub_thread_key_type* key, void* f); void ub_thread_key_set(ub_thread_key_type key, void* v); void* ub_thread_key_get(ub_thread_key_type key); +#define ub_thread_setname(thread, name) /* nop */ #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */ @@ -294,6 +320,7 @@ typedef void* ub_thread_key_type; #define ub_thread_key_create(key, f) (*(key)) = NULL #define ub_thread_key_set(key, v) (key) = (v) #define ub_thread_key_get(key) (key) +#define ub_thread_setname(thread, name) /* nop */ #endif /* HAVE_WINDOWS_THREADS */ #endif /* HAVE_SOLARIS_THREADS */ Index: usr.sbin/unbound/util/log.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/log.c,v diff -u -p -r1.11 log.c --- usr.sbin/unbound/util/log.c 31 Aug 2025 21:41:10 -0000 1.11 +++ usr.sbin/unbound/util/log.c 21 Sep 2026 16:28:10 -0000 @@ -174,10 +174,10 @@ void log_thread_set(int* num) int log_thread_get(void) { - unsigned int* tid; + int* tid; if(!key_created) return 0; - tid = (unsigned int*)ub_thread_key_get(logkey); - return (int)(tid?*tid:0); + tid = ub_thread_key_get(logkey); + return (tid?*tid:0); } void log_ident_set(const char* id) @@ -229,7 +229,7 @@ log_vmsg(int pri, const char* type, const char *format, va_list args) { char message[MAXSYSLOGMSGLEN]; - unsigned int* tid = (unsigned int*)ub_thread_key_get(logkey); + int tid = log_thread_get(); time_t now; #if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R) char tmbuf[32]; @@ -241,8 +241,8 @@ log_vmsg(int pri, const char* type, vsnprintf(message, sizeof(message), format, args); #ifdef HAVE_SYSLOG_H if(logging_to_syslog) { - syslog(pri, "[%d:%x] %s: %s", - (int)getpid(), tid?*tid:0, type, message); + syslog(pri, "[%d:%d] %s: %s", + (int)getpid(), tid, type, message); return; } #elif defined(UB_ON_WINDOWS) @@ -263,8 +263,8 @@ log_vmsg(int pri, const char* type, tp=MSG_GENERIC_SUCCESS; wt=EVENTLOG_SUCCESS; } - snprintf(m, sizeof(m), "[%s:%x] %s: %s", - ident, tid?*tid:0, type, message); + snprintf(m, sizeof(m), "[%s:%d] %s: %s", + ident, tid, type, message); s = RegisterEventSource(NULL, SERVICE_NAME); if(!s) return; ReportEvent(s, wt, 0, tp, NULL, 1, 0, &str, NULL); @@ -294,9 +294,9 @@ log_vmsg(int pri, const char* type, tzbuf[3] = ':'; tzbuf[6] = 0; } - fprintf(logfile, "%s.%3.3d%s %s[%d:%x] %s: %s\n", + fprintf(logfile, "%s.%3.3d%s %s[%d:%d] %s: %s\n", tmbuf, (int)tv.tv_usec/1000, tzbuf, - ident, (int)getpid(), tid?*tid:0, type, message); + ident, (int)getpid(), tid, type, message); #ifdef UB_ON_WINDOWS /* line buffering does not work on windows */ fflush(logfile); @@ -310,19 +310,19 @@ log_vmsg(int pri, const char* type, if(log_time_asc && strftime(tmbuf, sizeof(tmbuf), "%b %d %H:%M:%S", localtime_r(&now, &tm))%(sizeof(tmbuf)) != 0) { /* %sizeof buf!=0 because old strftime returned max on error */ - fprintf(logfile, "%s %s[%d:%x] %s: %s\n", tmbuf, - ident, (int)getpid(), tid?*tid:0, type, message); + fprintf(logfile, "%s %s[%d:%d] %s: %s\n", tmbuf, + ident, (int)getpid(), tid, type, message); } else #elif defined(UB_ON_WINDOWS) if(log_time_asc && GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, tmbuf, sizeof(tmbuf)) && GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, dtbuf, sizeof(dtbuf))) { - fprintf(logfile, "%s %s %s[%d:%x] %s: %s\n", dtbuf, tmbuf, - ident, (int)getpid(), tid?*tid:0, type, message); + fprintf(logfile, "%s %s %s[%d:%d] %s: %s\n", dtbuf, tmbuf, + ident, (int)getpid(), tid, type, message); } else #endif - fprintf(logfile, "[" ARG_LL "d] %s[%d:%x] %s: %s\n", (long long)now, - ident, (int)getpid(), tid?*tid:0, type, message); + fprintf(logfile, "[" ARG_LL "d] %s[%d:%d] %s: %s\n", (long long)now, + ident, (int)getpid(), tid, type, message); #ifdef UB_ON_WINDOWS /* line buffering does not work on windows */ fflush(logfile); Index: usr.sbin/unbound/util/module.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/module.h,v diff -u -p -r1.21 module.h --- usr.sbin/unbound/util/module.h 31 Aug 2025 21:41:10 -0000 1.21 +++ usr.sbin/unbound/util/module.h 21 Sep 2026 16:28:10 -0000 @@ -375,6 +375,8 @@ struct module_env { * @param q: which query state to reactivate upon return. * @param was_ratelimited: it will signal back if the query failed to pass the * ratelimit check. + * @param ratelimit_incremented: set to true if the ratelimit counter + * was increased. * @return: false on failure (memory or socket related). no query was * sent. Or returns an outbound entry with qsent and qstate set. * This outbound_entry will be used on later module invocations @@ -385,7 +387,8 @@ struct module_env { int check_ratelimit, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, - char* tls_auth_name, struct module_qstate* q, int* was_ratelimited); + char* tls_auth_name, struct module_qstate* q, int* was_ratelimited, + int* ratelimit_incremented); /** * Detach-subqueries. @@ -411,6 +414,8 @@ struct module_env { * @param qstate: the state to find mesh state, and that wants to * receive the results from the new subquery. * @param qinfo: what to query for (copied). + * @param cinfo: if non-NULL client specific info that may affect + * IP-based actions that apply to the query result. * @param qflags: what flags to use (RD, CD flag or not). * @param prime: if it is a (stub) priming query. * @param valrec: validation lookup recursion, does not need validation @@ -419,8 +424,9 @@ struct module_env { * @return: false on error, true if success (and init may be needed). */ int (*attach_sub)(struct module_qstate* qstate, - struct query_info* qinfo, uint16_t qflags, int prime, - int valrec, struct module_qstate** newq); + struct query_info* qinfo, struct respip_client_info* cinfo, + uint16_t qflags, int prime, int valrec, + struct module_qstate** newq); /** * Add detached query. @@ -440,6 +446,8 @@ struct module_env { * @param qstate: the state to find mesh state, and that wants to receive * the results from the new subquery. * @param qinfo: what to query for (copied). + * @param cinfo: if non-NULL client specific info that may affect + * IP-based actions that apply to the query result. * @param qflags: what flags to use (RD / CD flag or not). * @param prime: if it is a (stub) priming query. * @param valrec: if it is a validation recursion query (lookup of key, DS). @@ -449,9 +457,9 @@ struct module_env { * @return: false on error, true if success (and init may be needed). */ int (*add_sub)(struct module_qstate* qstate, - struct query_info* qinfo, uint16_t qflags, int prime, - int valrec, struct module_qstate** newq, - struct mesh_state** sub); + struct query_info* qinfo, struct respip_client_info* cinfo, + uint16_t qflags, int prime, int valrec, + struct module_qstate** newq, struct mesh_state** sub); /** * Kill newly attached sub. If attach_sub returns newq for @@ -693,6 +701,16 @@ struct module_qstate { time_t qstarttime; /** whether a message from cachedb will be used for the reply */ int is_cachedb_answer; + /** whether the reply is subnet specific */ + int is_subnet_answer; + /** if the response as error is from error_response_cache, and is + * suitable for caching (briefly) the error response. Set by the + * iterator when no_cache_store is enabled, and there is an error. */ + int error_response_cache; + /** if the iterator sees that the forward/stub has no_cache set. + * to signal to calling modules that their setting of no_cache for + * other reasons, has to take into account the fwd/stub no_cache. */ + int fwd_stub_no_cache; /** * Attributes of clients that share the qstate that may affect IP-based @@ -712,6 +730,12 @@ struct module_qstate { /** whether the reply should be dropped */ int is_drop; + /** the global quota that was reached, by one of the modules. + * So that continued counting can go on from that point. */ + int global_quota_reached; + /** the global quota that a query started with, it is a subquery, + * so that calling mesh states can see the increase. */ + int global_quota_started; }; /** @@ -721,7 +745,7 @@ struct module_func_block { /** text string name of module */ const char* name; - /** + /** * Set up the module for start. This is called only once at startup. * Privileged operations like opening device files may be done here. * The function ptr can be NULL, if it is not used. Index: usr.sbin/unbound/util/net_help.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/net_help.c,v diff -u -p -r1.35 net_help.c --- usr.sbin/unbound/util/net_help.c 26 Sep 2025 07:32:37 -0000 1.35 +++ usr.sbin/unbound/util/net_help.c 21 Sep 2026 16:28:10 -0000 @@ -242,7 +242,7 @@ int extstrtoaddr(const char* str, struct sockaddr_storage* addr, socklen_t* addrlen, int port) { - char* s; + const char* s; if((s=strchr(str, '@'))) { char buf[MAX_ADDR_STRLEN]; if(s-str >= MAX_ADDR_STRLEN) { @@ -268,7 +268,7 @@ ipstrtoaddr(const char* ip, int port, st p = (uint16_t) port; if(str_is_ip6(ip)) { char buf[MAX_ADDR_STRLEN]; - char* s; + const char* s; struct sockaddr_in6* sa = (struct sockaddr_in6*)addr; *addrlen = (socklen_t)sizeof(struct sockaddr_in6); memset(sa, 0, *addrlen); @@ -304,8 +304,9 @@ ipstrtoaddr(const char* ip, int port, st int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr, socklen_t* addrlen, int* net) { + const char* s; char buf[64]; - char* s; + char* b = NULL; *net = (str_is_ip6(str)?128:32); if((s=strchr(str, '/'))) { if(atoi(s+1) > *net) { @@ -323,15 +324,15 @@ int netblockstrtoaddr(const char* str, i return 0; } strlcpy(buf, str, sizeof(buf)); - s = strchr(buf, '/'); - if(s) *s = 0; - s = buf; + b = strchr(buf, '/'); + if(b) *b = 0; + b = buf; } - if(!ipstrtoaddr(s?s:str, port, addr, addrlen)) { + if(!ipstrtoaddr(b?b:str, port, addr, addrlen)) { log_err("cannot parse ip address: '%s'", str); return 0; } - if(s) { + if(b) { addr_mask(addr, *addrlen, *net); } return 1; @@ -783,7 +784,7 @@ sockaddr_cmp_scopeid(struct sockaddr_sto } int -addr_is_ip6(struct sockaddr_storage* addr, socklen_t len) +addr_is_ip6(const struct sockaddr_storage* addr, socklen_t len) { if(len == (socklen_t)sizeof(struct sockaddr_in6) && ((struct sockaddr_in6*)addr)->sin6_family == AF_INET6) @@ -1226,10 +1227,13 @@ setup_ticket_keys_cb(void* sslctx) #endif /* HAVE_SSL */ int -listen_sslctx_setup(void* ctxt) +listen_sslctx_setup(void* ctxt, const char* tls_protocols) { #ifdef HAVE_SSL + int allow12, allow13; SSL_CTX* ctx = (SSL_CTX*)ctxt; + cfg_tls_protocols_allowed(tls_protocols, &allow12, &allow13); + /* no SSLv2, SSLv3 because has defects */ #if SSL_OP_NO_SSLv2 != 0 if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) @@ -1259,12 +1263,24 @@ listen_sslctx_setup(void* ctxt) return 0; } #endif -#if defined(SSL_OP_NO_TLSv1_2) && defined(SSL_OP_NO_TLSv1_3) - /* if we have tls 1.3 disable 1.2 */ - if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_2) & SSL_OP_NO_TLSv1_2) - != SSL_OP_NO_TLSv1_2){ - log_crypto_err("could not set SSL_OP_NO_TLSv1_2"); - return 0; +#if defined(SSL_OP_NO_TLSv1_2) + if(!allow12) { + /* we are not allowed to use TLS1.2 */ + if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_2) & SSL_OP_NO_TLSv1_2) + != SSL_OP_NO_TLSv1_2){ + log_crypto_err("could not set SSL_OP_NO_TLSv1_2"); + return 0; + } + } +#endif +#if defined(SSL_OP_NO_TLSv1_3) + if(!allow13) { + /* we are not allowed to use TLS1.3 */ + if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_3) & SSL_OP_NO_TLSv1_3) + != SSL_OP_NO_TLSv1_3){ + log_crypto_err("could not set SSL_OP_NO_TLSv1_3"); + return 0; + } } #endif #if defined(SSL_OP_NO_RENEGOTIATION) @@ -1305,7 +1321,7 @@ listen_sslctx_setup(void* ctxt) SSL_CTX_set_security_level(ctx, 0); #endif #else - (void)ctxt; + (void)ctxt; (void)tls_protocols; #endif /* HAVE_SSL */ return 1; } @@ -1341,7 +1357,7 @@ listen_sslctx_setup_2(void* ctxt) void* listen_sslctx_create(const char* key, const char* pem, const char* verifypem, const char* tls_ciphers, const char* tls_ciphersuites, int set_ticket_keys_cb, - int is_dot, int is_doh) + int is_dot, int is_doh, const char* tls_protocols) { #ifdef HAVE_SSL SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method()); @@ -1359,7 +1375,7 @@ void* listen_sslctx_create(const char* k SSL_CTX_free(ctx); return NULL; } - if(!listen_sslctx_setup(ctx)) { + if(!listen_sslctx_setup(ctx, tls_protocols)) { SSL_CTX_free(ctx); return NULL; } @@ -1430,12 +1446,15 @@ void* listen_sslctx_create(const char* k SSL_CTX_set_alpn_select_cb(ctx, doh_alpn_select_cb, NULL); #endif } +#else /* HAVE_SSL_CTX_SET_ALPN_SELECT_CB */ + (void)is_dot; (void)is_doh; #endif /* HAVE_SSL_CTX_SET_ALPN_SELECT_CB */ return ctx; #else (void)key; (void)pem; (void)verifypem; (void)tls_ciphers; (void)tls_ciphersuites; (void)set_ticket_keys_cb; (void)is_dot; (void)is_doh; + (void)tls_protocols; return NULL; #endif /* HAVE_SSL */ } @@ -1688,6 +1707,10 @@ int check_auth_name_for_ssl(char* auth_n /** set the authname on an SSL structure, SSL* ssl */ int set_auth_name_on_ssl(void* ssl, char* auth_name, int use_sni) { +#ifdef HAVE_SSL_SET1_DNSNAME + struct sockaddr_storage tmpaddr; + socklen_t tmpaddrlen = (socklen_t)sizeof(tmpaddr); +#endif if(!auth_name) return 1; #ifdef HAVE_SSL if(use_sni) { @@ -1697,7 +1720,20 @@ int set_auth_name_on_ssl(void* ssl, char (void)ssl; (void)use_sni; #endif -#ifdef HAVE_SSL_SET1_HOST +#ifdef HAVE_SSL_SET1_DNSNAME + SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL); + if(ipstrtoaddr(auth_name, UNBOUND_DNS_PORT, &tmpaddr, &tmpaddrlen)) { + if(!SSL_set1_ipaddr(ssl, auth_name)) { + log_err("SSL_set1_ipaddr failed"); + return 0; + } + } else { + if(!SSL_set1_dnsname(ssl, auth_name)) { + log_err("SSL_set1_dnsname failed"); + return 0; + } + } +#elif defined(HAVE_SSL_SET1_HOST) SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL); /* setting the hostname makes openssl verify the * host name in the x509 certificate in the @@ -1797,7 +1833,7 @@ void ub_openssl_lock_delete(void) #endif /* OPENSSL_THREADS */ } -int listen_sslctx_setup_ticket_keys(struct config_strlist* tls_session_ticket_keys) { +int listen_sslctx_setup_ticket_keys(struct config_strlist* tls_session_ticket_keys, char* chroot) { #ifdef HAVE_SSL size_t s = 1; struct config_strlist* p; @@ -1815,14 +1851,18 @@ int listen_sslctx_setup_ticket_keys(stru size_t n; unsigned char *data; FILE *f; + char* fstr; data = (unsigned char *)malloc(80); if(!data) return 0; - f = fopen(p->str, "rb"); + fstr = p->str; + if(chroot && strncmp(fstr, chroot, strlen(chroot)) == 0) + fstr += strlen(chroot); + f = fopen(fstr, "rb"); if(!f) { - log_err("could not read tls-session-ticket-key %s: %s", p->str, strerror(errno)); + log_err("could not read tls-session-ticket-key %s: %s", fstr, strerror(errno)); free(data); return 0; } @@ -1830,11 +1870,11 @@ int listen_sslctx_setup_ticket_keys(stru fclose(f); if(n != 80) { - log_err("tls-session-ticket-key %s is %d bytes, must be 80 bytes", p->str, (int)n); + log_err("tls-session-ticket-key %s is %d bytes, must be 80 bytes", fstr, (int)n); free(data); return 0; } - verbose(VERB_OPS, "read tls-session-ticket-key: %s", p->str); + verbose(VERB_OPS, "read tls-session-ticket-key: %s", fstr); keys->key_name = data; keys->aes_key = data + 16; @@ -1845,7 +1885,7 @@ int listen_sslctx_setup_ticket_keys(stru keys->key_name = NULL; return 1; #else - (void)tls_session_ticket_keys; + (void)tls_session_ticket_keys; (void)chroot; return 0; #endif } Index: usr.sbin/unbound/util/net_help.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/net_help.h,v diff -u -p -r1.16 net_help.h --- usr.sbin/unbound/util/net_help.h 31 Aug 2025 21:41:10 -0000 1.16 +++ usr.sbin/unbound/util/net_help.h 21 Sep 2026 16:28:10 -0000 @@ -307,7 +307,7 @@ int sockaddr_cmp_scopeid(struct sockaddr * @param len: the length of addr. * @return: true if sockaddr is ip6. */ -int addr_is_ip6(struct sockaddr_storage* addr, socklen_t len); +int addr_is_ip6(const struct sockaddr_storage* addr, socklen_t len); /** * Make sure the sockaddr ends in zeroes. For tree insertion and subsequent @@ -478,9 +478,10 @@ void log_cert(unsigned level, const char /** * Set SSL_OP_NOxxx options on SSL context to disable bad crypto * @param ctxt: SSL_CTX* + * @param tls_protocols: configure string with allowed TLS protocols to use. * @return false on failure. */ -int listen_sslctx_setup(void* ctxt); +int listen_sslctx_setup(void* ctxt, const char* tls_protocols); /** * Further setup of listening SSL context, after keys loaded. @@ -499,12 +500,13 @@ void listen_sslctx_setup_2(void* ctxt); * to be set. * @param is_dot: if the TLS connection is for DoT to set the appropriate ALPN. * @param is_doh: if the TLS connection is for DoH to set the appropriate ALPN. + * @param tls_protocols: configure string with allowed TLS protocols to use. * return SSL_CTX* or NULL on failure (logged). */ void* listen_sslctx_create(const char* key, const char* pem, const char* verifypem, const char* tls_ciphers, const char* tls_ciphersuites, int set_ticket_keys_cb, - int is_dot, int is_doh); + int is_dot, int is_doh, const char* tls_protocols); /** * create SSL connect context @@ -563,9 +565,11 @@ void ub_openssl_lock_delete(void); /** * setup TLS session ticket * @param tls_session_ticket_keys: TLS ticket secret filenames + * @param chroot: if not NULL, the chroot that is in use. * @return false on failure (alloc failure). */ -int listen_sslctx_setup_ticket_keys(struct config_strlist* tls_session_ticket_keys); +int listen_sslctx_setup_ticket_keys( + struct config_strlist* tls_session_ticket_keys, char* chroot); /** Free memory used for TLS session ticket keys */ void listen_sslctx_delete_ticket_keys(void); Index: usr.sbin/unbound/util/netevent.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/netevent.c,v diff -u -p -r1.42 netevent.c --- usr.sbin/unbound/util/netevent.c 26 Sep 2025 07:32:37 -0000 1.42 +++ usr.sbin/unbound/util/netevent.c 21 Sep 2026 16:28:10 -0000 @@ -122,6 +122,10 @@ #define NUM_UDP_PER_SELECT 1 #endif +/** The number of TCP queries over a TCP connection, per read indication + * from select. */ +#define NUM_TCP_PER_SELECT 100 + /** timeout in millisec to wait for write to unblock, packets dropped after.*/ #define SEND_BLOCKED_WAIT_TIMEOUT 200 /** max number of times to wait for write to unblock, packets dropped after.*/ @@ -951,6 +955,10 @@ static int consume_pp2_header(struct sld { struct sockaddr_in* addr = (struct sockaddr_in*)&rep->client_addr; + if(ntohs(header->len) < PP2_HEADER_LEN_INET) { + verbose(VERB_OPS, "proxy_protocol: header too short for IPv4 address"); + return 0; + } addr->sin_family = AF_INET; addr->sin_addr.s_addr = header->addr.addr4.src_addr; addr->sin_port = header->addr.addr4.src_port; @@ -963,6 +971,10 @@ static int consume_pp2_header(struct sld { struct sockaddr_in6* addr = (struct sockaddr_in6*)&rep->client_addr; + if(ntohs(header->len) < PP2_HEADER_LEN_INET6) { + verbose(VERB_OPS, "proxy_protocol: header too short for IPv6 address"); + return 0; + } memset(addr, 0, sizeof(*addr)); addr->sin6_family = AF_INET6; memcpy(&addr->sin6_addr, @@ -1827,7 +1839,6 @@ doq_send_retry(struct comm_point* c, str char host[256], port[32]; struct ngtcp2_cid scid; uint8_t token[NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN]; - ngtcp2_tstamp ts; ngtcp2_ssize tokenlen, ret; if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, @@ -1841,12 +1852,10 @@ doq_send_retry(struct comm_point* c, str scid.datalen = c->doq_socket->sv_scidlen; doq_cid_randfill(&scid, scid.datalen, c->doq_socket->rnd); - ts = doq_get_timestamp_nanosec(); - tokenlen = ngtcp2_crypto_generate_retry_token(token, c->doq_socket->static_secret, c->doq_socket->static_secret_len, hd->version, (void*)&paddr->addr, paddr->addrlen, &scid, - &hd->dcid, ts); + &hd->dcid, doq_get_timestamp_nanosec()); if(tokenlen < 0) { log_err("ngtcp2_crypto_generate_retry_token failed: %s", ngtcp2_strerror(tokenlen)); @@ -1895,13 +1904,11 @@ doq_verify_retry_token(struct comm_point struct ngtcp2_cid* ocid, struct ngtcp2_pkt_hd* hd) { char host[256], port[32]; - ngtcp2_tstamp ts; if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, sizeof(host), port, sizeof(port))) { log_err("doq_verify_retry_token failed"); return 0; } - ts = doq_get_timestamp_nanosec(); verbose(VERB_ALGO, "doq: verifying retry token from %s %s", host, port); if(ngtcp2_crypto_verify_retry_token(ocid, @@ -1913,7 +1920,7 @@ doq_verify_retry_token(struct comm_point c->doq_socket->static_secret, c->doq_socket->static_secret_len, hd->version, (void*)&paddr->addr, paddr->addrlen, &hd->dcid, - 10*NGTCP2_SECONDS, ts) != 0) { + 10*NGTCP2_SECONDS, doq_get_timestamp_nanosec()) != 0) { verbose(VERB_ALGO, "doq: could not verify retry token " "from %s %s", host, port); return 0; @@ -1928,13 +1935,11 @@ doq_verify_token(struct comm_point* c, s struct ngtcp2_pkt_hd* hd) { char host[256], port[32]; - ngtcp2_tstamp ts; if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, sizeof(host), port, sizeof(port))) { log_err("doq_verify_token failed"); return 0; } - ts = doq_get_timestamp_nanosec(); verbose(VERB_ALGO, "doq: verifying token from %s %s", host, port); if(ngtcp2_crypto_verify_regular_token( #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN @@ -1944,7 +1949,7 @@ doq_verify_token(struct comm_point* c, s #endif c->doq_socket->static_secret, c->doq_socket->static_secret_len, (void*)&paddr->addr, paddr->addrlen, 3600*NGTCP2_SECONDS, - ts) != 0) { + doq_get_timestamp_nanosec()) != 0) { verbose(VERB_ALGO, "doq: could not verify token from %s %s", host, port); return 0; @@ -2171,6 +2176,7 @@ doq_pickup_timer(struct comm_point* c) { struct doq_timer* t; struct timeval tv; + ngtcp2_tstamp ts = 0; int have_time = 0; memset(&tv, 0, sizeof(tv)); @@ -2180,27 +2186,24 @@ doq_pickup_timer(struct comm_point* c) t->worker_doq_socket == c->doq_socket) { /* pick up this element */ t->worker_doq_socket = c->doq_socket; + memcpy(&tv, &t->time_real, sizeof(tv)); + ts = t->time_mono; have_time = 1; - memcpy(&tv, &t->time, sizeof(tv)); break; } } lock_rw_unlock(&c->doq_socket->table->lock); - + c->doq_socket->marked_time = ts; if(have_time) { struct timeval rel; timeval_subtract(&rel, &tv, c->doq_socket->now_tv); comm_timer_set(c->doq_socket->timer, &rel); - memcpy(&c->doq_socket->marked_time, &tv, - sizeof(c->doq_socket->marked_time)); verbose(VERB_ALGO, "doq pickup timer at %d.%6.6d in %d.%6.6d", (int)tv.tv_sec, (int)tv.tv_usec, (int)rel.tv_sec, (int)rel.tv_usec); } else { if(comm_timer_is_set(c->doq_socket->timer)) comm_timer_disable(c->doq_socket->timer); - memset(&c->doq_socket->marked_time, 0, - sizeof(c->doq_socket->marked_time)); verbose(VERB_ALGO, "doq timer disabled"); } } @@ -2213,13 +2216,14 @@ doq_done_setup_timer_and_write(struct co uint8_t cid[NGTCP2_MAX_CIDLEN]; rbnode_type* node; struct timeval new_tv; + ngtcp2_tstamp new_ts; int write_change = 0, timer_change = 0; /* No longer in callbacks, so the pointer to doq_socket is back * to NULL. */ conn->doq_socket = NULL; - if(doq_conn_check_timer(conn, &new_tv)) + if(doq_conn_check_timer(conn, &new_tv, &new_ts)) timer_change = 1; if( (conn->write_interest && !conn->on_write_list) || (!conn->write_interest && conn->on_write_list)) @@ -2265,7 +2269,7 @@ doq_done_setup_timer_and_write(struct co } if(timer_change) { doq_timer_set(c->doq_socket->table, &conn->timer, - c->doq_socket, &new_tv); + c->doq_socket, &new_tv, new_ts); } lock_rw_unlock(&c->doq_socket->table->lock); lock_basic_unlock(&conn->lock); @@ -2429,7 +2433,7 @@ doq_write_blocked_pkt(struct comm_point* return 1; } -/** doq find a timer that timeouted and return the conn, locked. */ +/** doq find a timer that timed out and return the conn, locked. */ static struct doq_conn* doq_timer_timeout_conn(struct doq_server_socket* doq_socket) { @@ -2442,7 +2446,7 @@ doq_timer_timeout_conn(struct doq_server conn = t->conn; /* If now < timer then no further timeouts in tree. */ - if(timeval_smaller(doq_socket->now_tv, &t->time)) { + if(timeval_smaller(doq_socket->now_tv, &t->time_real)) { lock_rw_unlock(&doq_socket->table->lock); return NULL; } @@ -2465,11 +2469,11 @@ doq_timer_erase_marker(struct doq_server { struct doq_timer* t; lock_rw_wrlock(&doq_socket->table->lock); - t = doq_timer_find_time(doq_socket->table, &doq_socket->marked_time); + t = doq_timer_find_time(doq_socket->table, doq_socket->marked_time); if(t && t->worker_doq_socket == doq_socket) t->worker_doq_socket = NULL; lock_rw_unlock(&doq_socket->table->lock); - memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time)); + doq_socket->marked_time = 0; } void @@ -2723,6 +2727,7 @@ doq_server_socket_create(struct doq_tabl { size_t doq_buffer_size = 4096; /* bytes buffer size, for one packet. */ struct doq_server_socket* doq_socket; + log_assert(table != NULL); doq_socket = calloc(1, sizeof(*doq_socket)); if(!doq_socket) { return NULL; @@ -2775,7 +2780,7 @@ doq_server_socket_create(struct doq_tabl free(doq_socket); return NULL; } - memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time)); + doq_socket->marked_time = 0; comm_base_timept(base, &doq_socket->now_tt, &doq_socket->now_tv); doq_socket->cfg = cfg; return doq_socket; @@ -2804,6 +2809,7 @@ doq_lookup_repinfo(struct doq_table* tab { struct doq_conn* conn; struct doq_conn_key key; + log_assert(table != NULL); doq_conn_key_from_repinfo(&key, repinfo); lock_rw_rdlock(&table->lock); conn = doq_conn_find(table, &key.paddr.addr, @@ -2938,6 +2944,8 @@ setup_tcp_handler(struct comm_point* c, c->tcp_is_reading = 1; c->tcp_byte_count = 0; c->tcp_keepalive = 0; + /* reset to configured value before applying load-based reduction */ + c->tcp_timeout_msec = c->tcp_parent->tcp_timeout_msec; /* if more than half the tcp handlers are in use, use a shorter * timeout for this TCP connection, we need to make space for * other connections to be able to get attention */ @@ -2973,6 +2981,62 @@ void comm_base_handle_slow_accept(int AT } } +/** out of resources in the accept path: pause all listening for + * NETEVENT_SLOW_ACCEPT_TIME and re-arm via comm_base_handle_slow_accept. + * + * If the routine fails, the socket is accepted and then closed, draining it + * from the waiting list of connections to be accepted. + * @param c: the comm point that is a listening socket. + * @param msec: if 0: uses the slow accept time. Otherwise, sets the time + * to wait. + */ +static void +comm_point_slow_accept(struct comm_point* c, int msec) +{ + struct comm_base* b = c->ev->base; + struct timeval tv; + struct ub_event* slowev; + if(!b->stop_accept) + return; + if(b->eb->slow_accept_enabled) + return; + /* Allocate the event */ + slowev = ub_event_new(b->eb->base, -1, UB_EV_TIMEOUT, + comm_base_handle_slow_accept, b); + if(!slowev) { + /* The slow accept was not enabled yet, to handle + * the allocation failure, instead drain the incoming + * connection. */ + int new_fd = accept(c->fd, NULL, NULL); + if(new_fd != -1) { + verbose(VERB_ALGO, "slow accept: event_new failed, " + "drop connection"); + sock_close(new_fd); + } + return; + } + ub_comm_base_now(b); + if(b->eb->last_slow_log+SLOW_LOG_TIME <= b->eb->secs) { + b->eb->last_slow_log = b->eb->secs; + verbose(VERB_OPS, "out of resources on accept, " + "slow down accept for %d msec", + NETEVENT_SLOW_ACCEPT_TIME); + } + b->eb->slow_accept_enabled = 1; + fptr_ok(fptr_whitelist_stop_accept(b->stop_accept)); + (*b->stop_accept)(b->cb_arg); + /* set timeout, no mallocs */ + if(msec == 0) + msec = NETEVENT_SLOW_ACCEPT_TIME; + tv.tv_sec = msec/1000; + tv.tv_usec = (msec%1000)*1000; + b->eb->slow_accept = slowev; + if(ub_event_add(b->eb->slow_accept, &tv) != 0) { + /* we do not want to log here, + * error: "event_add failed." */ + } +} + int comm_point_perform_accept(struct comm_point* c, struct sockaddr_storage* addr, socklen_t* addrlen) { @@ -3006,6 +3070,14 @@ int comm_point_perform_accept(struct com if(c->ev->base->stop_accept) { struct comm_base* b = c->ev->base; struct timeval tv; + struct ub_event* slowev = ub_event_new( + b->eb->base, -1, UB_EV_TIMEOUT, + comm_base_handle_slow_accept, b); + if(!slowev) { + verbose(VERB_ALGO, "slow accept: " + "event_new failed"); + return -1; + } verbose(VERB_ALGO, "out of file descriptors: " "slow accept"); ub_comm_base_now(b); @@ -3025,15 +3097,8 @@ int comm_point_perform_accept(struct com /* set timeout, no mallocs */ tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000; tv.tv_usec = (NETEVENT_SLOW_ACCEPT_TIME%1000)*1000; - b->eb->slow_accept = ub_event_new(b->eb->base, - -1, UB_EV_TIMEOUT, - comm_base_handle_slow_accept, b); - if(b->eb->slow_accept == NULL) { - /* we do not want to log here, because - * that would spam the logfiles. - * error: "event_base_set failed." */ - } - else if(ub_event_add(b->eb->slow_accept, &tv) + b->eb->slow_accept = slowev; + if(ub_event_add(b->eb->slow_accept, &tv) != 0) { /* we do not want to log here, * error: "event_add failed." */ @@ -3165,6 +3230,26 @@ static int http2_submit_settings(struct } #endif /* HAVE_NGHTTP2 */ +/** Clear http2 stream mesh states */ +static void http2_session_clear_meshstate(struct http2_session* h2_session) +{ +#ifdef HAVE_NGHTTP2 + /* Since the session gets closed, remove the mesh state references. */ + struct http2_stream* h2_stream; + for(h2_stream = h2_session->first_stream; h2_stream; + h2_stream = h2_stream->next) { + if(h2_stream->mesh_state) { + mesh_state_remove_reply(h2_stream->mesh, + h2_stream->mesh_state, h2_session->c, + h2_stream, NULL); + h2_stream->mesh_state = NULL; + } + } +#else + (void)h2_session; +#endif /* HAVE_NGHTTP2 */ +} + #ifdef HAVE_NGHTTP2 /** Delete http2 stream. After session delete or stream close callback */ static void http2_stream_delete(struct http2_session* h2_session, @@ -3172,7 +3257,7 @@ static void http2_stream_delete(struct h { if(h2_stream->mesh_state) { mesh_state_remove_reply(h2_stream->mesh, h2_stream->mesh_state, - h2_session->c); + h2_session->c, h2_stream, NULL); h2_stream->mesh_state = NULL; } http2_req_stream_clear(h2_stream); @@ -3214,6 +3299,13 @@ comm_point_tcp_accept_callback(int fd, s /* find free tcp handler. */ if(!c->tcp_free) { log_warn("accepted too many tcp, connections full"); + /* Wait for a short moment (say 50msec) so that other + * TCP connections can complete. Or timeout, at the busy + * timeout of about 200msec. That stops this routine from + * spinning endlessly, and gives time to complete the other + * requests. But it is not as slow as the 2000msec wait + * time for when the kernel is out of buffers. */ + comm_point_slow_accept(c, NETEVENT_SLOW_ACCEPT_QUEUE_TIME); return; } /* accept incoming connection. */ @@ -3235,6 +3327,7 @@ comm_point_tcp_accept_callback(int fd, s if(!c_hdl->h2_session || !http2_session_server_create(c_hdl->h2_session)) { log_warn("failed to create nghttp2"); + comm_point_slow_accept(c, 0); return; } if(!c_hdl->h2_session || @@ -3242,6 +3335,7 @@ comm_point_tcp_accept_callback(int fd, s log_warn("failed to submit http2 settings"); if(c_hdl->h2_session) http2_session_server_delete(c_hdl->h2_session); + comm_point_slow_accept(c, 0); return; } if(!c->ssl) { @@ -3258,11 +3352,12 @@ comm_point_tcp_accept_callback(int fd, s comm_point_tcp_handle_callback, c_hdl); } if(!c_hdl->ev->ev) { - log_warn("could not ub_event_new, dropped tcp"); + log_warn("could not ub_event_new, for new tcp"); #ifdef HAVE_NGHTTP2 if(c_hdl->type == comm_http && c_hdl->h2_session) http2_session_server_delete(c_hdl->h2_session); #endif + comm_point_slow_accept(c, 0); return; } log_assert(fd != -1); @@ -3276,6 +3371,10 @@ comm_point_tcp_accept_callback(int fd, s #endif return; } + /* move per-netblock TCP-connection-limit handle to the handler so that + * comm_point_close() on the handler decrements the count on close */ + c_hdl->tcl_addr = c->tcl_addr; + c->tcl_addr = NULL; /* Copy remote_address to client_address. * Simplest way/time for streams to do that. */ c_hdl->repinfo.client_addrlen = c_hdl->repinfo.remote_addrlen; @@ -4178,8 +4277,8 @@ recv_error: if(errno == EINTR || errno == EAGAIN) return 1; #ifdef ECONNRESET - if(errno == ECONNRESET && verbosity < 2) - return 0; /* silence reset by peer */ + if(errno == ECONNRESET && verbosity < 2) + return 0; /* silence reset by peer */ #endif if(recv_initial) { #ifdef ECONNREFUSED @@ -4546,6 +4645,10 @@ comm_point_tcp_handle_write(int fd, stru static int tcp_req_info_read_again(int fd, struct comm_point* c) { + /* One event-loop visit drains at most this many pipelined queries; + * the rest is re-queued, so that other file descriptors get + * serviced in between. */ + int budget = NUM_TCP_PER_SELECT; while(c->tcp_req_info->read_again) { int r; c->tcp_req_info->read_again = 0; @@ -4562,6 +4665,16 @@ tcp_req_info_read_again(int fd, struct c } return 0; } + if(--budget <= 0 && c->tcp_req_info->read_again) { + /* Defer the rest of the drain to the next loop turn. + * This uses a zero delay timer. For TLS the undrained + * remainder sits in OpenSSL's user-space buffer. */ + struct timeval tv; + memset(&tv, 0, sizeof(tv)); + verbose(VERB_ALGO, "Defer tcp_req_info read again"); + comm_timer_set(c->tcp_req_info->read_again_timer, &tv); + return 1; + } } return 1; } @@ -4575,6 +4688,7 @@ tcp_more_read_again(int fd, struct comm_ /* this continues until the read routines get EAGAIN or so, * and thus does not call the callback, and the bool is 0 */ int* moreread = c->tcp_more_read_again; + int budget = NUM_TCP_PER_SELECT; while(moreread && *moreread) { *moreread = 0; if(!comm_point_tcp_handle_read(fd, c, 0)) { @@ -4587,6 +4701,30 @@ tcp_more_read_again(int fd, struct comm_ } return; } + if(--budget <= 0 && *moreread) { + /* Defer the rest of the drain to the next loop turn. + * This uses a zero delay timer. For TLS the undrained + * remainder sits in OpenSSL's user-space buffer. */ + struct timeval tv; + memset(&tv, 0, sizeof(tv)); + if(!c->tcp_more_read_again_timer) { + c->tcp_more_read_again_timer = comm_timer_create(c->ev->base, tcp_more_read_again_cb, c); + if(!c->tcp_more_read_again_timer) { + log_err("out of memory for tcp more read again timer"); + reclaim_tcp_handler(c); + if(!c->tcp_do_close) { + fptr_ok(fptr_whitelist_comm_point( + c->callback)); + (void)(*c->callback)(c, c->cb_arg, + NETEVENT_CLOSED, NULL); + } + return; + } + } + verbose(VERB_ALGO, "Defer more read again"); + comm_timer_set(c->tcp_more_read_again_timer, &tv); + return; + } } } @@ -4615,6 +4753,23 @@ tcp_more_write_again(int fd, struct comm } void +tcp_read_again_cb(void* arg) +{ + struct tcp_req_info* req = (struct tcp_req_info*)arg; + verbose(VERB_ALGO, "tcp_read_again_cb"); + if(!tcp_req_info_read_again(req->cp->fd, req->cp)) + return; +} + +void +tcp_more_read_again_cb(void* arg) +{ + struct comm_point* c = (struct comm_point*)arg; + verbose(VERB_ALGO, "tcp_more_read_again_cb"); + tcp_more_read_again(c->fd, c); +} + +void comm_point_tcp_handle_callback(int fd, short event, void* arg) { struct comm_point* c = (struct comm_point*)arg; @@ -4868,8 +5023,17 @@ http_process_initial_header(struct comm_ return 0; } } else if(strncasecmp(line, "Content-Length: ", 16) == 0) { - if(!c->http_is_chunked) - c->tcp_byte_count = (size_t)atoi(line+16); + if(!c->http_is_chunked) { + char* end = NULL; + long long cl; + errno = 0; + cl = strtoll(line+16, &end, 10); + if(end == line+16 || errno != 0 || cl < 0) { + verbose(VERB_ALGO, "http invalid Content-Length: " ARG_LL "d", cl); + return 0; /* reject */ + } + c->tcp_byte_count = (size_t)cl; + } } else if(strncasecmp(line, "Transfer-Encoding: chunked", 19+7) == 0) { c->tcp_byte_count = 0; c->http_is_chunked = 1; @@ -4925,9 +5089,15 @@ http_process_chunk_header(struct comm_po if(c->http_in_chunk_headers == 1) { /* read chunked start line */ char* end = NULL; - c->tcp_byte_count = (size_t)strtol(line, &end, 16); - if(end == line) + long chunk_sz; + errno = 0; + chunk_sz = strtol(line, &end, 16); + if(end == line || errno != 0 || chunk_sz < 0) { + verbose(VERB_ALGO, "http invalid chunk size: %ld", + chunk_sz); return 0; + } + c->tcp_byte_count = (size_t)chunk_sz; c->http_in_chunk_headers = 0; /* remove header text from front of buffer */ http_moveover_buffer(c->buffer); @@ -5005,6 +5175,14 @@ http_chunked_segment(struct comm_point* c->http_stored = 0; sldns_buffer_skip(c->buffer, (ssize_t)c->tcp_byte_count); sldns_buffer_clear(c->http_temp); + if(sldns_buffer_remaining(c->buffer) > + sldns_buffer_capacity(c->http_temp)) { + verbose(VERB_OPS, "http chunked: surplus %d exceeds " + "temp buffer %d", (int)sldns_buffer_remaining( + c->buffer), (int)sldns_buffer_capacity( + c->http_temp)); + return 0; + } sldns_buffer_write(c->http_temp, sldns_buffer_current(c->buffer), sldns_buffer_remaining(c->buffer)); @@ -5335,6 +5513,13 @@ comm_point_http_handle_read(int fd, stru if(c->http_in_headers || c->http_in_chunk_headers) { /* if header is done, process the header */ if(!http_header_done(c->buffer)) { + if(sldns_buffer_limit(c->buffer) == + sldns_buffer_capacity(c->buffer)) { + verbose(VERB_OPS, "http header line " + "exceeds %d bytes, transfer " + "failed", (int)sldns_buffer_capacity(c->buffer)); + return 0; + } /* copy remaining data to front of buffer * and set rest for writing into it */ http_moveover_buffer(c->buffer); @@ -5883,6 +6068,7 @@ comm_point_create_doq(struct comm_base * struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); short evbits; + log_assert(table != NULL); if(!c) return NULL; c->ev = (struct internal_event*)calloc(1, @@ -6025,7 +6211,7 @@ comm_point_create_tcp_handler(struct com c->pp2_enabled = parent->pp2_enabled; c->pp2_header_state = pp2_header_none; if(spoolbuf) { - c->tcp_req_info = tcp_req_info_create(spoolbuf); + c->tcp_req_info = tcp_req_info_create(base, spoolbuf); if(!c->tcp_req_info) { log_err("could not create tcp commpoint"); sldns_buffer_free(c->buffer); @@ -6574,7 +6760,10 @@ comm_point_close(struct comm_point* c) c->event_added = 0; } } - tcl_close_connection(c->tcl_addr); + if(c->tcl_addr) { + tcl_close_connection(c->tcl_addr); + c->tcl_addr = NULL; + } if(c->tcp_req_info) tcp_req_info_clear(c->tcp_req_info); if(c->h2_session) @@ -6584,6 +6773,9 @@ comm_point_close(struct comm_point* c) *c->tcp_more_read_again = 0; if(c->tcp_more_write_again && *c->tcp_more_write_again) *c->tcp_more_write_again = 0; + if(c->tcp_more_read_again_timer && + comm_timer_is_set(c->tcp_more_read_again_timer)) + comm_timer_disable(c->tcp_more_read_again_timer); /* close fd after removing from event lists, or epoll.. is messed up */ if(c->fd != -1 && !c->do_not_close) { @@ -6623,6 +6815,7 @@ comm_point_delete(struct comm_point* c) free(c->tcp_handlers); } free(c->timeout); + comm_timer_delete(c->tcp_more_read_again_timer); if(c->type == comm_tcp || c->type == comm_local || c->type == comm_http) { sldns_buffer_free(c->buffer); #ifdef USE_DNSCRYPT @@ -6667,7 +6860,9 @@ comm_point_send_reply(struct comm_reply log_assert(repinfo && repinfo->c); #ifdef USE_DNSCRYPT buffer = repinfo->c->dnscrypt_buffer; - if(!dnsc_handle_uncurved_request(repinfo)) { + if(!dnsc_handle_uncurved_request(repinfo, + repinfo->c->tcp_req_info? + repinfo->c->tcp_req_info->spool_buffer:repinfo->c->buffer)) { return; } #else @@ -6728,7 +6923,6 @@ comm_point_send_reply(struct comm_reply tcp_req_info_send_reply(repinfo->c->tcp_req_info); } else if(repinfo->c->use_h2) { if(!http2_submit_dns_response(repinfo->c->h2_session)) { - comm_point_drop_reply(repinfo); return; } repinfo->c->h2_stream = NULL; @@ -6762,6 +6956,7 @@ comm_point_drop_reply(struct comm_reply* if(repinfo->c->type == comm_http) { if(repinfo->c->h2_session) { repinfo->c->h2_session->is_drop = 1; + http2_session_clear_meshstate(repinfo->c->h2_session); if(!repinfo->c->h2_session->postpone_drop) reclaim_http_handler(repinfo->c); return; Index: usr.sbin/unbound/util/netevent.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/netevent.h,v diff -u -p -r1.26 netevent.h --- usr.sbin/unbound/util/netevent.h 26 Sep 2025 07:32:37 -0000 1.26 +++ usr.sbin/unbound/util/netevent.h 21 Sep 2026 16:28:10 -0000 @@ -111,6 +111,8 @@ typedef int comm_point_callback_type(str /** timeout to slow accept calls when not possible, in msec. */ #define NETEVENT_SLOW_ACCEPT_TIME 2000 +/** timeout to slow accept calls when tcp queue is full, in msec. */ +#define NETEVENT_SLOW_ACCEPT_QUEUE_TIME 50 /** timeout to slow down log print, so it does not spam the logs, in sec */ #define SLOW_LOG_TIME 10 /** for doq, the maximum dcid length, in ngtcp2 it is 20. */ @@ -187,6 +189,8 @@ struct comm_reply { /** port number for doq */ int doq_srcport; #endif /* HAVE_NGTCP2 */ + /** The doq stream to register mesh states to. */ + struct doq_stream* doq_stream; }; /** @@ -380,6 +384,9 @@ struct comm_point { * Or leave NULL if it is not used at all. */ int* tcp_more_write_again; + /** resume timer for tcp_more_read_again */ + struct comm_timer* tcp_more_read_again_timer; + /** if set, read/write completes: read/write state of tcp is toggled. buffer reset/bytecount reset. @@ -1093,8 +1100,10 @@ struct doq_server_socket { struct doq_pkt_addr* blocked_paddr; /** timer for this worker on this comm_point to wait on. */ struct comm_timer* timer; +#ifdef HAVE_NGTCP2 /** the timer that is marked by the doq_socket as waited on. */ - struct timeval marked_time; + ngtcp2_tstamp marked_time; +#endif /** the current time for use by time functions, time_t. */ time_t* now_tt; /** the current time for use by time functions, timeval. */ @@ -1126,6 +1135,12 @@ void doq_send_pkt(struct comm_point* c, /** doq timer callback function. */ void doq_timer_cb(void* arg); + +/** tcp read again callback function. For tcp req info listen. */ +void tcp_read_again_cb(void* arg); + +/** tcp more read again callback function. For outside network. */ +void tcp_more_read_again_cb(void* arg); /** * This routine is published for checks and tests, and is only used internally. Index: usr.sbin/unbound/util/proxy_protocol.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/proxy_protocol.c,v diff -u -p -r1.1.1.3 proxy_protocol.c --- usr.sbin/unbound/util/proxy_protocol.c 4 Sep 2024 09:35:36 -0000 1.1.1.3 +++ usr.sbin/unbound/util/proxy_protocol.c 21 Sep 2026 16:28:10 -0000 @@ -185,14 +185,23 @@ pp2_read_header(uint8_t* buf, size_t buf (header->ver_cmd & 0xF) != PP2_CMD_PROXY) { return PP_PARSE_UNKNOWN_CMD; } - /* Check for supported family and protocol */ - if(header->fam_prot != PP2_UNSPEC_UNSPEC && - header->fam_prot != PP2_INET_STREAM && - header->fam_prot != PP2_INET_DGRAM && - header->fam_prot != PP2_INET6_STREAM && - header->fam_prot != PP2_INET6_DGRAM && - header->fam_prot != PP2_UNIX_STREAM && - header->fam_prot != PP2_UNIX_DGRAM) { + /* Check for supported family and protocol, and that len covers + * the per-family address block (proxy-protocol.txt s2.2). */ + switch(header->fam_prot) { + case PP2_UNSPEC_UNSPEC: + break; + case PP2_INET_STREAM: + case PP2_INET_DGRAM: + if(ntohs(header->len) < PP2_HEADER_LEN_INET) + return PP_PARSE_SIZE; + break; + case PP2_INET6_STREAM: + case PP2_INET6_DGRAM: + if(ntohs(header->len) < PP2_HEADER_LEN_INET6) + return PP_PARSE_SIZE; + break; + default: + /* PP2_UNIX_STREAM, PP2_UNIX_DGRAM, others. */ return PP_PARSE_UNKNOWN_FAM_PROT; } /* We have a correct header */ Index: usr.sbin/unbound/util/proxy_protocol.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/proxy_protocol.h,v diff -u -p -r1.1.1.2 proxy_protocol.h --- usr.sbin/unbound/util/proxy_protocol.h 12 Apr 2024 15:44:28 -0000 1.1.1.2 +++ usr.sbin/unbound/util/proxy_protocol.h 21 Sep 2026 16:28:10 -0000 @@ -54,6 +54,15 @@ /** PROXYv2 version (protocol value) */ #define PP2_VERSION 0x2 +/** PROXYv2 minimum header.len value for TCP/UDP over IPv4 */ +#define PP2_HEADER_LEN_INET 12 + +/** PROXYv2 minimum header.len value for TCP/UDP over IPv6 */ +#define PP2_HEADER_LEN_INET6 36 + +/** PROXYv2 minimum header.len value for TCP/UDP over AF_UNIX */ +#define PP2_HEADER_LEN_UNIX 216 + /** * PROXYv2 command (protocol value). */ Index: usr.sbin/unbound/util/timehist.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/timehist.h,v diff -u -p -r1.2 timehist.h --- usr.sbin/unbound/util/timehist.h 12 Aug 2017 11:22:46 -0000 1.2 +++ usr.sbin/unbound/util/timehist.h 21 Sep 2026 16:28:10 -0000 @@ -42,6 +42,10 @@ #ifndef UTIL_TIMEHIST_H #define UTIL_TIMEHIST_H +#ifdef __QNX__ +/* For struct timeval */ +#include +#endif /* __QNX__ */ /** Number of buckets in a histogram */ #define NUM_BUCKETS_HIST 40 Index: usr.sbin/unbound/util/tube.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/tube.c,v diff -u -p -r1.10 tube.c --- usr.sbin/unbound/util/tube.c 31 Aug 2025 21:41:10 -0000 1.10 +++ usr.sbin/unbound/util/tube.c 21 Sep 2026 16:28:11 -0000 @@ -145,6 +145,20 @@ void tube_remove_bg_write(struct tube* t } } +/** Drain the pipe of bytes. */ +static void +fd_drain(int fd, uint32_t len) +{ + uint8_t discard[256]; + uint32_t remaining = len; + while(remaining > 0) { + ssize_t n = read(fd, discard, + remaining < sizeof(discard) ? remaining : sizeof(discard)); + if(n <= 0) break; + remaining -= (uint32_t)n; + } +} + int tube_handle_listen(struct comm_point* c, void* arg, int error, struct comm_reply* ATTR_UNUSED(reply_info)) @@ -184,6 +198,9 @@ tube_handle_listen(struct comm_point* c, tube->cmd_msg = (uint8_t*)calloc(1, tube->cmd_len); if(!tube->cmd_msg) { log_err("malloc failure"); + /* Drain the remaining bytes, since they belong to this + * message. The next message starts after it. */ + fd_drain(c->fd, tube->cmd_len); tube->cmd_read = 0; return 0; } @@ -374,6 +391,9 @@ int tube_read_msg(struct tube* tube, uin *buf = (uint8_t*)malloc(*len); if(!*buf) { log_err("tube read out of memory"); + /* Drain the remaining bytes, since they belong to this + * message. The next message starts after it. */ + fd_drain(fd, *len); (void)fd_set_nonblock(fd); return 0; } Index: usr.sbin/unbound/util/data/dname.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/data/dname.c,v diff -u -p -r1.9 dname.c --- usr.sbin/unbound/util/data/dname.c 26 Sep 2025 07:32:37 -0000 1.9 +++ usr.sbin/unbound/util/data/dname.c 21 Sep 2026 16:28:11 -0000 @@ -192,34 +192,34 @@ pkt_dname_len(sldns_buffer* pkt) while(1) { /* read next label */ if(sldns_buffer_remaining(pkt) < 1) - return 0; + goto fail; labellen = sldns_buffer_read_u8(pkt); if(LABEL_IS_PTR(labellen)) { /* compression ptr */ uint16_t ptr; if(sldns_buffer_remaining(pkt) < 1) - return 0; + goto fail; ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt)); if(ptrcount++ > MAX_COMPRESS_PTRS) - return 0; /* loop! */ + goto fail; /* loop! */ if(sldns_buffer_limit(pkt) <= ptr) - return 0; /* out of bounds! */ + goto fail; /* out of bounds! */ if(!endpos) endpos = sldns_buffer_position(pkt); sldns_buffer_set_position(pkt, ptr); } else { /* label contents */ if(labellen > 0x3f) - return 0; /* label too long */ + goto fail; /* label too long */ len += 1 + labellen; if(len > LDNS_MAX_DOMAINLEN) - return 0; + goto fail; if(labellen == 0) { /* end of dname */ break; } if(sldns_buffer_remaining(pkt) < labellen) - return 0; + goto fail; sldns_buffer_skip(pkt, (ssize_t)labellen); } } @@ -227,6 +227,13 @@ pkt_dname_len(sldns_buffer* pkt) sldns_buffer_set_position(pkt, endpos); return len; +fail: + /* Restore the position on failure too: callers (rdata_copy) compute + * the consumed field length from the buffer position and must not + * see a partial walk of a name that failed to parse. */ + if(endpos) + sldns_buffer_set_position(pkt, endpos); + return 0; } int Index: usr.sbin/unbound/util/data/msgencode.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/data/msgencode.c,v diff -u -p -r1.17 msgencode.c --- usr.sbin/unbound/util/data/msgencode.c 26 Sep 2025 07:32:37 -0000 1.17 +++ usr.sbin/unbound/util/data/msgencode.c 21 Sep 2026 16:28:11 -0000 @@ -352,7 +352,6 @@ compress_any_dname(uint8_t* dname, sldns (p = compress_tree_lookup(tree, dname, labs, &insertpt))) { if(!write_compressed_dname(pkt, dname, labs, p)) return RETVAL_TRUNC; - (*compress_count)++; } else { if(!dname_buffer_write(pkt, dname)) return RETVAL_TRUNC; @@ -360,6 +359,7 @@ compress_any_dname(uint8_t* dname, sldns if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && !compress_tree_store(dname, labs, pos, region, p, insertpt)) return RETVAL_OUTMEM; + (*compress_count)++; return RETVAL_OK; } @@ -496,10 +496,18 @@ packed_rrset_encode(struct ub_packed_rrs return r; sldns_buffer_write(pkt, &key->rk.type, 2); sldns_buffer_write(pkt, &key->rk.rrset_class, 2); - if(data->rr_ttl[j] < adjust) + if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) { + sldns_buffer_write_u32(pkt, 0); + } else if(adjust == 0) { + sldns_buffer_write_u32(pkt, data->rr_ttl[j]); + } else if(TTL_IS_EXPIRED(data->rr_ttl[j], adjust)) { sldns_buffer_write_u32(pkt, - SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0); - else sldns_buffer_write_u32(pkt, data->rr_ttl[j]-adjust); + EXPIRED_REPLY_TTL_CALC( + data->rr_ttl[j], data->ttl_add)); + } else { + sldns_buffer_write_u32(pkt, + data->rr_ttl[j] - adjust); + } if(c) { if((r=compress_rdata(pkt, data->rr_data[j], data->rr_len[j], region, tree, c, @@ -533,10 +541,18 @@ packed_rrset_encode(struct ub_packed_rrs } sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG); sldns_buffer_write(pkt, &key->rk.rrset_class, 2); - if(data->rr_ttl[i] < adjust) + if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) { + sldns_buffer_write_u32(pkt, 0); + } else if(adjust == 0) { + sldns_buffer_write_u32(pkt, data->rr_ttl[i]); + } else if(TTL_IS_EXPIRED(data->rr_ttl[i], adjust)) { sldns_buffer_write_u32(pkt, - SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0); - else sldns_buffer_write_u32(pkt, data->rr_ttl[i]-adjust); + EXPIRED_REPLY_TTL_CALC( + data->rr_ttl[i], data->ttl_add)); + } else { + sldns_buffer_write_u32(pkt, + data->rr_ttl[i] - adjust); + } /* rrsig rdata cannot be compressed, perform 100+ byte * memcopy. */ sldns_buffer_write(pkt, data->rr_data[i], @@ -618,7 +634,7 @@ insert_query(struct query_info* qinfo, s size_t qname_len = qinfo->local_alias ? qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; if(sldns_buffer_remaining(buffer) < - qinfo->qname_len+sizeof(uint16_t)*2) + qname_len+sizeof(uint16_t)*2) return RETVAL_TRUNC; /* buffer too small */ /* the query is the first name inserted into the tree */ if(!compress_tree_store(qname, dname_count_labels(qname), @@ -804,7 +820,7 @@ reply_info_encode(struct query_info* qin return 1; } -uint16_t +size_t calc_edns_field_size(struct edns_data* edns) { size_t rdatalen = 0; @@ -840,7 +856,7 @@ calc_edns_option_size(struct edns_data* } uint16_t -calc_ede_option_size(struct edns_data* edns, uint16_t* txt_size) +calc_ede_option_size(struct edns_data* edns, size_t* txt_size) { size_t rdatalen = 0; struct edns_option* opt; @@ -942,6 +958,10 @@ attach_edns_record_max_msg_sz(sldns_buff padding_option = opt; continue; } + if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz) + break; /* no space for it */ + if(!sldns_buffer_available(pkt, 4 + opt->opt_len)) + break; sldns_buffer_write_u16(pkt, opt->opt_code); sldns_buffer_write_u16(pkt, opt->opt_len); if(opt->opt_len != 0) @@ -952,12 +972,18 @@ attach_edns_record_max_msg_sz(sldns_buff padding_option = opt; continue; } + if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz) + break; /* no space for it */ + if(!sldns_buffer_available(pkt, 4 + opt->opt_len)) + break; sldns_buffer_write_u16(pkt, opt->opt_code); sldns_buffer_write_u16(pkt, opt->opt_len); if(opt->opt_len != 0) sldns_buffer_write(pkt, opt->opt_data, opt->opt_len); } - if (padding_option && edns->padding_block_size ) { + if (padding_option && edns->padding_block_size && + sldns_buffer_position(pkt)+4 <= max_msg_sz && + sldns_buffer_available(pkt, 4) /* if there is space for it */) { size_t pad_pos = sldns_buffer_position(pkt); size_t msg_sz = ((pad_pos + 3) / edns->padding_block_size + 1) * edns->padding_block_size; @@ -993,15 +1019,15 @@ attach_edns_record(sldns_buffer* pkt, st attach_edns_record_max_msg_sz(pkt, edns, edns->udp_size); } -int -reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, +int +reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow, - int cached, struct regional* region, uint16_t udpsize, + int cached, struct regional* region, uint16_t udpsize, struct edns_data* edns, int dnssec, int secure) { uint16_t flags; unsigned int attach_edns = 0; - uint16_t edns_field_size, ede_size, ede_txt_size; + size_t edns_field_size, ede_size, ede_txt_size; if(!cached || rep->authoritative) { /* original flags, copy RD and CD bits from query. */ @@ -1028,12 +1054,12 @@ reply_info_answer_encode(struct query_in * calculate sizes once here */ edns_field_size = calc_edns_field_size(edns); ede_size = calc_ede_option_size(edns, &ede_txt_size); - if(sldns_buffer_capacity(pkt) < udpsize) + if(sldns_buffer_capacity(pkt) < (size_t)udpsize) udpsize = sldns_buffer_capacity(pkt); if(!edns || !edns->edns_present) { attach_edns = 0; /* EDEs are optional, try to fit anything else before them */ - } else if(udpsize < LDNS_HEADER_SIZE + edns_field_size - ede_size) { + } else if((size_t)udpsize < (size_t)LDNS_HEADER_SIZE + edns_field_size - ede_size) { /* packet too small to contain edns, omit it. */ attach_edns = 0; } else { @@ -1047,13 +1073,13 @@ reply_info_answer_encode(struct query_in return 0; } if(attach_edns) { - if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size) + if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size) attach_edns_record_max_msg_sz(pkt, edns, udpsize); - else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) { + else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) { ede_trim_text(&edns->opt_list_inplace_cb_out); ede_trim_text(&edns->opt_list_out); attach_edns_record_max_msg_sz(pkt, edns, udpsize); - } else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) { + } else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) { edns_opt_list_remove(&edns->opt_list_inplace_cb_out, LDNS_EDNS_EDE); edns_opt_list_remove(&edns->opt_list_out, LDNS_EDNS_EDE); attach_edns_record_max_msg_sz(pkt, edns, udpsize); @@ -1103,9 +1129,11 @@ extended_error_encode(sldns_buffer* buf, sldns_buffer_write(buf, &flags, sizeof(uint16_t)); sldns_buffer_write(buf, &flags, sizeof(uint16_t)); if(qinfo) { - const uint8_t* qname = qinfo->local_alias ? + const uint8_t* qname = + (qinfo->local_alias && qinfo->local_alias->rrset) ? qinfo->local_alias->rrset->rk.dname : qinfo->qname; - size_t qname_len = qinfo->local_alias ? + size_t qname_len = + (qinfo->local_alias && qinfo->local_alias->rrset) ? qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; if(sldns_buffer_current(buf) == qname) @@ -1115,22 +1143,30 @@ extended_error_encode(sldns_buffer* buf, sldns_buffer_write_u16(buf, qinfo->qclass); } sldns_buffer_flip(buf); - if(edns) { + if(edns && edns->edns_present) { + size_t edns_field_size, ede_size, ede_txt_size; struct edns_data es = *edns; es.edns_version = EDNS_ADVERTISED_VERSION; es.udp_size = EDNS_ADVERTISED_SIZE; es.ext_rcode = (uint8_t)(rcode >> 4); es.bits &= EDNS_DO; - if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > - edns->udp_size) { + /* EDEs are optional. If space is a concern try in order: + * - removing any EXTRA-TEXT fields from explicit EDEs, or + * - removing all EDEs, + * to see if EDNS can fit. */ + edns_field_size = calc_edns_field_size(&es); + ede_size = calc_ede_option_size(&es, &ede_txt_size); + if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size) + attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); + else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_txt_size) { + ede_trim_text(&es.opt_list_inplace_cb_out); + ede_trim_text(&es.opt_list_out); + attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); + } else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_size) { edns_opt_list_remove(&es.opt_list_inplace_cb_out, LDNS_EDNS_EDE); edns_opt_list_remove(&es.opt_list_out, LDNS_EDNS_EDE); - if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > - edns->udp_size) { - return; - } + attach_edns_record_max_msg_sz(buf, &es, edns->udp_size); } - attach_edns_record(buf, &es); } } Index: usr.sbin/unbound/util/data/msgencode.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/data/msgencode.h,v diff -u -p -r1.1.1.6 msgencode.h --- usr.sbin/unbound/util/data/msgencode.h 26 Sep 2025 07:30:48 -0000 1.1.1.6 +++ usr.sbin/unbound/util/data/msgencode.h 21 Sep 2026 16:28:11 -0000 @@ -66,9 +66,9 @@ struct edns_data; * @param secure: if 1, the AD bit is set in the reply. * @return: 0 on error (server failure). */ -int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, +int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, uint16_t id, uint16_t qflags, struct sldns_buffer* dest, time_t timenow, - int cached, struct regional* region, uint16_t udpsize, + int cached, struct regional* region, uint16_t udpsize, struct edns_data* edns, int dnssec, int secure); /** @@ -106,7 +106,7 @@ void qinfo_query_encode(struct sldns_buf * @param edns: edns data or NULL. * @return octets to reserve for EDNS. */ -uint16_t calc_edns_field_size(struct edns_data* edns); +size_t calc_edns_field_size(struct edns_data* edns); /** * Calculate the size of a specific EDNS option in packet. @@ -127,7 +127,7 @@ uint16_t calc_edns_option_size(struct ed * extra text. * @return octets the option will take up. */ -uint16_t calc_ede_option_size(struct edns_data* edns, uint16_t* txt_size); +uint16_t calc_ede_option_size(struct edns_data* edns, size_t* txt_size); /** * Attach EDNS record to buffer. Buffer has complete packet. There must Index: usr.sbin/unbound/util/data/msgparse.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/data/msgparse.c,v diff -u -p -r1.13 msgparse.c --- usr.sbin/unbound/util/data/msgparse.c 4 Sep 2024 09:36:41 -0000 1.13 +++ usr.sbin/unbound/util/data/msgparse.c 21 Sep 2026 16:28:11 -0000 @@ -53,6 +53,8 @@ #include "sldns/parseutil.h" #include "sldns/wire2str.h" +#define MAX_PARSED_EDNS_OPTIONS 100 + /** smart comparison of (compressed, valid) dnames from packet */ static int smart_compare(sldns_buffer* pkt, uint8_t* dnow, @@ -685,6 +687,9 @@ calc_size(sldns_buffer* pkt, uint16_t ty } rdf++; } + /* rdata ended before all _dname_count names were seen */ + if(count != 0) + return 0; /* the rdata is too short. */ } /* remaining rdata */ rr->size += pkt_len; @@ -950,6 +955,7 @@ parse_edns_options_from_query(uint8_t* r struct comm_reply* repinfo, uint32_t now, struct regional* region, struct cookie_secrets* cookie_secrets) { + int i = 0, nsid_seen = 0, cookie_seen = 0, padding_seen = 0; /* To respond with a Keepalive option, the client connection must have * received one message with a TCP Keepalive EDNS option, and that * option must have 0 length data. Subsequent messages sent on that @@ -969,7 +975,7 @@ parse_edns_options_from_query(uint8_t* r /* while still more options, and have code+len to read */ /* ignores partial content (i.e. rdata len 3) */ - while(rdata_len >= 4) { + while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) { uint16_t opt_code = sldns_read_uint16(rdata_ptr); uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); uint8_t server_cookie[40]; @@ -984,8 +990,9 @@ parse_edns_options_from_query(uint8_t* r /* handle parse time edns options here */ switch(opt_code) { case LDNS_EDNS_NSID: - if (!cfg || !cfg->nsid) + if (!cfg || !cfg->nsid || nsid_seen) break; + nsid_seen = 1; if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_NSID, cfg->nsid_len, cfg->nsid, region)) { @@ -1026,9 +1033,13 @@ parse_edns_options_from_query(uint8_t* r break; case LDNS_EDNS_PADDING: - if(!cfg || !cfg->pad_responses || - !c || c->type != comm_tcp ||!c->ssl) + if(!cfg || !cfg->pad_responses || !c || padding_seen) + break; + if(!((c->type == comm_tcp && c->ssl) || + (c->type == comm_http && c->ssl) || + c->type == comm_doq)) break; + padding_seen = 1; if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_PADDING, 0, NULL, region)) { @@ -1039,8 +1050,9 @@ parse_edns_options_from_query(uint8_t* r break; case LDNS_EDNS_COOKIE: - if(!cfg || !cfg->do_answer_cookie || !repinfo) + if(!cfg || !cfg->do_answer_cookie || !repinfo || cookie_seen) break; + cookie_seen = 1; if(opt_len != 8 && (opt_len < 16 || opt_len > 40)) { verbose(VERB_ALGO, "worker request: " "badly formatted cookie"); @@ -1062,13 +1074,13 @@ parse_edns_options_from_query(uint8_t* r * purposes. It will be overwritten if (re)creation * is needed. */ - if(repinfo->remote_addr.ss_family == AF_INET) { + if(repinfo->client_addr.ss_family == AF_INET) { memcpy(server_cookie + 16, - &((struct sockaddr_in*)&repinfo->remote_addr)->sin_addr, 4); + &((struct sockaddr_in*)&repinfo->client_addr)->sin_addr, 4); } else { cookie_is_v4 = 0; memcpy(server_cookie + 16, - &((struct sockaddr_in6*)&repinfo->remote_addr)->sin6_addr, 16); + &((struct sockaddr_in6*)&repinfo->client_addr)->sin6_addr, 16); } if(cfg->cookie_secret_file && @@ -1080,10 +1092,10 @@ parse_edns_options_from_query(uint8_t* r cookie_is_v4, server_cookie, now); } else { /* Use the cookie option value to validate. */ - cookie_val_status = edns_cookie_server_validate( - rdata_ptr, opt_len, cfg->cookie_secret, - cfg->cookie_secret_len, cookie_is_v4, - server_cookie, now); + cookie_val_status = edns_cookie_server_validate( + rdata_ptr, opt_len, cfg->cookie_secret, + cfg->cookie_secret_len, cookie_is_v4, + server_cookie, now); } if(cookie_val_status == COOKIE_STATUS_VALID_RENEW) edns->cookie_valid = 1; @@ -1124,8 +1136,8 @@ parse_edns_options_from_query(uint8_t* r cookie_is_v4, now); lock_basic_unlock(&cookie_secrets->lock); } else { - edns_cookie_server_write(server_cookie, - cfg->cookie_secret, cookie_is_v4, now); + edns_cookie_server_write(server_cookie, + cfg->cookie_secret, cookie_is_v4, now); } if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_COOKIE, 24, server_cookie, @@ -1146,6 +1158,7 @@ parse_edns_options_from_query(uint8_t* r } rdata_ptr += opt_len; rdata_len -= opt_len; + i++; } return LDNS_RCODE_NOERROR; } @@ -1160,6 +1173,7 @@ parse_extract_edns_from_response_msg(str struct rrset_parse* found_prev = 0; size_t rdata_len; uint8_t* rdata_ptr; + int i = 0; /* since the class encodes the UDP size, we cannot use hash table to * find the EDNS OPT record. Scan the packet. */ while(rrset) { @@ -1219,7 +1233,7 @@ parse_extract_edns_from_response_msg(str /* while still more options, and have code+len to read */ /* ignores partial content (i.e. rdata len 3) */ - while(rdata_len >= 4) { + while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) { uint16_t opt_code = sldns_read_uint16(rdata_ptr); uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); rdata_ptr += 4; @@ -1234,6 +1248,7 @@ parse_extract_edns_from_response_msg(str } rdata_ptr += opt_len; rdata_len -= opt_len; + i++; } /* ignore rrsigs */ return LDNS_RCODE_NOERROR; @@ -1361,3 +1376,15 @@ msgparse_rrset_remove_rr(const char* str * the rr->next works fine to continue. */ return rrset->rr_count == 0; } + +#ifdef UNBOUND_DEBUG +time_t debug_expired_reply_ttl_calc(time_t ttl, time_t ttl_add) { + /* Check that we are serving expired when this is called */ + /* ttl (absolute) should be later than ttl_add */ + /* It is also called during the grace period for type DNAME, + * and then the 'SERVE_EXPIRED' boolean may not be on. */ + log_assert(ttl_add <= ttl); + return (SERVE_EXPIRED_REPLY_TTL < (ttl) - (ttl_add) ? + SERVE_EXPIRED_REPLY_TTL : (ttl) - (ttl_add)); +} +#endif Index: usr.sbin/unbound/util/data/msgparse.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/data/msgparse.h,v diff -u -p -r1.14 msgparse.h --- usr.sbin/unbound/util/data/msgparse.h 26 Sep 2025 07:32:37 -0000 1.14 +++ usr.sbin/unbound/util/data/msgparse.h 21 Sep 2026 16:28:11 -0000 @@ -98,6 +98,31 @@ extern time_t SERVE_EXPIRED_REPLY_TTL; /** If we serve the original TTL or decrementing TTLs */ extern int SERVE_ORIGINAL_TTL; +/** calculate the prefetch TTL as 90% of original. Calculation + * without numerical overflow (uin32_t) */ +#define PREFETCH_TTL_CALC(ttl) ((ttl) - (ttl)/10) + +/* caclulate the TTL used for expired answers to somewhat make sense wrt the + * original TTL; don't reply with higher TTL than the original */ +#ifdef UNBOUND_DEBUG +time_t debug_expired_reply_ttl_calc(time_t ttl, time_t ttl_add); +#define EXPIRED_REPLY_TTL_CALC(ttl, ttl_add) \ + debug_expired_reply_ttl_calc(ttl, ttl_add) +#else +#define EXPIRED_REPLY_TTL_CALC(ttl, ttl_add) \ + (SERVE_EXPIRED_REPLY_TTL < (ttl) - (ttl_add) ? \ + SERVE_EXPIRED_REPLY_TTL : (ttl) - (ttl_add)) +#endif + +/** Update the reply_info TTL from an RRSet's TTL, essentially keeping the TTL + * sane with all the (progressively added) rrsets to the message */ +#define UPDATE_TTL_FROM_RRSET(ttl, rrsetttl) \ + ((ttl) = ((ttl) < (rrsetttl)) ? (ttl) : (rrsetttl)) + +/** Check if TTL is expired. 0 TTL is considered expired. + * Used mainly to identify parts of the code that do this comparison. */ +#define TTL_IS_EXPIRED(ttl, now) ((ttl) <= (now)) + /** * Data stored in scratch pad memory during parsing. * Stores the data that will enter into the msgreply and packet result. Index: usr.sbin/unbound/util/data/msgreply.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/data/msgreply.c,v diff -u -p -r1.28 msgreply.c --- usr.sbin/unbound/util/data/msgreply.c 26 Sep 2025 07:32:37 -0000 1.28 +++ usr.sbin/unbound/util/data/msgreply.c 21 Sep 2026 16:28:11 -0000 @@ -178,9 +178,9 @@ reply_info_alloc_rrset_keys(struct reply int reply_info_can_answer_expired(struct reply_info* rep, time_t timenow) { - log_assert(rep->ttl < timenow); + log_assert(TTL_IS_EXPIRED(rep->ttl, timenow)); /* Really expired */ - if(SERVE_EXPIRED_TTL && rep->serve_expired_ttl < timenow) return 0; + if(SERVE_EXPIRED_TTL && TTL_IS_EXPIRED(rep->serve_expired_ttl, timenow)) return 0; /* Ignore expired failure answers */ if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR && FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN && @@ -188,12 +188,13 @@ reply_info_can_answer_expired(struct rep return 1; } -int reply_info_could_use_expired(struct reply_info* rep, time_t timenow) +int +reply_info_could_use_expired(struct reply_info* rep, time_t timenow) { - log_assert(rep->ttl < timenow); + log_assert(TTL_IS_EXPIRED(rep->ttl, timenow)); /* Really expired */ - if(SERVE_EXPIRED_TTL && rep->serve_expired_ttl < timenow && - !SERVE_EXPIRED_TTL_RESET) return 0; + if(SERVE_EXPIRED_TTL && TTL_IS_EXPIRED(rep->serve_expired_ttl, timenow) + && !SERVE_EXPIRED_TTL_RESET) return 0; /* Ignore expired failure answers */ if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR && FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN && @@ -229,7 +230,7 @@ make_new_reply_info(const struct reply_i } /** find the minimumttl in the rdata of SOA record */ -static time_t +static uint32_t soa_find_minttl(struct rr_parse* rr) { uint16_t rlen = sldns_read_uint16(rr->ttl_data+4); @@ -237,7 +238,7 @@ soa_find_minttl(struct rr_parse* rr) return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */ /* minimum TTL is the last 32bit value in the rdata of the record */ /* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/ - return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4); + return sldns_read_uint32(rr->ttl_data+6+rlen-4); } /** do the rdata copy */ @@ -247,37 +248,41 @@ rdata_copy(sldns_buffer* pkt, struct pac sldns_pkt_section section) { uint16_t pkt_len; + size_t tolen; + uint32_t ttl; const sldns_rr_descriptor* desc; - *rr_ttl = sldns_read_uint32(rr->ttl_data); + ttl = sldns_read_uint32(rr->ttl_data); /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */ - if((*rr_ttl & 0x80000000U)) - *rr_ttl = 0; + /* RFC 8767 Section 4. values with high-order bit as positive, not 0. ++ * As such, it will be capped by MAX_TTL below. */ if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { /* negative response. see if TTL of SOA record larger than the * minimum-ttl in the rdata of the SOA record */ - if(*rr_ttl > soa_find_minttl(rr)) *rr_ttl = soa_find_minttl(rr); + if(ttl > soa_find_minttl(rr)) ttl = soa_find_minttl(rr); if(!SERVE_ORIGINAL_TTL) { /* If MIN_NEG_TTL is configured skip setting MIN_TTL */ - if(MIN_NEG_TTL <= 0 && *rr_ttl < MIN_TTL) { - *rr_ttl = MIN_TTL; + if(MIN_NEG_TTL <= 0 && ttl < (uint32_t)MIN_TTL) { + ttl = (uint32_t)MIN_TTL; } - if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL; + if(ttl > (uint32_t)MAX_TTL) ttl = (uint32_t)MAX_TTL; } /* MAX_NEG_TTL overrides the min and max ttl of everything * else; it is for a more specific record */ - if(*rr_ttl > MAX_NEG_TTL) *rr_ttl = MAX_NEG_TTL; + if(ttl > (uint32_t)MAX_NEG_TTL) ttl = (uint32_t)MAX_NEG_TTL; /* MIN_NEG_TTL overrides the min and max ttl of everything * else if configured; it is for a more specific record */ - if(MIN_NEG_TTL > 0 && *rr_ttl < MIN_NEG_TTL) { - *rr_ttl = MIN_NEG_TTL; + if(MIN_NEG_TTL > 0 && ttl < (uint32_t)MIN_NEG_TTL) { + ttl = (uint32_t)MIN_NEG_TTL; } } else if(!SERVE_ORIGINAL_TTL) { - if(*rr_ttl < MIN_TTL) *rr_ttl = MIN_TTL; - if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL; + if(ttl < (uint32_t)MIN_TTL) ttl = (uint32_t)MIN_TTL; + if(ttl > (uint32_t)MAX_TTL) ttl = (uint32_t)MAX_TTL; } - if(*rr_ttl < data->ttl) - data->ttl = *rr_ttl; + if((time_t)ttl < data->ttl) + data->ttl = (time_t)ttl; + /* We have concluded the TTL checks */ + *rr_ttl = (time_t)ttl; if(rr->outside_packet) { /* uncompressed already, only needs copy */ @@ -289,9 +294,13 @@ rdata_copy(sldns_buffer* pkt, struct pac (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t))); /* insert decompressed size into rdata len stored in memory */ /* -2 because rdatalen bytes are not included. */ + tolen = rr->size; + if(tolen < 2) + return 0; pkt_len = htons(rr->size - 2); memmove(to, &pkt_len, sizeof(uint16_t)); to += 2; + tolen -= 2; /* read packet rdata len */ pkt_len = sldns_buffer_read_u16(pkt); if(sldns_buffer_remaining(pkt) < pkt_len) @@ -300,16 +309,29 @@ rdata_copy(sldns_buffer* pkt, struct pac if(pkt_len > 0 && desc && desc->_dname_count > 0) { int count = (int)desc->_dname_count; int rdf = 0; - size_t len; - size_t oldpos; + size_t len, dlen; + size_t oldpos, newpos; /* decompress dnames. */ while(pkt_len > 0 && count) { switch(desc->_wireformat[rdf]) { case LDNS_RDF_TYPE_DNAME: oldpos = sldns_buffer_position(pkt); - dname_pkt_copy(pkt, to, + dlen = pkt_dname_len(pkt); + if(dlen == 0) + return 0; /* malformed */ + if(dlen > tolen) + return 0; /* alloc mismatch */ + newpos = sldns_buffer_position(pkt); + if(oldpos > newpos) + return 0; /* should have moved forward*/ + sldns_buffer_set_position(pkt, oldpos); + dname_pkt_copy(pkt, to, sldns_buffer_current(pkt)); - to += pkt_dname_len(pkt); + sldns_buffer_set_position(pkt, newpos); + to += dlen; + tolen -= dlen; + if(sldns_buffer_position(pkt)-oldpos > pkt_len) + return 0; /* malformed: walks diverged */ pkt_len -= sldns_buffer_position(pkt)-oldpos; count--; len = 0; @@ -322,9 +344,12 @@ rdata_copy(sldns_buffer* pkt, struct pac break; } if(len) { + if(len > tolen) + return 0; /* alloc mismatch */ log_assert(len <= pkt_len); memmove(to, sldns_buffer_current(pkt), len); to += len; + tolen -= len; sldns_buffer_skip(pkt, (ssize_t)len); pkt_len -= len; } @@ -332,8 +357,11 @@ rdata_copy(sldns_buffer* pkt, struct pac } } /* copy remaining rdata */ - if(pkt_len > 0) + if(pkt_len > 0) { + if(pkt_len > tolen) + return 0; /* alloc mismatch */ memmove(to, sldns_buffer_current(pkt), pkt_len); + } return 1; } @@ -479,7 +507,11 @@ parse_copy_decompress_rrset(sldns_buffer } pk->entry.data = (void*)data; pk->entry.key = (void*)pk; - pk->entry.hash = pset->hash; + pk->rk.flags |= (data->ttl == 0) ? PACKED_RRSET_UPSTREAM_0TTL : 0; + if( (pk->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) != 0) + pk->entry.hash = rrset_key_hash(&pk->rk); + else + pk->entry.hash = pset->hash; data->trust = get_rrset_trust(msg, pset); return 1; } @@ -617,6 +649,29 @@ reply_info_set_ttls(struct reply_info* r } } +void +reply_info_absolute_ttls(struct reply_info* rep, time_t ttl, time_t ttl_add) +{ + size_t i, j; + rep->ttl = ttl; + rep->prefetch_ttl = PREFETCH_TTL_CALC(ttl); + rep->serve_expired_ttl = ttl + SERVE_EXPIRED_TTL; + /* Don't set rep->serve_expired_norec_ttl; this should only be set + * on cached records when encountering an error */ + log_assert(rep->serve_expired_norec_ttl == 0); + for(i=0; irrset_count; i++) { + struct packed_rrset_data* data = (struct packed_rrset_data*) + rep->ref[i].key->entry.data; + if(i>0 && rep->ref[i].key == rep->ref[i-1].key) + continue; + data->ttl = ttl; + for(j=0; jcount + data->rrsig_count; j++) { + data->rr_ttl[j] = ttl; + } + data->ttl_add = ttl_add; + } +} + void reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc) { @@ -1084,6 +1139,17 @@ reply_all_rrsets_secure(struct reply_inf return 1; } +int reply_an_ns_rrsets_secure(struct reply_info* rep) +{ + size_t i; + for(i=0; ian_numrrsets+rep->ns_numrrsets; i++) { + if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) + ->security != sec_status_secure ) + return 0; + } + return 1; +} + struct reply_info* parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region, struct query_info* qi) @@ -1475,8 +1541,12 @@ struct edns_option* edns_opt_list_find(s int local_alias_shallow_copy_qname(struct local_rrset* local_alias, uint8_t** qname, size_t* qname_len) { - struct ub_packed_rrset_key* rrset = local_alias->rrset; - struct packed_rrset_data* d = rrset->entry.data; + struct ub_packed_rrset_key* rrset; + struct packed_rrset_data* d; + rrset = local_alias->rrset; + if(!rrset) return 0; + d = rrset->entry.data; + if(!d) return 0; /* Sanity check: our current implementation only supports * a single CNAME RRset as a local alias. */ Index: usr.sbin/unbound/util/data/msgreply.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/data/msgreply.h,v diff -u -p -r1.18 msgreply.h --- usr.sbin/unbound/util/data/msgreply.h 26 Sep 2025 07:32:37 -0000 1.18 +++ usr.sbin/unbound/util/data/msgreply.h 21 Sep 2026 16:28:11 -0000 @@ -44,6 +44,10 @@ #include "util/storage/lruhash.h" #include "util/data/packed_rrset.h" #include "sldns/rrdef.h" +#ifdef __QNX__ +/* For struct timeval */ +#include +#endif /* __QNX__ */ struct sldns_buffer; struct comm_reply; struct alloc_cache; @@ -60,10 +64,6 @@ struct local_rrset; struct dns_msg; enum comm_point_type; -/** calculate the prefetch TTL as 90% of original. Calculation - * without numerical overflow (uin32_t) */ -#define PREFETCH_TTL_CALC(ttl) ((ttl) - (ttl)/10) - /** * Structure to store query information that makes answers to queries * different. @@ -340,6 +340,15 @@ void reply_info_sortref(struct reply_inf */ void reply_info_set_ttls(struct reply_info* rep, time_t timenow); +/** + * Set TTLs inside the replyinfo to the given absolute values. + * @param rep: reply info. rrsets must be filled in. + * Also refs must be filled in. + * @param ttl: absolute ttl value to be set. + * @param ttl_add: the current time to be used verbatim for ttl_add in the rrsets. + */ +void reply_info_absolute_ttls(struct reply_info* rep, time_t ttl, time_t ttl_add); + /** * Delete reply_info and packed_rrsets (while they are not yet added to the * hashtables.). Returns rrsets to the alloc cache. @@ -485,6 +494,9 @@ int reply_check_cname_chain(struct query */ int reply_all_rrsets_secure(struct reply_info* rep); +/** Check status of answer and authority section RRs. */ +int reply_an_ns_rrsets_secure(struct reply_info* rep); + /** * Find answer rrset in reply, the one matching qinfo. Follows CNAMEs, so the * result may have a different owner name. @@ -572,7 +584,7 @@ void log_query_info(enum verbosity_value struct query_info* qinf); /** - * Append edns option to edns option list + * Append edns option to edns option list. * @param list: the edns option list to append the edns option to. * @param code: the edns option's code. * @param len: the edns option's length. @@ -584,17 +596,20 @@ int edns_opt_list_append(struct edns_opt uint8_t* data, struct regional* region); /** - * Append edns EDE option to edns options list + * Append edns EDE option to edns options list. + * We need ATTR_NONSTRING because we are trimming the trailing \0 of static + * string (TXT) when assigning to ede.text; it silences compiler nonstring + * warnings. * @param LIST: the edns option list to append the edns option to. * @param REGION: region to allocate the new edns option. * @param CODE: the EDE code. - * @param TXT: Additional text for the option + * @param TXT: Additional text for the option. */ #define EDNS_OPT_LIST_APPEND_EDE(LIST, REGION, CODE, TXT) \ do { \ struct { \ uint16_t code; \ - char text[sizeof(TXT) - 1]; \ + char ATTR_NONSTRING(text[sizeof(TXT) - 1]) ; \ } ede = { htons(CODE), TXT }; \ verbose(VERB_ALGO, "attached EDE code: %d with" \ " message: '%s'", CODE, TXT); \ Index: usr.sbin/unbound/util/data/packed_rrset.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/data/packed_rrset.c,v diff -u -p -r1.7 packed_rrset.c --- usr.sbin/unbound/util/data/packed_rrset.c 13 Apr 2024 12:24:57 -0000 1.7 +++ usr.sbin/unbound/util/data/packed_rrset.c 21 Sep 2026 16:28:11 -0000 @@ -198,6 +198,7 @@ get_cname_target(struct ub_packed_rrset_ { struct packed_rrset_data* d; size_t len; + if(!rrset) return; if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME) return; @@ -296,7 +297,7 @@ int packed_rr_to_string(struct ub_packed wlen = (size_t)sldns_wire2str_rr_buf(rr, rlen, dest, dest_len); if(wlen >= dest_len) { /* the output string was truncated */ - log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest); + verbose(VERB_ALGO, "rrbuf failure %d %s", (int)d->rr_len[i], dest); dest[0] = 0; return 0; } @@ -336,10 +337,9 @@ packed_rrset_copy_region(struct ub_packe struct ub_packed_rrset_key* ck = regional_alloc(region, sizeof(struct ub_packed_rrset_key)); struct packed_rrset_data* d; - struct packed_rrset_data* data = (struct packed_rrset_data*) - key->entry.data; + struct packed_rrset_data* data = key->entry.data; size_t dsize, i; - time_t adjust = 0; + time_t now_control; if(!ck) return NULL; ck->id = key->id; @@ -352,22 +352,34 @@ packed_rrset_copy_region(struct ub_packe if(!ck->rk.dname) return NULL; dsize = packed_rrset_sizeof(data); - d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize); + d = regional_alloc_init(region, data, dsize); if(!d) return NULL; ck->entry.data = d; packed_rrset_ptr_fixup(d); - /* make TTLs relative - once per rrset */ - adjust = SERVE_ORIGINAL_TTL ? data->ttl_add : now; - for(i=0; icount + d->rrsig_count; i++) { - if(d->rr_ttl[i] < adjust) - d->rr_ttl[i] = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0; - else d->rr_ttl[i] -= adjust; + /* make TTLs relative - once per rr */ + if(now > 0) { + /* NS RRSets may be here with ttl_add higher than now because + * of the novel ghost attack mitigation i.e., using the + * qstarttime for NS RRSets. In that case make sure that the + * returned TTL is not higher than the original one. */ + /* For types other than type NS, auth zone and rpz code + * can have ttl_add values. Also time could conceivably move + * in reverse, due to operator action, and it is prudent + * to not assert on that here. + * So there is no assertion d->ttl_add <= now || type==NS */ + now_control = SERVE_ORIGINAL_TTL ? data->ttl_add + : (d->ttl_add > now ? d->ttl_add : now ); + for(i=0; icount + d->rrsig_count; i++) { + if(TTL_IS_EXPIRED(d->rr_ttl[i], now_control)) { + d->rr_ttl[i] = EXPIRED_REPLY_TTL_CALC(d->rr_ttl[i], data->ttl_add); + } else d->rr_ttl[i] -= now_control; + } + if(TTL_IS_EXPIRED(d->ttl, now_control)) { + d->ttl = EXPIRED_REPLY_TTL_CALC(d->ttl, data->ttl_add); + } else d->ttl -= now_control; + d->ttl_add = 0; /* TTLs have been made relative */ } - if(d->ttl < adjust) - d->ttl = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0; - else d->ttl -= adjust; - d->ttl_add = 0; /* TTLs have been made relative */ return ck; } Index: usr.sbin/unbound/util/data/packed_rrset.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/data/packed_rrset.h,v diff -u -p -r1.8 packed_rrset.h --- usr.sbin/unbound/util/data/packed_rrset.h 21 Feb 2025 13:20:40 -0000 1.8 +++ usr.sbin/unbound/util/data/packed_rrset.h 21 Sep 2026 16:28:11 -0000 @@ -70,6 +70,10 @@ typedef uint64_t rrset_id_type; #define PACKED_RRSET_RPZ 0x8 /** this rrset is A/AAAA and is an unverified glue record */ #define PACKED_RRSET_UNVERIFIED_GLUE 0x10 +/** this rrset has a 0TTL from upstream */ +#define PACKED_RRSET_UPSTREAM_0TTL 0x20 +/** this rrset has 0TTL from upstream and also has had grace TTL applied */ +#define PACKED_RRSET_0TTL_GRACE 0x40 /** number of rrs and rrsets for integer overflow protection. More than * this is not really possible (64K packet has much less RRs and RRsets) in @@ -99,6 +103,7 @@ struct packed_rrset_key { * o PACKED_RRSET_FIXEDTTL (not supposed to be cached) * o PACKED_RRSET_RPZ * o PACKED_RRSET_UNVERIFIED_GLUE + * o PACKED_RRSET_UPSTREAM_0TTL (not supposed to be cached) */ uint32_t flags; /** the rrset type in network format */ Index: usr.sbin/unbound/util/shm_side/shm_main.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/shm_side/shm_main.c,v diff -u -p -r1.8 shm_main.c --- usr.sbin/unbound/util/shm_side/shm_main.c 31 Aug 2025 21:41:10 -0000 1.8 +++ usr.sbin/unbound/util/shm_side/shm_main.c 21 Sep 2026 16:28:11 -0000 @@ -185,6 +185,16 @@ int shm_main_init(struct daemon* daemon) shm_stat = daemon->shm_info->ptr_ctl; shm_stat->num_threads = daemon->num; + lock_basic_init(&daemon->shm_info->lock); + daemon->shm_info->volley_in_progress = 0; + daemon->shm_info->thread_volley = (int*)calloc( + daemon->num, sizeof(int)); + if(!daemon->shm_info->thread_volley) { + log_err("shm fail: malloc failure"); + free(daemon->shm_info); + daemon->shm_info = NULL; + return 0; + } #else (void)daemon; #endif /* HAVE_SHMGET */ @@ -214,6 +224,9 @@ void shm_main_shutdown(struct daemon* da if (daemon->shm_info->ptr_arr) shmdt(daemon->shm_info->ptr_arr); + lock_basic_destroy(&daemon->shm_info->lock); + free(daemon->shm_info->thread_volley); + free(daemon->shm_info); daemon->shm_info = NULL; #else @@ -221,13 +234,125 @@ void shm_main_shutdown(struct daemon* da #endif /* HAVE_SHMGET */ } +#ifdef HAVE_SHMGET +/** Copy general info into the stat structure. */ +static void +shm_general_info(struct worker* worker) +{ + struct ub_shm_stat_info *shm_stat; + /* Point to data into SHM */ +#ifndef S_SPLINT_S + shm_stat = worker->daemon->shm_info->ptr_ctl; + shm_stat->time.now_sec = (long long)worker->env.now_tv->tv_sec; + shm_stat->time.now_usec = (long long)worker->env.now_tv->tv_usec; +#endif + + stat_timeval_subtract(&shm_stat->time.up_sec, &shm_stat->time.up_usec, worker->env.now_tv, &worker->daemon->time_boot); + stat_timeval_subtract(&shm_stat->time.elapsed_sec, &shm_stat->time.elapsed_usec, worker->env.now_tv, &worker->daemon->time_last_stat); + + shm_stat->mem.msg = (long long)slabhash_get_mem(worker->env.msg_cache); + shm_stat->mem.rrset = (long long)slabhash_get_mem(&worker->env.rrset_cache->table); + shm_stat->mem.dnscrypt_shared_secret = 0; +#ifdef USE_DNSCRYPT + if(worker->daemon->dnscenv) { + shm_stat->mem.dnscrypt_shared_secret = (long long)slabhash_get_mem( + worker->daemon->dnscenv->shared_secrets_cache); + shm_stat->mem.dnscrypt_nonce = (long long)slabhash_get_mem( + worker->daemon->dnscenv->nonces_cache); + } +#endif + shm_stat->mem.val = (long long)mod_get_mem(&worker->env, "validator"); + shm_stat->mem.iter = (long long)mod_get_mem(&worker->env, "iterator"); + shm_stat->mem.respip = (long long)mod_get_mem(&worker->env, "respip"); + + /* subnet mem value is available in shm, also when not enabled, + * to make the struct easier to memmap by other applications, + * independent of the configuration of unbound */ + shm_stat->mem.subnet = 0; +#ifdef CLIENT_SUBNET + shm_stat->mem.subnet = (long long)mod_get_mem(&worker->env, + "subnetcache"); +#endif + /* ipsecmod mem value is available in shm, also when not enabled, + * to make the struct easier to memmap by other applications, + * independent of the configuration of unbound */ + shm_stat->mem.ipsecmod = 0; +#ifdef USE_IPSECMOD + shm_stat->mem.ipsecmod = (long long)mod_get_mem(&worker->env, + "ipsecmod"); +#endif +#ifdef WITH_DYNLIBMODULE + shm_stat->mem.dynlib = (long long)mod_get_mem(&worker->env, "dynlib"); +#endif +} +#endif /* HAVE_SHMGET */ + +#ifdef HAVE_SHMGET +/** See if the thread is first. Caller has lock. */ +static int +shm_thread_is_first(struct shm_main_info* shm_info, int thread_num, + struct daemon* daemon) +{ + /* The usual method, all threads executed last time, and there + * is no statistics callback in progress. */ + if(!shm_info->volley_in_progress) + return 1; + /* See if we are already active, if so, the timer seems to have fired + * twice for this thread which means other thread(s) have not gone + * through their stats callbacks yet. + * (There should have been a last thread to reset + * shm_info->volley_in_progress and shm_info->thread_volley) + * The other thread(s) are not yet active during this statistics round, + * so this thread must be the first of this new round disregarding the + * other busy thread(s). + * When the other thread(s) have time again, they will process their + * stats callback and hopefully properly end a stats round where all + * threads got to calculate their statistics. */ + if(shm_info->thread_volley[thread_num] != 0) { + /* The new round starts and zeroes the total. The previous + * partial total is discarded. That means while other thread(s) + * are performing a long task, eg. loading a large zone + * perhaps, the total is not updated and stays the same in the + * shared memory area. Once that other thread(s) perform the + * statistic callback again, the total is updated again. + * + * The threads busy with long tasks have 0 in the array. + * The array is inited for a new round. */ + memset(shm_info->thread_volley, 0, + ((size_t)daemon->num) * sizeof(int)); + return 1; + } + return 0; +} +#endif /* HAVE_SHMGET */ + +#ifdef HAVE_SHMGET +/** See if the thread is last. Caller has lock. */ +static int +shm_thread_is_last(struct daemon* daemon) +{ + /* Being last means that all threads have been active for this stats + * round and this thread is the last one; also active. All the + * thread_volley values should be true then. */ + int i; + for(i=0; inum; i++) { + if(!daemon->shm_info->thread_volley[i]) + return 0; + } + return 1; +} +#endif /* HAVE_SHMGET */ + void shm_main_run(struct worker *worker) { #ifdef HAVE_SHMGET - struct ub_shm_stat_info *shm_stat; struct ub_stats_info *stat_total; struct ub_stats_info *stat_info; int offset; + double total_mesh_time_median; + struct shm_main_info* shm_info = worker->daemon->shm_info; + if(!shm_info) + return; #ifndef S_SPLINT_S verbose(VERB_DETAIL, "SHM run - worker [%d] - daemon [%p] - timenow(%u) - timeboot(%u)", @@ -235,73 +360,43 @@ void shm_main_run(struct worker *worker) #endif offset = worker->thread_num + 1; - stat_total = worker->daemon->shm_info->ptr_arr; - stat_info = worker->daemon->shm_info->ptr_arr + offset; + stat_total = shm_info->ptr_arr; + stat_info = shm_info->ptr_arr + offset; /* Copy data to the current position */ server_stats_compile(worker, stat_info, 0); - /* First thread, zero fill total, and copy general info */ - if (worker->thread_num == 0) { - - /* Copy data to the current position */ - memset(stat_total, 0, sizeof(struct ub_stats_info)); - - /* Point to data into SHM */ -#ifndef S_SPLINT_S - shm_stat = worker->daemon->shm_info->ptr_ctl; - shm_stat->time.now_sec = (long long)worker->env.now_tv->tv_sec; - shm_stat->time.now_usec = (long long)worker->env.now_tv->tv_usec; -#endif - - stat_timeval_subtract(&shm_stat->time.up_sec, &shm_stat->time.up_usec, worker->env.now_tv, &worker->daemon->time_boot); - stat_timeval_subtract(&shm_stat->time.elapsed_sec, &shm_stat->time.elapsed_usec, worker->env.now_tv, &worker->daemon->time_last_stat); - - shm_stat->mem.msg = (long long)slabhash_get_mem(worker->env.msg_cache); - shm_stat->mem.rrset = (long long)slabhash_get_mem(&worker->env.rrset_cache->table); - shm_stat->mem.dnscrypt_shared_secret = 0; -#ifdef USE_DNSCRYPT - if(worker->daemon->dnscenv) { - shm_stat->mem.dnscrypt_shared_secret = (long long)slabhash_get_mem( - worker->daemon->dnscenv->shared_secrets_cache); - shm_stat->mem.dnscrypt_nonce = (long long)slabhash_get_mem( - worker->daemon->dnscenv->nonces_cache); - } -#endif - shm_stat->mem.val = (long long)mod_get_mem(&worker->env, - "validator"); - shm_stat->mem.iter = (long long)mod_get_mem(&worker->env, - "iterator"); - shm_stat->mem.respip = (long long)mod_get_mem(&worker->env, - "respip"); - - /* subnet mem value is available in shm, also when not enabled, - * to make the struct easier to memmap by other applications, - * independent of the configuration of unbound */ - shm_stat->mem.subnet = 0; -#ifdef CLIENT_SUBNET - shm_stat->mem.subnet = (long long)mod_get_mem(&worker->env, - "subnetcache"); -#endif - /* ipsecmod mem value is available in shm, also when not enabled, - * to make the struct easier to memmap by other applications, - * independent of the configuration of unbound */ - shm_stat->mem.ipsecmod = 0; -#ifdef USE_IPSECMOD - shm_stat->mem.ipsecmod = (long long)mod_get_mem(&worker->env, - "ipsecmod"); -#endif -#ifdef WITH_DYNLIBMODULE - shm_stat->mem.dynlib = (long long)mod_get_mem(&worker->env, - "dynlib"); -#endif + /* Lock the lock and see if this thread is first or last of the + * stat threads. It can then zero value or sum up values. */ + lock_basic_lock(&shm_info->lock); + if(shm_thread_is_first(shm_info, worker->thread_num, worker->daemon)) { + /* First thread, zero fill total. */ + memset(&shm_info->total_in_progress, 0, + sizeof(struct ub_stats_info)); + shm_info->volley_in_progress = 1; } - - server_stats_add(stat_total, stat_info); - - /* print the thread statistics */ - stat_total->mesh_time_median /= (double)worker->daemon->num; - + shm_info->thread_volley[worker->thread_num] = 1; + if(worker->thread_num == 0) { + /* Thread 0, copy general info. */ + shm_general_info(worker); + } + /* Add thread data to the total */ + total_mesh_time_median = shm_info->total_in_progress.mesh_time_median; + server_stats_add(&shm_info->total_in_progress, stat_info); + /* By adding the value/num per stat thread, for the median, + * it is going to add up to the sum/num. */ + shm_info->total_in_progress.mesh_time_median = total_mesh_time_median + + (stat_info->mesh_time_median/(double)worker->daemon->num); + + if(shm_thread_is_last(worker->daemon)) { + /* Copy over the total */ + memcpy(stat_total, &shm_info->total_in_progress, + sizeof(struct ub_stats_info)); + shm_info->volley_in_progress = 0; + memset(shm_info->thread_volley, 0, + ((size_t)worker->daemon->num) * sizeof(int)); + } + lock_basic_unlock(&shm_info->lock); #else (void)worker; #endif /* HAVE_SHMGET */ Index: usr.sbin/unbound/util/shm_side/shm_main.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/shm_side/shm_main.h,v diff -u -p -r1.1 shm_main.h --- usr.sbin/unbound/util/shm_side/shm_main.h 12 Aug 2017 11:22:46 -0000 1.1 +++ usr.sbin/unbound/util/shm_side/shm_main.h 21 Sep 2026 16:28:11 -0000 @@ -47,6 +47,8 @@ struct worker; /* get struct ub_shm_stat_info */ #include "libunbound/unbound.h" +#include "util/locks.h" + /** * The SHM info. */ @@ -59,6 +61,19 @@ struct shm_main_info { int key; int id_ctl; int id_arr; + + /** This mutex is on the volley information. */ + lock_basic_type lock; + /** If there is a volley, a number of stat timer callbacks by the + * threads, in progress. If not, there is no volley in progress and the + * previous stat run has terminated succesfully for all threads. + * Usually activated by the first thread and deactivated by the last + * thread that starts its stat callback. */ + int volley_in_progress; + /** Per thread, if they have put in stats. 0 if not. */ + int* thread_volley; + /** The total stats of the thread stat timers, it is in progress */ + struct ub_stats_info total_in_progress; }; int shm_main_init(struct daemon* daemon); Index: usr.sbin/unbound/util/storage/lookup3.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/util/storage/lookup3.c,v diff -u -p -r1.8 lookup3.c --- usr.sbin/unbound/util/storage/lookup3.c 4 Sep 2024 09:36:41 -0000 1.8 +++ usr.sbin/unbound/util/storage/lookup3.c 21 Sep 2026 16:28:11 -0000 @@ -255,10 +255,10 @@ uint32_t initval) /* the { case 3 : c+=k[2]; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 2 : b+=k[1]; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 1 : a+=k[0]; final(a,b,c); ATTR_FALLTHROUGH @@ -531,37 +531,37 @@ uint32_t hashlittle( const void *key, si { case 12: c+=((uint32_t)k[11])<<24; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 11: c+=((uint32_t)k[10])<<16; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 10: c+=((uint32_t)k[9])<<8; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 9 : c+=k[8]; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 8 : b+=((uint32_t)k[7])<<24; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 7 : b+=((uint32_t)k[6])<<16; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 6 : b+=((uint32_t)k[5])<<8; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 5 : b+=k[4]; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 4 : a+=((uint32_t)k[3])<<24; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 3 : a+=((uint32_t)k[2])<<16; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 2 : a+=((uint32_t)k[1])<<8; ATTR_FALLTHROUGH - /* fallthrough */ + /* fallthrough */ case 1 : a+=k[0]; break; case 0 : return c; Index: usr.sbin/unbound/validator/autotrust.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/autotrust.c,v diff -u -p -r1.20 autotrust.c --- usr.sbin/unbound/validator/autotrust.c 31 Aug 2025 21:41:10 -0000 1.20 +++ usr.sbin/unbound/validator/autotrust.c 21 Sep 2026 16:28:11 -0000 @@ -160,10 +160,12 @@ verbose_key(struct autr_ta* ta, enum ver * Parse comments * @param str: to parse * @param ta: trust key autotrust metadata + * @param header_seen: if an autotrust file header was seen. + * Without such a header it is a list of resource records. * @return false on failure. */ static int -parse_comments(char* str, struct autr_ta* ta) +parse_comments(char* str, struct autr_ta* ta, int header_seen) { int len = (int)strlen(str), pos = 0, timestamp = 0; char* comment = (char*) malloc(sizeof(char)*len+1); @@ -196,10 +198,18 @@ parse_comments(char* str, struct autr_ta free(comment); return 0; } - if (pos <= 0) - ta->s = AUTR_STATE_VALID; - else - { + if (pos <= 0) { + if(header_seen) { + /* There was an autotrust trust anchor file header, + * with a ;; id=.. line, so the entries + * have to have ;;state= annotations. */ + log_err("trust anchor in state file has no ;;state= " + "annotation, ignoring"); + free(comment); + return 0; + } + ta->s = AUTR_STATE_VALID; + } else { int s = (int) comments[pos] - '0'; switch(s) { @@ -391,6 +401,15 @@ autr_rrset_delete(struct ub_packed_rrset } } +/** delete autotrust key data */ +static void +autr_ta_delete(struct autr_ta* ta) +{ + if(!ta) return; + free(ta->rr); + free(ta); +} + void autr_point_delete(struct trust_anchor* tp) { if(!tp) @@ -404,8 +423,7 @@ void autr_point_delete(struct trust_anch struct autr_ta* p = tp->autr->keys, *np; while(p) { np = p->next; - free(p->rr); - free(p); + autr_ta_delete(p); p = np; } free(tp->autr->file); @@ -449,8 +467,7 @@ add_trustanchor_frm_rr(struct val_anchor return NULL; *tp = find_add_tp(anchors, rr, rr_len, dname_len); if(!*tp) { - free(ta->rr); - free(ta); + autr_ta_delete(ta); return NULL; } /* add ta to tp */ @@ -523,12 +540,14 @@ add_trustanchor_frm_str(struct val_ancho * @param prev: passed to ldns. * @param prev_len: length of prev * @param skip: if true, the result is NULL, but not an error, skip it. + * @param header_seen: if an autotrust file header was seen. + * Without such a header it is a list of resource records. * @return false on failure, otherwise the tp read. */ static struct trust_anchor* load_trustanchor(struct val_anchors* anchors, char* str, const char* fname, uint8_t* origin, size_t origin_len, uint8_t** prev, size_t* prev_len, - int* skip) + int* skip, int header_seen) { struct autr_ta* ta = NULL; struct trust_anchor* tp = NULL; @@ -538,7 +557,11 @@ load_trustanchor(struct val_anchors* anc if(!ta) return NULL; lock_basic_lock(&tp->lock); - if(!parse_comments(str, ta)) { + if(!parse_comments(str, ta, header_seen)) { + /* ta was already linked into the list of keys, unlink it */ + log_assert(tp->autr->keys == ta); + tp->autr->keys = ta->next; + autr_ta_delete(ta); lock_basic_unlock(&tp->lock); return NULL; } @@ -846,19 +869,32 @@ parse_id(struct val_anchors* anchors, ch * @param anchors: the anchor is added to this, if "id:" is seen. * @param anchor: the anchor as result value or previously returned anchor * value to read the variable lines into. + * @param header_seen: if a header ';;id: example.com.' was seen. + * @param nm: file name. * @return: 0 no match, -1 failed syntax error, +1 success line read. * +2 revoked trust anchor file. */ static int parse_var_line(char* line, struct val_anchors* anchors, - struct trust_anchor** anchor) + struct trust_anchor** anchor, int* header_seen, const char* nm) { struct trust_anchor* tp = *anchor; int r = 0; if(strncmp(line, ";;id: ", 6) == 0) { + *header_seen = 1; *anchor = parse_id(anchors, line+6); if(!*anchor) return -1; - else return 1; + lock_basic_lock(&(*anchor)->lock); + if(*anchor && !(*anchor)->autr->file) { + (*anchor)->autr->file = strdup(nm); + if(!(*anchor)->autr->file) { + lock_basic_unlock(&(*anchor)->lock); + log_err("malloc failure"); + return -1; + } + } + lock_basic_unlock(&(*anchor)->lock); + if(*anchor) return 1; } else if(strncmp(line, ";;REVOKED", 9) == 0) { if(tp) { log_err("REVOKED statement must be at start of file"); @@ -992,14 +1028,15 @@ int autr_read_file(struct val_anchors* a FILE* fd; /* keep track of line numbers */ int line_nr = 0; - /* single line */ - char line[10240]; + /* single line, enough space for large DNSKEY, 64K, in hex and dname */ + char line[10240+65536*2]; /* trust point being read */ struct trust_anchor *tp = NULL, *tp2; int r; /* for $ORIGIN parsing */ uint8_t *origin=NULL, *prev=NULL; size_t origin_len=0, prev_len=0; + int header_seen = 0; if (!(fd = fopen(nm, "r"))) { log_err("unable to open %s for reading: %s", @@ -1008,7 +1045,7 @@ int autr_read_file(struct val_anchors* a } verbose(VERB_ALGO, "reading autotrust anchor file %s", nm); while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) { - if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) { + if(r == -1 || (r = parse_var_line(line, anchors, &tp, &header_seen, nm)) == -1) { log_err("could not parse auto-trust-anchor-file " "%s line %d", nm, line_nr); fclose(fd); @@ -1030,7 +1067,7 @@ int autr_read_file(struct val_anchors* a continue; r = 0; if(!(tp2=load_trustanchor(anchors, line, nm, origin, - origin_len, &prev, &prev_len, &r))) { + origin_len, &prev, &prev_len, &r, header_seen))) { if(!r) log_err("failed to load trust anchor from %s " "at line %i, skipping", nm, line_nr); /* try to do the rest */ @@ -1194,6 +1231,11 @@ void autr_write_file(struct module_env* #endif char tempf[2048]; log_assert(tp->autr); + if(!fname) { + log_err("autotrust: trust point has no backing file, " + "skipping write"); + return; + } if(!env) { log_err("autr_write_file: Module environment is NULL."); return; @@ -1255,12 +1297,13 @@ void autr_write_file(struct module_env* * @param tp: trust point to verify with * @param rrset: DNSKEY rrset to verify. * @param qstate: qstate with region. + * @param vq: validator query state. * @return false on failure, true if verification successful. */ static int verify_dnskey(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* rrset, - struct module_qstate* qstate) + struct module_qstate* qstate, struct val_qstate* vq) { char reasonbuf[256]; char* reason = NULL; @@ -1268,7 +1311,7 @@ verify_dnskey(struct module_env* env, st int downprot = env->cfg->harden_algo_downgrade; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason, - NULL, qstate, reasonbuf, sizeof(reasonbuf)); + NULL, qstate, vq, reasonbuf, sizeof(reasonbuf)); /* sigalg is ignored, it returns algorithms signalled to exist, but * in 5011 there are no other rrsets to check. if downprot is * enabled, then it checks that the DNSKEY is signed with all @@ -1308,16 +1351,18 @@ min_expiry(struct module_env* env, struc static int rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, size_t i, - struct module_qstate* qstate) + struct module_qstate* qstate, struct val_qstate* vq) { enum sec_status sec; char* reason = NULL; + size_t num_tagmatches = 0; verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d", (int)i); /* no algorithm downgrade protection necessary, if it is selfsigned * revoked it can be removed. */ sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i, - &reason, NULL, LDNS_SECTION_ANSWER, qstate); + &reason, NULL, LDNS_SECTION_ANSWER, qstate, vq, + &num_tagmatches); return (sec == sec_status_secure); } @@ -1533,7 +1578,7 @@ init_events(struct trust_anchor* tp) static void check_contains_revoked(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, - int* changed, struct module_qstate* qstate) + int* changed, struct module_qstate* qstate, struct val_qstate* vq) { struct packed_rrset_data* dd = (struct packed_rrset_data*) dnskey_rrset->entry.data; @@ -1553,7 +1598,8 @@ check_contains_revoked(struct module_env } if(!ta) continue; /* key not found */ - if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) { + if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate, + vq)) { /* checked if there is an rrsig signed by this key. */ /* same keytag, but stored can be revoked already, so * compare keytags, with +0 or +128(REVOKE flag) */ @@ -1992,8 +2038,7 @@ autr_cleanup_keys(struct trust_anchor* t != LDNS_RR_TYPE_DNSKEY) { struct autr_ta* np = p->next; /* remove */ - free(p->rr); - free(p); + autr_ta_delete(p); /* snip and go to next item */ *prevp = np; p = np; @@ -2168,7 +2213,7 @@ autr_tp_remove(struct module_env* env, s int autr_process_prime(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, - struct module_qstate* qstate) + struct module_qstate* qstate, struct val_qstate* vq) { int changed = 0; log_assert(tp && tp->autr); @@ -2209,7 +2254,7 @@ int autr_process_prime(struct module_env return 1; /* trust point exists */ } /* check for revoked keys to remove immediately */ - check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate); + check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate, vq); if(changed) { verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble"); if(!autr_assemble(tp)) { @@ -2225,7 +2270,7 @@ int autr_process_prime(struct module_env } } /* verify the dnskey rrset and see if it is valid. */ - if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) { + if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate, vq)) { verbose(VERB_ALGO, "autotrust: dnskey did not verify."); /* only increase failure count if this is not the first prime, * this means there was a previous successful probe */ @@ -2318,7 +2363,7 @@ autr_debug_print_tp(struct trust_anchor* if(tp->dnskey_rrset) { log_packed_rrset(NO_VERBOSE, "DNSKEY:", tp->dnskey_rrset); } - log_info("file %s", tp->autr->file); + log_info("file %s", (tp->autr->file?tp->autr->file:"null")); (void)autr_ctime_r(&tp->autr->last_queried, buf); if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf); @@ -2416,7 +2461,7 @@ probe_anchor(struct module_env* env, str qinfo.qclass); if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, - &probe_answer_cb, env, 0)) { + &probe_answer_cb, env, 0, NULL)) { log_err("out of memory making 5011 probe"); } } Index: usr.sbin/unbound/validator/autotrust.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/autotrust.h,v diff -u -p -r1.4 autotrust.h --- usr.sbin/unbound/validator/autotrust.h 20 Sep 2018 23:15:40 -0000 1.4 +++ usr.sbin/unbound/validator/autotrust.h 21 Sep 2026 16:28:11 -0000 @@ -50,6 +50,7 @@ struct module_env; struct module_qstate; struct val_env; struct sldns_buffer; +struct val_qstate; /** Autotrust anchor states */ typedef enum { @@ -190,13 +191,14 @@ void autr_point_delete(struct trust_anch * @param dnskey_rrset: DNSKEY rrset probed (can be NULL if bad prime result). * allocated in a region. Has not been validated yet. * @param qstate: qstate with region. + * @param vq: validator query state. * @return false if trust anchor was revoked completely. * Otherwise logs errors to log, does not change return value. * On errors, likely the trust point has been unchanged. */ int autr_process_prime(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, - struct module_qstate* qstate); + struct module_qstate* qstate, struct val_qstate* vq); /** * Debug printout of rfc5011 tracked anchors Index: usr.sbin/unbound/validator/val_anchor.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_anchor.c,v diff -u -p -r1.11 val_anchor.c --- usr.sbin/unbound/validator/val_anchor.c 31 Aug 2025 21:41:10 -0000 1.11 +++ usr.sbin/unbound/validator/val_anchor.c 21 Sep 2026 16:28:11 -0000 @@ -534,7 +534,10 @@ readkeyword_bindfile(FILE* in, sldns_buf while((c = getc(in)) != EOF ) { if(comments && c == '#') { /* # blabla */ skip_to_eol(in, &c); - if(c == EOF) return 0; + if(c == EOF) { + log_err("trusted-keys, %d, got EOF", *line); + return 0; + } (*line)++; continue; } else if(comments && c=='/' && numdone>0 && /* /_/ bla*/ @@ -543,7 +546,10 @@ readkeyword_bindfile(FILE* in, sldns_buf sldns_buffer_skip(buf, -1); numdone--; skip_to_eol(in, &c); - if(c == EOF) return 0; + if(c == EOF) { + log_err("trusted-keys, %d, got EOF", *line); + return 0; + } (*line)++; continue; } else if(comments && c=='*' && numdone>0 && /* /_* bla *_/ */ @@ -560,7 +566,10 @@ readkeyword_bindfile(FILE* in, sldns_buf if(c == '\n') (*line)++; } - if(c == EOF) return 0; + if(c == EOF) { + log_err("trusted-keys, %d, got EOF", *line); + return 0; + } continue; } /* not a comment, complete the keyword */ @@ -581,7 +590,8 @@ readkeyword_bindfile(FILE* in, sldns_buf } /* space for 1 char + 0 string terminator */ if(sldns_buffer_remaining(buf) < 2) { - fatal_exit("trusted-keys, %d, string too long", *line); + log_err("trusted-keys, %d, string too long", *line); + return 0; } sldns_buffer_write_u8(buf, (uint8_t)c); numdone++; @@ -595,7 +605,10 @@ readkeyword_bindfile(FILE* in, sldns_buf break; } } - if(c == EOF) return 0; + if(c == EOF) { + log_err("trusted-keys, %d, got EOF", *line); + return 0; + } return numdone; } if(is_bind_special(c)) @@ -623,7 +636,7 @@ skip_to_special(FILE* in, sldns_buffer* } return 1; } - log_err("trusted-keys, line %d, expected %c got EOF", *line, spec); + log_err("trusted-keys, line %d, expected %c, read failed", *line, spec); return 0; } Index: usr.sbin/unbound/validator/val_neg.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_neg.c,v diff -u -p -r1.11 val_neg.c --- usr.sbin/unbound/validator/val_neg.c 31 Aug 2025 21:41:10 -0000 1.11 +++ usr.sbin/unbound/validator/val_neg.c 21 Sep 2026 16:28:11 -0000 @@ -62,6 +62,13 @@ #include "sldns/rrdef.h" #include "sldns/sbuffer.h" +/** + * The maximum salt length that the negative cache is willing to use. + * Larger salt increases the computation time, while recommendations are + * for zero salt length for zones. + */ +#define MAX_SALT_LENGTH 64 + int val_neg_data_compare(const void* a, const void* b) { struct val_neg_data* x = (struct val_neg_data*)a; @@ -826,7 +833,11 @@ void neg_insert_data(struct val_neg_cach (slen != 0 && zone->nsec3_salt && s && memcmp(zone->nsec3_salt, s, slen) != 0))) { - if(slen > 0) { + if(slen > MAX_SALT_LENGTH) { + /* RFC 9276 s3.1: operators SHOULD NOT use a salt; large + * salts inflate per-hash block count. Decline to cache. */ + return; + } else if(slen > 0) { uint8_t* sa = memdup(s, slen); if(sa) { free(zone->nsec3_salt); @@ -927,6 +938,10 @@ void val_neg_addreply(struct val_neg_cac continue; if(!dname_subdomain_c(rep->rrsets[i]->rk.dname, zone->name)) continue; + if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC && + !nsec_nextowner_subdomain(rep->rrsets[i], zone->name)) { + continue; /* nextowner not in zone */ + } /* insert NSEC into this zone's tree */ neg_insert_data(neg, zone, rep->rrsets[i]); } @@ -1011,6 +1026,10 @@ void val_neg_addreferral(struct val_neg_ continue; if(!dname_subdomain_c(rep->rrsets[i]->rk.dname, zone->name)) continue; + if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC && + !nsec_nextowner_subdomain(rep->rrsets[i], zone->name)) { + continue; /* nextowner not in zone */ + } /* insert NSEC into this zone's tree */ neg_insert_data(neg, zone, rep->rrsets[i]); } @@ -1066,11 +1085,7 @@ grab_nsec(struct rrset_cache* rrset_cach qname, qname_len, qtype, qclass, flags, now, 0); struct packed_rrset_data* d; if(!k) return NULL; - d = (struct packed_rrset_data*)k->entry.data; - if(d->ttl < now) { - lock_rw_unlock(&k->entry.lock); - return NULL; - } + d = k->entry.data; /* only secure or unchecked records that have signatures. */ if( ! ( d->security == sec_status_secure || (d->security == sec_status_unchecked && @@ -1103,12 +1118,14 @@ grab_nsec(struct rrset_cache* rrset_cach * @param rrset_cache: rrset cache * @param now: to check ttl against * @param region: where to alloc result + * @param topname: do not look higher than this name, so that the + * result cannot be taken from a zone above the current trust anchor. * @return rrset or NULL */ static struct ub_packed_rrset_key* neg_find_nsec(struct val_neg_cache* neg_cache, uint8_t* qname, size_t qname_len, uint16_t qclass, struct rrset_cache* rrset_cache, time_t now, - struct regional* region) + struct regional* region, uint8_t* topname) { int labs; uint32_t flags; @@ -1126,6 +1143,11 @@ neg_find_nsec(struct val_neg_cache* neg_ lock_basic_unlock(&neg_cache->lock); return NULL; } + if(topname && !dname_subdomain_c(zone->name, topname)) { + /* Reject NSEC not within trust anchor's bailiwick */ + lock_basic_unlock(&neg_cache->lock); + return NULL; + } /* NSEC only for now */ if(zone->nsec3_hash) { @@ -1169,6 +1191,15 @@ neg_find_nsec3_ce(struct val_neg_zone* z uint8_t hashce[NSEC3_SHA_LEN]; uint8_t b32[257]; size_t celen, b32len; + int hashmax = MAX_NSEC3_CALCULATIONS; + if(qlabs > hashmax) { + /* strip leading labels so the walk costs at most + * MAX_NSEC3_CALCULATIONS hashes, mirroring val_nsec3.c */ + while(qlabs > hashmax) { + dname_remove_label(&qname, &qname_len); + qlabs--; + } + } *nclen = 0; while(qlabs > 0) { @@ -1207,8 +1238,8 @@ neg_params_ok(struct val_neg_zone* zone, return 0; return (h == zone->nsec3_hash && it == zone->nsec3_iter && slen == zone->nsec3_saltlen && - (slen != 0 && zone->nsec3_salt && s - && memcmp(zone->nsec3_salt, s, slen) == 0)); + (slen == 0 || (slen != 0 && zone->nsec3_salt && s + && memcmp(zone->nsec3_salt, s, slen) == 0))); } /** get next closer for nsec3 proof */ @@ -1269,6 +1300,12 @@ neg_nsec3_proof_ds(struct val_neg_zone* if(!zone->nsec3_hash) return NULL; /* not nsec3 zone */ + if(!topname && qlabs > zone->labs + 1) + return NULL; /* iterator caller; opt-out proof would be discarded + * at the !topname check below anyway. + * The qlabs check allows the exact-match for + * the one-label-below-zone case. */ + if(!(data=neg_find_nsec3_ce(zone, qname, qname_len, qlabs, buf, hashnc, &nclen))) { return NULL; @@ -1291,8 +1328,10 @@ neg_nsec3_proof_ds(struct val_neg_zone* !nsec3_has_type(ce_rrset, 0, LDNS_RR_TYPE_NS)) return NULL; if(!(msg = dns_msg_create(qname, qname_len, - LDNS_RR_TYPE_DS, zone->dclass, region, 1))) + LDNS_RR_TYPE_DS, zone->dclass, region, 2))) /* ce + soa */ return NULL; + /* The cache response means recursion is available. */ + msg->rep->flags |= BIT_RA; /* TTL reduced in grab_nsec */ if(!dns_msg_authadd(msg, region, ce_rrset, 0)) return NULL; @@ -1327,6 +1366,8 @@ neg_nsec3_proof_ds(struct val_neg_zone* if(!(msg = dns_msg_create(qname, qname_len, LDNS_RR_TYPE_DS, zone->dclass, region, 3))) return NULL; + /* The cache response means recursion is available. */ + msg->rep->flags |= BIT_RA; /* now=0 because TTL was reduced in grab_nsec */ if(!dns_msg_authadd(msg, region, ce_rrset, 0)) return NULL; @@ -1404,7 +1445,7 @@ val_neg_getmsg(struct val_neg_cache* neg /* Get best available NSEC for qname */ nsec = neg_find_nsec(neg, qinfo->qname, qinfo->qname_len, qinfo->qclass, - rrset_cache, now, region); + rrset_cache, now, region, topname); /* Matching NSEC, use to generate No Data answer. Not creating answers * yet for No Data proven using wildcard. */ @@ -1417,6 +1458,8 @@ val_neg_getmsg(struct val_neg_cache* neg if(!(msg = dns_msg_create(qinfo->qname, qinfo->qname_len, qinfo->qtype, qinfo->qclass, region, 2))) return NULL; + /* The cache response means recursion is available. */ + msg->rep->flags |= BIT_RA; if(!dns_msg_authadd(msg, region, nsec, 0)) return NULL; if(addsoa && !add_soa(rrset_cache, now, region, msg, NULL)) @@ -1430,6 +1473,8 @@ val_neg_getmsg(struct val_neg_cache* neg if(!(msg = dns_msg_create(qinfo->qname, qinfo->qname_len, qinfo->qtype, qinfo->qclass, region, 3))) return NULL; + /* The cache response means recursion is available. */ + msg->rep->flags |= BIT_RA; if(!(ce = nsec_closest_encloser(qinfo->qname, nsec))) return NULL; dname_count_size_labels(ce, &ce_len); @@ -1480,7 +1525,7 @@ val_neg_getmsg(struct val_neg_cache* neg * proof */ if(!(wcrr = neg_find_nsec(neg, wc_qinfo.qname, wc_qinfo.qname_len, qinfo->qclass, - rrset_cache, now, region))) + rrset_cache, now, region, topname))) return NULL; nodata_wc = NULL; Index: usr.sbin/unbound/validator/val_nsec.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_nsec.c,v diff -u -p -r1.12 val_nsec.c --- usr.sbin/unbound/validator/val_nsec.c 4 Sep 2024 09:36:41 -0000 1.12 +++ usr.sbin/unbound/validator/val_nsec.c 21 Sep 2026 16:28:11 -0000 @@ -177,7 +177,8 @@ static int nsec_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen) { struct packed_rrset_data* d = (struct packed_rrset_data*) nsec->entry.data; @@ -189,7 +190,7 @@ nsec_verify_rrset(struct module_env* env if(d->security == sec_status_secure) return 1; d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason, - reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified, + reason_bogus, LDNS_SECTION_AUTHORITY, qstate, vq, &verified, reasonbuf, reasonlen); if(d->security == sec_status_secure) { rrset_update_sec_status(env->rrset_cache, nsec, *env->now); @@ -203,7 +204,7 @@ val_nsec_prove_nodata_dsreply(struct mod struct query_info* qinfo, struct reply_info* rep, struct key_entry_key* kkey, time_t* proof_ttl, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns( rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC, @@ -221,26 +222,32 @@ val_nsec_prove_nodata_dsreply(struct mod * 2) this is not a delegation point */ if(nsec) { if(!nsec_verify_rrset(env, ve, nsec, kkey, reason, - reason_bogus, qstate, reasonbuf, reasonlen)) { + reason_bogus, qstate, vq, reasonbuf, reasonlen)) { verbose(VERB_ALGO, "NSEC RRset for the " "referral did not verify."); return sec_status_bogus; } - sec = val_nsec_proves_no_ds(nsec, qinfo); - if(sec == sec_status_bogus) { - /* something was wrong. */ - *reason = "NSEC does not prove absence of DS"; - *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; - return sec; - } else if(sec == sec_status_insecure) { - /* this wasn't a delegation point. */ - return sec; - } else if(sec == sec_status_secure) { - /* this proved no DS. */ - *proof_ttl = ub_packed_rrset_ttl(nsec); - return sec; + /* If the NSEC was a wildcard, the verify rewrites the + * owner to '*.zone'. Check the NSEC owner matches. */ + if(query_dname_compare(nsec->rk.dname, qinfo->qname) == 0) { + sec = val_nsec_proves_no_ds(nsec, qinfo); + if(sec == sec_status_bogus) { + /* something was wrong. */ + *reason = "NSEC does not prove absence of DS"; + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec; + } else if(sec == sec_status_insecure) { + /* this wasn't a delegation point. */ + return sec; + } else if(sec == sec_status_secure) { + /* this proved no DS. */ + *proof_ttl = ub_packed_rrset_ttl(nsec); + return sec; + } } /* if unchecked, fall through to next proof */ + /* For *.closest-encloser NSEC, there is a closer-match + * check for the wildcard below. */ } /* Otherwise, there is no NSEC at qname. This could be an ENT. @@ -252,7 +259,7 @@ val_nsec_prove_nodata_dsreply(struct mod if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC)) continue; if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason, - reason_bogus, qstate, reasonbuf, reasonlen)) { + reason_bogus, qstate, vq, reasonbuf, reasonlen)) { verbose(VERB_ALGO, "NSEC for empty non-terminal " "did not verify."); *reason = "NSEC for empty non-terminal " Index: usr.sbin/unbound/validator/val_nsec.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_nsec.h,v diff -u -p -r1.6 val_nsec.h --- usr.sbin/unbound/validator/val_nsec.h 4 Sep 2024 09:36:41 -0000 1.6 +++ usr.sbin/unbound/validator/val_nsec.h 21 Sep 2026 16:28:11 -0000 @@ -52,6 +52,7 @@ struct ub_packed_rrset_key; struct reply_info; struct query_info; struct key_entry_key; +struct val_qstate; /** * Check DS absence. @@ -68,6 +69,7 @@ struct key_entry_key; * @param reason: string explaining why bogus. * @param reason_bogus: relevant EDE code for validation failure. * @param qstate: qstate with region. + * @param vq: validator qstate. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return security status. @@ -80,7 +82,8 @@ enum sec_status val_nsec_prove_nodata_ds struct val_env* ve, struct query_info* qinfo, struct reply_info* rep, struct key_entry_key* kkey, time_t* proof_ttl, char** reason, sldns_ede_code* reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen); + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen); /** * nsec typemap check, takes an NSEC-type bitmap as argument, checks for type. Index: usr.sbin/unbound/validator/val_nsec3.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_nsec3.c,v diff -u -p -r1.10 val_nsec3.c --- usr.sbin/unbound/validator/val_nsec3.c 21 Feb 2025 13:20:40 -0000 1.10 +++ usr.sbin/unbound/validator/val_nsec3.c 21 Sep 2026 16:28:11 -0000 @@ -60,11 +60,6 @@ #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. @@ -456,6 +451,67 @@ filter_init(struct nsec3_filter* filter, } } +/** Check if the NSEC3s have the same parameter set. */ +static int +param_set_same(struct nsec3_filter* flt, char** reason) +{ + size_t rrsetnum; + int rrnum; + struct ub_packed_rrset_key* rrset; + int have_params = 0; + int first_algo = 0; + size_t first_iter = 0; + uint8_t* first_salt = NULL; + size_t first_saltlen = 0; + + /* If the NSEC3 parameter sets have distinct values, then they are + * from different NSEC3 chains, and we do not want that. */ + for(rrset=filter_first(flt, &rrsetnum, &rrnum); rrset; + rrset=filter_next(flt, &rrsetnum, &rrnum)) { + if(!have_params) { + first_algo = nsec3_get_algo(rrset, rrnum); + first_iter = nsec3_get_iter(rrset, rrnum); + if(!nsec3_get_salt(rrset, rrnum, &first_salt, + &first_saltlen)) { + verbose(VERB_ALGO, "NSEC3 salt malformed"); + if(reason) + *reason = "NSEC3 salt malformed"; + return 0; + } + have_params = 1; + } else { + uint8_t* salt = NULL; + size_t saltlen = 0; + if(nsec3_get_algo(rrset, rrnum) != first_algo) { + verbose(VERB_ALGO, "NSEC3 algorithm mismatch"); + if(reason) + *reason = "NSEC3 algorithm mismatch"; + return 0; + } + if(nsec3_get_iter(rrset, rrnum) != first_iter) { + verbose(VERB_ALGO, "NSEC3 iterations mismatch"); + if(reason) + *reason = "NSEC3 iterations mismatch"; + return 0; + } + if(!nsec3_get_salt(rrset, rrnum, &salt, &saltlen)) { + verbose(VERB_ALGO, "NSEC3 salt malformed"); + if(reason) + *reason = "NSEC3 salt malformed"; + return 0; + } + if(saltlen != first_saltlen || + memcmp(salt, first_salt, saltlen) != 0) { + verbose(VERB_ALGO, "NSEC3 salt mismatch"); + if(reason) + *reason = "NSEC3 salt mismatch"; + return 0; + } + } + } + return 1; +} + /** * Find max iteration count using config settings and key size * @param ve: validator environment with iteration count config settings. @@ -1192,6 +1248,12 @@ nsec3_prove_nameerror(struct module_env* filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone", @@ -1378,6 +1440,12 @@ nsec3_prove_nodata(struct module_env* en filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ 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, calc); @@ -1401,6 +1469,12 @@ nsec3_prove_wildcard(struct module_env* filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ @@ -1447,7 +1521,8 @@ static int list_is_secure(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen) { struct packed_rrset_data* d; size_t i; @@ -1463,7 +1538,7 @@ list_is_secure(struct module_env* env, s continue; d->security = val_verify_rrset_entry(env, ve, list[i], kkey, reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate, - &verified, reasonbuf, reasonlen); + vq, &verified, reasonbuf, reasonlen); if(d->security != sec_status_secure) { verbose(VERB_ALGO, "NSEC3 did not verify"); return 0; @@ -1478,7 +1553,8 @@ nsec3_prove_nods(struct module_env* env, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, struct nsec3_cache_table* ct, char* reasonbuf, + size_t reasonlen) { struct nsec3_filter flt; struct ce_response ce; @@ -1494,7 +1570,7 @@ nsec3_prove_nods(struct module_env* env, return sec_status_bogus; /* no valid NSEC3s, bogus */ } if(!list_is_secure(env, ve, list, num, kkey, reason, reason_bogus, - qstate, reasonbuf, reasonlen)) { + qstate, vq, reasonbuf, reasonlen)) { *reason = "not all NSEC3 records secure"; return sec_status_bogus; /* not all NSEC3 records secure */ } @@ -1503,6 +1579,13 @@ nsec3_prove_nods(struct module_env* env, *reason = "no NSEC3 records"; return sec_status_bogus; /* no RRs */ } + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + *reason = "NSEC3 name is not b32.signer name"; + return sec_status_bogus; + } + if(!param_set_same(&flt, reason)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ @@ -1596,6 +1679,12 @@ nsec3_prove_nxornodata(struct module_env filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ + if(query_dname_compare(flt.zone, kkey->name) != 0) { + verbose(VERB_ALGO, "NSEC3 name is not b32.signer name"); + return sec_status_bogus; + } + if(!param_set_same(&flt, NULL)) + return sec_status_bogus; /* nsec3 params from distinct chains*/ if(nsec3_iteration_count_high(ve, &flt, kkey)) return sec_status_insecure; /* iteration count too high */ Index: usr.sbin/unbound/validator/val_nsec3.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_nsec3.h,v diff -u -p -r1.7 val_nsec3.h --- usr.sbin/unbound/validator/val_nsec3.h 4 Sep 2024 09:36:41 -0000 1.7 +++ usr.sbin/unbound/validator/val_nsec3.h 21 Sep 2026 16:28:11 -0000 @@ -78,6 +78,7 @@ struct reply_info; struct query_info; struct key_entry_key; struct sldns_buffer; +struct val_qstate; /** * 0 1 2 3 4 5 6 7 @@ -99,6 +100,12 @@ struct sldns_buffer; #define NSEC3_HASH_SHA1 0x01 /** + * 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 + +/** * Cache table for NSEC3 hashes. * It keeps a *pointer* to the region its items are allocated. */ @@ -209,6 +216,7 @@ nsec3_prove_wildcard(struct module_env* * @param reason: string for bogus result. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate. * @param ct: cached hashes table. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. @@ -224,7 +232,8 @@ nsec3_prove_nods(struct module_env* env, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, struct nsec3_cache_table* ct, char* reasonbuf, + size_t reasonlen); /** * Prove NXDOMAIN or NODATA. Index: usr.sbin/unbound/validator/val_secalgo.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_secalgo.c,v diff -u -p -r1.17 val_secalgo.c --- usr.sbin/unbound/validator/val_secalgo.c 4 Sep 2024 09:36:41 -0000 1.17 +++ usr.sbin/unbound/validator/val_secalgo.c 21 Sep 2026 16:28:11 -0000 @@ -745,11 +745,9 @@ verify_canonrrset(sldns_buffer* buf, int if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) &&(fake_dsa||fake_sha1)) return sec_status_secure; #endif -#ifndef USE_SHA1 if(fake_sha1 && (algo == LDNS_DSA || algo == LDNS_DSA_NSEC3 || algo == LDNS_RSASHA1 || algo == LDNS_RSASHA1_NSEC3)) return sec_status_secure; -#endif - + if(!setup_key_digest(algo, &evp_key, &digest_type, key, keylen)) { verbose(VERB_QUERY, "verify: failed to setup key"); *reason = "use of key for crypto failed"; @@ -1874,9 +1872,9 @@ _verify_nettle_rsa(sldns_buffer* buf, un } mod_offset = exp_offset + exp_len; nettle_rsa_public_key_init(&pubkey); - pubkey.size = keylen - mod_offset; nettle_mpz_set_str_256_u(pubkey.e, exp_len, &key[exp_offset]); - nettle_mpz_set_str_256_u(pubkey.n, pubkey.size, &key[mod_offset]); + nettle_mpz_set_str_256_u(pubkey.n, keylen - mod_offset, &key[mod_offset]); + pubkey.size = nettle_mpz_sizeinbase_256_u(pubkey.n); /* Digest content of "buf" and verify its RSA signature in "sigblock"*/ nettle_mpz_init_set_str_256_u(signature, sigblock_len, (uint8_t*)sigblock); Index: usr.sbin/unbound/validator/val_sigcrypt.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_sigcrypt.c,v diff -u -p -r1.16 val_sigcrypt.c --- usr.sbin/unbound/validator/val_sigcrypt.c 26 Sep 2025 07:32:37 -0000 1.16 +++ usr.sbin/unbound/validator/val_sigcrypt.c 21 Sep 2026 16:28:12 -0000 @@ -82,6 +82,8 @@ /** Maximum number of RRSIG validations for an RRset. */ #define MAX_VALIDATE_RRSIGS 8 +/** Maximum number of NSEC validations for a message. */ +#define MAX_VALIDATE_NSECS 8 /** return number of rrs in an rrset */ static size_t @@ -305,6 +307,8 @@ ds_create_dnskey_digest(struct module_en * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA); * DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */ sldns_buffer_clear(b); + if(!sldns_buffer_available(b, dnskey_rrset->rk.dname_len + dnskey_len-2)) + return 0; /* buffer too small */ sldns_buffer_write(b, dnskey_rrset->rk.dname, dnskey_rrset->rk.dname_len); query_dname_tolower(sldns_buffer_begin(b)); @@ -546,8 +550,10 @@ int algo_needs_missing(struct algo_needs * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param numverified: incremented when the number of RRSIG validations * increases. + * @param num_tagmatches: incremented for tag matches. * @return secure if any key signs *this* signature. bogus if no key signs it, * unchecked on error, or indeterminate if all keys are not supported by * the crypto library (openssl3+ only). @@ -559,7 +565,7 @@ dnskeyset_verify_rrset_sig(struct module struct rbtree_type** sortree, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* numverified) + struct val_qstate* vq, int* numverified, size_t* num_tagmatches) { /* find matching keys and check them */ enum sec_status sec = sec_status_bogus; @@ -578,6 +584,14 @@ dnskeyset_verify_rrset_sig(struct module } for(i=0; i MAX_TAG_MATCHES) { + *reason = "too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "verify sig: too many tag matches, " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } /* see if key matches keytag and algo */ if(algo != dnskey_get_algo(dnskey, i) || tag != dnskey_calc_keytag(dnskey, i)) @@ -585,6 +599,26 @@ dnskeyset_verify_rrset_sig(struct module numchecked ++; (*numverified)++; + if(vq && vq->num_validation_attempts++ > env->cfg->val_validation_attempts) { + *reason = "too many validation attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "verify sig: too many validation attempts, " + "val-validation-attempts (%d); bogus", env->cfg->val_validation_attempts); + return sec_status_bogus; + } + if(vq && (ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC || + ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC3) && + vq->num_nsec_attempts++ > MAX_VALIDATE_NSECS) { + *reason = "too many NSEC or NSEC3 validation attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "verify sig: too many NSEC or NSEC3 validation attempts, " + "(%d); bogus", MAX_VALIDATE_NSECS); + vq->num_nsec_attempts_exceeded = 1; + return sec_status_bogus; + } + /* see if key verifies */ sec = dnskey_verify_rrset_sig(env->scratch, env->scratch_buffer, ve, now, rrset, dnskey, i, @@ -624,11 +658,12 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate, int* verified, - char* reasonbuf, size_t reasonlen) + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen) { enum sec_status sec; - size_t i, num; + size_t i, num, num_tagmatches = 0; rbtree_type* sortree = NULL; /* make sure that for all DNSKEY algorithms there are valid sigs */ struct algo_needs needs; @@ -656,9 +691,19 @@ dnskeyset_verify_rrset(struct module_env } } for(i=0; i MAX_TAG_MATCHES) { + *reason = "too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many tag matches, " + "MAX_TAG_MATCHES (%d)", MAX_TAG_MATCHES); + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset, dnskey, i, &sortree, reason, reason_bogus, - section, qstate, verified); + section, qstate, vq, verified, &num_tagmatches); /* see which algorithm has been fixed up */ if(sec == sec_status_secure) { if(!sigalg) @@ -707,7 +752,8 @@ enum sec_status dnskey_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate) + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, size_t* num_tagmatches) { enum sec_status sec; size_t i, num, numchecked = 0, numindeterminate = 0; @@ -728,9 +774,26 @@ dnskey_verify_rrset(struct module_env* e } for(i=0; i MAX_TAG_MATCHES) { + *reason = "too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many tag matches, " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } if(algo != rrset_get_sig_algo(rrset, i) || tag != rrset_get_sig_keytag(rrset, i)) continue; + if(vq && vq->num_validation_attempts++ > env->cfg->val_validation_attempts) { + *reason = "too many validation attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many validation attempts, " + "val-validation-attempts (%d); bogus", env->cfg->val_validation_attempts); + return sec_status_bogus; + } + buf_canon = 0; sec = dnskey_verify_rrset_sig(env->scratch, env->scratch_buffer, ve, *env->now, rrset, @@ -1083,6 +1146,18 @@ insert_can_owner(sldns_buffer* buf, stru } } +/** lowercase a wire dname but never step past end */ +static void +canon_dname_tolower(uint8_t* d, uint8_t* end) +{ + uint8_t lab; + while(d < end && (lab = *d) != 0) { + if((size_t)lab+1 > (size_t)(end-d)) return; /* malformed */ + for(d++; lab; lab--, d++) + *d = (uint8_t)tolower((unsigned char)*d); + } +} + /** * Canonicalize Rdata in buffer. * @param buf: buffer at position just after the rdata. @@ -1094,6 +1169,8 @@ canonicalize_rdata(sldns_buffer* buf, st size_t len) { uint8_t* datstart = sldns_buffer_current(buf)-len+2; + uint8_t* datend = sldns_buffer_current(buf); + size_t firstlen; switch(ntohs(rrset->rk.type)) { case LDNS_RR_TYPE_NXT: case LDNS_RR_TYPE_NS: @@ -1106,15 +1183,16 @@ canonicalize_rdata(sldns_buffer* buf, st case LDNS_RR_TYPE_PTR: case LDNS_RR_TYPE_DNAME: /* type only has a single argument, the name */ - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; case LDNS_RR_TYPE_MINFO: case LDNS_RR_TYPE_RP: case LDNS_RR_TYPE_SOA: /* two names after another */ - query_dname_tolower(datstart); - query_dname_tolower(datstart + - dname_valid(datstart, len-2)); + canon_dname_tolower(datstart, datend); + firstlen = dname_valid(datstart, len-2); + if(firstlen && firstlen < len-2) + canon_dname_tolower(datstart + firstlen, datend); return; case LDNS_RR_TYPE_RT: case LDNS_RR_TYPE_AFSDB: @@ -1124,7 +1202,7 @@ canonicalize_rdata(sldns_buffer* buf, st if(len < 2+2+1) /* rdlen, skiplen, 1byteroot */ return; datstart += 2; - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; case LDNS_RR_TYPE_SIG: /* downcase the RRSIG, compat with BIND (kept it from SIG) */ @@ -1133,16 +1211,17 @@ canonicalize_rdata(sldns_buffer* buf, st if(len < 2+18+1) return; datstart += 18; - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; case LDNS_RR_TYPE_PX: /* skip, then two names after another */ if(len < 2+2+1) return; datstart += 2; - query_dname_tolower(datstart); - query_dname_tolower(datstart + - dname_valid(datstart, len-2-2)); + canon_dname_tolower(datstart, datend); + firstlen = dname_valid(datstart, len-2-2); + if(firstlen && firstlen < len-2-2) + canon_dname_tolower(datstart + firstlen, datend); return; case LDNS_RR_TYPE_NAPTR: if(len < 2+4) @@ -1163,14 +1242,14 @@ canonicalize_rdata(sldns_buffer* buf, st datstart += (size_t)datstart[0]+1; if(len < 1) /* check name is at least 1 byte*/ return; - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; case LDNS_RR_TYPE_SRV: /* skip fixed part */ if(len < 2+6+1) return; datstart += 6; - query_dname_tolower(datstart); + canon_dname_tolower(datstart, datend); return; /* do not canonicalize NSEC rdata name, compat with @@ -1292,14 +1371,32 @@ rrset_canonical(struct regional* region, } sldns_buffer_clear(buf); + if(sldns_buffer_remaining(buf) < siglen || siglen < 18+1) { + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } sldns_buffer_write(buf, sig, siglen); /* canonicalize signer name */ - query_dname_tolower(sldns_buffer_begin(buf)+18); + canon_dname_tolower(sldns_buffer_begin(buf)+18, + sldns_buffer_current(buf)); + + if(sldns_buffer_remaining(buf) < k->rk.dname_len+2) { + /* Check if the first can_owner name can fit in the buffer. + * The length is k->rk.dname_len or k->rk.dname_len+2 + * if it has '*.' in prefixed. Checks the upper bound, + * also realistically the rest of the rrtype, rrclass, origttl, + * rdata and so on has to be inserted, so that extra space has + * to be there. */ + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } RBTREE_FOR(walk, struct canon_rr*, (*sortree)) { /* see if there is enough space left in the buffer */ if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + d->rr_len[walk->rr_idx]) { - log_err("verify: failed to canonicalize, " + verbose(VERB_ALGO, "verify: failed to canonicalize, " "rrset too big"); return 0; } @@ -1308,6 +1405,13 @@ rrset_canonical(struct regional* region, sldns_buffer_write(buf, can_owner, can_owner_len); else insert_can_owner(buf, k, sig, &can_owner, &can_owner_len); + /* Check again, if the rdata can fit in the buffer */ + if(sldns_buffer_remaining(buf) < 2 + 2 + 4 + + d->rr_len[walk->rr_idx]) { + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } sldns_buffer_write(buf, &k->rk.type, 2); sldns_buffer_write(buf, &k->rk.rrset_class, 2); sldns_buffer_write(buf, sig+4, 4); @@ -1322,10 +1426,11 @@ rrset_canonical(struct regional* region, * the non-existence proves. */ if(ntohs(k->rk.type) == LDNS_RR_TYPE_NSEC && section == LDNS_SECTION_AUTHORITY && qstate) { - k->rk.dname = regional_alloc_init(qstate->region, can_owner, + uint8_t* new_dname = regional_alloc_init(qstate->region, can_owner, can_owner_len); - if(!k->rk.dname) + if(!new_dname) return 0; + k->rk.dname = new_dname; k->rk.dname_len = can_owner_len; } @@ -1358,11 +1463,17 @@ rrset_canonicalize_to_buffer(struct regi canonical_sort(k, d, sortree, rrs); sldns_buffer_clear(buf); + if(sldns_buffer_remaining(buf) < k->rk.dname_len) { + /* Check if the first can_owner name can fit in the buffer. */ + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } RBTREE_FOR(walk, struct canon_rr*, sortree) { /* see if there is enough space left in the buffer */ if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + d->rr_len[walk->rr_idx]) { - log_err("verify: failed to canonicalize, " + verbose(VERB_ALGO, "verify: failed to canonicalize, " "rrset too big"); return 0; } @@ -1375,6 +1486,13 @@ rrset_canonicalize_to_buffer(struct regi query_dname_tolower(can_owner); can_owner_len = k->rk.dname_len; } + /* Check again, if the rdata can fit in the buffer */ + if(sldns_buffer_remaining(buf) < 2 + 2 + 4 + + d->rr_len[walk->rr_idx]) { + verbose(VERB_ALGO, "verify: failed to canonicalize, " + "rrset too big"); + return 0; + } sldns_buffer_write(buf, &k->rk.type, 2); sldns_buffer_write(buf, &k->rk.rrset_class, 2); sldns_buffer_write_u32(buf, d->rr_ttl[walk->rr_idx]); @@ -1570,6 +1688,18 @@ dnskey_verify_rrset_sig(struct regional* *reason_bogus = LDNS_EDE_NO_ZONE_KEY_BIT_SET; return sec_status_bogus; } + if((dnskey_get_flags(dnskey, dnskey_idx) & LDNS_KEY_REVOKE_KEY) && + /* The REVOKE key is allowed to check sigs on itself. */ + !(ntohs(rrset->rk.type) == LDNS_RR_TYPE_DNSKEY && + query_dname_compare(rrset->rk.dname, dnskey->rk.dname)==0) + ) { + verbose(VERB_QUERY, "verify: dnskey has REVOKE bit set, " + "not usable for data validation per RFC 5011 s2.1"); + *reason = "dnskey revoked"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSKEY_MISSING; + return sec_status_bogus; + } if(dnskey_get_protocol(dnskey, dnskey_idx) != LDNS_DNSSEC_KEYPROTO) { /* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */ @@ -1597,6 +1727,30 @@ dnskey_verify_rrset_sig(struct regional* *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; return sec_status_bogus; /* signer name offtree */ } + /* NSEC3, the owner name must be the .signername */ + if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC3 && + rrset->rk.dname_len > 0) { + uint8_t* dnameless = rrset->rk.dname; + size_t dnamelesslen = rrset->rk.dname_len; + dname_remove_label(&dnameless, &dnamelesslen); + if(query_dname_compare(dnameless, signer) != 0) { + verbose(VERB_QUERY, "verify: NSEC3 owner name is not b32.signer name"); + *reason = "NSEC3 owner name is not b32.signer name"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; /* NSEC3 owner not b32.signer */ + } + } + /* NSEC, a next owner that is not under the signer is not allowed.*/ + if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC && + !nsec_nextowner_subdomain(rrset, signer)) { + verbose(VERB_QUERY, "verify: NSEC next owner overreaches signer name"); + *reason = "NSEC next owner overreaches signer name"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; /* nextowner overreaching */ + } + sigblock = (unsigned char*)signer+signer_len; if(siglen < 2+18+signer_len+1) { verbose(VERB_QUERY, "verify: too short, no signature data"); @@ -1650,6 +1804,13 @@ dnskey_verify_rrset_sig(struct regional* if((int)sig[2+3] > dname_signame_label_count(rrset->rk.dname)) { verbose(VERB_QUERY, "verify: labelcount out of range"); *reason = "signature labelcount out of range"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } + if((int)sig[2+3] < dname_signame_label_count(signer)) { + verbose(VERB_QUERY, "verify: RRSIG label count too low for signer"); + *reason = "signature labelcount lower than signature signer"; if(reason_bogus) *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; return sec_status_bogus; Index: usr.sbin/unbound/validator/val_sigcrypt.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_sigcrypt.h,v diff -u -p -r1.7 val_sigcrypt.h --- usr.sbin/unbound/validator/val_sigcrypt.h 4 Sep 2024 09:36:41 -0000 1.7 +++ usr.sbin/unbound/validator/val_sigcrypt.h 21 Sep 2026 16:28:12 -0000 @@ -53,6 +53,7 @@ struct ub_packed_rrset_key; struct rbtree_type; struct regional; struct sldns_buffer; +struct val_qstate; /** number of entries in algorithm needs array */ #define ALGO_NEEDS_MAX 256 @@ -262,6 +263,7 @@ uint16_t dnskey_get_flags(struct ub_pack * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param verified: if not NULL the number of RRSIG validations is returned. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. @@ -273,8 +275,9 @@ enum sec_status dnskeyset_verify_rrset(s struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate, int* verified, - char* reasonbuf, size_t reasonlen); + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen); /** * verify rrset against one specific dnskey (from rrset) @@ -287,13 +290,16 @@ enum sec_status dnskeyset_verify_rrset(s * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. + * @param num_tagmatches: incremented to keep track of tag matches. * @return secure if *this* key signs any of the signatures on rrset. * unchecked on error or and bogus on bad signature. */ enum sec_status dnskey_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate); + sldns_pkt_section section, struct module_qstate* qstate, + struct val_qstate* vq, size_t* num_tagmatches); /** * verify rrset, with specific dnskey(from set), for a specific rrsig @@ -311,7 +317,7 @@ enum sec_status dnskey_verify_rrset(stru * pass false at start. pass old value only for same rrset and same * signature (but perhaps different key) for reuse. * @param reason: if bogus, a string returned, fixed or alloced in scratch. - * @param reason_bogus: EDE (8914) code paired with the reason of failure. + * @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. * @return secure if this key signs this signature. unchecked on error or Index: usr.sbin/unbound/validator/val_utils.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_utils.c,v diff -u -p -r1.17 val_utils.c --- usr.sbin/unbound/validator/val_utils.c 4 Sep 2024 09:36:41 -0000 1.17 +++ usr.sbin/unbound/validator/val_utils.c 21 Sep 2026 16:28:12 -0000 @@ -157,7 +157,7 @@ val_classify_response(uint16_t query_fla } /** Get signer name from RRSIG */ -static void +void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen) { /* RRSIG rdata is not allowed to be compressed, it is stored @@ -406,7 +406,8 @@ val_verify_rrset(struct module_env* env, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int *verified, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, int *verified, char* reasonbuf, + size_t reasonlen) { enum sec_status sec; struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> @@ -431,7 +432,8 @@ val_verify_rrset(struct module_env* env, log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname, ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class)); sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason, - reason_bogus, section, qstate, verified, reasonbuf, reasonlen); + reason_bogus, section, qstate, vq, verified, reasonbuf, + reasonlen); verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec)); regional_free_all(env->scratch); @@ -439,10 +441,15 @@ val_verify_rrset(struct module_env* env, * only improves security status * and bogus is set only once, even if we rechecked the status */ if(sec > d->security) { + int wc_expanded = 0; d->security = sec; - if(sec == sec_status_secure) + if(sec == sec_status_secure) { + uint8_t* wc = NULL; + size_t wclen = 0; d->trust = rrset_trust_validated; - else if(sec == sec_status_bogus) { + if(val_rrset_wildcard(rrset, &wc, &wclen) && wc) + wc_expanded = 1; + } else if(sec == sec_status_bogus) { size_t i; /* update ttl for rrset to fixed value. */ d->ttl = ve->bogus_ttl; @@ -455,7 +462,11 @@ val_verify_rrset(struct module_env* env, lock_basic_unlock(&ve->bogus_lock); } /* if status updated - store in cache for reuse */ - rrset_update_sec_status(env->rrset_cache, rrset, *env->now); + /* For a wildcard rrset, that is secure, do not store this + * into the cache, because it changes proofs around the + * item. */ + if(!wc_expanded) + rrset_update_sec_status(env->rrset_cache, rrset, *env->now); } return sec; @@ -466,7 +477,8 @@ val_verify_rrset_entry(struct module_env struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* verified, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen) { /* temporary dnskey rrset-key */ struct ub_packed_rrset_key dnskey; @@ -480,7 +492,8 @@ val_verify_rrset_entry(struct module_env dnskey.entry.key = &dnskey; dnskey.entry.data = kd->rrset_data; sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason, - reason_bogus, section, qstate, verified, reasonbuf, reasonlen); + reason_bogus, section, qstate, vq, verified, reasonbuf, + reasonlen); return sec; } @@ -490,13 +503,20 @@ verify_dnskeys_with_ds_rr(struct module_ struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - int *nonechecked, char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, int *nonechecked, char* reasonbuf, + size_t reasonlen, size_t* num_tagmatches, + size_t* num_tagmatches_dnskeysig) { enum sec_status sec = sec_status_bogus; size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0; num = rrset_get_count(dnskey_rrset); *nonechecked = 0; for(i=0; i MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS match attempt reached " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } /* Skip DNSKEYs that don't match the basic criteria. */ if(ds_get_key_algo(ds_rrset, ds_idx) != dnskey_get_algo(dnskey_rrset, i) @@ -509,6 +529,15 @@ verify_dnskeys_with_ds_rr(struct module_ ds_get_key_algo(ds_rrset, ds_idx), ds_get_keytag(ds_rrset, ds_idx)); + if(vq && vq->num_hash_attempts++ > env->cfg->val_hash_attempts) { + *reason = "too many hash attempts"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + verbose(VERB_ALGO, "rrset failed to verify: too many hash attempts, " + "val-hash-attempts (%d); bogus", env->cfg->val_hash_attempts); + return sec_status_bogus; + } + /* Convert the candidate DNSKEY into a hash using the * same DS hash algorithm. */ if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset, @@ -532,8 +561,14 @@ verify_dnskeys_with_ds_rr(struct module_ /* Otherwise, we have a match! Make sure that the DNSKEY * verifies *with this key* */ + if(*num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS that matched has too many DNSKEY to RRSIG tag matches " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + return sec_status_bogus; + } sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, - i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate); + i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate, + vq, num_tagmatches_dnskeysig); if(sec == sec_status_secure) { return sec; } @@ -577,14 +612,14 @@ val_verify_DNSKEY_with_DS(struct module_ struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { /* as long as this is false, we can consider this DS rrset to be * equivalent to no DS rrset. */ int has_useful_ds = 0, digest_algo, alg, has_algo_refusal = 0, nonechecked, has_checked_ds = 0; struct algo_needs needs; - size_t i, num; + size_t i, num, num_tagmatches = 0, num_tagmatches_dnskeysig = 0; enum sec_status sec; if(dnskey_rrset->rk.dname_len != ds_rrset->rk.dname_len || @@ -606,6 +641,13 @@ val_verify_DNSKEY_with_DS(struct module_ } num = rrset_get_count(ds_rrset); for(i=0; i MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS verify attempt reached " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "DS verify has too many tag matches"; + return sec_status_bogus; + } + /* Check to see if we can understand this DS. * And check it is the strongest digest */ if(!ds_digest_algo_is_supported(ds_rrset, i) || @@ -614,9 +656,16 @@ val_verify_DNSKEY_with_DS(struct module_ continue; } + if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "DS verify attempt reached " + "DNSKEY to RRSIG MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "DS verify has too many DNSKEY to RRSIG tag matches"; + return sec_status_bogus; + } sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, - ds_rrset, i, reason, reason_bogus, qstate, - &nonechecked, reasonbuf, reasonlen); + ds_rrset, i, reason, reason_bogus, qstate, vq, + &nonechecked, reasonbuf, reasonlen, &num_tagmatches, + &num_tagmatches_dnskeysig); if(sec == sec_status_insecure) { /* DNSKEY too large unsupported or algo refused by * crypto lib. */ @@ -678,12 +727,12 @@ val_verify_new_DNSKEYs(struct regional* struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { uint8_t sigalg[ALGO_NEEDS_MAX+1]; enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve, dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason, - reason_bogus, qstate, reasonbuf, reasonlen); + reason_bogus, qstate, vq, reasonbuf, reasonlen); if(sec == sec_status_secure) { return key_entry_create_rrset(region, @@ -709,14 +758,14 @@ val_verify_DNSKEY_with_TA(struct module_ struct ub_packed_rrset_key* ta_ds, struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen) + struct val_qstate* vq, char* reasonbuf, size_t reasonlen) { /* as long as this is false, we can consider this anchor to be * equivalent to no anchor. */ int has_useful_ta = 0, digest_algo = 0, alg, has_algo_refusal = 0, nonechecked, has_checked_ds = 0; struct algo_needs needs; - size_t i, num; + size_t i, num, num_tagmatches = 0, num_tagmatches_dnskeysig = 0; enum sec_status sec; if(ta_ds && (dnskey_rrset->rk.dname_len != ta_ds->rk.dname_len || @@ -752,6 +801,15 @@ val_verify_DNSKEY_with_TA(struct module_ if(ta_ds) { num = rrset_get_count(ta_ds); for(i=0; i MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "anchor DS verify attempt reached " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "anchor DS verify has too many tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } + /* Check to see if we can understand this DS. * And check it is the strongest digest */ if(!ds_digest_algo_is_supported(ta_ds, i) || @@ -759,9 +817,18 @@ val_verify_DNSKEY_with_TA(struct module_ ds_get_digest_algo(ta_ds, i) != digest_algo) continue; + if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "anchor DS verify has too many DNSKEY to RRSIG tag matches " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "anchor DS verify has too many DNSKEY to RRSIG tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, - ta_ds, i, reason, reason_bogus, qstate, &nonechecked, - reasonbuf, reasonlen); + ta_ds, i, reason, reason_bogus, qstate, vq, + &nonechecked, reasonbuf, reasonlen, &num_tagmatches, + &num_tagmatches_dnskeysig); if(sec == sec_status_insecure) { has_algo_refusal = 1; continue; @@ -804,8 +871,16 @@ val_verify_DNSKEY_with_TA(struct module_ /* we saw a useful TA */ has_useful_ta = 1; + if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) { + verbose(VERB_ALGO, "anchor DS that matched has too many DNSKEY to RRSIG tag matches " + "MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES); + *reason = "anchor DS that matched has too many DNSKEY to RRSIG tag matches"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } sec = dnskey_verify_rrset(env, ve, dnskey_rrset, - ta_dnskey, i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate); + ta_dnskey, i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate, vq, &num_tagmatches_dnskeysig); if(sec == sec_status_secure) { if(!sigalg || algo_needs_set_secure(&needs, (uint8_t)dnskey_get_algo(ta_dnskey, i))) { @@ -853,12 +928,13 @@ val_verify_new_DNSKEYs_with_ta(struct re struct ub_packed_rrset_key* ta_ds_rrset, struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, - struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) + struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf, + size_t reasonlen) { uint8_t sigalg[ALGO_NEEDS_MAX+1]; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset, - downprot?sigalg:NULL, reason, reason_bogus, qstate, + downprot?sigalg:NULL, reason, reason_bogus, qstate, vq, reasonbuf, reasonlen); if(sec == sec_status_secure) { @@ -1043,7 +1119,7 @@ val_fill_reply(struct reply_info* chase, chase->rrsets[chase->an_numrrsets++] = orig->rrsets[j]; chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i]; } - } + } /* AUTHORITY section */ for(i = (skip > orig->an_numrrsets)?skip:orig->an_numrrsets; ian_numrrsets+orig->ns_numrrsets; @@ -1066,10 +1142,10 @@ val_fill_reply(struct reply_info* chase, if(query_dname_compare(name, orig->rrsets[i]->rk.dname) == 0) chase->rrsets[chase->an_numrrsets - +orig->ns_numrrsets+chase->ar_numrrsets++] + +chase->ns_numrrsets+chase->ar_numrrsets++] = orig->rrsets[i]; } else if(rrset_has_signer(orig->rrsets[i], name, len)) { - chase->rrsets[chase->an_numrrsets+orig->ns_numrrsets+ + chase->rrsets[chase->an_numrrsets+chase->ns_numrrsets+ chase->ar_numrrsets++] = orig->rrsets[i]; } } @@ -1077,6 +1153,23 @@ val_fill_reply(struct reply_info* chase, chase->ar_numrrsets; } +void val_reply_remove_answers(struct reply_info* rep, size_t index, + size_t count) +{ + log_assert(index < rep->rrset_count); + log_assert(index < rep->an_numrrsets); + if(count == 0) + return; /* nothing to do */ + log_assert(index+(count-1) < rep->rrset_count); + log_assert(index+(count-1) < rep->an_numrrsets); + if(rep->rrset_count - (count-1) - index - 1 > 0) + memmove(rep->rrsets+index, rep->rrsets+index+(count-1)+1, + sizeof(struct ub_packed_rrset_key*)* + (rep->rrset_count - (count-1) - index - 1)); + rep->an_numrrsets -= count; + rep->rrset_count -= count; +} + void val_reply_remove_auth(struct reply_info* rep, size_t index) { log_assert(index < rep->rrset_count); @@ -1310,15 +1403,18 @@ val_find_DS(struct module_env* env, uint /* DS rrset exists. Return it to the validator immediately*/ struct ub_packed_rrset_key* copy = packed_rrset_copy_region( rrset, region, *env->now); + struct packed_rrset_data* d; lock_rw_unlock(&rrset->entry.lock); if(!copy) return NULL; + d = (struct packed_rrset_data*)copy->entry.data; msg = dns_msg_create(nm, nmlen, LDNS_RR_TYPE_DS, c, region, 1); if(!msg) return NULL; msg->rep->rrsets[0] = copy; msg->rep->rrset_count++; msg->rep->an_numrrsets++; + UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl); return msg; } /* lookup in rrset and negative cache for NSEC/NSEC3 */ @@ -1331,4 +1427,44 @@ val_find_DS(struct module_env* env, uint msg = val_neg_getmsg(env->neg_cache, &qinfo, region, env->rrset_cache, env->scratch_buffer, *env->now, 0, topname, env->cfg); return msg; +} + +int derive_cname_from_dname(struct ub_packed_rrset_key* cname, + struct ub_packed_rrset_key* dname, uint8_t* out, size_t outlen) +{ + size_t prefix_len; + uint8_t* dname_target = NULL; + size_t dname_target_len = 0; + if(!dname_strict_subdomain_c(cname->rk.dname, dname->rk.dname)) + return 0; /* Invalid: CNAME owner must be subdomain */ + get_cname_target(dname, &dname_target, &dname_target_len); + if(!dname_target || !dname_target_len) + return 0; /* DNAME malformed */ + if(cname->rk.dname_len < dname->rk.dname_len) + return 0; /* Not possible, due to subdomain, but check */ + if(cname->rk.dname_len == 0) + return 0; /* Not possible, but check */ + prefix_len = cname->rk.dname_len - dname->rk.dname_len; + if(prefix_len + dname_target_len > outlen) + return 0; /* Buffer too small */ + memmove(out, cname->rk.dname, prefix_len); + memmove(out+prefix_len, dname_target, dname_target_len); + return 1; +} + +int nsec_nextowner_subdomain(struct ub_packed_rrset_key* rrset, uint8_t* name) +{ + struct packed_rrset_data* d; + uint8_t* next; + size_t nextlen; + if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_NSEC) + return 0; + d = (struct packed_rrset_data*)rrset->entry.data; + if(!d || d->count == 0) + return 0; + next = d->rr_data[0]+2; + nextlen = dname_valid(next, d->rr_len[0]-2); + if(nextlen == 0) + return 0; /* malformed */ + return dname_subdomain_c(next, name); } Index: usr.sbin/unbound/validator/val_utils.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/val_utils.h,v diff -u -p -r1.9 val_utils.h --- usr.sbin/unbound/validator/val_utils.h 4 Sep 2024 09:36:41 -0000 1.9 +++ usr.sbin/unbound/validator/val_utils.h 21 Sep 2026 16:28:12 -0000 @@ -55,6 +55,11 @@ struct regional; struct val_anchors; struct rrset_cache; struct sock_list; +struct val_qstate; + +/** Maximum number of matches with key tag and algorithm, for DNSKEY to + * RRSIG and DS to DNSKEY. Since the number is O(N*N), there is a limit. */ +#define MAX_TAG_MATCHES 256 /** * Response classifications for the validator. The different types of proofs. @@ -124,6 +129,7 @@ void val_find_signer(enum val_classifica * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param verified: if not NULL, the number of RRSIG validations is returned. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. @@ -133,7 +139,8 @@ enum sec_status val_verify_rrset_entry(s struct val_env* ve, struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* verified, char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, int* verified, char* reasonbuf, + size_t reasonlen); /** * Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but @@ -148,6 +155,7 @@ enum sec_status val_verify_rrset_entry(s * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return: sec_status_secure if a DS matches. @@ -158,7 +166,7 @@ enum sec_status val_verify_DNSKEY_with_D struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS @@ -172,8 +180,9 @@ enum sec_status val_verify_DNSKEY_with_D * algorithm is enough. The list of signalled algorithms is returned, * must have enough space for ALGO_NEEDS_MAX+1. * @param reason: reason of failure. Fixed string or alloced in scratch. -* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. + * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return: sec_status_secure if a DS matches. @@ -185,7 +194,7 @@ enum sec_status val_verify_DNSKEY_with_T struct ub_packed_rrset_key* ta_ds, struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Verify new DNSKEYs with DS rrset. The DS contains hash values that should @@ -202,6 +211,7 @@ enum sec_status val_verify_DNSKEY_with_T * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return a KeyEntry. This will either contain the now trusted @@ -219,7 +229,7 @@ struct key_entry_key* val_verify_new_DNS struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Verify rrset with trust anchor: DS and DNSKEY rrset. @@ -235,6 +245,7 @@ struct key_entry_key* val_verify_new_DNS * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param vq: validator qstate with attempt counts. * @param reasonbuf: buffer to use for fail reason string print. * @param reasonlen: length of reasonbuf. * @return a KeyEntry. This will either contain the now trusted @@ -253,7 +264,7 @@ struct key_entry_key* val_verify_new_DNS struct ub_packed_rrset_key* ta_ds_rrset, struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - char* reasonbuf, size_t reasonlen); + struct val_qstate* vq, char* reasonbuf, size_t reasonlen); /** * Determine if DS rrset is usable for validator or not. @@ -315,6 +326,16 @@ void val_fill_reply(struct reply_info* c size_t cname_skip, uint8_t* name, size_t len, uint8_t* signer); /** + * Remove rrsets with index .. index+count from reply, from the answer section. + * @param rep: reply to remove it from. + * @param index: rrset to remove, must be in the answer section. + * @param count: number of rrsets to remove, starting from the index. + * with count=1, it removes only the index rrset. + */ +void val_reply_remove_answers(struct reply_info* rep, size_t index, + size_t count); + +/** * Remove rrset with index from reply, from the authority section. * @param rep: reply to remove it from. * @param index: rrset to remove, must be in the authority section. @@ -426,5 +447,23 @@ int val_favorite_ds_algo(struct ub_packe */ struct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t c, struct regional* region, uint8_t* topname); + +/** + * Derive expected CNAME target from DNAME substitution per RFC 6672 s3.1 + * @param cname: CNAME RRset, (e.g., b.d.a005.test CNAME 'some cname target') + * @param dname: DNAME RRset, (e.g., d.a005.test DNAME tgt.a005.test) + * @param out: Output buffer for expected CNAME target + * @param outlen: Output buffer size + * @return: 1 on success, 0 on error + */ +int derive_cname_from_dname(struct ub_packed_rrset_key* cname, + struct ub_packed_rrset_key* dname, uint8_t* out, size_t outlen); + +/** Get signer name from RRSIG, sname is NULL if malformed. */ +void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, + size_t* slen); + +/** See if the NSEC nextowner name is a subdomain of the name. */ +int nsec_nextowner_subdomain(struct ub_packed_rrset_key* rrset, uint8_t* name); #endif /* VALIDATOR_VAL_UTILS_H */ Index: usr.sbin/unbound/validator/validator.c =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/validator.c,v diff -u -p -r1.28 validator.c --- usr.sbin/unbound/validator/validator.c 26 Sep 2025 07:32:37 -0000 1.28 +++ usr.sbin/unbound/validator/validator.c 21 Sep 2026 16:28:12 -0000 @@ -68,6 +68,9 @@ #define MAX_VALIDATE_AT_ONCE 8 /** Max number of validation suspends allowed, error out otherwise. */ #define MAX_VALIDATION_SUSPENDS 16 +/** Max answer RRsets for qtype ANY that are validated. The lists is + * shortened to fit this limit. */ +#define MAX_RRSETS_ANY_VALIDATED 24 /* forward decl for cache response and normal super inform calls of a DS */ static void process_ds_response(struct module_qstate* qstate, @@ -347,13 +350,17 @@ static void val_restart(struct val_qstate* vq) { struct comm_timer* temp_timer; - int restart_count; + int restart_count, num_validation_attempts, num_hash_attempts; if(!vq) return; temp_timer = vq->suspend_timer; restart_count = vq->restart_count+1; + num_validation_attempts = vq->num_validation_attempts; + num_hash_attempts = vq->num_hash_attempts; memset(vq, 0, sizeof(*vq)); vq->suspend_timer = temp_timer; vq->restart_count = restart_count; + vq->num_validation_attempts = num_validation_attempts; + vq->num_hash_attempts = num_hash_attempts; vq->state = VAL_INIT_STATE; } @@ -452,6 +459,24 @@ already_validated(struct dns_msg* ret_ms return 0; } +/** If it is possible to restart the validation state */ +static int +val_can_restart(struct module_qstate* qstate, struct val_qstate* vq, + struct val_env* ve) +{ + /* For validation failures that are limits exceeded on the amount + * of work that the DNSSEC validator is willing to do, the restart + * is not allowed. A restart would increase the amount of effort + * spent even further. */ + if(vq->restart_count < ve->max_restart && + vq->num_validation_attempts <= qstate->env->cfg->val_validation_attempts && + vq->num_hash_attempts <= qstate->env->cfg->val_hash_attempts && + !vq->num_nsec_attempts_exceeded) + return 1; + (void)qstate; + return 0; +} + /** * Generate a request for DNS data. * @@ -496,7 +521,7 @@ generate_request(struct module_qstate* q struct mesh_state* sub = NULL; fptr_ok(fptr_whitelist_modenv_add_sub( qstate->env->add_sub)); - if(!(*qstate->env->add_sub)(qstate, &ask, + if(!(*qstate->env->add_sub)(qstate, &ask, NULL, (uint16_t)(BIT_RD|flags), 0, valrec, newq, &sub)){ log_err("Could not generate request: out of memory"); return 0; @@ -505,7 +530,7 @@ generate_request(struct module_qstate* q else { fptr_ok(fptr_whitelist_modenv_attach_sub( qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &ask, + if(!(*qstate->env->attach_sub)(qstate, &ask, NULL, (uint16_t)(BIT_RD|flags), 0, valrec, newq)){ log_err("Could not generate request: out of memory"); return 0; @@ -517,6 +542,14 @@ generate_request(struct module_qstate* q /* add our blacklist to the query blacklist */ sock_list_merge(&(*newq)->blacklist, (*newq)->region, vq->chain_blacklist); + /* start its global quota counter where this one is. */ + if(qstate->global_quota_reached > + (*newq)->global_quota_reached) { + (*newq)->global_quota_started = + qstate->global_quota_reached; + (*newq)->global_quota_reached = + qstate->global_quota_reached; + } } qstate->ext_state[id] = module_wait_subquery; return 1; @@ -710,6 +743,37 @@ validate_msg_signatures(struct module_qs ((struct packed_rrset_data*)chase_reply->rrsets[i-1]->entry.data)->security == sec_status_secure && dname_strict_subdomain_c(s->rk.dname, chase_reply->rrsets[i-1]->rk.dname) ) { + /* Check that the CNAME target matches the DNAME + * derivation. Zone changes during the redirection + * lookups or looped DNAMEs can have such a CNAME. */ + uint8_t expected_target[LDNS_MAX_DOMAINLEN]; + uint8_t* cname_target = NULL; + size_t cname_target_len = 0; + get_cname_target(s, &cname_target, &cname_target_len); + if(!cname_target || + !derive_cname_from_dname(s, /* CNAME RRset */ + chase_reply->rrsets[i-1], /* DNAME RRset */ + expected_target, /* Output buffer */ + sizeof(expected_target))) { + verbose(VERB_ALGO, "DNAME CNAME derivation failed"); + errinf_ede(qstate, "DNAME CNAME derivation failed", reason_bogus); + errinf_origin(qstate, qstate->reply_origin); + chase_reply->security = sec_status_bogus; + update_reason_bogus(chase_reply, reason_bogus); + return 0; + } + if(query_dname_compare(cname_target, expected_target) != 0) { + verbose(VERB_ALGO, "CNAME target mismatch: not synthesized from DNAME"); + errinf_ede(qstate, "CNAME target mismatch: not synthesized from DNAME", reason_bogus); + errinf_dname(qstate, ", for", s->rk.dname); + errinf_dname(qstate, "CNAME", cname_target); + errinf(qstate, ","); + errinf_origin(qstate, qstate->reply_origin); + chase_reply->security = sec_status_bogus; + update_reason_bogus(chase_reply, reason_bogus); + return 0; + } + /* CNAME was synthesized by our own iterator */ /* since the DNAME verified, mark the CNAME as secure */ ((struct packed_rrset_data*)s->entry.data)->security = @@ -721,8 +785,8 @@ validate_msg_signatures(struct module_qs /* Verify the answer rrset */ sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, - &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified, - reasonbuf, sizeof(reasonbuf)); + &reason_bogus, LDNS_SECTION_ANSWER, qstate, vq, + &verified, reasonbuf, sizeof(reasonbuf)); /* If the (answer) rrset failed to validate, then this * message is BAD. */ if(sec != sec_status_secure) { @@ -766,7 +830,7 @@ validate_msg_signatures(struct module_qs continue; s = chase_reply->rrsets[i]; sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, - &reason_bogus, LDNS_SECTION_AUTHORITY, qstate, + &reason_bogus, LDNS_SECTION_AUTHORITY, qstate, vq, &verified, reasonbuf, sizeof(reasonbuf)); /* If anything in the authority section fails to be secure, * we have a bad message. */ @@ -813,7 +877,7 @@ validate_msg_signatures(struct module_qs if(sname && query_dname_compare(sname, key_entry->name)==0) (void)val_verify_rrset_entry(env, ve, s, key_entry, &reason, NULL, LDNS_SECTION_ADDITIONAL, qstate, - &verified, reasonbuf, sizeof(reasonbuf)); + vq, &verified, reasonbuf, sizeof(reasonbuf)); /* the additional section can fail to be secure, * it is optional, check signature in case we need * to clean the additional section later. */ @@ -882,10 +946,10 @@ validate_suspend_setup_timer(struct modu 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; + /* One step of back-off after the first suspend so a single bad + * message still yields, but does not grow exponentially on its own. */ + if(vq->suspend_count > 0) + slack += 1; if(slack != 0 && slack <= 12 /* No numeric overflow. */) { usec = usec << slack; } @@ -986,6 +1050,29 @@ remove_spurious_authority(struct reply_i } /** + * Cap the number of answer RRsets for validation of type ANY. + * This limits the number of RRSIG validations performed. + * It is allowed to return a subset of available RRsets when processing + * ANY query. + * @param chase_reply: the chased reply, shorten if if too long. + * @param orig_reply: original reply, remove the records here as well, + * so it can be marked as DNSSEC valid. + * @param skip: the number of rrsets skipped in the answer section due to + * CNAME chain that is followed. + * @param max_rrsets: the number allowed. + */ +static void +shorten_answer_any(struct reply_info* chase_reply, + struct reply_info* orig_reply, size_t skip, size_t max_rrsets) +{ + if(chase_reply->an_numrrsets > max_rrsets) { + size_t to_rem = chase_reply->an_numrrsets - max_rrsets; + val_reply_remove_answers(chase_reply, max_rrsets, to_rem); + val_reply_remove_answers(orig_reply, skip+max_rrsets, to_rem); + } +} + +/** * Given a "positive" response -- a response that contains an answer to the * question, and no CNAME chain, validate this response. * @@ -1012,7 +1099,14 @@ validate_positive_response(struct module uint8_t* wc = NULL; size_t wl; int wc_cached = 0; + int wc_to_cache = 0; + uint8_t* cache_wc = NULL; + size_t cache_wl = 0; + struct ub_packed_rrset_key* cache_s = NULL; int wc_NSEC_ok = 0; + /* This is used to update the RRset cache, with the combination + * of the dname expansion and this wildcard, for security status. */ + struct ub_packed_rrset_key* wc_rrset = NULL; int nsec3s_seen = 0; size_t i; struct ub_packed_rrset_key* s; @@ -1031,14 +1125,20 @@ validate_positive_response(struct module ntohs(s->rk.type), ntohs(s->rk.rrset_class)); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } if(wc && !wc_cached && env->cfg->aggressive_nsec) { - rrset_cache_update_wildcard(env->rrset_cache, s, wc, wl, - env->alloc, *env->now); + /* Postpone cache adjust until proof has succeeded. */ + wc_to_cache = 1; + cache_wc = wc; + cache_wl = wl; + cache_s = s; wc_cached = 1; } - + if(wc) wc_rrset = s; } /* validate the AUTHORITY section as well - this will generally be @@ -1095,8 +1195,15 @@ validate_positive_response(struct module "did not exist"); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } + if(wc_to_cache) { + rrset_cache_update_wildcard(env->rrset_cache, cache_s, + cache_wc, cache_wl, env->alloc, *env->now); + } verbose(VERB_ALGO, "Successfully validated positive response"); chase_reply->security = sec_status_secure; @@ -1348,16 +1455,20 @@ validate_nameerror_response(struct modul * trusted DNSKEY rrset that signs this response must already have been * completed. * + * @param env: module env. * @param chase_reply: answer to validate. */ static void -validate_referral_response(struct reply_info* chase_reply) +validate_referral_response(struct module_env* env, struct reply_info* chase_reply) { - size_t i; + size_t i, count; enum sec_status s; /* message security equals lowest rrset security */ chase_reply->security = sec_status_secure; - for(i=0; irrset_count; i++) { + if(env->cfg->val_clean_additional) + count = chase_reply->rrset_count; + else count = chase_reply->an_numrrsets+chase_reply->ns_numrrsets; + for(i=0; irrsets[i] ->entry.data)->security; if(s < chase_reply->security) @@ -1496,6 +1607,16 @@ validate_any_response(struct module_env* "did not exist"); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + /* Make the expanded name and wildcard RRSIG rrsets bogus */ + for(i=0; ian_numrrsets; i++) { + uint8_t* cwc = NULL; + size_t cwl = 0; + s = chase_reply->rrsets[i]; + if(val_rrset_wildcard(s, &cwc, &cwl) && cwc) { + ((struct packed_rrset_data*)s-> + entry.data)->security = sec_status_bogus; + } + } return; } @@ -1533,6 +1654,9 @@ validate_cname_response(struct module_en uint8_t* wc = NULL; size_t wl; int wc_NSEC_ok = 0; + /* This is used to update the RRset cache, with the combination + * of the dname expansion and this wildcard, for security status. */ + struct ub_packed_rrset_key* wc_rrset = NULL; int nsec3s_seen = 0; size_t i; struct ub_packed_rrset_key* s; @@ -1553,6 +1677,7 @@ validate_cname_response(struct module_en update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); return; } + if(wc) wc_rrset = s; /* Refuse wildcarded DNAMEs rfc 4597. * Do not follow a wildcarded DNAME because @@ -1564,6 +1689,9 @@ validate_cname_response(struct module_en ntohs(s->rk.type), ntohs(s->rk.rrset_class)); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } @@ -1628,6 +1756,9 @@ validate_cname_response(struct module_en "did not exist"); chase_reply->security = sec_status_bogus; update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); + if(wc_rrset) + ((struct packed_rrset_data*)wc_rrset-> + entry.data)->security = sec_status_bogus; return; } @@ -2204,7 +2335,7 @@ processValidate(struct module_qstate* qs key_entry_get_reason_bogus(vq->key_entry)); errinf_ede(qstate, "while building chain of trust", key_entry_get_reason_bogus(vq->key_entry)); - if(vq->restart_count >= ve->max_restart) + if(!val_can_restart(qstate, vq, ve)) key_cache_insert(ve->kcache, vq->key_entry, qstate->env->cfg->val_log_level >= 2); return 1; @@ -2227,6 +2358,9 @@ processValidate(struct module_qstate* qs &vq->qchase, vq->orig_msg->rep, vq->rrset_skip); if(subtype != VAL_CLASS_REFERRAL) remove_spurious_authority(vq->chase_reply, vq->orig_msg->rep); + if(subtype == VAL_CLASS_ANY) + shorten_answer_any(vq->chase_reply, vq->orig_msg->rep, + vq->rrset_skip, MAX_RRSETS_ANY_VALIDATED); /* check signatures in the message; * answer and authority must be valid, additional is only checked. */ @@ -2349,7 +2483,7 @@ processValidate(struct module_qstate* qs case VAL_CLASS_REFERRAL: verbose(VERB_ALGO, "Validating a referral response"); - validate_referral_response(vq->chase_reply); + validate_referral_response(qstate->env, vq->chase_reply); verbose(VERB_DETAIL, "validate(referral): %s", sec_status_to_string( vq->chase_reply->security)); @@ -2423,15 +2557,17 @@ processFinished(struct module_qstate* qs } if(subtype == VAL_CLASS_REFERRAL) { - /* for a referral, move to next unchecked rrset and check it*/ - vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep, - vq->rrset_skip); - if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) { - /* and restart for this rrset */ - verbose(VERB_ALGO, "validator: go to next rrset"); - vq->chase_reply->security = sec_status_unchecked; - vq->state = VAL_INIT_STATE; - return 1; + if(qstate->env->cfg->val_clean_additional) { + /* for a referral, move to next unchecked rrset and check it*/ + vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep, + vq->rrset_skip); + if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) { + /* and restart for this rrset */ + verbose(VERB_ALGO, "validator: go to next rrset"); + vq->chase_reply->security = sec_status_unchecked; + vq->state = VAL_INIT_STATE; + return 1; + } } /* referral chase is done */ } @@ -2476,7 +2612,7 @@ processFinished(struct module_qstate* qs struct msgreply_entry* e; /* see if we can try again to fetch data */ - if(vq->restart_count < ve->max_restart) { + if(val_can_restart(qstate, vq, ve)) { verbose(VERB_ALGO, "validation failed, " "blacklist and retry to fetch data"); val_blacklist(&qstate->blacklist, qstate->region, @@ -2699,7 +2835,9 @@ val_operate(struct module_qstate* qstate if(!needs_validation(qstate, qstate->return_rcode, qstate->return_msg)) { /* no need to validate this */ - if(qstate->return_msg) + /* For valrec responses, leave at sec_status_unchecked, + * no security status has been requested for it. */ + if(qstate->return_msg && !qstate->is_valrec) qstate->return_msg->rep->security = sec_status_indeterminate; qstate->ext_state[id] = module_finished; @@ -2766,6 +2904,7 @@ val_operate(struct module_qstate* qstate * (this rrset is allocated in the wrong region, not the qstate). * @param ta: trust anchor. * @param qstate: qstate that needs key. + * @param vq: validator qstate. * @param id: module id. * @param sub_qstate: the sub query state, that is the lookup that fetched * the trust anchor data, it contains error information for the answer. @@ -2776,8 +2915,8 @@ val_operate(struct module_qstate* qstate */ static struct key_entry_key* primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, - struct trust_anchor* ta, struct module_qstate* qstate, int id, - struct module_qstate* sub_qstate) + struct trust_anchor* ta, struct module_qstate* qstate, + struct val_qstate* vq, int id, struct module_qstate* sub_qstate) { struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; struct key_entry_key* kkey = NULL; @@ -2817,7 +2956,8 @@ primeResponseToKE(struct ub_packed_rrset /* attempt to verify with trust anchor DS and DNSKEY */ kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve, dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot, - &reason, &reason_bogus, qstate, reasonbuf, sizeof(reasonbuf)); + &reason, &reason_bogus, qstate, vq, reasonbuf, + sizeof(reasonbuf)); if(!kkey) { log_err("out of memory: verifying prime TA"); return NULL; @@ -2930,7 +3070,7 @@ ds_response_to_ke(struct module_qstate* * bogus, then we are done. */ sec = val_verify_rrset_entry(qstate->env, ve, ds, vq->key_entry, &reason, &reason_bogus, - LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf, + LDNS_SECTION_ANSWER, qstate, vq, &verified, reasonbuf, sizeof(reasonbuf)); if(sec != sec_status_secure) { verbose(VERB_DETAIL, "DS rrset in DS response did " @@ -2981,7 +3121,7 @@ ds_response_to_ke(struct module_qstate* /* Try to prove absence of the DS with NSEC */ sec = val_nsec_prove_nodata_dsreply( qstate->env, ve, qinfo, msg->rep, vq->key_entry, - &proof_ttl, &reason, &reason_bogus, qstate, + &proof_ttl, &reason, &reason_bogus, qstate, vq, reasonbuf, sizeof(reasonbuf)); switch(sec) { case sec_status_secure: @@ -3019,7 +3159,7 @@ ds_response_to_ke(struct module_qstate* sec = nsec3_prove_nods(qstate->env, ve, msg->rep->rrsets + msg->rep->an_numrrsets, msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason, - &reason_bogus, qstate, &vq->nsec3_cache_table, + &reason_bogus, qstate, vq, &vq->nsec3_cache_table, reasonbuf, sizeof(reasonbuf)); switch(sec) { case sec_status_insecure: @@ -3087,9 +3227,65 @@ ds_response_to_ke(struct module_qstate* } sec = val_verify_rrset_entry(qstate->env, ve, cname, vq->key_entry, &reason, &reason_bogus, - LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf, + LDNS_SECTION_ANSWER, qstate, vq, &verified, reasonbuf, sizeof(reasonbuf)); if(sec == sec_status_secure) { + /* Check for wildcard expansion */ + uint8_t* wc = NULL; + size_t wl = 0; + + if(!val_rrset_wildcard(cname, &wc, &wl)) { + verbose(VERB_ALGO, "CNAME has inconsistent wildcard signatures"); + reason = "wildcard CNAME inconsistent signatures"; + errinf_ede(qstate, reason, reason_bogus); + goto return_bogus; + } + + if(wc != NULL) { + /* Wildcard expansion detected - require NSEC proof */ + /* So this is a wildcard CNAME response to DS. + * If the wildcard is bogus then we have bogus. + * If the wildcard is true, then there is + * not a referral point here or lower, + * that can be insecure, + * and also no DS records, here or lower. */ + /* For a valid chain, to DS, but this + * wildcard CNAME happens in a middle label, + * then that can not happen, because there is + * data under that label, and thus the wildcard + * should not expand. + * If we are going to the wildcard, that also + * does not expand the wildcard, when above it. + * So for valids lookup chains to DS, no + * wildcard CNAME is expected on middle labels. + * For lookups to an insecure point, the + * delegation is information under the label, + * and thus the wildcard does not expand. + * So, no insecure point is possible. + * Can not get a valid chain of trust, or + * to a delegation point for insecure. + * Or the wildcard, its nxdomain for the qname + * proof, is invalid, in which case this is + * a bogus reply. + * If this was a lookup where a wildcard + * expansion is genuinely expected, eg, + * a dnssec valid wildcard query, then the + * lookup should go to the right point, and + * not into the wildcard under the zone name. + * For insecure, or wildcard missing + * signatures, it would have to have found + * the DS or insecure point earlier, in the + * downwards search. + * So for missing signatures, it turns the + * missing signatures into a failure to the + * wildcard CNAME, as the reported log. + */ + verbose(VERB_ALGO, "wildcard CNAME in chain of trust means no DS can be found and it is also not a delegation point that can be insecure"); + reason = "wildcard CNAME in chain of trust means no DS found and it is also not a delegation point that can be insecure"; + errinf_ede(qstate, reason, reason_bogus); + goto return_bogus; + } + verbose(VERB_ALGO, "CNAME validated, " "proof that DS does not exist"); /* and that it is not a referral point */ @@ -3152,6 +3348,7 @@ process_ds_response(struct module_qstate uint8_t* olds = vq->empty_DS_name; int ret; *suspend = 0; + vq->num_nsec_attempts = 0; vq->empty_DS_name = NULL; if(sub_qstate && sub_qstate->rpz_applied) { verbose(VERB_ALGO, "rpz was applied to the DS lookup, " @@ -3163,6 +3360,8 @@ process_ds_response(struct module_qstate } ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske, sub_qstate); + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; if(ret != 0) { switch(ret) { case 1: @@ -3204,7 +3403,7 @@ process_ds_response(struct module_qstate vq->chain_blacklist = NULL; /* fresh blacklist for next part*/ /* Keep the forState.state on FINDKEY. */ } else if(key_entry_isbad(dske) - && vq->restart_count < ve->max_restart) { + && val_can_restart(qstate, vq, ve)) { vq->empty_DS_name = olds; val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3254,6 +3453,7 @@ process_dnskey_response(struct module_qs char* reason = NULL; sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + vq->num_nsec_attempts = 0; if(sub_qstate && sub_qstate->rpz_applied) { verbose(VERB_ALGO, "rpz was applied to the DNSKEY lookup, " "make it insecure"); @@ -3273,7 +3473,7 @@ process_dnskey_response(struct module_qs verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to " "DNSKEY query."); - if(vq->restart_count < ve->max_restart) { + if(val_can_restart(qstate, vq, ve)) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3310,7 +3510,9 @@ process_dnskey_response(struct module_qs downprot = qstate->env->cfg->harden_algo_downgrade; vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env, ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, - qstate, reasonbuf, sizeof(reasonbuf)); + qstate, vq, reasonbuf, sizeof(reasonbuf)); + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; if(!vq->key_entry) { log_err("out of memory in verify new DNSKEYs"); @@ -3321,7 +3523,7 @@ process_dnskey_response(struct module_qs * state. */ if(!key_entry_isgood(vq->key_entry)) { if(key_entry_isbad(vq->key_entry)) { - if(vq->restart_count < ve->max_restart) { + if(val_can_restart(qstate, vq, ve)) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3373,6 +3575,7 @@ process_prime_response(struct module_qst struct trust_anchor* ta = anchor_find(qstate->env->anchors, vq->trust_anchor_name, vq->trust_anchor_labs, vq->trust_anchor_len, vq->qchase.qclass); + vq->num_nsec_attempts = 0; if(!ta) { /* trust anchor revoked, restart with less anchors */ vq->state = VAL_INIT_STATE; @@ -3391,19 +3594,23 @@ process_prime_response(struct module_qst if(ta->autr) { if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset, - qstate)) { + qstate, vq)) { + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; /* trust anchor revoked, restart with less anchors */ vq->state = VAL_INIT_STATE; vq->trust_anchor_name = NULL; return; } } - vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id, + vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, vq, id, sub_qstate); lock_basic_unlock(&ta->lock); + /* New NSEC attempt count for next message validation. */ + vq->num_nsec_attempts = 0; if(vq->key_entry) { if(key_entry_isbad(vq->key_entry) - && vq->restart_count < ve->max_restart) { + && val_can_restart(qstate, vq, ve)) { val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); qstate->errinf = NULL; @@ -3446,6 +3653,11 @@ val_inform_super(struct module_qstate* q if(!vq) { verbose(VERB_ALGO, "super: has no validator state"); return; + } + /* Pick up the global quota limit from the subquery. */ + if(qstate->global_quota_reached > qstate->global_quota_started) { + super->global_quota_reached += qstate->global_quota_reached - + qstate->global_quota_started; } if(vq->wait_prime_ta) { vq->wait_prime_ta = 0; Index: usr.sbin/unbound/validator/validator.h =================================================================== RCS file: /cvs/src/usr.sbin/unbound/validator/validator.h,v diff -u -p -r1.11 validator.h --- usr.sbin/unbound/validator/validator.h 31 Aug 2025 21:41:10 -0000 1.11 +++ usr.sbin/unbound/validator/validator.h 21 Sep 2026 16:28:12 -0000 @@ -231,6 +231,19 @@ struct val_qstate { struct comm_timer* suspend_timer; /** Number of suspends */ int suspend_count; + + /** Number of DNSKEY RRSIG validation attempts. This is the number of + * cryptographic operations done for the mesh state. */ + int num_validation_attempts; + /** Number of DS hash verification attempts. This is the number of + * hash operations done for the mesh state. + * It does not count NSEC3 hashes. */ + int num_hash_attempts; + /** Number of NSEC validations. And NSEC3 too. This is reset per + * answer. */ + int num_nsec_attempts; + /** The nsec attempts have been exceeded. */ + int num_nsec_attempts_exceeded; }; /**