Description: Allow multiple WAN interfaces (untested)
Origin: upstream

diff -ruN linuxigd-cvs/arcoscom_extra.c linuxigd-cvs.3/arcoscom_extra.c
--- linuxigd-cvs/arcoscom_extra.c	1970-01-01 03:00:00.000000000 +0300
+++ linuxigd-cvs.3/arcoscom_extra.c	2008-01-03 19:11:02.000000000 +0300
@@ -0,0 +1,133 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <net/if.h>
+
+#include "globals.h"
+#include "util.h"
+
+void initGlobals( globals_p ioGlobales ) {
+   memset( ( void * ) ioGlobales, sizeof( struct GLOBALS ), 0 );
+}
+
+int parseCommandLine(int argc, char ** argv, globals_p ioGlobales ) {
+   int ret = 0;
+   register int argc_count;
+   int parameters_without_switches = 0;
+   int lan_switch_found = 0;
+   int wan_switch_found = 0;
+   
+   for( argc_count = 1; argc_count < argc && !ret; ++argc_count ) {
+      if( !strcmp( argv[ argc_count ], "-f" ) ) { // foreground parameter
+         lan_switch_found = 0;
+         wan_switch_found = 0;
+         parameters_without_switches = 0;
+		   ioGlobales->foreground = 1;
+      }
+      else if( !strcmp( argv[ argc_count ], "-L" ) ) { // LAN interfaces parameter
+         lan_switch_found = 1;
+         wan_switch_found = 0;
+         parameters_without_switches = 0;
+      }
+      else if( !strcmp( argv[ argc_count ], "-W" ) ) { // WAN interfaces parameter
+         lan_switch_found = 0;
+         wan_switch_found = 1;
+         parameters_without_switches = 0;
+      }
+      else {
+         if( wan_switch_found ) { // It's a WAN interface name
+            if( 0 == ioGlobales->extCount ) {
+               strncpy( ioGlobales->extInterfaceName, argv[ argc_count ], IFNAMSIZ );
+            }
+            if( ioGlobales->extCount < MAX_WAN_IFACES ) {
+               strncpy( ioGlobales->extInterfaces[ ioGlobales->extCount ], argv[ argc_count ], IFNAMSIZ );
+               ioGlobales->extCount++;
+            }
+         }
+         else if( lan_switch_found ) { // It's a LAN interface name
+            if( 0 == ioGlobales->intCount ) {
+               strncpy( ioGlobales->intInterfaceName, argv[ argc_count ], IFNAMSIZ );
+               // Get the internal ip address to start the daemon on
+               if( 0 == GetIpAddressStr(ioGlobales->intIpAddress, ioGlobales->intInterfaceName) ) {
+                  fprintf(stderr, "Invalid internal interface name '%s'\n", ioGlobales->intInterfaceName);
+                  ret = EXIT_FAILURE;
+               }
+            }
+            if( ioGlobales->intCount < MAX_WAN_IFACES ) {
+               strncpy( ioGlobales->intInterfaces[ ioGlobales->intCount ], argv[ argc_count ], IFNAMSIZ );
+               // Get the internal ip address to start the daemon on
+               if( 0 == GetIpAddressStr( 
+                           ioGlobales->intIpAddresses[ ioGlobales->intCount ],
+                           ioGlobales->intInterfaces[ ioGlobales->intCount ]
+                           )
+                 ) {
+                  fprintf(stderr, "Invalid internal interface name '%s'\n", ioGlobales->intInterfaceName);
+                  ret = EXIT_FAILURE;
+               }
+               ioGlobales->intCount++;
+            }
+         }
+         else {
+            switch( parameters_without_switches ) {
+               case 0: // Obsolete WAN interface
+                  if( 0 == ioGlobales->extCount ) {
+                     strncpy( ioGlobales->extInterfaceName, argv[ argc_count ], IFNAMSIZ );
+                  }
+                  if( ioGlobales->extCount < MAX_WAN_IFACES ) {
+                     strncpy( ioGlobales->extInterfaces[ ioGlobales->extCount ], argv[ argc_count ], IFNAMSIZ );
+                     ioGlobales->extCount++;
+                  }
+                  break;
+               case 1: // Obsolete LAN interface
+                  if( 0 == ioGlobales->intCount ) {
+                     strncpy( ioGlobales->intInterfaceName, argv[ argc_count ], IFNAMSIZ );
+	                  // Get the internal ip address to start the daemon on
+	                  if( 0 == GetIpAddressStr(ioGlobales->intIpAddress, ioGlobales->intInterfaceName) ) {
+		                  fprintf(stderr, "Invalid internal interface name '%s'\n", ioGlobales->intInterfaceName);
+		                  ret = EXIT_FAILURE;
+	                  }
+                  }
+                  if( ioGlobales->intCount < MAX_LAN_IFACES ) {
+                     strncpy( ioGlobales->intInterfaces[ ioGlobales->intCount ], argv[ argc_count ], IFNAMSIZ );
+	                  // Get the internal ip address to start the daemon on
+	                  if( 0 == GetIpAddressStr( 
+	                              ioGlobales->intIpAddresses[ ioGlobales->intCount ],
+	                              ioGlobales->intInterfaces[ ioGlobales->intCount ]
+	                              )
+	                    ) {
+		                  fprintf(stderr, "Invalid internal interface name '%s'\n", ioGlobales->intInterfaceName);
+		                  ret = EXIT_FAILURE;
+	                  }
+                     ioGlobales->intCount++;
+                  }
+                  break;
+               default:
+                  ret = 1;
+                  break;
+            }
+         }
+         parameters_without_switches++;
+      }
+   }   
+  
+   if( !ioGlobales->intCount || !ioGlobales->extCount ) {
+      fprintf(stderr, "Parameters error found.\n", ioGlobales->intInterfaceName);
+      ret = 1;
+   }
+   
+   return ret;
+}
+
+void printUsage( void ) {
+   printf(
+      "SINGLE WAN INTERFACE USAGE:\n"
+      "   upnpd [-f] <external ifname> <internal ifname>\n"
+      "MULTIPLE WAN INTERFACE USAGE (subject to change):\n"
+      "   upnpd [-f] -W <external ifname list> -L <internal ifname list>\n"
+      "\n"
+      "  -f\tdon't daemonize\n"
+      "Examples:\n"
+      "   upnpd ppp0 eth0\n"
+      "   upnpd -W ppp0 ppp1 -L eth0\n"
+      );
+}
--- linuxigd-cvs/arcoscom_extra.h	1970-01-01 03:00:00.000000000 +0300
+++ linuxigd-cvs.3/arcoscom_extra.h	2008-01-03 19:11:02.000000000 +0300
@@ -0,0 +1,10 @@
+#ifndef _ARCOSCOM_EXTRA_H_
+#define _ARCOSCOM_EXTRA_H_
+
+#include "globals.h"
+
+void initGlobals( globals_p ioGlobales );
+int parseCommandLine(int argc, char ** argv, globals_p ioGlobales );
+void printUsage( void );
+
+#endif // _ARCOSCOM_EXTRA_H_
--- linuxigd-cvs/CHANGES	2008-01-03 18:40:37.000000000 +0300
+++ linuxigd-cvs.3/CHANGES	2008-01-03 19:11:02.000000000 +0300
@@ -1,3 +1,10 @@
+2007-10-23 Samuel Díaz García <samueldg@arcoscom.com>
+  * Multiple WAN interfaces: First attempt.
+
+  * Prepared code for multiple LAN interfaces.
+
+  * Changed command line arguments (with backward compatibility).
+
 2007-06-30 Magnus Hyllander <mhyllander@users.sourceforge.net>
   * Added the listenport option, which lets you select which UPnP port
     to listen to. The port number is passed to UpnpInit when
