From: Willy Tarreau Date: Fri, 26 Oct 2012 17:57:58 +0000 (+0200) Subject: BUG/MEDIUM: tcp: transparent bind to the source only when address is set X-Git-Tag: v1.5-dev13~98 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f2877a7dd32a6e9cdb488d14be65851270d8c65;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: tcp: transparent bind to the source only when address is set Thomas Heil reported that health checks did not work anymore when a backend or server has "usesrc clientip". This is because the source address is not set and tcp_bind_socket() tries to bind to that address anyway. The solution consists in explicitly clearing the source address in the checks and to make tcp_bind_socket() avoid binding when the address is not set. This also has an indirect benefit that a useless bind() syscall will be avoided when using "source 0.0.0.0 usesrc clientip" in health checks. --- diff --git a/src/checks.c b/src/checks.c index 32f8c91765..326ffde5b4 100644 --- a/src/checks.c +++ b/src/checks.c @@ -1308,6 +1308,9 @@ static struct task *process_chk(struct task *t) set_target_server(&conn->target, s); conn_prepare(conn, &check_conn_cb, s->check.proto, s->check.xprt, s); + /* no client address */ + clear_addr(&conn->addr.from); + if (is_addr(&s->check.addr)) /* we'll connect to the check addr specified on the server */ conn->addr.to = s->check.addr; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index d0424d98f5..b94f9b22e8 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -170,14 +170,18 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); if (foreign_ok) { - ret = bind(fd, (struct sockaddr *)&bind_addr, get_addr_len(&bind_addr)); - if (ret < 0) - return 2; + if (is_addr(&bind_addr)) { + ret = bind(fd, (struct sockaddr *)&bind_addr, get_addr_len(&bind_addr)); + if (ret < 0) + return 2; + } } else { - ret = bind(fd, (struct sockaddr *)local, get_addr_len(local)); - if (ret < 0) - return 1; + if (is_addr(local)) { + ret = bind(fd, (struct sockaddr *)local, get_addr_len(local)); + if (ret < 0) + return 1; + } } if (!flags) @@ -295,15 +299,17 @@ int tcp_connect_server(struct connection *conn, int data) if (srv != NULL && srv->state & SRV_BIND_SRC) { int ret, flags = 0; - switch (srv->state & SRV_TPROXY_MASK) { - case SRV_TPROXY_ADDR: - case SRV_TPROXY_CLI: - flags = 3; - break; - case SRV_TPROXY_CIP: - case SRV_TPROXY_DYN: - flags = 1; - break; + if (is_addr(&conn->addr.from)) { + switch (srv->state & SRV_TPROXY_MASK) { + case SRV_TPROXY_ADDR: + case SRV_TPROXY_CLI: + flags = 3; + break; + case SRV_TPROXY_CIP: + case SRV_TPROXY_DYN: + flags = 1; + break; + } } #ifdef SO_BINDTODEVICE @@ -368,15 +374,17 @@ int tcp_connect_server(struct connection *conn, int data) else if (be->options & PR_O_BIND_SRC) { int ret, flags = 0; - switch (be->options & PR_O_TPXY_MASK) { - case PR_O_TPXY_ADDR: - case PR_O_TPXY_CLI: - flags = 3; - break; - case PR_O_TPXY_CIP: - case PR_O_TPXY_DYN: - flags = 1; - break; + if (is_addr(&conn->addr.from)) { + switch (be->options & PR_O_TPXY_MASK) { + case PR_O_TPXY_ADDR: + case PR_O_TPXY_CLI: + flags = 3; + break; + case PR_O_TPXY_CIP: + case PR_O_TPXY_DYN: + flags = 1; + break; + } } #ifdef SO_BINDTODEVICE