BUG/MEDIUM: tcp-checks: disable quick-ack unless next rule is an expect
Using "option tcp-checks" without any rule is different from not using
it at all in that checks are sent with the TCP quick ack mode enabled,
causing servers to log incoming port probes.
This commit fixes this behaviour by disabling quick-ack on tcp-checks
unless the next rule exists and is an expect. All combinations were
tested and now the behaviour is as expected : basic port probes are
now doing a SYN-SYN/ACK-RST sequence.
This fix must be backported to 1.5.
(cherry picked from commit f3d3482c984593b21a6d3de6d66a83a338316b85)
diff --git a/src/checks.c b/src/checks.c
index 50c8559..f6afe42 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1381,6 +1381,7 @@
struct connection *conn = check->conn;
struct protocol *proto;
int ret;
+ int quickack;
/* tcpcheck send/expect initialisation */
if (check->type == PR_O2_TCPCHK_CHK)
@@ -1436,6 +1437,9 @@
set_host_port(&conn->addr.to, check->port);
}
+ /* only plain tcp-check supports quick ACK */
+ quickack = check->type == 0 || check->type == PR_O2_TCPCHK_CHK;
+
if (check->type == PR_O2_TCPCHK_CHK && !LIST_ISEMPTY(&s->proxy->tcpcheck_rules)) {
struct tcpcheck_rule *r = (struct tcpcheck_rule *) s->proxy->tcpcheck_rules.n;
/* if first step is a 'connect', then tcpcheck_main must run it */
@@ -1443,11 +1447,13 @@
tcpcheck_main(conn);
return SN_ERR_UP;
}
+ if (r->action == TCPCHK_ACT_EXPECT)
+ quickack = 0;
}
ret = SN_ERR_INTERNAL;
if (proto->connect)
- ret = proto->connect(conn, check->type, (check->type) ? 0 : 2);
+ ret = proto->connect(conn, check->type, quickack ? 2 : 0);
conn->flags |= CO_FL_WAKE_DATA;
if (s->check.send_proxy) {
conn->send_proxy_ofs = 1;
@@ -1850,7 +1856,7 @@
static void tcpcheck_main(struct connection *conn)
{
char *contentptr;
- struct tcpcheck_rule *cur = NULL;
+ struct tcpcheck_rule *cur, *next;
int done = 0, ret = 0;
struct check *check = conn->owner;
struct server *s = check->server;
@@ -1946,6 +1952,11 @@
break;
}
+ /* have 'next' point to the next rule or NULL if we're on the last one */
+ next = (struct tcpcheck_rule *)cur->list.n;
+ if (&next->list == head)
+ next = NULL;
+
if (check->current_step->action == TCPCHK_ACT_CONNECT) {
struct protocol *proto;
struct xprt_ops *xprt;
@@ -1995,7 +2006,9 @@
ret = SN_ERR_INTERNAL;
if (proto->connect)
- ret = proto->connect(conn, 1, 0);
+ ret = proto->connect(conn,
+ 1 /* I/O polling is always needed */,
+ (next && next->action == TCPCHK_ACT_EXPECT) ? 0 : 2);
conn->flags |= CO_FL_WAKE_DATA;
if (check->current_step->conn_opts & TCPCHK_OPT_SEND_PROXY) {
conn->send_proxy_ofs = 1;