--- linuxigd-cvs/etc/upnpd.rc	2006-08-16 03:34:56.000000000 +0400
+++ linuxigd-cvs.3/etc/upnpd.rc	2008-01-03 19:11:02.000000000 +0300
@@ -34,7 +34,7 @@
 	if [ ! -f /var/lock/subsys/upnpd ]; then
 	    echo -n $"Starting $prog: "
 	    [ "$ALLOW_MULTICAST" != "no" ] && route add -net 239.0.0.0 netmask 255.0.0.0 $INTIFACE
-	    daemon "$UPNPD" $EXTIFACE $INTIFACE
+	    daemon "$UPNPD" -W $EXTIFACE -L $INTIFACE
 	    RETVAL=$?
 	    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/upnpd
 	    echo
--- linuxigd-cvs/globals.h	2008-01-03 18:40:40.000000000 +0300
+++ linuxigd-cvs.3/globals.h	2008-01-03 19:11:02.000000000 +0300
@@ -6,17 +6,23 @@
 #define CHAIN_NAME_LEN 32
 #define BITRATE_LEN 32
 #define PATH_LEN 64
-#define RESULT_LEN 512
+#define RESULT_LEN 1024
 #define NUM_LEN 32
+#define MAX_IFACES 8
+#define MAX_LAN_IFACES MAX_IFACES
+#define MAX_WAN_IFACES MAX_IFACES
 
 #ifndef min
 #define min(a,b) ((a) < (b) ? (a) : (b))
 #endif
 
