diff --git a/doc/SOCKS4.protocol.txt b/doc/SOCKS4.protocol.txt new file mode 100644 index 0000000000..06aee8aed0 --- /dev/null +++ b/doc/SOCKS4.protocol.txt @@ -0,0 +1 @@ +Please reference to "https://www.openssh.com/txt/socks4.protocol". \ No newline at end of file diff --git a/doc/configuration.txt b/doc/configuration.txt index dcbe1eb707..26d473bb39 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -11900,6 +11900,11 @@ check-ssl See the "ssl" option for more information and "no-check-ssl" to disable this option. +check-via-socks4 + This option enables outgoinng health checks using upstream socks4 proxy. By + default, the health checks won't go through socks tunnel even it was enabled + for normal traffic. + ciphers This setting is only available when support for OpenSSL was built in. This option sets the string describing the list of cipher algorithms that is @@ -12560,6 +12565,11 @@ stick It may also be used as "default-server" setting to reset any previous "default-server" "non-stick" setting. +socks4 : + This option enables upstream socks4 tunnel for outgoinng connections to the + server. Using this option won't force the health check to go via socks4 by + default. You will have to use the keyword "check-via-socks4" to enable it. + tcp-ut Sets the TCP User Timeout for all outgoing connections to this server. This option is available on Linux since version 2.6.37. It allows haproxy to diff --git a/examples/socks4.cfg b/examples/socks4.cfg new file mode 100644 index 0000000000..2cbd417584 --- /dev/null +++ b/examples/socks4.cfg @@ -0,0 +1,55 @@ +global + log /dev/log local0 + log /dev/log local1 notice + stats timeout 30s + +defaults + log global + mode http + option httplog + option dontlognull + timeout connect 5000 + timeout client 50000 + timeout server 50000 + +listen SMTP-20025 + bind 0.0.0.0:20025 + mode tcp + option tcplog + maxconn 2000 + timeout connect 5000 + timeout client 50000 + timeout server 50000 + option tcp-check + server SMTPS1 192.0.2.1:25 check inter 30000 fastinter 1000 + server SMTPS2_Via_SocksProxy1 192.0.2.2:25 socks4 127.0.0.1:1080 check-via-socks4 check inter 30000 fastinter 1000 backup + +listen SSL-20080 + bind 0.0.0.0:20080 + mode tcp + option tcplog + maxconn 2000 + timeout connect 5000 + timeout client 50000 + timeout server 50000 + option tcp-check + server HTTPS1_Via_SocksProxy1 192.0.2.1:443 ssl verify none socks4 127.0.0.1:1080 check inter 30000 fastinter 1000 + server HTTPS2 192.0.2.2:443 ssl verify none check inter 30000 fastinter 1000 backup + +# HAProxy web ui +listen stats + bind 0.0.0.0:20936 + mode http + log global + + maxconn 10 + timeout client 100s + timeout server 100s + timeout connect 100s + timeout queue 100s + + stats enable + stats uri /haproxy?stats + stats realm HAProxy\ Statistics + stats admin if TRUE + stats show-node diff --git a/include/proto/connection.h b/include/proto/connection.h index ede3726383..915be87bf2 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -60,6 +60,10 @@ int conn_sock_send(struct connection *conn, const void *buf, int len, int flags) /* drains any pending bytes from the socket */ int conn_sock_drain(struct connection *conn); +/* scoks4 proxy handshake */ +int conn_send_socks4_proxy_request(struct connection *conn); +int conn_recv_socks4_proxy_response(struct connection *conn); + /* returns true is the transport layer is ready */ static inline int conn_xprt_ready(const struct connection *conn) { @@ -889,6 +893,11 @@ static inline const char *conn_err_code_str(struct connection *c) case CO_ER_SSL_HANDSHAKE_HB: return "SSL handshake failure after heartbeat"; case CO_ER_SSL_KILLED_HB: return "Stopped a TLSv1 heartbeat attack (CVE-2014-0160)"; case CO_ER_SSL_NO_TARGET: return "Attempt to use SSL on an unknown target (internal error)"; + + case CO_ER_SOCKS4_SEND: return "SOCKS4 Proxy write error during handshake"; + case CO_ER_SOCKS4_RECV: return "SOCKS4 Proxy read error during handshake"; + case CO_ER_SOCKS4_DENY: return "SOCKS4 Proxy deny the request"; + case CO_ER_SOCKS4_ABORT: return "SOCKS4 Proxy handshake aborted by server"; } return NULL; } diff --git a/include/types/checks.h b/include/types/checks.h index f89abcbab5..03d2305774 100644 --- a/include/types/checks.h +++ b/include/types/checks.h @@ -189,6 +189,8 @@ struct check { char *sni; /* Server name */ char *alpn_str; /* ALPN to use for checks */ int alpn_len; /* ALPN string length */ + + int via_socks4; /* check the connection via socks4 proxy */ }; struct check_status { diff --git a/include/types/connection.h b/include/types/connection.h index bae41cfda3..49ec6d54b8 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -47,6 +47,15 @@ struct server; struct session; struct pipe; +/* socks4 upstream proxy definitions */ +struct socks4_request { + uint8_t version; /* SOCKS version number, 1 byte, must be 0x04 for this version */ + uint8_t command; /* 0x01 = establish a TCP/IP stream connection */ + uint16_t port; /* port number, 2 bytes (in network byte order) */ + uint32_t ip; /* IP address, 4 bytes (in network byte order) */ + char user_id[8]; /* the user ID string, variable length, terminated with a null (0x00); Using "HAProxy\0" */ +}; + /* Note: subscribing to these events is only valid after the caller has really * attempted to perform the operation, and failed to proceed or complete. */ @@ -155,8 +164,8 @@ enum { CO_FL_EARLY_SSL_HS = 0x00004000, /* We have early data pending, don't start SSL handshake yet */ CO_FL_EARLY_DATA = 0x00008000, /* At least some of the data are early data */ - /* unused : 0x00010000 */ - /* unused : 0x00020000 */ + CO_FL_SOCKS4_SEND = 0x00010000, /* handshaking with upstream SOCKS4 proxy, going to send the handshake */ + CO_FL_SOCKS4_RECV = 0x00020000, /* handshaking with upstream SOCKS4 proxy, going to check if handshake succeed */ /* flags used to remember what shutdown have been performed/reported */ CO_FL_SOCK_RD_SH = 0x00040000, /* SOCK layer was notified about shutr/read0 */ @@ -182,7 +191,7 @@ enum { CO_FL_ACCEPT_CIP = 0x08000000, /* receive a valid NetScaler Client IP header */ /* below we have all handshake flags grouped into one */ - CO_FL_HANDSHAKE = CO_FL_SEND_PROXY | CO_FL_SSL_WAIT_HS | CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP, + CO_FL_HANDSHAKE = CO_FL_SEND_PROXY | CO_FL_SSL_WAIT_HS | CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP | CO_FL_SOCKS4_SEND | CO_FL_SOCKS4_RECV, /* when any of these flags is set, polling is defined by socket-layer * operations, as opposed to data-layer. Transport is explicitly not @@ -205,8 +214,10 @@ enum { * must be done after clearing this flag. */ CO_FL_XPRT_TRACKED = 0x80000000, -}; + /* below we have all SOCKS handshake flags grouped into one */ + CO_FL_SOCKS4 = CO_FL_SOCKS4_SEND | CO_FL_SOCKS4_RECV, +}; /* possible connection error codes */ enum { @@ -254,6 +265,11 @@ enum { CO_ER_SSL_KILLED_HB, /* Stopped a TLSv1 heartbeat attack (CVE-2014-0160) */ CO_ER_SSL_NO_TARGET, /* unknown target (not client nor server) */ CO_ER_SSL_EARLY_FAILED, /* Server refused early data */ + + CO_ER_SOCKS4_SEND, /* SOCKS4 Proxy write error during handshake */ + CO_ER_SOCKS4_RECV, /* SOCKS4 Proxy read error during handshake */ + CO_ER_SOCKS4_DENY, /* SOCKS4 Proxy deny the request */ + CO_ER_SOCKS4_ABORT, /* SOCKS4 Proxy handshake aborted by server */ }; /* source address settings for outgoing connections */ @@ -425,7 +441,7 @@ struct connection { /* first cache line */ enum obj_type obj_type; /* differentiates connection from applet context */ unsigned char err_code; /* CO_ER_* */ - signed short send_proxy_ofs; /* <0 = offset to (re)send from the end, >0 = send all */ + signed short send_proxy_ofs; /* <0 = offset to (re)send from the end, >0 = send all (reused for SOCKS4) */ unsigned int flags; /* CO_FL_* */ const struct protocol *ctrl; /* operations at the socket layer */ const struct xprt_ops *xprt; /* operations at the transport layer */ @@ -576,6 +592,8 @@ struct tlv_ssl { /* Max number of file descriptors we send in one sendmsg() */ #define MAX_SEND_FD 253 +#define SOCKS4_HS_RSP_LEN 8 + #endif /* _TYPES_CONNECTION_H */ /* diff --git a/include/types/server.h b/include/types/server.h index 0d53d26009..219f5ab1df 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -141,6 +141,7 @@ enum srv_initaddr { #define SRV_F_AGENTADDR 0x0080 /* this server has a agent addr configured */ #define SRV_F_COOKIESET 0x0100 /* this server has a cookie configured, so don't generate dynamic cookies */ #define SRV_F_FASTOPEN 0x0200 /* Use TCP Fast Open to connect to server */ +#define SRV_F_SOCKS4_PROXY 0x0400 /* this server uses SOCKS4 proxy */ /* configured server options for send-proxy (server->pp_opts) */ #define SRV_PP_V1 0x0001 /* proxy protocol version 1 */ @@ -336,6 +337,8 @@ struct server { char reason[128]; } op_st_chg; /* operational status change's reason */ char adm_st_chg_cause[48]; /* administrative status change's cause */ + + struct sockaddr_storage socks4_addr; /* the address of the SOCKS4 Proxy, including the port */ }; /* Descriptor for a "server" keyword. The ->parse() function returns 0 in case of diff --git a/src/backend.c b/src/backend.c index b8e56cf594..28ed993a2e 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1533,12 +1533,18 @@ int connect_server(struct stream *s) if (srv && srv->pp_opts) { srv_conn->flags |= CO_FL_PRIVATE; + srv_conn->flags |= CO_FL_SEND_PROXY; srv_conn->send_proxy_ofs = 1; /* must compute size */ if (cli_conn) conn_get_to_addr(cli_conn); } assign_tproxy_address(s); + + if (srv && (srv->flags & SRV_F_SOCKS4_PROXY)) { + srv_conn->send_proxy_ofs = 1; + srv_conn->flags |= CO_FL_SOCKS4; + } } else if (!conn_xprt_ready(srv_conn)) { if (srv_conn->mux->reset) diff --git a/src/checks.c b/src/checks.c index d264aecf8d..90f4614771 100644 --- a/src/checks.c +++ b/src/checks.c @@ -1612,6 +1612,11 @@ static int connect_conn_chk(struct task *t) conn->addr.to = s->addr; } + if (s->check.via_socks4 && (s->flags & SRV_F_SOCKS4_PROXY)) { + conn->send_proxy_ofs = 1; + conn->flags |= CO_FL_SOCKS4; + } + proto = protocol_by_family(conn->addr.to.ss_family); conn->target = &s->obj_type; diff --git a/src/connection.c b/src/connection.c index 4b4a31482e..f0ca2bb165 100644 --- a/src/connection.c +++ b/src/connection.c @@ -27,6 +27,8 @@ #include #include +#include + DECLARE_POOL(pool_head_connection, "connection", sizeof(struct connection)); DECLARE_POOL(pool_head_connstream, "conn_stream", sizeof(struct conn_stream)); @@ -69,6 +71,14 @@ void conn_fd_handler(int fd) if (unlikely(conn->flags & CO_FL_ERROR)) goto leave; + if (conn->flags & CO_FL_SOCKS4_SEND) + if (!conn_send_socks4_proxy_request(conn)) + goto leave; + + if (conn->flags & CO_FL_SOCKS4_RECV) + if (!conn_recv_socks4_proxy_response(conn)) + goto leave; + if (conn->flags & CO_FL_ACCEPT_CIP) if (!conn_recv_netscaler_cip(conn, CO_FL_ACCEPT_CIP)) goto leave; @@ -959,6 +969,209 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag) return 0; } + +int conn_send_socks4_proxy_request(struct connection *conn) +{ + struct socks4_request req_line; + + /* we might have been called just after an asynchronous shutw */ + if (conn->flags & CO_FL_SOCK_WR_SH) + goto out_error; + + if (!conn_ctrl_ready(conn)) + goto out_error; + + req_line.version = 0x04; + req_line.command = 0x01; + req_line.port = get_net_port(&(conn->addr.to)); + req_line.ip = is_inet_addr(&(conn->addr.to)); + memcpy(req_line.user_id, "HAProxy\0", 8); + + if (conn->send_proxy_ofs > 0) { + /* + * This is the first call to send the request + */ + conn->send_proxy_ofs = -(int)sizeof(req_line); + } + + if (conn->send_proxy_ofs < 0) { + int ret = 0; + + /* we are sending the socks4_req_line here. If the data layer + * has a pending write, we'll also set MSG_MORE. + */ + ret = conn_sock_send( + conn, + ((char *)(&req_line)) + (sizeof(req_line)+conn->send_proxy_ofs), + -conn->send_proxy_ofs, + (conn->flags & CO_FL_XPRT_WR_ENA) ? MSG_MORE : 0); + + DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Before send remain is [%d], sent [%d]\n", + conn->handle.fd, -conn->send_proxy_ofs, ret); + + if (ret < 0) { + goto out_error; + } + + conn->send_proxy_ofs += ret; /* becomes zero once complete */ + if (conn->send_proxy_ofs != 0) { + goto out_wait; + } + } + + /* OK we've the whole request sent */ + conn->flags &= ~CO_FL_SOCKS4_SEND; + __conn_sock_stop_send(conn); + + /* The connection is ready now, simply return and let the connection + * handler notify upper layers if needed. + */ + if (conn->flags & CO_FL_WAIT_L4_CONN) + conn->flags &= ~CO_FL_WAIT_L4_CONN; + + if (conn->flags & CO_FL_SEND_PROXY) { + /* + * Get the send_proxy_ofs ready for the send_proxy due to we are + * reusing the "send_proxy_ofs", and SOCKS4 handshake should be done + * before sending PROXY Protocol. + */ + conn->send_proxy_ofs = 1; + } + return 1; + + out_error: + /* Write error on the file descriptor */ + conn->flags |= CO_FL_ERROR; + if (conn->err_code == CO_ER_NONE) { + conn->err_code = CO_ER_SOCKS4_SEND; + } + return 0; + + out_wait: + __conn_sock_stop_recv(conn); + return 0; +} + +int conn_recv_socks4_proxy_response(struct connection *conn) +{ + char line[SOCKS4_HS_RSP_LEN]; + int ret; + + /* we might have been called just after an asynchronous shutr */ + if (conn->flags & CO_FL_SOCK_RD_SH) + goto fail; + + if (!conn_ctrl_ready(conn)) + goto fail; + + if (!fd_recv_ready(conn->handle.fd)) + return 0; + + do { + /* SOCKS4 Proxy will response with 8 bytes, 0x00 | 0x5A | 0x00 0x00 | 0x00 0x00 0x00 0x00 + * Try to peek into it, before all 8 bytes ready. + */ + ret = recv(conn->handle.fd, line, SOCKS4_HS_RSP_LEN, MSG_PEEK); + + if (ret == 0) { + /* the socket has been closed or shutdown for send */ + DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], errno[%d], looks like the socket has been closed or shutdown for send\n", + conn->handle.fd, ret, errno); + if (conn->err_code == CO_ER_NONE) { + conn->err_code = CO_ER_SOCKS4_RECV; + } + goto fail; + } + + if (ret > 0) { + if (ret == SOCKS4_HS_RSP_LEN) { + DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received 8 bytes, the response is [%02X|%02X|%02X %02X|%02X %02X %02X %02X]\n", + conn->handle.fd, line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7]); + }else{ + DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], first byte is [%02X], last bye is [%02X]\n", conn->handle.fd, ret, line[0], line[ret-1]); + } + } else { + DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: Received ret[%d], errno[%d]\n", conn->handle.fd, ret, errno); + } + + if (ret < 0) { + if (errno == EINTR) { + continue; + } + if (errno == EAGAIN) { + fd_cant_recv(conn->handle.fd); + __conn_sock_want_recv(conn); + return 0; + } + goto recv_abort; + } + } while (0); + + if (ret < SOCKS4_HS_RSP_LEN) { + /* Missing data. Since we're using MSG_PEEK, we can only poll again if + * we are not able to read enough data. + */ + fd_cant_recv(conn->handle.fd); + __conn_sock_want_recv(conn); + return 0; + } + + /* + * Base on the SOCSK4 protocol: + * + * +----+----+----+----+----+----+----+----+ + * | VN | CD | DSTPORT | DSTIP | + * +----+----+----+----+----+----+----+----+ + * # of bytes: 1 1 2 4 + * VN is the version of the reply code and should be 0. CD is the result + * code with one of the following values: + * 90: request granted + * 91: request rejected or failed + * 92: request rejected becasue SOCKS server cannot connect to identd on the client + * 93: request rejected because the client program and identd report different user-ids + * The remaining fields are ignored. + */ + if (line[1] != 90) { + conn->flags &= ~CO_FL_SOCKS4_RECV; + + DPRINTF(stderr, "SOCKS PROXY HS FD[%04X]: FAIL, the response is [%02X|%02X|%02X %02X|%02X %02X %02X %02X]\n", + conn->handle.fd, line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7]); + if (conn->err_code == CO_ER_NONE) { + conn->err_code = CO_ER_SOCKS4_DENY; + } + goto fail; + } + + /* remove the 8 bytes response from the stream */ + do { + ret = recv(conn->handle.fd, line, SOCKS4_HS_RSP_LEN, 0); + if (ret < 0 && errno == EINTR) { + continue; + } + if (ret != SOCKS4_HS_RSP_LEN) { + if (conn->err_code == CO_ER_NONE) { + conn->err_code = CO_ER_SOCKS4_RECV; + } + goto fail; + } + } while (0); + + conn->flags &= ~CO_FL_SOCKS4_RECV; + return 1; + + recv_abort: + if (conn->err_code == CO_ER_NONE) { + conn->err_code = CO_ER_SOCKS4_ABORT; + } + conn->flags |= (CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH); + goto fail; + + fail: + __conn_sock_stop_both(conn); + conn->flags |= CO_FL_ERROR; + return 0; +} + /* Note: is explicitly allowed to be NULL */ int make_proxy_line(char *buf, int buf_len, struct server *srv, struct connection *remote) { diff --git a/src/proto_tcp.c b/src/proto_tcp.c index f59502932d..7ae28f085e 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -294,6 +294,7 @@ int tcp_connect_server(struct connection *conn, int flags) struct proxy *be; struct conn_src *src; int use_fastopen = 0; + struct sockaddr_storage *addr; conn->flags |= CO_FL_WAIT_L4_CONN; /* connection in progress */ @@ -514,7 +515,8 @@ int tcp_connect_server(struct connection *conn, int flags) if (global.tune.server_rcvbuf) setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf)); - if (connect(fd, (struct sockaddr *)&conn->addr.to, get_addr_len(&conn->addr.to)) == -1) { + addr = (conn->flags & CO_FL_SOCKS4) ? &srv->socks4_addr : &conn->addr.to; + if (connect(fd, (const struct sockaddr *)addr, get_addr_len(addr)) == -1) { if (errno == EINPROGRESS || errno == EALREADY) { /* common case, let's wait for connect status */ conn->flags |= CO_FL_WAIT_L4_CONN; @@ -567,10 +569,6 @@ int tcp_connect_server(struct connection *conn, int flags) conn->flags |= CO_FL_ADDR_TO_SET; - /* Prepare to send a few handshakes related to the on-wire protocol. */ - if (conn->send_proxy_ofs) - conn->flags |= CO_FL_SEND_PROXY; - conn_ctrl_init(conn); /* registers the FD */ fdtab[fd].linger_risk = 1; /* close hard if needed */ @@ -663,6 +661,7 @@ int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir) */ int tcp_connect_probe(struct connection *conn) { + struct sockaddr_storage *addr; int fd = conn->handle.fd; socklen_t lskerr; int skerr; @@ -701,7 +700,11 @@ int tcp_connect_probe(struct connection *conn) * - connecting (EALREADY, EINPROGRESS) * - connected (EISCONN, 0) */ - if (connect(fd, (struct sockaddr *)&conn->addr.to, get_addr_len(&conn->addr.to)) < 0) { + addr = &conn->addr.to; + if ((conn->flags & CO_FL_SOCKS4) && obj_type(conn->target) == OBJ_TYPE_SERVER) + addr = &objt_server(conn->target)->socks4_addr; + + if (connect(fd, (const struct sockaddr *)addr, get_addr_len(addr)) == -1) { if (errno == EALREADY || errno == EINPROGRESS) { __conn_sock_stop_recv(conn); fd_cant_send(fd); diff --git a/src/server.c b/src/server.c index 52c71a6788..541dc696fe 100644 --- a/src/server.c +++ b/src/server.c @@ -322,6 +322,14 @@ static int srv_parse_check_send_proxy(char **args, int *cur_arg, return 0; } +/* Parse the "check-via-socks4" server keyword */ +static int srv_parse_check_via_socks4(char **args, int *cur_arg, + struct proxy *curproxy, struct server *newsrv, char **err) +{ + newsrv->check.via_socks4 = 1; + return 0; +} + /* Parse the "cookie" server keyword */ static int srv_parse_cookie(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err) @@ -888,6 +896,55 @@ static int srv_parse_track(char **args, int *cur_arg, return 0; } +/* Parse the "socks4" server keyword */ +static int srv_parse_socks4(char **args, int *cur_arg, + struct proxy *curproxy, struct server *newsrv, char **err) +{ + char *errmsg; + int port_low, port_high; + struct sockaddr_storage *sk; + struct protocol *proto; + + errmsg = NULL; + + if (!*args[*cur_arg + 1]) { + memprintf(err, "'%s' expects : as argument.\n", args[*cur_arg]); + goto err; + } + + /* 'sk' is statically allocated (no need to be freed). */ + sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, &errmsg, NULL, NULL, 1); + if (!sk) { + memprintf(err, "'%s %s' : %s\n", args[*cur_arg], args[*cur_arg + 1], errmsg); + goto err; + } + + proto = protocol_by_family(sk->ss_family); + if (!proto || !proto->connect) { + ha_alert("'%s %s' : connect() not supported for this address family.\n", args[*cur_arg], args[*cur_arg + 1]); + goto err; + } + + newsrv->flags |= SRV_F_SOCKS4_PROXY; + newsrv->socks4_addr = *sk; + + if (port_low != port_high) { + ha_alert("'%s' does not support port offsets (found '%s').\n", args[*cur_arg], args[*cur_arg + 1]); + goto err; + } + + if (!port_low) { + ha_alert("'%s': invalid port range %d-%d.\n", args[*cur_arg], port_low, port_high); + goto err; + } + + return 0; + + err: + free(errmsg); + return ERR_ALERT | ERR_FATAL; +} + /* parse the "tfo" server keyword */ static int srv_parse_tfo(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err) @@ -1286,6 +1343,8 @@ static struct srv_kw_list srv_kws = { "ALL", { }, { { "stick", srv_parse_stick, 0, 1 }, /* Enable stick-table persistence */ { "tfo", srv_parse_tfo, 0, 0 }, /* enable TCP Fast Open of server */ { "track", srv_parse_track, 1, 1 }, /* Set the current state of the server, tracking another one */ + { "socks4", srv_parse_socks4, 1, 1 }, /* Set the socks4 proxy of the server*/ + { "check-via-socks4", srv_parse_check_via_socks4, 0, 1 }, /* enable socks4 proxy for health checks */ { NULL, NULL, 0 }, }}; @@ -1721,6 +1780,9 @@ static void srv_settings_cpy(struct server *srv, struct server *src, int srv_tmp if (srv_tmpl) srv->srvrq = src->srvrq; + + srv->check.via_socks4 = src->check.via_socks4; + srv->socks4_addr = src->socks4_addr; } struct server *new_server(struct proxy *proxy)