[MEDIUM] add support for source interface binding at the server level

Add support for "interface <name>" after the "source" statement on
the server line.
This commit is contained in:
Willy Tarreau 2009-02-04 20:20:58 +01:00
parent d53f96b3f0
commit c76721da57
5 changed files with 65 additions and 24 deletions

View File

@ -4294,6 +4294,7 @@ slowstart <start_time_in_ms>
seen as failed.
source <addr>[:<port>] [usesrc { <addr2>[:<port2>] | client | clientip } ]
source <addr>[:<port>] [interface <name>] ...
The "source" parameter sets the source address which will be used when
connecting to the server. It follows the exact same parameters and principle
as the backend "source" keyword, except that it only applies to the server

View File

@ -91,6 +91,8 @@ struct server {
#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
struct sockaddr_in tproxy_addr; /* non-local address we want to bind to for connect() */
#endif
int iface_len; /* bind interface name length */
char *iface_name; /* bind interface name or NULL */
struct server *tracknext, *tracked; /* next server in a tracking list, tracked server */
char *trackit; /* temporary variable to make assignment deferrable */

View File

@ -1718,6 +1718,11 @@ int connect_server(struct session *s)
remote = (struct sockaddr_in *)&s->cli_addr;
break;
}
#endif
#ifdef SO_BINDTODEVICE
/* Note: this might fail if not CAP_NET_RAW */
if (s->srv->iface_name)
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, s->srv->iface_name, s->srv->iface_len);
#endif
ret = tcpv4_bind_socket(fd, flags, &s->srv->source_addr, remote);
if (ret) {

View File

@ -1976,39 +1976,66 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
newsrv->state |= SRV_BIND_SRC;
newsrv->source_addr = *str2sa(args[cur_arg + 1]);
cur_arg += 2;
if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
while (*(args[cur_arg])) {
if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
#if !defined(CONFIG_HAP_LINUX_TPROXY)
if (newsrv->source_addr.sin_addr.s_addr == INADDR_ANY) {
Alert("parsing [%s:%d] : '%s' requires an explicit '%s' address.\n",
file, linenum, "usesrc", "source");
return -1;
}
if (newsrv->source_addr.sin_addr.s_addr == INADDR_ANY) {
Alert("parsing [%s:%d] : '%s' requires an explicit '%s' address.\n",
file, linenum, "usesrc", "source");
return -1;
}
#endif
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
file, linenum, "usesrc");
return -1;
}
if (!strcmp(args[cur_arg + 1], "client")) {
newsrv->state |= SRV_TPROXY_CLI;
} else if (!strcmp(args[cur_arg + 1], "clientip")) {
newsrv->state |= SRV_TPROXY_CIP;
} else {
newsrv->state |= SRV_TPROXY_ADDR;
newsrv->tproxy_addr = *str2sa(args[cur_arg + 1]);
}
global.last_checks |= LSTCHK_NETADM;
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', or 'clientip' as argument.\n",
file, linenum, "usesrc");
return -1;
}
if (!strcmp(args[cur_arg + 1], "client")) {
newsrv->state |= SRV_TPROXY_CLI;
} else if (!strcmp(args[cur_arg + 1], "clientip")) {
newsrv->state |= SRV_TPROXY_CIP;
} else {
newsrv->state |= SRV_TPROXY_ADDR;
newsrv->tproxy_addr = *str2sa(args[cur_arg + 1]);
}
global.last_checks |= LSTCHK_NETADM;
#if !defined(CONFIG_HAP_LINUX_TPROXY)
global.last_checks |= LSTCHK_CTTPROXY;
global.last_checks |= LSTCHK_CTTPROXY;
#endif
cur_arg += 2;
cur_arg += 2;
continue;
#else /* no TPROXY support */
Alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
Alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
file, linenum, "usesrc");
return -1;
#endif /* defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) */
} /* "usesrc" */
if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
#ifdef SO_BINDTODEVICE
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s' : missing interface name.\n",
file, linenum, args[0]);
return -1;
}
if (newsrv->iface_name)
free(newsrv->iface_name);
newsrv->iface_name = strdup(args[cur_arg + 1]);
newsrv->iface_len = strlen(newsrv->iface_name);
global.last_checks |= LSTCHK_NETADM;
#else
Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
file, linenum, args[0], args[cur_arg]);
return -1;
#endif
}
cur_arg += 2;
continue;
}
/* this keyword in not an option of "source" */
break;
} /* while */
}
else if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside: needs "source" first */
Alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",

View File

@ -589,6 +589,12 @@ void process_chk(struct task *t, int *next)
remote = (struct sockaddr_in *)&s->tproxy_addr;
flags = 3;
}
#endif
#ifdef SO_BINDTODEVICE
/* Note: this might fail if not CAP_NET_RAW */
if (s->iface_name)
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
s->iface_name, s->iface_len);
#endif
ret = tcpv4_bind_socket(fd, flags, &s->source_addr, remote);
if (ret) {