From 54bfeb9313b47a73dfbdef8b68d5011f40cad0a6 Mon Sep 17 00:00:00 2001
From: Wichert Akkerman <wichert@wiggy.net>
Date: Mon, 5 May 2008 16:41:47 +0200
Subject: [PATCH] Use gateway id in names in firewall table names

This makes it possible to run multiple gateways on the same machine.
---
 src/fw_iptables.c |  251 +++++++++++++++++++++++++++++------------------------
 src/fw_iptables.h |   22 +++---
 wifidog.conf      |    5 +-
 3 files changed, 152 insertions(+), 126 deletions(-)

diff --git a/src/fw_iptables.c b/src/fw_iptables.c
index 1e25b4e..f19d485 100644
--- a/src/fw_iptables.c
+++ b/src/fw_iptables.c
@@ -59,34 +59,65 @@ extern pthread_mutex_t	config_mutex;
 Used to supress the error output of the firewall during destruction */ 
 static int fw_quiet = 0;
 
+/** @internal
+ * @brief Insert $ID$ with the gateway's id in a string.
+ *
+ * This function can replace the input string with a new one. It assumes
+ * the input string is dynamically allocted and can be free()ed safely.
+ *
+ * This function must be called with the CONFIG_LOCK held.
+ */
+static void
+iptables_insert_gateway_id(char **input)
+{
+	char *token;
+	const s_config *config;
+	char *buffer;
+
+	if (strstr(*input, "$ID$")==NULL)
+		return;
+
+
+	while ((token=strstr(*input, "$ID$"))!=NULL)
+		/* This string may look odd but it's standard POSIX and ISO C */
+		memcpy(token, "%1$s", 4);
+
+	config = config_get_config();
+	safe_asprintf(&buffer, *input, config->gw_id);
+
+	free(*input);
+	*input=buffer;
+}
+
 /** @internal 
  * */
 static int
 iptables_do_command(const char *format, ...)
 {
-    va_list vlist;
-    char *fmt_cmd,
-        *cmd;
-    int rc;
+	va_list vlist;
+	char *fmt_cmd;
+	char *cmd;
+	int rc;
 
-    va_start(vlist, format);
-    safe_vasprintf(&fmt_cmd, format, vlist);
-	 va_end(vlist);
+	va_start(vlist, format);
+	safe_vasprintf(&fmt_cmd, format, vlist);
+	va_end(vlist);
 
-    safe_asprintf(&cmd, "iptables %s", fmt_cmd);
+	safe_asprintf(&cmd, "iptables %s", fmt_cmd);
+	free(fmt_cmd);
 
-    free(fmt_cmd);
+	iptables_insert_gateway_id(&cmd);
 
-    debug(LOG_DEBUG, "Executing command: %s", cmd);
-	
-    rc = execute(cmd, fw_quiet);
+	debug(LOG_DEBUG, "Executing command: %s", cmd);
 
-    if (rc!=0)
-        debug(LOG_ERR, "iptables comand tailed: %s", cmd);
+	rc = execute(cmd, fw_quiet);
 
-    free(cmd);
+	if (rc!=0)
+		debug(LOG_ERR, "iptables comand failed: %s", cmd);
 
-    return rc;
+	free(cmd);
+
+	return rc;
 }
 
 /**
@@ -189,137 +220,130 @@ int
 iptables_fw_init(void)
 {
 	const s_config *config;
-	char * gw_interface = NULL;
-	char * gw_address = NULL;
 	char * ext_interface = NULL;
 	int gw_port = 0;
 	t_trusted_mac *p;
-   
+
 	fw_quiet = 0;
 
-	 LOCK_CONFIG();
-    config = config_get_config();
-	 gw_interface = safe_strdup(config->gw_interface);
-	 gw_address = safe_strdup(config->gw_address);
-	 gw_port = config->gw_port;
-     if (config->external_interface) {
-	    ext_interface = safe_strdup(config->external_interface);
-     } else {
-	    ext_interface = get_ext_iface();
-     }
-	 UNLOCK_CONFIG();
-    
+	LOCK_CONFIG();
+	config = config_get_config();
+	gw_port = config->gw_port;
+	if (config->external_interface) {
+		ext_interface = safe_strdup(config->external_interface);
+	} else {
+		ext_interface = get_ext_iface();
+	}
+
 	if (ext_interface == NULL) {
+		UNLOCK_CONFIG();
 		debug(LOG_ERR, "FATAL: no external interface");
-		/* XXX leaks safe_strdup()'d strings */
 		return 0;
 	}
