- Fix that the ratelimit is decremented on successful

referrals. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.
This commit is contained in:
W.C.A. Wijngaards
2026-05-27 12:16:23 +02:00
parent a23f95f620
commit 758c649611
16 changed files with 63 additions and 23 deletions
+5 -3
View 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;
+4 -2
View 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;
+3
View 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
+11 -2
View 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;
+4
View 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.
+5 -3
View 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;
+8 -2
View 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
+2 -1
View 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,
+3 -1
View 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,
+4 -1
View 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.
+2 -2
View 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;
+4 -2
View 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;
+2 -1
View 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,
+1 -1
View 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;
+1 -1
View 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.
+4 -1
View 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.