]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: checks: Add the addr option for tcp-check connect rule
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 31 Mar 2020 06:15:58 +0000 (08:15 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 27 Apr 2020 07:39:37 +0000 (09:39 +0200)
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.

doc/configuration.txt
include/types/checks.h
src/checks.c

index bc5f88ad25a62e4e0e4141a2682db56adf2d09e3..ecd218bf0f4def82cbc6bf87e24b95761a5984f6 100644 (file)
@@ -9821,9 +9821,12 @@ tcp-check connect [params*]
     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 @@ tcp-check connect [params*]
                  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.
index 0edc726d948496a148b6d11ee3e196624792ed5e..29d0ebd116e2ce4b685d751378d2147e80cdac52 100644 (file)
@@ -220,11 +220,12 @@ struct analyze_status {
 #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 {
index 7ac6611497b8d459b00034fc832567b678147f6b..cf6d0d3e36c0f26e46bc55cdc3235939b0c1d0f7 100644 (file)
@@ -2807,7 +2807,7 @@ static enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct
        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 @@ static enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct
                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 @@ static int init_srv_check(struct server *srv)
 
        /* 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 @@ static int init_srv_check(struct server *srv)
 
        /* 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 @@ static struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, st
                                                    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 @@ static struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, st
                        }
                        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 @@ static struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, st
 #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 @@ static struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, st
        chk->connect.sni     = sni;
        chk->connect.alpn    = alpn;
        chk->connect.alpn_len= alpn_len;
+       if (sk)
+               chk->connect.addr = *sk;
        return chk;
 
   error: