BUG/MEDIUM: dns: Don't yield in do-resolve action on a final evaluation
When an action is evaluated, flags are passed to know if it is the first call
(ACT_OPT_FIRST) and if it must be the last one (ACT_OPT_FINAL). For the
do-resolve DNS action, the ACT_OPT_FINAL flag must be handled because the
action may yield. It must never yield when this flag is set. Otherwise, it may
lead to a wakeup loop of the stream because the inspected-delay of a tcp-request
content ruleset was reached without stopping the rules evaluation.
This patch is related to the issue #222. It must be backported as far as 2.0.
(cherry picked from commit 385101e53816dc1b7bc1fc957adc512ce8a07cb4)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 5c038f759959adf95b4b347aba9d97e60ab87e93)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit af018c4865400dda4553a732df4c43751a4ff88c)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/dns.c b/src/dns.c
index 18e64d9..095040e 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -2182,10 +2182,8 @@
locked = 1;
}
- if (resolution->step == RSLV_STEP_RUNNING) {
- ret = ACT_RET_YIELD;
- goto end;
- }
+ if (resolution->step == RSLV_STEP_RUNNING)
+ goto yield;
if (resolution->step == RSLV_STEP_NONE) {
/* We update the variable only if we have a valid response. */
if (resolution->status == RSLV_STATUS_VALID) {
@@ -2219,14 +2217,7 @@
}
}
- free(s->dns_ctx.hostname_dn); s->dns_ctx.hostname_dn = NULL;
- s->dns_ctx.hostname_dn_len = 0;
- dns_unlink_resolution(s->dns_ctx.dns_requester);
-
- pool_free(dns_requester_pool, s->dns_ctx.dns_requester);
- s->dns_ctx.dns_requester = NULL;
-
- goto end;
+ goto release_requester;
}
/* need to configure and start a new DNS resolution */
@@ -2247,26 +2238,38 @@
/* Check if there is a fresh enough response in the cache of our associated resolution */
req = s->dns_ctx.dns_requester;
- if (!req || !req->resolution) {
- dns_trigger_resolution(s->dns_ctx.dns_requester);
- ret = ACT_RET_YIELD;
- goto end;
- }
+ if (!req || !req->resolution)
+ goto release_requester; /* on error, ignore the action */
res = req->resolution;
exp = tick_add(res->last_resolution, resolvers->hold.valid);
if (resolvers->t && res->status == RSLV_STATUS_VALID && tick_isset(res->last_resolution)
- && !tick_is_expired(exp, now_ms)) {
+ && !tick_is_expired(exp, now_ms)) {
goto use_cache;
}
dns_trigger_resolution(s->dns_ctx.dns_requester);
+
+ yield:
+ if (flags & ACT_FLAG_FINAL)
+ goto release_requester;
ret = ACT_RET_YIELD;
end:
if (locked)
HA_SPIN_UNLOCK(DNS_LOCK, &resolvers->lock);
return ret;
+
+ release_requester:
+ free(s->dns_ctx.hostname_dn);
+ s->dns_ctx.hostname_dn = NULL;
+ s->dns_ctx.hostname_dn_len = 0;
+ if (s->dns_ctx.dns_requester) {
+ dns_unlink_resolution(s->dns_ctx.dns_requester);
+ pool_free(dns_requester_pool, s->dns_ctx.dns_requester);
+ s->dns_ctx.dns_requester = NULL;
+ }
+ goto end;
}