-	 /*
-	  *
-	  * Everything in the MANGLE table
-	  *
-	  */
+	/*
+	 *
+	 * Everything in the MANGLE table
+	 *
+	 */
 
-	 		/* Create new chains */
-			iptables_do_command("-t mangle -N " TABLE_WIFIDOG_TRUSTED);
-			iptables_do_command("-t mangle -N " TABLE_WIFIDOG_OUTGOING);
-			iptables_do_command("-t mangle -N " TABLE_WIFIDOG_INCOMING);
+	/* Create new chains */
+	iptables_do_command("-t mangle -N " TABLE_WIFIDOG_TRUSTED);
+	iptables_do_command("-t mangle -N " TABLE_WIFIDOG_OUTGOING);
+	iptables_do_command("-t mangle -N " TABLE_WIFIDOG_INCOMING);
 
-			/* Assign links and rules to these new chains */
-			iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_OUTGOING, gw_interface);
-			iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_TRUSTED, gw_interface);//this rule will be inserted before the prior one
-			iptables_do_command("-t mangle -I POSTROUTING 1 -o %s -j " TABLE_WIFIDOG_INCOMING, gw_interface);
+	/* Assign links and rules to these new chains */
+	iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_OUTGOING, config->gw_interface);
+	iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_TRUSTED, config->gw_interface);//this rule will be inserted before the prior one
+	iptables_do_command("-t mangle -I POSTROUTING 1 -o %s -j " TABLE_WIFIDOG_INCOMING, config->gw_interface);
 
-            for (p = config->trustedmaclist; p != NULL; p = p->next)
-                iptables_do_command("-t mangle -A " TABLE_WIFIDOG_TRUSTED " -m mac --mac-source %s -j MARK --set-mark %d", p->mac, FW_MARK_KNOWN);
+	for (p = config->trustedmaclist; p != NULL; p = p->next)
+		iptables_do_command("-t mangle -A " TABLE_WIFIDOG_TRUSTED " -m mac --mac-source %s -j MARK --set-mark %d", p->mac, FW_MARK_KNOWN);
 
-	 /*
-	  *
-	  * Everything in the NAT table
-	  *
-	  */
+	/*
+	 *
+	 * Everything in the NAT table
+	 *
+	 */
 
-	 		/* Create new chains */
-			iptables_do_command("-t nat -N " TABLE_WIFIDOG_OUTGOING);
-			iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_ROUTER);
-			iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
-			iptables_do_command("-t nat -N " TABLE_WIFIDOG_GLOBAL);
-			iptables_do_command("-t nat -N " TABLE_WIFIDOG_UNKNOWN);
-			iptables_do_command("-t nat -N " TABLE_WIFIDOG_AUTHSERVERS);
+	/* Create new chains */
+	iptables_do_command("-t nat -N " TABLE_WIFIDOG_OUTGOING);
+	iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_ROUTER);
+	iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
+	iptables_do_command("-t nat -N " TABLE_WIFIDOG_GLOBAL);
+	iptables_do_command("-t nat -N " TABLE_WIFIDOG_UNKNOWN);
+	iptables_do_command("-t nat -N " TABLE_WIFIDOG_AUTHSERVERS);
 
-			/* Assign links and rules to these new chains */
-			iptables_do_command("-t nat -A PREROUTING -i %s -j " TABLE_WIFIDOG_OUTGOING, gw_interface);
+	/* Assign links and rules to these new chains */
+	iptables_do_command("-t nat -A PREROUTING -i %s -j " TABLE_WIFIDOG_OUTGOING, config->gw_interface);
 
-			iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -d %s -j " TABLE_WIFIDOG_WIFI_TO_ROUTER, gw_address);
-			iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_ROUTER " -j ACCEPT");
+	iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -d %s -j " TABLE_WIFIDOG_WIFI_TO_ROUTER, config->gw_address);
+	iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_ROUTER " -j ACCEPT");
 
-			iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -j " TABLE_WIFIDOG_WIFI_TO_INTERNET);
-			iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_KNOWN);
-			iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_PROBATION);
-			iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
+	iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -j " TABLE_WIFIDOG_WIFI_TO_INTERNET);
+	iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_KNOWN);
+	iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_PROBATION);
+	iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
 
-			iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_AUTHSERVERS);
-			iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_GLOBAL);
-			iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p tcp --dport 80 -j REDIRECT --to-ports %d", gw_port);
+	iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_AUTHSERVERS);
+	iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_GLOBAL);
+	iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p tcp --dport 80 -j REDIRECT --to-ports %d", gw_port);
 
 
-	 /*
-	  *
-	  * Everything in the FILTER table
-	  *
-	  */
+	/*
+	 *
+	 * Everything in the FILTER table
+	 *
+	 */
 
