]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix that the ratelimit is decremented on successful
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 27 May 2026 10:16:23 +0000 (12:16 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 27 May 2026 10:16:23 +0000 (12:16 +0200)
  referrals. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.

16 files changed:
daemon/worker.c
dnstap/unbound-dnstap-socket.c
doc/Changelog
iterator/iterator.c
iterator/iterator.h
libunbound/libworker.c
libunbound/worker.h
pythonmod/interface.i
services/outside_network.c
services/outside_network.h
smallapp/worker_cb.c
testcode/doqclient.c
testcode/fake_event.c
util/fptr_wlist.c
util/fptr_wlist.h
util/module.h

index a5dd9bc028e8290636ebdbd57ce11b47dd054429..8c695e1dc823e7a831fd80efc8f2d069aa45b755 100644 (file)
@@ -2535,7 +2535,8 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
        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(
@@ -2547,7 +2548,7 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
                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;
        }
@@ -2596,7 +2597,8 @@ struct outbound_entry* libworker_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 90b0f6003ff6416bcbc5406166191d218d454966..d6d5e2a7e800df9c79bf9a9d8572240cc835c82b 100644 (file)
@@ -1659,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;
@@ -1693,7 +1694,8 @@ struct outbound_entry* libworker_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;
index 5e398a34f199c53dc41b62d6511b4dbf57f561a6..186a5cd8d48cd4361ec2ee45326b85d4bdcbbe43 100644 (file)
@@ -4,6 +4,9 @@
          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.
 
 26 May 2026: Wouter
        - Fix for mesh new client and mesh new callback to rollback the
index ae54da0d97eebe681f616388a4ac142b8cef4cea..25b4401bfb8b4b12a47e64d2dd24810f58a23e4d 100644 (file)
@@ -3054,7 +3054,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
 
        /* 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);
@@ -3080,7 +3082,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                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);
@@ -3439,6 +3442,12 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                iq->deleg_msg = iq->response;
                /* Keep current delegation point for label comparison */
                old_dp = iq->dp;
+               /* 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);
                if (qstate->env->cfg->qname_minimisation)
                        iq->minimisation_state = INIT_MINIMISE_STATE;
index 87e54d41e7cd88fd142d4562bca4c6aab171ba42..df5449c5253380ba346e1dac101f3138405f033a 100644 (file)
@@ -380,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.
index 6e7244c03fee5ea2f8b6aa39c1e1ab141bf686bd..c8692ba26d765fe0486dfbdc8fab42fa9d3973c5 100644 (file)
@@ -879,7 +879,8 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
        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 +892,7 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
                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 +977,8 @@ struct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
        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 0fa5bfa99430528c50393bdd5a67ba01e1b0614c..9ca4b2d96f6fe1a9e2b38d4677f7580d9088f23e 100644 (file)
@@ -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_query(struct query_info* qinfo,
        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* arg);
  * @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(struct query_info* qinfo,
        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 
index 7ac868df5002ef5bcb779c9c50f0a8bae07219e2..735f2ed50ea0f95d5a3e0862797843e760f38c81 100644 (file)
@@ -729,7 +729,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);
     void (*detach_subs)(struct module_qstate* qstate);
     int (*attach_sub)(struct module_qstate* qstate,
         struct query_info* qinfo, struct respip_client_info* cinfo,
index be65c6114b276796817fc8ab0b89ca2d86d7900b..38598ed48b9f2ccc7fdc6156df1a58f23c1b327a 100644 (file)
@@ -3490,7 +3490,8 @@ outnet_serviced_query(struct outside_network* outnet,
        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;
@@ -3562,6 +3563,7 @@ outnet_serviced_query(struct outside_network* outnet,
                                        "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,
index 390d4befef8438f9e6b2de769d33f12d416f1d17..a2dd2c6d665a666caa7d783ee33cb3e455134c85 100644 (file)
@@ -660,6 +660,8 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
  * @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.
  */
@@ -669,7 +671,8 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
        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.
index 92ebe386d2697d52806d89534660f676fc8f2c00..9807aac8ef3f0d13804f0c72be3609f1e7aa7adf 100644 (file)
@@ -102,7 +102,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;
@@ -136,7 +136,7 @@ struct outbound_entry* libworker_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;
index 8a34ca31b122da33da16c2707f77348fb4dee881..11064e486a1a2da60533025c13594bdf265178b7 100644 (file)
@@ -2595,7 +2595,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 +2630,8 @@ struct outbound_entry* libworker_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;
index ce439edd1294a1fb998a1aefbcfff1ffb471db75..b457ba42e4e0dd7355ce1d284ae07f60eb08d849 100644 (file)
@@ -1275,7 +1275,8 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
        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,
index a451340650ab98cb58350bb0f5828b414ea02dd4..18a2fc11bb30431c56fd2903c38b59018644c73d 100644 (file)
@@ -362,7 +362,7 @@ fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
        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;
index a1a75625d59092fea0df452a47d790711755d846..f76d2c3a30e95b3f812e173eb15ad71dc06e46f3 100644 (file)
@@ -214,7 +214,7 @@ int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
        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.
index a6fa6be9062ac81db702290887e7e3ed78d460a2..631eb530bbf03025534626140576bd384efedca6 100644 (file)
@@ -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.