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 32f8c91..326ffde 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1308,6 +1308,9 @@
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 d0424d9..b94f9b2 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -170,14 +170,18 @@
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 @@
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 @@
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