-	 		/* Create new chains */
-			iptables_do_command("-t filter -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
-			iptables_do_command("-t filter -N " TABLE_WIFIDOG_AUTHSERVERS);
-			iptables_do_command("-t filter -N " TABLE_WIFIDOG_LOCKED);
-			iptables_do_command("-t filter -N " TABLE_WIFIDOG_GLOBAL);
-			iptables_do_command("-t filter -N " TABLE_WIFIDOG_VALIDATE);
-			iptables_do_command("-t filter -N " TABLE_WIFIDOG_KNOWN);
-			iptables_do_command("-t filter -N " TABLE_WIFIDOG_UNKNOWN);
+	/* Create new chains */
+	iptables_do_command("-t filter -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
+	iptables_do_command("-t filter -N " TABLE_WIFIDOG_AUTHSERVERS);
+	iptables_do_command("-t filter -N " TABLE_WIFIDOG_LOCKED);
+	iptables_do_command("-t filter -N " TABLE_WIFIDOG_GLOBAL);
+	iptables_do_command("-t filter -N " TABLE_WIFIDOG_VALIDATE);
+	iptables_do_command("-t filter -N " TABLE_WIFIDOG_KNOWN);
+	iptables_do_command("-t filter -N " TABLE_WIFIDOG_UNKNOWN);
 
-			/* Assign links and rules to these new chains */
+	/* Assign links and rules to these new chains */
 
-            /* Insert at the beginning */
-			iptables_do_command("-t filter -I FORWARD -i %s -j " TABLE_WIFIDOG_WIFI_TO_INTERNET, gw_interface);
+	/* Insert at the beginning */
+	iptables_do_command("-t filter -I FORWARD -i %s -j " TABLE_WIFIDOG_WIFI_TO_INTERNET, config->gw_interface);
 
 
-			iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state INVALID -j DROP");
+	iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state INVALID -j DROP");
 
-			/* XXX: Why this? it means that connections setup after authentication
-			   stay open even after the connection is done... 
-			   iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state RELATED,ESTABLISHED -j ACCEPT");*/
+	/* XXX: Why this? it means that connections setup after authentication
+	   stay open even after the connection is done... 
+	   iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state RELATED,ESTABLISHED -j ACCEPT");*/
 
-			//Won't this rule NEVER match anyway?!?!? benoitg, 2007-06-23
-			//iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -i %s -m state --state NEW -j DROP", ext_interface);
-            
-            /* TCPMSS rule for PPPoE */
-   			iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -o %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu", ext_interface);
+	//Won't this rule NEVER match anyway?!?!? benoitg, 2007-06-23
+	//iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -i %s -m state --state NEW -j DROP", ext_interface);
 
-			iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_AUTHSERVERS);
-			iptables_fw_set_authservers();
+	/* TCPMSS rule for PPPoE */
+	iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -o %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu", ext_interface);
 
-			iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_LOCKED, FW_MARK_LOCKED);
-			iptables_load_ruleset("filter", "locked-users", TABLE_WIFIDOG_LOCKED);
+	iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_AUTHSERVERS);
+	iptables_fw_set_authservers();
 
-			iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_GLOBAL);
-			iptables_load_ruleset("filter", "global", TABLE_WIFIDOG_GLOBAL);
-			iptables_load_ruleset("nat", "global", TABLE_WIFIDOG_GLOBAL);
+	iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_LOCKED, FW_MARK_LOCKED);
+	iptables_load_ruleset("filter", "locked-users", TABLE_WIFIDOG_LOCKED);
 
-			iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_VALIDATE, FW_MARK_PROBATION);
-			iptables_load_ruleset("filter", "validating-users", TABLE_WIFIDOG_VALIDATE);
+	iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_GLOBAL);
+	iptables_load_ruleset("filter", "global", TABLE_WIFIDOG_GLOBAL);
+	iptables_load_ruleset("nat", "global", TABLE_WIFIDOG_GLOBAL);
 
-			iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_KNOWN, FW_MARK_KNOWN);
-			iptables_load_ruleset("filter", "known-users", TABLE_WIFIDOG_KNOWN);
-    
-			iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
-			iptables_load_ruleset("filter", "unknown-users", TABLE_WIFIDOG_UNKNOWN);
-			iptables_do_command("-t filter -A " TABLE_WIFIDOG_UNKNOWN " -j REJECT --reject-with icmp-port-unreachable");
+	iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_VALIDATE, FW_MARK_PROBATION);
+	iptables_load_ruleset("filter", "validating-users", TABLE_WIFIDOG_VALIDATE);
 
