MINOR: checks: Add the addr option for tcp-check connect rule
With this option, it is now possible to use a specific address to open the
connection for a tcp-check connect rule. If the port option is also specified,
it is used in priority.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index bc5f88a..ecd218b 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -9821,9 +9821,12 @@
default Use default options of the server line to do the health
checks. This parameter is exclusive with all other options.
- port if not set, check port or server port is used.
- It tells HAProxy where to open the connection to.
- <port> must be a valid TCP port source integer, from 1 to 65535.
+ port if not set, check port or server port is used.
+ It tells HAProxy where to open the connection to.
+ <port> must be a valid TCP port source integer, from 1 to
+ 65535.
+
+ addr <ip> defines the IP address to do the health check.
send-proxy send a PROXY protocol string
@@ -9838,7 +9841,7 @@
for instance: "http/1.1,http/1.0" (without quotes).
If it is not set, the server ALPN is used.
- linger cleanly close the connection instead of using a single RST.
+ linger cleanly close the connection instead of using a single RST.
Examples:
# check HTTP and HTTPs services on a server.
diff --git a/include/types/checks.h b/include/types/checks.h
index 0edc726..29d0ebd 100644
--- a/include/types/checks.h
+++ b/include/types/checks.h
@@ -220,11 +220,12 @@
#define TCPCHK_OPT_SOCKS4 0x0010 /* check the connection via socks4 proxy */
struct tcpcheck_connect {
- uint16_t port; /* port to connect to */
- uint16_t options; /* options when setting up a new connection */
- char *sni; /* server name to use for SSL connections */
- char *alpn; /* ALPN to use for the SSL connection */
- int alpn_len; /* ALPN string length */
+ char *sni; /* server name to use for SSL connections */
+ char *alpn; /* ALPN to use for the SSL connection */
+ int alpn_len; /* ALPN string length */
+ uint16_t options; /* options when setting up a new connection */
+ uint16_t port; /* port to connect to */
+ struct sockaddr_storage addr; /* the address to the connect */
};
enum tcpcheck_send_type {
diff --git a/src/checks.c b/src/checks.c
index 7ac6611..cf6d0d3 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -2807,7 +2807,7 @@
struct protocol *proto;
struct xprt_ops *xprt;
char *comment;
- int status;
+ int status, port;
/* For a connect action we'll create a new connection. We may also have
* to kill a previous one. But we don't want to leave *without* a
@@ -2859,20 +2859,26 @@
goto fail_check;
}
- /* connect to the check addr if specified on the server. otherwise, use
- * the server addr
+ /* connect to the connect rule addr if specified, otherwise the check
+ * addr if specified on the server. otherwise, use the server addr
*/
- *conn->dst = (is_addr(&check->addr) ? check->addr : s->addr);
+ *conn->dst = (is_addr(&connect->addr)
+ ? connect->addr
+ : (is_addr(&check->addr) ? check->addr : s->addr));
proto = protocol_by_family(conn->dst->ss_family);
- if (connect->port)
- set_host_port(conn->dst, connect->port);
- else if (check->port)
- set_host_port(conn->dst, check->port);
- else {
- int i = get_host_port(&check->addr);
- set_host_port(conn->dst, ((i > 0) ? i : s->svc_port));
- }
+ port = 0;
+ if (!port && connect->port)
+ port = connect->port;
+ if (!port && is_inet_addr(&connect->addr))
+ port = get_host_port(&connect->addr);
+ if (!port && check->port)
+ port = check->port;
+ if (!port && is_inet_addr(&check->addr))
+ port = get_host_port(&check->addr);
+ if (!port)
+ port = s->svc_port;
+ set_host_port(conn->dst, port);
xprt = ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT)
? check->xprt
@@ -3929,7 +3935,7 @@
/* search the first action (connect / send / expect) in the list */
r = get_first_tcpcheck_rule(srv->proxy->tcpcheck_rules);
- if (!r || (r->action != TCPCHK_ACT_CONNECT) || !r->connect.port) {
+ if (!r || (r->action != TCPCHK_ACT_CONNECT) || (!r->connect.port && !get_host_port(&r->connect.addr))) {
ha_alert("config: %s '%s': server '%s' has neither service port nor check port "
"nor tcp_check rule 'connect' with port information.\n",
proxy_type_str(srv->proxy), srv->proxy->id, srv->id);
@@ -3939,7 +3945,7 @@
/* scan the tcp-check ruleset to ensure a port has been configured */
list_for_each_entry(r, srv->proxy->tcpcheck_rules, list) {
- if ((r->action == TCPCHK_ACT_CONNECT) && (!r->connect.port)) {
+ if ((r->action == TCPCHK_ACT_CONNECT) && (!r->connect.port || !get_host_port(&r->connect.addr))) {
ha_alert("config: %s '%s': server '%s' has neither service port nor check port, "
"and a tcp_check rule 'connect' with no port information.\n",
proxy_type_str(srv->proxy), srv->proxy->id, srv->id);
@@ -4081,6 +4087,7 @@
char **errmsg)
{
struct tcpcheck_rule *chk = NULL;
+ struct sockaddr_storage *sk = NULL;
char *comment = NULL, *sni = NULL, *alpn = NULL;
unsigned short conn_opts = 0;
long port = 0;
@@ -4106,6 +4113,36 @@
}
conn_opts = TCPCHK_OPT_DEFAULT_CONNECT;
}
+ else if (strcmp(args[cur_arg], "addr") == 0) {
+ int port1, port2;
+ struct protocol *proto;
+
+ if (!*(args[cur_arg+1])) {
+ memprintf(errmsg, "'%s' expects <ipv4|ipv6> as argument.", args[cur_arg]);
+ goto error;
+ }
+
+ sk = str2sa_range(args[cur_arg+1], NULL, &port1, &port2, errmsg, NULL, NULL, 1);
+ if (!sk) {
+ memprintf(errmsg, "'%s' : %s.", args[cur_arg], *errmsg);
+ goto error;
+ }
+
+ proto = protocol_by_family(sk->ss_family);
+ if (!proto || !proto->connect) {
+ memprintf(errmsg, "'%s' : connect() not supported for this address family.\n",
+ args[cur_arg]);
+ goto error;
+ }
+
+ if (port1 != port2) {
+ memprintf(errmsg, "'%s' : port ranges and offsets are not allowed in '%s'\n",
+ args[cur_arg], args[cur_arg+1]);
+ goto error;
+ }
+
+ cur_arg++;
+ }
else if (strcmp(args[cur_arg], "port") == 0) {
if (!*(args[cur_arg+1])) {
memprintf(errmsg, "'%s' expects a port number as argument.", args[cur_arg]);
@@ -4171,7 +4208,7 @@
#endif /* USE_OPENSSL */
else {
- memprintf(errmsg, "expects 'comment', 'port', 'send-proxy'"
+ memprintf(errmsg, "expects 'comment', 'port', 'addr', 'send-proxy'"
#ifdef USE_OPENSSL
", 'ssl', 'sni', 'alpn'"
#endif /* USE_OPENSSL */
@@ -4194,6 +4231,8 @@
chk->connect.sni = sni;
chk->connect.alpn = alpn;
chk->connect.alpn_len= alpn_len;
+ if (sk)
+ chk->connect.addr = *sk;
return chk;
error: