mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-13 23:14:46 +00:00
[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:
parent
0a3b9d90d3
commit
5e6e204d1c
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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,24 +801,50 @@ 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",
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
global.maxsock++;
|
||||
return 0;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user