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.
This commit is contained in:
Willy Tarreau 2012-10-26 19:57:58 +02:00
parent 422a0a5161
commit 5f2877a7dd
2 changed files with 35 additions and 24 deletions

View File

@ -1308,6 +1308,9 @@ static struct task *process_chk(struct task *t)
set_target_server(&conn->target, s); set_target_server(&conn->target, s);
conn_prepare(conn, &check_conn_cb, s->check.proto, s->check.xprt, 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)) if (is_addr(&s->check.addr))
/* we'll connect to the check addr specified on the server */ /* we'll connect to the check addr specified on the server */
conn->addr.to = s->check.addr; conn->addr.to = s->check.addr;

View File

@ -170,15 +170,19 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if (foreign_ok) { if (foreign_ok) {
if (is_addr(&bind_addr)) {
ret = bind(fd, (struct sockaddr *)&bind_addr, get_addr_len(&bind_addr)); ret = bind(fd, (struct sockaddr *)&bind_addr, get_addr_len(&bind_addr));
if (ret < 0) if (ret < 0)
return 2; return 2;
} }
}
else { else {
if (is_addr(local)) {
ret = bind(fd, (struct sockaddr *)local, get_addr_len(local)); ret = bind(fd, (struct sockaddr *)local, get_addr_len(local));
if (ret < 0) if (ret < 0)
return 1; return 1;
} }
}
if (!flags) if (!flags)
return 0; return 0;
@ -295,6 +299,7 @@ int tcp_connect_server(struct connection *conn, int data)
if (srv != NULL && srv->state & SRV_BIND_SRC) { if (srv != NULL && srv->state & SRV_BIND_SRC) {
int ret, flags = 0; int ret, flags = 0;
if (is_addr(&conn->addr.from)) {
switch (srv->state & SRV_TPROXY_MASK) { switch (srv->state & SRV_TPROXY_MASK) {
case SRV_TPROXY_ADDR: case SRV_TPROXY_ADDR:
case SRV_TPROXY_CLI: case SRV_TPROXY_CLI:
@ -305,6 +310,7 @@ int tcp_connect_server(struct connection *conn, int data)
flags = 1; flags = 1;
break; break;
} }
}
#ifdef SO_BINDTODEVICE #ifdef SO_BINDTODEVICE
/* Note: this might fail if not CAP_NET_RAW */ /* Note: this might fail if not CAP_NET_RAW */
@ -368,6 +374,7 @@ int tcp_connect_server(struct connection *conn, int data)
else if (be->options & PR_O_BIND_SRC) { else if (be->options & PR_O_BIND_SRC) {
int ret, flags = 0; int ret, flags = 0;
if (is_addr(&conn->addr.from)) {
switch (be->options & PR_O_TPXY_MASK) { switch (be->options & PR_O_TPXY_MASK) {
case PR_O_TPXY_ADDR: case PR_O_TPXY_ADDR:
case PR_O_TPXY_CLI: case PR_O_TPXY_CLI:
@ -378,6 +385,7 @@ int tcp_connect_server(struct connection *conn, int data)
flags = 1; flags = 1;
break; break;
} }
}
#ifdef SO_BINDTODEVICE #ifdef SO_BINDTODEVICE
/* Note: this might fail if not CAP_NET_RAW */ /* Note: this might fail if not CAP_NET_RAW */