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
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
/* 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;
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]);
+
+ cur_arg ++;
+ continue;
+#else
+ Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
+ file, linenum, args[0], args[cur_arg]);
return -1;
+#endif
}
-#else
- Alert("parsing [%s:%d] : '%s' supports no option after the address list.\n",
+ Alert("parsing [%s:%d] : '%s' only supports the 'transparent' and 'interface' options.\n",
file, linenum, args[0]);
return -1;
-#endif
}
global.maxsock++;
return 0;
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;