From: Willy Tarreau Date: Wed, 4 Feb 2009 19:20:58 +0000 (+0100) Subject: [MEDIUM] add support for source interface binding at the server level X-Git-Tag: v1.3.16-rc1~50 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c76721da57d1468fe2546aa55c0ef6a7d99b03cb;p=thirdparty%2Fhaproxy.git [MEDIUM] add support for source interface binding at the server level Add support for "interface " after the "source" statement on the server line. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index a804d23bd9..fd62ef1e85 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -4294,6 +4294,7 @@ slowstart seen as failed. source [:] [usesrc { [:] | client | clientip } ] +source [:] [interface ] ... 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 diff --git a/include/types/server.h b/include/types/server.h index 09eb1bade2..5c0186a884 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -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 */ diff --git a/src/backend.c b/src/backend.c index a6a0351af9..e1911c5e3b 100644 --- a/src/backend.c +++ b/src/backend.c @@ -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) { diff --git a/src/cfgparse.c b/src/cfgparse.c index 6507bff09d..5136e9471e 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -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 [:], '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 [:], '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", diff --git a/src/checks.c b/src/checks.c index aad1643891..eb316cbb63 100644 --- a/src/checks.c +++ b/src/checks.c @@ -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) {