]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: dns: add tempo between 2 connection attempts for dns servers
authorAurelien DARRAGON <adarragon@haproxy.com>
Tue, 29 Apr 2025 18:13:00 +0000 (20:13 +0200)
committerAurelien DARRAGON <adarragon@haproxy.com>
Tue, 29 Apr 2025 19:20:11 +0000 (21:20 +0200)
As reported by Lukas Tribus on the mailing list [1], trying to connect to
a nameserver with invalid network settings causes haproxy to retry a new
connection attempt immediately which eventually causes unexpected CPU usage
on the thread responsible for the applet (namely 100% on one CPU will be
observed).

This can be reproduced with the test config below:

 resolvers default
  nameserver ns1 tcp4@8.8.8.8:53 source 192.168.99.99
 listen listen
  mode http
  bind :8080
  server s1 www.google.com resolvers default init-addr none

To fix this the issue, we add a temporisation of one second between a new
connection attempt is retried. We do this in dns_session_create() when we
know that the applet was created in the release callback (when previous
query attempt was unsuccessful), which means initial connection is not
affected.

[1]: https://www.mail-archive.com/haproxy@formilux.org/msg45665.html

This should fix GH #2909 and may be backported to all stable versions.
This patch depends on ("MINOR: applet: add appctx_schedule() macro")

src/dns.c

index 14c811a10860c51820cf460517011f84612f9952..ce7c9a28be42992e64089f20b4f9d636cf16118c 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -806,7 +806,7 @@ void dns_session_free(struct dns_session *ds)
        pool_free(dns_session_pool, ds);
 }
 
-static struct appctx *dns_session_create(struct dns_session *ds);
+static struct appctx *dns_session_create(struct dns_session *ds, int tempo);
 
 static int dns_session_init(struct appctx *appctx)
 {
@@ -912,7 +912,7 @@ static void dns_session_release(struct appctx *appctx)
 
        /* Create a new appctx, We hope we can
         * create from the release callback! */
-       ds->appctx = dns_session_create(ds);
+       ds->appctx = dns_session_create(ds, 1);
        if (!ds->appctx) {
                dns_session_free(ds);
                HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock);
@@ -937,8 +937,10 @@ static struct applet dns_session_applet = {
 /*
  * Function used to create an appctx for a DNS session
  * It sets its context into appctx->svcctx.
+ * if <tempo> is set, then the session startup will be delayed by 1
+ * second
  */
-static struct appctx *dns_session_create(struct dns_session *ds)
+static struct appctx *dns_session_create(struct dns_session *ds, int tempo)
 {
        struct appctx *appctx;
 
@@ -947,10 +949,14 @@ static struct appctx *dns_session_create(struct dns_session *ds)
                goto out_close;
        appctx->svcctx = (void *)ds;
 
-       if (appctx_init(appctx) == -1) {
-               ha_alert("out of memory in dns_session_create().\n");
-               goto out_free_appctx;
+       if (!tempo) {
+               if (appctx_init(appctx) == -1) {
+                       ha_alert("out of memory in dns_session_create().\n");
+                       goto out_free_appctx;
+               }
        }
+       else
+               appctx_schedule(appctx, tick_add(now_ms, MS_TO_TICKS(1000)));
 
        return appctx;
 
@@ -1072,7 +1078,7 @@ struct dns_session *dns_session_new(struct dns_stream_server *dss)
        ds->task_exp->process = dns_process_query_exp;
        ds->task_exp->context = ds;
 
-       ds->appctx = dns_session_create(ds);
+       ds->appctx = dns_session_create(ds, 0);
        if (!ds->appctx)
                goto error;