CLEANUP: proto_tcp: use the same code to bind servers and backends

The tproxy and source binding code has now be factored out for
servers and backends. A nice effect is that the code now supports
having backends use source port ranges, though the config does not
support it yet. This change has reduced the executable by around
700 bytes.
This commit is contained in:
Willy Tarreau 2012-12-08 22:49:11 +01:00
parent ef9a360555
commit a4380b4f15

View File

@ -247,6 +247,7 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
int fd; int fd;
struct server *srv; struct server *srv;
struct proxy *be; struct proxy *be;
struct conn_src *src;
switch (obj_type(conn->target)) { switch (obj_type(conn->target)) {
case OBJ_TYPE_PROXY: case OBJ_TYPE_PROXY:
@ -303,11 +304,18 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
* - server-specific at first * - server-specific at first
* - proxy-specific next * - proxy-specific next
*/ */
if (srv != NULL && srv->conn_src.opts & CO_SRC_BIND) { if (srv && srv->conn_src.opts & CO_SRC_BIND)
src = &srv->conn_src;
else if (be->conn_src.opts & CO_SRC_BIND)
src = &be->conn_src;
else
src = NULL;
if (src) {
int ret, flags = 0; int ret, flags = 0;
if (is_addr(&conn->addr.from)) { if (is_addr(&conn->addr.from)) {
switch (srv->conn_src.opts & CO_SRC_TPROXY_MASK) { switch (src->opts & CO_SRC_TPROXY_MASK) {
case CO_SRC_TPROXY_ADDR: case CO_SRC_TPROXY_ADDR:
case CO_SRC_TPROXY_CLI: case CO_SRC_TPROXY_CLI:
flags = 3; flags = 3;
@ -321,16 +329,16 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
#ifdef SO_BINDTODEVICE #ifdef SO_BINDTODEVICE
/* Note: this might fail if not CAP_NET_RAW */ /* Note: this might fail if not CAP_NET_RAW */
if (srv->conn_src.iface_name) if (src->iface_name)
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, srv->conn_src.iface_name, srv->conn_src.iface_len + 1); setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, src->iface_name, src->iface_len + 1);
#endif #endif
if (srv->conn_src.sport_range) { if (src->sport_range) {
int attempts = 10; /* should be more than enough to find a spare port */ int attempts = 10; /* should be more than enough to find a spare port */
struct sockaddr_storage src; struct sockaddr_storage sa;
ret = 1; ret = 1;
src = srv->conn_src.source_addr; sa = src->source_addr;
do { do {
/* note: in case of retry, we may have to release a previously /* note: in case of retry, we may have to release a previously
@ -343,76 +351,36 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
break; break;
attempts--; attempts--;
fdinfo[fd].local_port = port_range_alloc_port(srv->conn_src.sport_range); fdinfo[fd].local_port = port_range_alloc_port(src->sport_range);
if (!fdinfo[fd].local_port) if (!fdinfo[fd].local_port)
break; break;
fdinfo[fd].port_range = srv->conn_src.sport_range; fdinfo[fd].port_range = src->sport_range;
set_host_port(&src, fdinfo[fd].local_port); set_host_port(&sa, fdinfo[fd].local_port);
ret = tcp_bind_socket(fd, flags, &src, &conn->addr.from); ret = tcp_bind_socket(fd, flags, &sa, &conn->addr.from);
} while (ret != 0); /* binding NOK */ } while (ret != 0); /* binding NOK */
} }
else { else {
ret = tcp_bind_socket(fd, flags, &srv->conn_src.source_addr, &conn->addr.from); ret = tcp_bind_socket(fd, flags, &src->source_addr, &conn->addr.from);
} }
if (ret) { if (unlikely(ret != 0)) {
port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port); port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
fdinfo[fd].port_range = NULL; fdinfo[fd].port_range = NULL;
close(fd); close(fd);
if (ret == 1) { if (ret == 1) {
Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n", Alert("Cannot bind to source address before connect() for backend %s. Aborting.\n",
be->id, srv->id);
send_log(be, LOG_EMERG,
"Cannot bind to source address before connect() for server %s/%s.\n",
be->id, srv->id);
} else {
Alert("Cannot bind to tproxy source address before connect() for server %s/%s. Aborting.\n",
be->id, srv->id);
send_log(be, LOG_EMERG,
"Cannot bind to tproxy source address before connect() for server %s/%s.\n",
be->id, srv->id);
}
return SN_ERR_RESOURCE;
}
}
else if (be->conn_src.opts & CO_SRC_BIND) {
int ret, flags = 0;
if (is_addr(&conn->addr.from)) {
switch (be->conn_src.opts & CO_SRC_BIND) {
case CO_SRC_TPROXY_ADDR:
case CO_SRC_TPROXY_CLI:
flags = 3;
break;
case CO_SRC_TPROXY_CIP:
case CO_SRC_TPROXY_DYN:
flags = 1;
break;
}
}
#ifdef SO_BINDTODEVICE
/* Note: this might fail if not CAP_NET_RAW */
if (be->conn_src.iface_name)
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, be->conn_src.iface_name, be->conn_src.iface_len + 1);
#endif
ret = tcp_bind_socket(fd, flags, &be->conn_src.source_addr, &conn->addr.from);
if (ret) {
close(fd);
if (ret == 1) {
Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
be->id); be->id);
send_log(be, LOG_EMERG, send_log(be, LOG_EMERG,
"Cannot bind to source address before connect() for proxy %s.\n", "Cannot bind to source address before connect() for backend %s.\n",
be->id); be->id);
} else { } else {
Alert("Cannot bind to tproxy source address before connect() for proxy %s. Aborting.\n", Alert("Cannot bind to tproxy source address before connect() for backend %s. Aborting.\n",
be->id); be->id);
send_log(be, LOG_EMERG, send_log(be, LOG_EMERG,
"Cannot bind to tproxy source address before connect() for proxy %s.\n", "Cannot bind to tproxy source address before connect() for backend %s.\n",
be->id); be->id);
} }
return SN_ERR_RESOURCE; return SN_ERR_RESOURCE;