]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] add support for source interface binding at the server level
authorWilly Tarreau <w@1wt.eu>
Wed, 4 Feb 2009 19:20:58 +0000 (20:20 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 4 Feb 2009 19:20:58 +0000 (20:20 +0100)
Add support for "interface <name>" after the "source" statement on
the server line.

doc/configuration.txt
include/types/server.h
src/backend.c
src/cfgparse.c
src/checks.c

index a804d23bd9e12714b91855e3121dc865a83c1ddc..fd62ef1e85116b6b49ebf9d5cc70954e2ee868b9 100644 (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
index 09eb1bade231793432ebc1732ef3cd610377fcc2..5c0186a88469f05573e19f54214db9d743ee8956 100644 (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 */
index a6a0351af98e6ed78f3b1ca0b60a1ec16ad5d166..e1911c5e3b5d07cafbb8c85ce2d8f1ffdcf2dd96 100644 (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) {
index 6507bff09d57937445a7e124d5903401e4c8f297..5136e9471e1d9c5c587bc63e74a9e60849107ae1 100644 (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",
index aad1643891ebad658b228ee3665f4b89ba4f4285..eb316cbb634f4fc958eba5e9419cebd298f8f356 100644 (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) {