From: W.C.A. Wijngaards Date: Wed, 15 Oct 2025 09:04:22 +0000 (+0200) Subject: - Fix to drop UDP for discard-timeout, but not stream connections. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=735c96aac783e8bb92bffae9627db1f1e9702711;p=thirdparty%2Funbound.git - Fix to drop UDP for discard-timeout, but not stream connections. --- diff --git a/doc/Changelog b/doc/Changelog index 9e7bd3323..7913a457b 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +15 October 2025: Wouter + - Fix to drop UDP for discard-timeout, but not stream connections. + 10 October 2025: Wouter - Fix #1358 Enabling FIPS in OpenSSL causes unit test to fail. diff --git a/doc/unbound.conf.rst b/doc/unbound.conf.rst index ec40136e0..4c85f5a04 100644 --- a/doc/unbound.conf.rst +++ b/doc/unbound.conf.rst @@ -496,6 +496,9 @@ These options are part of the **server:** clause. 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. diff --git a/services/mesh.c b/services/mesh.c index 40e68b70f..e78dc5e42 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -1728,28 +1728,37 @@ void mesh_query_done(struct mesh_state* mstate) 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; + 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 */ + /* 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; + } } i++;