[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.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 416e67c..10f7b2a 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -782,6 +782,8 @@
 	/* 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 @@
 		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;
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 94907ec..78f63fc 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -241,6 +241,16 @@
 		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;
 		msg = "cannot bind socket";