-	free(gw_interface);
-	free(gw_address);
+	iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_KNOWN, FW_MARK_KNOWN);
+	iptables_load_ruleset("filter", "known-users", TABLE_WIFIDOG_KNOWN);
 
-    return 1;
+	iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
+	iptables_load_ruleset("filter", "unknown-users", TABLE_WIFIDOG_UNKNOWN);
+	iptables_do_command("-t filter -A " TABLE_WIFIDOG_UNKNOWN " -j REJECT --reject-with icmp-port-unreachable");
+
+	UNLOCK_CONFIG();
+	return 1;
 }
 
 /** Remove the firewall rules
@@ -490,6 +514,7 @@ iptables_fw_counters_update(void)
 
     /* Look for outgoing traffic */
     safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_OUTGOING);
+    iptables_insert_gateway_id(&script);
     output = popen(script, "r");
     free(script);
     if (!output) {
diff --git a/src/fw_iptables.h b/src/fw_iptables.h
index aaf5921..6de59b3 100644
--- a/src/fw_iptables.h
+++ b/src/fw_iptables.h
@@ -31,17 +31,17 @@
 
 /*@{*/ 
 /**Iptable table names used by WifiDog */
-#define TABLE_WIFIDOG_OUTGOING  "WiFiDog_Outgoing"
-#define TABLE_WIFIDOG_WIFI_TO_INTERNET "WiFiDog_WIFI2Internet"
-#define TABLE_WIFIDOG_WIFI_TO_ROUTER "WiFiDog_WIFI2Router"
-#define TABLE_WIFIDOG_INCOMING  "WiFiDog_Incoming"
-#define TABLE_WIFIDOG_AUTHSERVERS "WiFiDog_AuthServers"
-#define TABLE_WIFIDOG_GLOBAL  "WiFiDog_Global"
-#define TABLE_WIFIDOG_VALIDATE  "WiFiDog_Validate"
-#define TABLE_WIFIDOG_KNOWN     "WiFiDog_Known"
-#define TABLE_WIFIDOG_UNKNOWN   "WiFiDog_Unknown"
-#define TABLE_WIFIDOG_LOCKED    "WiFiDog_Locked"
-#define TABLE_WIFIDOG_TRUSTED    "WiFiDog_Trusted"
+#define TABLE_WIFIDOG_OUTGOING  "WiFiDog_$ID$_Outgoing"
+#define TABLE_WIFIDOG_WIFI_TO_INTERNET "WiFiDog_$ID$_WIFI2Internet"
+#define TABLE_WIFIDOG_WIFI_TO_ROUTER "WiFiDog_$ID$_WIFI2Router"
+#define TABLE_WIFIDOG_INCOMING  "WiFiDog_$ID$_Incoming"
+#define TABLE_WIFIDOG_AUTHSERVERS "WiFiDog_$ID$_AuthServers"
+#define TABLE_WIFIDOG_GLOBAL  "WiFiDog_$ID$_Global"
+#define TABLE_WIFIDOG_VALIDATE  "WiFiDog_$ID$_Validate"
+#define TABLE_WIFIDOG_KNOWN     "WiFiDog_$ID$_Known"
+#define TABLE_WIFIDOG_UNKNOWN   "WiFiDog_$ID$_Unknown"
+#define TABLE_WIFIDOG_LOCKED    "WiFiDog_$ID$_Locked"
+#define TABLE_WIFIDOG_TRUSTED    "WiFiDog_$ID$_Trusted"
 /*@}*/ 
 
 /** Used by iptables_fw_access to select if the client should be granted of denied access */
diff --git a/wifidog.conf b/wifidog.conf
index 8c7d74d..3c6c7d3 100644
--- a/wifidog.conf
+++ b/wifidog.conf
@@ -6,8 +6,9 @@
 # Optional
 #
 # Set this to the node ID on the auth server
-# this is used to give a customized login page to the clients and for
-# monitoring/statistics purpose
+# This is used to give a customized login page to the clients and for
+# monitoring/statistics purpose. If you run multiple gateways on the same
+# machine each gateway needs to have a different gateway id.
 # If none is supplied, the mac address of the GatewayInterface interface will be used,
 # without the : separators
 
-- 
1.5.5.1

