[MINOR] add support for bind interface name

By appending "interface <name>" to a "bind" line, it is now possible
to specifically bind to a physical interface name. Note that this
currently only works on Linux and requires root privileges.
This commit is contained in:
Willy Tarreau 2009-02-04 17:19:29 +01:00
parent 0a3b9d90d3
commit 5e6e204d1c
4 changed files with 60 additions and 10 deletions

View File

@ -853,6 +853,7 @@ balance url_param <param> [check_post [<max_wait>]]
bind [<address>]:<port> [, ...]
bind [<address>]:<port> [, ...] interface <interface>
bind [<address>]:<port> [, ...] transparent
Define one or several listening addresses and/or ports in a frontend.
May be used in sections : defaults | frontend | listen | backend
@ -868,6 +869,16 @@ bind [<address>]:<port> [, ...] transparent
mandatory. Note that in the case of an IPv6 address, the port
is always the number after the last colon (':').
<interface> is an optional physical interface name. This is currently
only supported on Linux. The interface must be a physical
interface, not an aliased interface. When specified, all
addresses on the same line will only be accepted if the
incoming packet physically come through the designated
interface. It is also possible to bind multiple frontends to
the same address if they are bound to different interfaces.
Note that binding to a physical interface requires root
privileges.
transparent is an optional keyword which is supported only on certain
Linux kernels. It indicates that the addresses will be bound
even if they do not belong to the local machine. Any packet

View File

@ -96,6 +96,7 @@ struct listener {
mode_t mode; /* 0 to leave unchanged */
} ux;
} perm;
char *interface; /* interface name or NULL */
};
/* This structure contains all information needed to easily handle a protocol.

View File

@ -782,6 +782,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
/* Now let's parse the proxy-specific keywords */
if (!strcmp(args[0], "bind")) { /* new listen addresses */
struct listener *last_listen;
int cur_arg;
if (curproxy == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
return -1;
@ -799,25 +801,51 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
curproxy->listen = str2listener(args[1], last_listen);
if (!curproxy->listen)
return -1;
if (*args[2]) {
cur_arg = 2;
while (*(args[cur_arg])) {
if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
#ifdef SO_BINDTODEVICE
struct listener *l;
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s' : missing interface name.\n",
file, linenum, args[0]);
return -1;
}
for (l = curproxy->listen; l != last_listen; l = l->next)
l->interface = strdup(args[cur_arg + 1]);
global.last_checks |= LSTCHK_NETADM;
cur_arg += 2;
continue;
#else
Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
file, linenum, args[0], args[cur_arg]);
return -1;
#endif
}
if (!strcmp(args[cur_arg], "transparent")) { /* transparently bind to these addresses */
#ifdef CONFIG_HAP_LINUX_TPROXY
if (!strcmp(args[2], "transparent")) { /* transparently bind to these addresses */
struct listener *l;
for (l = curproxy->listen; l != last_listen; l = l->next)
l->options |= LI_O_FOREIGN;
}
else {
Alert("parsing [%s:%d] : '%s' only supports the 'transparent' option.\n",
file, linenum, args[0]);
return -1;
}
cur_arg ++;
continue;
#else
Alert("parsing [%s:%d] : '%s' supports no option after the address list.\n",
file, linenum, args[0]);
Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
file, linenum, args[0], args[cur_arg]);
return -1;
#endif
}
Alert("parsing [%s:%d] : '%s' only supports the 'transparent' and 'interface' options.\n",
file, linenum, args[0]);
return -1;
}
global.maxsock++;
return 0;
}

View File

@ -240,6 +240,16 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
msg = "cannot make listening socket transparent";
err |= ERR_ALERT;
}
#endif
#ifdef SO_BINDTODEVICE
/* Note: this might fail if not CAP_NET_RAW */
if (listener->interface) {
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
listener->interface, strlen(listener->interface)) == -1) {
msg = "cannot bind listener to device";
err |= ERR_WARN;
}
}
#endif
if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
err |= ERR_RETRYABLE | ERR_ALERT;