MEDIUM: checks: Add implicit tcp-check connect rule
After the configuration parsing, when its validity check, an implicit tcp-check
connect rule is added in front of the tcp-check ruleset if the first non-comment
rule is not a connect one. This implicit rule is flagged to use the default
check parameter.
This means now, all tcp-check rulesets begin with a connect and are never
empty. When tcp-check healthchecks are used, all connections are thus handled by
tcpcheck_main() function.
diff --git a/include/types/checks.h b/include/types/checks.h
index 2fc8012..521dca8 100644
--- a/include/types/checks.h
+++ b/include/types/checks.h
@@ -211,10 +211,11 @@
unsigned char lr[HANA_OBS_SIZE]; /* result for l4/l7: 0 = ignore, 1 - error, 2 - OK */
};
-#define TCPCHK_OPT_NONE 0x0000 /* no options specified, default */
-#define TCPCHK_OPT_SEND_PROXY 0x0001 /* send proxy-protocol string */
-#define TCPCHK_OPT_SSL 0x0002 /* SSL connection */
-#define TCPCHK_OPT_LINGER 0x0004 /* Do not RST connection, let it linger */
+#define TCPCHK_OPT_NONE 0x0000 /* no options specified, default */
+#define TCPCHK_OPT_SEND_PROXY 0x0001 /* send proxy-protocol string */
+#define TCPCHK_OPT_SSL 0x0002 /* SSL connection */
+#define TCPCHK_OPT_LINGER 0x0004 /* Do not RST connection, let it linger */
+#define TCPCHK_OPT_DEFAULT_CONNECT 0x0008 /* Do a connect using server params */
struct tcpcheck_connect {
uint16_t port; /* port to connect to */
diff --git a/src/checks.c b/src/checks.c
index 36283b6..2feb011 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1604,7 +1604,6 @@
struct conn_stream *cs = check->cs;
struct connection *conn = cs_conn(cs);
struct protocol *proto;
- struct tcpcheck_rule *tcp_rule = NULL;
int ret;
int connflags = 0;
@@ -1612,12 +1611,6 @@
if (conn)
return SF_ERR_INTERNAL;
- /* tcpcheck send/expect initialisation */
- if (check->type == PR_O2_TCPCHK_CHK) {
- check->current_step = check->last_started_step = NULL;
- tcp_rule = get_first_tcpcheck_rule(check->tcpcheck_rules);
- }
-
/* prepare the check buffer.
* This should not be used if check is the secondary agent check
* of a server as s->proxy->check_req will relate to the
@@ -1671,7 +1664,9 @@
/* for tcp-checks, the initial connection setup is handled separately as
* it may be sent to a specific port and not to the server's.
*/
- if (tcp_rule && tcp_rule->action == TCPCHK_ACT_CONNECT) {
+ if (check->type == PR_O2_TCPCHK_CHK) {
+ /* tcpcheck initialisation */
+ check->current_step = check->last_started_step = NULL;
tcpcheck_main(check);
return SF_ERR_UP;
}
@@ -1723,12 +1718,8 @@
return SF_ERR_RESOURCE;
cs_attach(cs, check, &check_conn_cb);
- /* only plain tcp-check supports quick ACK */
- if (check->type != 0)
- connflags |= CONNECT_HAS_DATA;
- if ((check->type == 0 || check->type == PR_O2_TCPCHK_CHK) &&
- (!tcp_rule || tcp_rule->action != TCPCHK_ACT_EXPECT))
- connflags |= CONNECT_DELACK_ALWAYS;
+ /* only plain tcp check supports quick ACK */
+ connflags |= (check->type ? CONNECT_HAS_DATA : CONNECT_DELACK_ALWAYS);
ret = SF_ERR_INTERNAL;
if (proto && proto->connect)
@@ -2738,6 +2729,12 @@
if (!check->last_started_step)
return 1;
+ /* last step is the first implicit connect */
+ if (check->last_started_step->index == 0 &&
+ check->last_started_step->action == TCPCHK_ACT_CONNECT &&
+ (check->last_started_step->connect.options & TCPCHK_OPT_DEFAULT_CONNECT))
+ return 0;
+
return check->last_started_step->index + 1;
}
@@ -2957,38 +2954,31 @@
goto fail_check;
}
- if (is_addr(&check->addr)) {
- /* we'll connect to the check addr specified on the server */
- *conn->dst = check->addr;
- }
- else {
- /* we'll connect to the addr on the server */
- *conn->dst = s->addr;
- }
+ /* connect to the check addr if specified on the
+ * server. otherwise, use the server addr
+ */
+ *conn->dst = (is_addr(&check->addr) ? check->addr : s->addr);
proto = protocol_by_family(conn->dst->ss_family);
- /* port */
if (connect->port)
set_host_port(conn->dst, connect->port);
else if (check->port)
set_host_port(conn->dst, check->port);
- else if (s->svc_port)
- set_host_port(conn->dst, s->svc_port);
-
- if (connect->options & TCPCHK_OPT_SSL) {
- xprt = xprt_get(XPRT_SSL);
- }
else {
- xprt = xprt_get(XPRT_RAW);
+ int i = get_host_port(&check->addr);
+
+ set_host_port(conn->dst, ((i > 0) ? i : s->svc_port));
}
- conn_prepare(conn, proto, xprt);
+ xprt = ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT)
+ ? check->xprt
+ : ((connect->options & TCPCHK_OPT_SSL) ? xprt_get(XPRT_SSL) : xprt_get(XPRT_RAW)));
+ conn_prepare(conn, proto, xprt);
if (conn_install_mux(conn, &mux_pt_ops, cs, proxy, NULL) < 0) {
ret = SF_ERR_RESOURCE;
goto fail_check;
}
-
cs_attach(cs, check, &check_conn_cb);
ret = SF_ERR_INTERNAL;
@@ -3000,18 +2990,42 @@
flags |= CONNECT_DELACK_ALWAYS;
ret = proto->connect(conn, flags);
}
- if (conn_ctrl_ready(conn) &&
- connect->options & TCPCHK_OPT_SEND_PROXY) {
- conn->send_proxy_ofs = 1;
- conn->flags |= CO_FL_SEND_PROXY;
- if (xprt_add_hs(conn) < 0)
- ret = SF_ERR_RESOURCE;
+
+ if (connect->options & TCPCHK_OPT_DEFAULT_CONNECT) {
+#ifdef USE_OPENSSL
+ if (ret == SF_ERR_NONE) {
+ if (s->check.sni)
+ ssl_sock_set_servername(conn, s->check.sni);
+ if (s->check.alpn_str)
+ ssl_sock_set_alpn(conn, (unsigned char *)s->check.alpn_str,
+ s->check.alpn_len);
+ }
+#endif
+ if (s->check.via_socks4 && (s->flags & SRV_F_SOCKS4_PROXY)) {
+ conn->send_proxy_ofs = 1;
+ conn->flags |= CO_FL_SOCKS4;
+ }
+ if (s->check.send_proxy && !(check->state & CHK_ST_AGENT)) {
+ conn->send_proxy_ofs = 1;
+ conn->flags |= CO_FL_SEND_PROXY;
+ }
+ }
+ else {
+ /* TODO: add sock4 and sni option */
+ if (connect->options & TCPCHK_OPT_SEND_PROXY) {
+ conn->send_proxy_ofs = 1;
+ conn->flags |= CO_FL_SEND_PROXY;
+ }
+
+ if (conn_ctrl_ready(conn) && (connect->options & TCPCHK_OPT_LINGER)) {
+ /* Some servers don't like reset on close */
+ fdtab[cs->conn->handle.fd].linger_risk = 0;
+ }
}
- if (conn_ctrl_ready(conn) &&
- connect->options & TCPCHK_OPT_LINGER) {
- /* Some servers don't like reset on close */
- fdtab[cs->conn->handle.fd].linger_risk = 0;
+ if (conn_ctrl_ready(conn) && (conn->flags & (CO_FL_SEND_PROXY | CO_FL_SOCKS4))) {
+ if (xprt_add_hs(conn) < 0)
+ ret = SF_ERR_RESOURCE;
}
/* It can return one of :
@@ -3796,6 +3810,35 @@
REGISTER_POST_CHECK(start_checks);
+static int check_proxy_tcpcheck(struct proxy *px)
+{
+ struct tcpcheck_rule *chk;
+ int ret = 0;
+
+ if (!px->tcpcheck_rules)
+ goto out;
+
+ /* If there is no connect rule preceeding all send / expect rules, an
+ * implicit one is inserted before all others
+ */
+ chk = get_first_tcpcheck_rule(px->tcpcheck_rules);
+ if (!chk || chk->action != TCPCHK_ACT_CONNECT) {
+ chk = calloc(1, sizeof(*chk));
+ if (!chk) {
+ ha_alert("config : proxy '%s': unable to add implicit tcp-check connect rule "
+ "(out of memory).\n", px->id);
+ ret |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ chk->action = TCPCHK_ACT_CONNECT;
+ chk->connect.options = TCPCHK_OPT_DEFAULT_CONNECT;
+ LIST_ADD(px->tcpcheck_rules, &chk->list);
+ }
+
+ out:
+ return ret;
+}
+
static int init_srv_check(struct server *srv)
{
const char *err;
@@ -3929,6 +3972,8 @@
free(srv->agent.send_string);
}
+
+REGISTER_POST_PROXY_CHECK(check_proxy_tcpcheck);
REGISTER_POST_SERVER_CHECK(init_srv_check);
REGISTER_POST_SERVER_CHECK(init_srv_agent_check);