+typedef char T_INTERFACENAME[ IFNAMSIZ ]; // Interface name type.
+
 struct GLOBALS {
-  char extInterfaceName[IFNAMSIZ]; // The name of the external interface, picked up from the
+  T_INTERFACENAME extInterfaceName; // The name of the external interface, picked up from the
                                    // command line
-  char intInterfaceName[IFNAMSIZ]; // The name of the internal interface, picked from command line
+  T_INTERFACENAME intInterfaceName; // The name of the internal interface, picked from command line
+   char intIpAddress[16];     // Server internal ip address
 
   // All vars below are read from /etc/upnpd.conf in main.c
   int debug;  // 1 - print debug messages to syslog
@@ -36,6 +42,15 @@
   char descDocName[PATH_LEN];
   char xmlPath[PATH_LEN];
   int listenport;	//The port to listen on
+
+// Now we can use lists for external and/or internal interfaces with diferent params  
+  T_INTERFACENAME extInterfaces[ MAX_WAN_IFACES ]; // Pointer to external interfaces names array.
+  int extCount; // Number of external interfaces. Must be <= MAX_WAN_IFACES
+  T_INTERFACENAME intInterfaces[ MAX_LAN_IFACES ]; // Pointer to internal interfaces names array.
+  char intIpAddresses[ MAX_LAN_IFACES ][ 16 ];     // Server internal ip address
+  int intCount; // Number of internal interfaces. Must be <= MAX_LAN_IFACES
+
+  int foreground;
 };
 
 typedef struct GLOBALS* globals_p;
--- linuxigd-cvs/main.c	2008-01-03 18:40:41.000000000 +0300
+++ linuxigd-cvs.3/main.c	2008-01-03 19:11:02.000000000 +0300
@@ -15,6 +15,7 @@
 #include "gatedevice.h"
 #include "util.h"
 #include "pmlist.h"
+#include "arcoscom_extra.h"
 
 // Global variables
 globals g_vars;
