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;
 }