Blob Blame History Raw
From 7b952299ea7dbe17289d5f34d5c2867a8077fb19 Mon Sep 17 00:00:00 2001
From: Ryan O'Hara <rohara@redhat.com>
Date: Thu, 28 Feb 2019 08:22:45 -0600
Subject: [PATCH] BUG/MEDIUM: tcp-check: single connect rule can't detect DOWN
 servers

When tcpcheck is used to do TCP port monitoring only and the script is
composed by a single "tcp-check connect" rule (whatever port and ssl
options enabled), then the server can't be seen as DOWN.
Simple configuration to reproduce:

  backend b
    [...]
    option tcp-check
    tcp-check connect
    server s1 127.0.0.1:22 check

The main reason for this issue is that the piece of code which validates
that we're not at the end of the chained list (of rules) prevents
executing the validation of the establishment of the TCP connection.
Since validation is not executed, the rule is terminated and the report
says no errors were encountered, hence the server is UP all the time.

The workaround is simple: move the connection validation outsied the
CONNECT rule processing loop, into the main function.
That way, if the connection status is not CONNECTED, then HAProxy will
now add more time to wait for it. If the time is expired, an error is
now well reported.
---
 src/checks.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/checks.c b/src/checks.c
index 27a23b21..f280367b 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -2246,6 +2246,25 @@ static void tcpcheck_main(struct connection *conn)
 		} /* end expect */
 	} /* end loop over double chained step list */
 
+	/* don't do anything until the connection is established */
+	if (!(conn->flags & CO_FL_CONNECTED)) {
+		/* update expire time, should be done by process_chk */
+		/* we allow up to min(inter, timeout.connect) for a connection
+		 * to establish but only when timeout.check is set
+		 * as it may be to short for a full check otherwise
+		 */
+                while (tick_is_expired(t->expire, now_ms)) {
+                        int t_con;
+
+                        t_con = tick_add(t->expire, s->proxy->timeout.connect);
+                        t->expire = tick_add(t->expire, MS_TO_TICKS(check->inter));
+
+                        if (s->proxy->timeout.check)
+                                t->expire = tick_first(t->expire, t_con);
+                }
+		return;
+        }
+
 	/* We're waiting for some I/O to complete, we've reached the end of the
 	 * rules, or both. Do what we have to do, otherwise we're done.
 	 */
-- 
2.20.1