@@ -22,36 +23,19 @@
 int main (int argc, char** argv)
 {
 	char descDocUrl[7+15+1+5+1+sizeof(g_vars.descDocName)+1]; // http://ipaddr:port/docName<null>
-	char intIpAddress[16];     // Server internal ip address
 	sigset_t sigsToCatch;
 	int ret, signum, arg = 1, foreground = 0;
+	
+	initGlobals( &g_vars );
 
-	if (argc < 3 || argc > 4) {
-	  printf("Usage: upnpd [-f] <external ifname> <internal ifname>\n");
-	  printf("  -f\tdon't daemonize\n");
-	  printf("Example: upnpd ppp0 eth0\n");
-	  exit(0);
-	}
+   if( parseCommandLine( argc, argv, &g_vars ) ) {
+      printUsage();
+      exit( 0 );
+   }
 
 	parseConfigFile(&g_vars);
 
-	// check for '-f' option
-	if (strcmp(argv[arg], "-f") == 0) {
-		foreground = 1;
-		arg++;
-	}
-
-	// Save interface names for later use
-	strncpy(g_vars.extInterfaceName, argv[arg++], IFNAMSIZ);
-	strncpy(g_vars.intInterfaceName, argv[arg++], IFNAMSIZ);
-
-	// Get the internal ip address to start the daemon on
-	if (GetIpAddressStr(intIpAddress, g_vars.intInterfaceName) == 0) {
-		fprintf(stderr, "Invalid internal interface name '%s'\n", g_vars.intInterfaceName);
-		exit(EXIT_FAILURE);
-	}
-
-	if (!foreground) {
+	if (!g_vars.foreground) {
 		struct rlimit resourceLimit = { 0, 0 };
 		pid_t pid, sid;
 		unsigned int i;
@@ -114,9 +98,9 @@
 
 	// Initialize UPnP SDK on the internal Interface
 	trace(3, "Initializing UPnP SDK ... ");
-	if ( (ret = UpnpInit(intIpAddress,g_vars.listenport) ) != UPNP_E_SUCCESS)
+	if ( (ret = UpnpInit(g_vars.intIpAddress,g_vars.listenport) ) != UPNP_E_SUCCESS)
 	{
-		syslog (LOG_ERR, "Error Initializing UPnP SDK on IP %s port %d",intIpAddress,g_vars.listenport);
+		syslog (LOG_ERR, "Error Initializing UPnP SDK on IP %s port %d",g_vars.intIpAddress,g_vars.listenport);
 		syslog (LOG_ERR, "  UpnpInit returned %d", ret);
 		UpnpFinish();
 		exit(1);
--- linuxigd-cvs/Makefile	2008-01-03 18:40:38.000000000 +0300
+++ linuxigd-cvs.3/Makefile	2008-01-03 19:11:02.000000000 +0300
@@ -6,7 +6,7 @@
 CC=gcc
 INCLUDES=
 LIBS= -lpthread -lupnp -lixml -lthreadutil
-FILES= main.o gatedevice.o pmlist.o util.o config.o
+FILES= arcoscom_extra.o main.o gatedevice.o pmlist.o util.o config.o
 
 CFLAGS += -Wall -g -O2
 
--- linuxigd-cvs/pmlist.c	2008-01-03 18:40:41.000000000 +0300
+++ linuxigd-cvs.3/pmlist.c	2008-01-03 19:12:12.000000000 +0300
@@ -233,9 +233,12 @@
 {
     if (enabled)
     {
+      register int external_iface_count;
+
       char dest[DEST_LEN];
       snprintf(dest, DEST_LEN, "%s:%s", internalClient, internalPort);
 
+      for( external_iface_count = 0; external_iface_count < g_vars.extCount; ++external_iface_count ) {
 #if HAVE_LIBIPTC
 	char *buffer = malloc(strlen(internalClient) + strlen(internalPort) + 2);
 	if (buffer == NULL) {
@@ -251,17 +254,17 @@
 	  iptc_add_rule("filter", g_vars.forwardChainName, protocol, NULL, NULL, NULL, internalClient, NULL, internalPort, "ACCEPT", NULL, g_vars.forwardRulesAppend ? TRUE : FALSE);
 	}
 	trace(3, "iptc_add_rule %s %s %s %s %s %s %s %s",
-	      "nat", g_vars.preroutingChainName, protocol, g_vars.extInterfaceName, externalPort, "DNAT", dest, "APPEND");
-	iptc_add_rule("nat", g_vars.preroutingChainName, protocol, g_vars.extInterfaceName, NULL, NULL, NULL, NULL, externalPort, "DNAT", dest, TRUE);
+	      "nat", g_vars.preroutingChainName, protocol, g_vars.extInterfaces[ external_iface_count ], externalPort, "DNAT", dest, "APPEND");
+	iptc_add_rule("nat", g_vars.preroutingChainName, protocol, g_vars.extInterfaces[ external_iface_count ], NULL, NULL, NULL, NULL, externalPort, "DNAT", dest, TRUE);
 #else
 	int status;
 	
 	if (g_vars.createForwardRules)
 	{
-	  char *args[] = {g_vars.iptables, g_vars.forwardRulesAppend ? "-A" : "-I", g_vars.forwardChainName, "-p", protocol, "-d", internalClient, "--dport", internalPort, "-j", "ACCEPT", NULL};
+	  char *args[] = {g_vars.iptables, g_vars.forwardRulesAppend ? "-A" : "-I", g_vars.forwardChainName, "-i", g_vars.extInterfaces[ external_iface_count ], "-p", protocol, "-d", internalClient, "--dport", internalPort, "-j", "ACCEPT", NULL};
 	  
-	  trace(3, "%s %s %s -p %s -d %s --dport %s -j ACCEPT", 
-		g_vars.iptables,g_vars.forwardRulesAppend ? "-A" : "-I",g_vars.forwardChainName, protocol, internalClient, internalPort);
+	  trace(3, "%s %s %s -i %s -p %s -d %s --dport %s -j ACCEPT", 
+		g_vars.iptables,g_vars.forwardRulesAppend ? "-A" : "-I",g_vars.forwardChainName, g_vars.extInterfaces[ external_iface_count ], protocol, internalClient, internalPort);
 	  if (!fork()) {
 	    int rc = execv(g_vars.iptables, args);
 	    exit(rc);
@@ -271,10 +274,10 @@
 	}
 
 	{
-	  char *args[] = {g_vars.iptables, "-t", "nat", "-A", g_vars.preroutingChainName, "-i", g_vars.extInterfaceName, "-p", protocol, "--dport", externalPort, "-j", "DNAT", "--to", dest, NULL};
+	  char *args[] = {g_vars.iptables, "-t", "nat", "-A", g_vars.preroutingChainName, "-i", g_vars.extInterfaces[ external_iface_count ], "-p", protocol, "--dport", externalPort, "-j", "DNAT", "--to", dest, NULL};
 
 	  trace(3, "%s -t nat -A %s -i %s -p %s --dport %s -j DNAT --to %s", 
-		g_vars.iptables, g_vars.preroutingChainName, g_vars.extInterfaceName, protocol, externalPort, dest);
+		g_vars.iptables, g_vars.preroutingChainName, g_vars.extInterfaces[ external_iface_count ], protocol, externalPort, dest);
 	  if (!fork()) {
 	    int rc = execv(g_vars.iptables, args);
 	    exit(rc);
@@ -283,6 +286,7 @@
 	  }
 	}
 #endif
+      } // for
     }
     return 1;
 }
@@ -291,13 +295,15 @@
 {
     if (enabled)
     {
+      register int external_iface_count;
       char dest[DEST_LEN];
       snprintf(dest, DEST_LEN, "%s:%s", internalClient, internalPort);
 
+      for( external_iface_count = 0; external_iface_count < g_vars.extCount; ++external_iface_count ) {
 #if HAVE_LIBIPTC
 	trace(3, "iptc_delete_rule %s %s %s %s %s %s %s",
-	      "nat", g_vars.preroutingChainName, protocol, g_vars.extInterfaceName, externalPort, "DNAT", dest);
-	iptc_delete_rule("nat", g_vars.preroutingChainName, protocol, g_vars.extInterfaceName, NULL, NULL, NULL, NULL, externalPort, "DNAT", dest);
+	      "nat", g_vars.preroutingChainName, protocol, g_vars.extInterfaces[ external_iface_count ], externalPort, "DNAT", dest);
+	iptc_delete_rule("nat", g_vars.preroutingChainName, protocol, g_vars.extInterfaces[ external_iface_count ], NULL, NULL, NULL, NULL, externalPort, "DNAT", dest);
 	if (g_vars.createForwardRules)
 	{
 	  trace(3, "iptc_delete_rule %s %s %s %s %s %s",
@@ -308,10 +314,10 @@
 	int status;
 	
 	{
-	  char *args[] = {g_vars.iptables, "-t", "nat", "-D", g_vars.preroutingChainName, "-i", g_vars.extInterfaceName, "-p", protocol, "--dport", externalPort, "-j", "DNAT", "--to", dest, NULL};
+	  char *args[] = {g_vars.iptables, "-t", "nat", "-D", g_vars.preroutingChainName, "-i", g_vars.extInterfaces[ external_iface_count ], "-p", protocol, "--dport", externalPort, "-j", "DNAT", "--to", dest, NULL};
 
 	  trace(3, "%s -t nat -D %s -i %s -p %s --dport %s -j DNAT --to %s",
-		g_vars.iptables, g_vars.preroutingChainName, g_vars.extInterfaceName, protocol, externalPort, dest);
+		g_vars.iptables, g_vars.preroutingChainName, g_vars.extInterfaces[ external_iface_count ], protocol, externalPort, dest);
 	  
 	  if (!fork()) {
 	    int rc = execv(g_vars.iptables, args);
@@ -323,10 +329,10 @@
 
 	if (g_vars.createForwardRules)
 	{
-	  char *args[] = {g_vars.iptables, "-D", g_vars.forwardChainName, "-p", protocol, "-d", internalClient, "--dport", internalPort, "-j", "ACCEPT", NULL};
+	  char *args[] = {g_vars.iptables, "-D", g_vars.forwardChainName, "-i", g_vars.extInterfaces[ external_iface_count ], "-p", protocol, "-d", internalClient, "--dport", internalPort, "-j", "ACCEPT", NULL};
 	  
-	  trace(3, "%s -D %s -p %s -d %s --dport %s -j ACCEPT",
-		g_vars.iptables, g_vars.forwardChainName, protocol, internalClient, internalPort);
+	  trace(3, "%s -D %s -i %s -p %s -d %s --dport %s -j ACCEPT",
+		g_vars.iptables, g_vars.forwardChainName, g_vars.extInterfaces[ external_iface_count ], protocol, internalClient, internalPort);
 	  if (!fork()) {
 	    int rc = execv(g_vars.iptables, args);
 	    exit(rc);
@@ -335,6 +341,7 @@
 	  }
 	}
 #endif
+      } // for
     }
     return 1;
 }
