]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] add support for bind interface name
authorWilly Tarreau <w@1wt.eu>
Wed, 4 Feb 2009 16:19:29 +0000 (17:19 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 4 Feb 2009 16:19:29 +0000 (17:19 +0100)
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.

doc/configuration.txt
include/types/protocols.h
src/cfgparse.c
src/proto_tcp.c

index b2cb48fed676236d9ba037abebec013b95549b3d..59a8322866fa1365d1ac20d25204f9e311d2c930 100644 (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
index 4c64551bb9fc4703f46b67613bddafa3eab146d3..5c3b60847e1fc0b5f535578599cab7c20433a213 100644 (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.
index 416e67ca2524a1121c37fd22851a1b8716a7551f..10f7b2accf3d9e60b9fd3dfb69e9649df68e5305 100644 (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,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]);
+
+                               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;
index 94907ec762f3fc97e0dca623ba0cc73e41b59859..78f63fcea422d7cedc45611eb8873d65f35091ba 100644 (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;