make iptables-restore and iptables-save work again!
diff --git a/Makefile b/Makefile
index 60acf0e..dd28ae5 100644
--- a/Makefile
+++ b/Makefile
@@ -18,8 +18,8 @@
 DEPFILES = $(SHARED_LIBS:%.so=%.d)
 SH_CFLAGS:=$(CFLAGS) -fPIC
 
-EXTRAS+=iptables iptables.o ip6tables ip6tables.o #iptables-save iptables-restore
-EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables $(DESTDIR)$(BINDIR)/ip6tables $(DESTDIR)$(MANDIR)/man8/iptables.8 #$(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore
+EXTRAS+=iptables iptables.o iptables-save iptables-restore # ip6tables ip6tables.o 
+EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables $(DESTDIR)$(MANDIR)/man8/iptables.8 $(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore # $(DESTDIR)$(BINDIR)/ip6tables 
 
 # Sparc64 hack
 ifeq ($(shell uname -m),sparc64)
diff --git a/iptables-restore.c b/iptables-restore.c
index f9a9595..5e01720 100644
--- a/iptables-restore.c
+++ b/iptables-restore.c
@@ -1,10 +1,23 @@
-/* Code to restore the iptables state, from file by iptables-save. */
+/* Code to restore the iptables state, from file by iptables-save. 
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * based on previous code from Rusty Russell <rusty@linuxcare.com.au>
+ *
+ * This coude is distributed under the terms of GNU GPL
+ */
+
 #include <getopt.h>
 #include <sys/errno.h>
 #include <string.h>
 #include <stdio.h>
-#include "packet-filter/userspace/iptables.h"
-#include "packet-filter/userspace/libiptc/libiptc.h"
+#include <stdlib.h>
+#include "iptables.h"
+#include "libiptc/libiptc.h"
+
+#ifdef DEBUG
+#define DEBUGP(x, args ...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args ...) 
+#endif
 
 /* Keeping track of external matches and targets.  */
 static struct option options[] = {
@@ -23,29 +36,28 @@
 	exit(1);
 }
 
-static int clean_slate(iptc_handle_t *handle)
+iptc_handle_t create_handle(const char *tablename)
 {
-	/* Skip over builtins. */
-	const char *i, *last = IPTC_LABEL_OUTPUT;
+	iptc_handle_t handle;
 
-	/* Be careful iterating: it isn't safe during delete. */
-	/* Re-iterate after each delete successful */
-	while ((i = iptc_next_chain(last, handle)) != NULL) {
-		if (!iptc_flush_entries(i, handle)
-		    || !iptc_delete_chain(i, handle))
-			return 0;
+	handle = iptc_init(tablename);
+	if (!handle) {
+		exit_error(PARAMETER_PROBLEM, "%s: unable to initialize"
+			"table '%s'\n", program_name, tablename);
+		exit(1);
 	}
-	return 1;
+	return handle;
 }
 
+
 int main(int argc, char *argv[])
 {
 	iptc_handle_t handle;
 	char buffer[10240];
 	int counters = 0, binary = 0, verbose = 0;
 	unsigned int line = 0;
-	int c;
-	const char *chain;
+	char curtable[IPT_TABLE_MAXNAMELEN + 1];
+	char curchain[IPT_FUNCTION_MAXNAMELEN + 1];
 	FILE *in;
 
 	program_name = "iptables-restore";
@@ -65,8 +77,8 @@
 		exit(1);
 	}
 	else in = stdin;
-
-	handle = iptc_init();
+/*
+	handle = iptc_init("filter");
 	if (!handle)
 		exit_error(VERSION_PROBLEM,
 			   "can't initialize iptables-restore: %s",
@@ -75,7 +87,7 @@
 	if (!clean_slate(&handle))
 		exit_error(OTHER_PROBLEM, "Deleting old chains: %s",
 			   iptc_strerror(errno));
-
+*/
 	/* Grab standard input. */
 	while (fgets(buffer, sizeof(buffer), in)) {
 		int ret;
@@ -85,37 +97,84 @@
 		else if (buffer[0] == '#') {
 			if (verbose) fputs(buffer, stdout);
 			continue;
-		} else if (strcmp(buffer, "COMMIT\n") == 0)
+		} else if (strcmp(buffer, "COMMIT\n") == 0) {
+			DEBUGP("Calling commit\n");
 			ret = iptc_commit(&handle);
-		else if (buffer[0] == ':') {
+		} else if (buffer[0] == '*') {
+			/* New table */
+			char *table;
+
+			table = strtok(buffer+1, " \t\n");
+			DEBUGP("line %u, table '%s'\n", line, table);
+			if (!table) {
+				exit_error(PARAMETER_PROBLEM, 
+					"%s: line %u table name invalid\n",
+					program_name, line);
+				exit(1);
+			}
+			strncpy(curtable, table, IPT_TABLE_MAXNAMELEN);
+
+			handle = create_handle(table);
+
+			DEBUGP("Cleaning all chains of table '%s'\n", table);
+			for_each_chain(flush_entries, verbose, 1, &handle) ;
+
+			DEBUGP("Deleting all user-defined chains of table '%s'\n", table);
+			for_each_chain(delete_chain, verbose, 0, &handle) ;
+
+			ret = 1;
+
+		} else if (buffer[0] == ':') {
 			/* New chain. */
-			char *chain, *policy;
+			char *policy, *chain;
 
 			/* FIXME: Don't ignore counters. */
+
 			chain = strtok(buffer+1, " \t\n");
+			DEBUGP("line %u, chain '%s'\n", line, chain);
 			if (!chain) {
 				exit_error(PARAMETER_PROBLEM,
 					   "%s: line %u chain name invalid\n",
 					   program_name, line);
 				exit(1);
 			}
+			strncpy(curchain, chain, IPT_FUNCTION_MAXNAMELEN);
+
+			/* why the f... does iptc_builtin not work here ? */
+//			if (!iptc_builtin(curchain, &handle)) {
+				DEBUGP("Creating new chain '%s'\n", curchain);
+				if (!iptc_create_chain(curchain, &handle))
+				DEBUGP("unable to create chain '%s':%s\n", curchain,
+					strerror(errno));
+//			}
+
 			policy = strtok(NULL, " \t\n");
+			DEBUGP("line %u, policy '%s'\n", line, policy);
 			if (!policy) {
 				exit_error(PARAMETER_PROBLEM,
 					   "%s: line %u policy invalid\n",
 					   program_name, line);
 				exit(1);
 			}
-			if (strcmp(policy, "-") != 0
-			    && !iptc_set_policy(chain, policy, &handle))
-				exit_error(OTHER_PROBLEM,
-					   "Can't set policy `%s'"
-					   " on `%s' line %u: %s\n",
-					   chain, policy, line,
-					   iptc_strerror(errno));
+
+			if (strcmp(policy, "-") != 0) {
+
+				DEBUGP("Setting policy of chain %s to %s\n",
+					chain, policy);
+
+				if (!iptc_set_policy(chain, policy, &handle))
+					exit_error(OTHER_PROBLEM,
+						"Can't set policy `%s'"
+						" on `%s' line %u: %s\n",
+						chain, policy, line,
+						iptc_strerror(errno));
+			}
+
+			ret = 1;
+
 		} else {
 			char *newargv[1024];
-			int i;
+			int i,a;
 			char *ptr = buffer;
 
 			/* FIXME: Don't ignore counters. */
@@ -127,9 +186,14 @@
 						   line);
 			}
 
-			/* strtok: a function only a coder could love */
 			newargv[0] = argv[0];
-			for (i = 1; i < sizeof(newargv)/sizeof(char *); i++) {
+			newargv[1] = "-t";
+			newargv[2] = (char *) &curtable;
+			newargv[3] = "-A";
+			newargv[4] = (char *) &curchain;
+
+			/* strtok: a function only a coder could love */
+			for (i = 5; i < sizeof(newargv)/sizeof(char *); i++) {
 				if (!(newargv[i] = strtok(ptr, " \t\n")))
 					break;
 				ptr = NULL;
@@ -141,7 +205,13 @@
 				exit(1);
 			}
 
-			ret = do_command(i, newargv, &handle);
+			DEBUGP("===>calling do_command(%u, argv, &%s, handle):\n",
+					i, curtable);
+
+			for (a = 0; a <= i; a++)
+				DEBUGP("argv[%u]: %s\n", a, newargv[a]);
+
+			ret = do_command(i, newargv, &newargv[2], &handle);
 		}
 		if (!ret) {
 			fprintf(stderr, "%s: line %u failed\n",
diff --git a/iptables-save.c b/iptables-save.c
index d858817..413e1ad 100644
--- a/iptables-save.c
+++ b/iptables-save.c
@@ -1,7 +1,13 @@
 /* Code to save the iptables state, in human readable-form. */
+/* Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
+ * 	    Harald Welte <laforge@gnumonks.org>
+ */
 #include <getopt.h>
 #include <sys/errno.h>
 #include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
 #include <dlfcn.h>
 #include <time.h>
 #include "libiptc/libiptc.h"
@@ -47,6 +53,8 @@
 			break;
 		}
 	}
+
+	printf(" ");
 }
 
 /* These are hardcoded backups in iptables.c, so they are safe */
@@ -55,6 +63,7 @@
 	u_int8_t num;
 };
 
+/* FIXME: why don't we use /etc/services ? */
 static const struct pprot chain_protos[] = {
 	{ "tcp", IPPROTO_TCP },
 	{ "udp", IPPROTO_UDP },
@@ -78,6 +87,7 @@
 	}
 }
 
+#if 0
 static int non_zero(const void *ptr, size_t size)
 {
 	unsigned int i;
@@ -88,74 +98,97 @@
 
 	return 1;
 }
+#endif
+
+static int print_match(const struct ipt_entry_match *e)
+{
+	struct iptables_match *match
+		= find_match(e->u.user.name, TRY_LOAD);
+
+	if (match) {
+		printf("-m %s ", e->u.user.name);
+		match->save(NULL, e);
+	} else {
+		if (e->u.match_size) {
+			fprintf(stderr,
+				"Can't find library for match `%s'\n",
+				e->u.user.name);
+			exit(1);
+		}
+	}
+	return 0;
+}
+
+/* print a given ip including mask if neccessary */
+static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
+{
+	if (!mask && !ip)
+		return;
+
+	printf("%s %s%u.%u.%u.%u",
+		prefix,
+		invert ? "! " : "",
+		IP_PARTS(ip));
+
+	if (mask != 0xffffffff) 
+		printf("/%u.%u.%u.%u ", IP_PARTS(mask));
+	else
+		printf(" ");
+}
 
 /* We want this to be readable, so only print out neccessary fields.
  * Because that's the kind of world I want to live in.  */
-static void print_rule(const struct ipt_entry *e, int counters)
+static void print_rule(const struct ipt_entry *e, 
+		iptc_handle_t *h, int counters)
 {
+	struct ipt_entry_target *t;
+
+	/* print counters */
 	if (counters)
 		printf("[%llu,%llu] ", e->counters.pcnt, e->counters.bcnt);
 
 	/* Print IP part. */
-	if (e->ip.smsk.s_addr)
-		printf("-s %s%u.%u.%u.%u/%u.%u.%u.%u ",
-		       e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
-		       IP_PARTS(e->ip.src.s_addr),
-		       IP_PARTS(e->ip.smsk.s_addr));
-	if (e->ip.dmsk.s_addr)
-		printf("-d %s%u.%u.%u.%u/%u.%u.%u.%u ",
-		       e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
-		       IP_PARTS(e->ip.dst.s_addr),
-		       IP_PARTS(e->ip.dmsk.s_addr));
+	print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
+			e->ip.invflags & IPT_INV_SRCIP);	
+
+	print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
+			e->ip.invflags & IPT_INV_SRCIP);
 
 	print_iface('i', e->ip.iniface, e->ip.iniface_mask,
 		    e->ip.invflags & IPT_INV_VIA_IN);
+
 	print_iface('o', e->ip.outiface, e->ip.outiface_mask,
 		    e->ip.invflags & IPT_INV_VIA_OUT);
+
 	print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
 
 	if (e->ip.flags & IPT_F_FRAG)
 		printf("%s-f ",
 		       e->ip.invflags & IPT_INV_FRAG ? "! " : "");
 
-	if (e->ip.flags & IPT_F_TOS)
-		printf("-t %s0x%02X ",
-		       e->ip.invflags & IPT_INV_TOS ? "! " : "",
-		       e->ip.tos);
-
 	/* Print matchinfo part */
-	if (e->match_name[0]) {
-		struct iptables_match *match
-			= find_match(e->match_name, TRY_LOAD);
-
-		if (match)
-			match->save(e);
-		else {
-			/* If some bits are non-zero, it implies we *need*
-			   to understand it */
-			if (non_zero(&e->matchinfo, sizeof(e->matchinfo))) {
-				fprintf(stderr,
-					"Can't find library for match `%s'\n",
-					e->match_name);
-				exit(1);
-			}
-		}
+	if (e->target_offset) {
+		IPT_MATCH_ITERATE(e, print_match);
 	}
 
+	/* Print target name */	
+	printf("-j %s ", iptc_get_target(e, h));
+
 	/* Print targinfo part */
-	if (e->target_name[0]) {
+	t = ipt_get_target(e);
+	if (t->u.user.name[0]) {
 		struct iptables_target *target
-			= find_target(e->target_name, TRY_LOAD);
+			= find_target(t->u.user.name, TRY_LOAD);
 
 		if (target)
-			target->save(e);
+			target->save(NULL, t);
 		else {
 			/* If some bits are non-zero, it implies we *need*
 			   to understand it */
-			if (non_zero(&e->targinfo, sizeof(e->targinfo))) {
+			if (t->u.target_size) {
 				fprintf(stderr,
 					"Can't find library for target `%s'\n",
-					e->target_name);
+					t->u.user.name);
 				exit(1);
 			}
 		}
@@ -164,15 +197,13 @@
 }
 
 /* Debugging prototype. */
-extern void dump_entries(iptc_handle_t handle);
-
 static int for_each_table(int (*func)(const char *tablename))
 {
         int ret = 1;
-	FILE *procfile;
+	FILE *procfile = NULL;
 	char tablename[IPT_TABLE_MAXNAMELEN+1];
 
-	procfile = fopen("/proc/net/ip_tables_names", O_RDONLY);
+	procfile = fopen("/proc/net/ip_tables_names", "r");
 	if (!procfile)
 		return 0;
 
@@ -189,21 +220,6 @@
 }
 	
 
-static int dump_table(const char *tablename)
-{
-	iptc_handle_t h;
-
-	if (!tablename)
-		return for_each_table(&dump_table);
-
-	/* Debugging dump. */
-	h = iptc_init(tablename);
-	if (!h)
-		exit_error(OTHER_PROBLEM, "iptc_init: %s\n",
-			   iptc_strerror(errno));
-	dump_entries(h);
-}
-	
 static int do_output(const char *tablename)
 {
 	iptc_handle_t h;
@@ -222,39 +238,29 @@
 
 		printf("# Generated by iptables-save v%s on %s",
 		       NETFILTER_VERSION, ctime(&now));
+		printf("*%s\n", tablename);
 
 		/* Dump out chain names */
 		for (chain = iptc_first_chain(&h);
 		     chain;
 		     chain = iptc_next_chain(&h)) {
+			const struct ipt_entry *e;
+
 			printf(":%s ", chain);
-			if (iptc_builtin(chain, &h)) {
+			if (iptc_builtin(chain, h)) {
 				struct ipt_counters count;
 				printf("%s ",
 				       iptc_get_policy(chain, &count, &h));
-				printf("%llu %llu\n", count.pcnt, count.bcnt);
+				printf("%llu:%llu\n", count.pcnt, count.bcnt);
 			} else {
 				printf("- 0 0\n");
 			}
-		}
 
-		/* Dump out rules */
-		for (chain = iptc_first_chain(&h);
-		     chain;
-		     chain = iptc_next_chain(&h)) {
-			unsigned int i;
-
-			for (i = 0; i < iptc_num_rules(chain, &h); i++) {
-				const struct ipt_entry *e
-					= iptc_get_rule(chain, i, &h);
-
-				if (!e)
-					exit_error(OTHER_PROBLEM,
-						   "Can't read rule %u"
-						   " of chain %s: %s\n",
-						   i, chain,
-						   iptc_strerror(errno));
-				print_rule(e, counters);
+			/* Dump out rules */
+			e = iptc_first_rule(chain, &h);
+			while(e) {
+				print_rule(e, &h, counters);
+				e = iptc_next_rule(e, &h);
 			}
 		}
 
@@ -296,7 +302,7 @@
 			tablename = optarg;
 			break;
 		case 'd':
-			dump_table(tablename);
+			do_output(tablename);
 			exit(0);
 		}
 	}
diff --git a/iptables-standalone.c b/iptables-standalone.c
index dfbc0fa..53d2189 100644
--- a/iptables-standalone.c
+++ b/iptables-standalone.c
@@ -33,14 +33,21 @@
 {
 	int ret;
 	char *table = "filter";
-	iptc_handle_t handle;
+	iptc_handle_t *handle;
+
+	handle = (iptc_handle_t *) malloc(sizeof(iptc_handle_t));
+	if (!handle) {
+		fprintf(stderr, "out of memory\n");
+		exit(1);
+	}
+	memset(handle, 0, sizeof(iptc_handle_t));
 
 	program_name = "iptables";
 	program_version = NETFILTER_VERSION;
 
-	ret = do_command(argc, argv, &table, &handle);
+	ret = do_command(argc, argv, &table, handle);
 	if (ret)
-		ret = iptc_commit(&handle);
+		ret = iptc_commit(handle);
 
 	if (!ret)
 		fprintf(stderr, "iptables: %s\n",
diff --git a/iptables.c b/iptables.c
index 4dbe891..73f400b 100644
--- a/iptables.c
+++ b/iptables.c
@@ -126,7 +126,7 @@
 };
 
 #ifndef __OPTIMIZE__
-static struct ipt_entry_target *
+struct ipt_entry_target *
 ipt_get_target(struct ipt_entry *e)
 {
 	return (void *)e + e->target_offset;
@@ -643,6 +643,9 @@
 				   name, dlerror());
 	}
 
+	if (ptr)
+		ptr->used = 1;
+
 	return ptr;
 }
 
@@ -893,6 +896,9 @@
 				   name, dlerror());
 	}
 
+	if (ptr)
+		ptr->used = 1;
+
 	return ptr;
 }
 
@@ -1290,7 +1296,7 @@
 	unsigned char *mask, *mptr;
 
 	size = sizeof(struct ipt_entry);
-	for (m = iptables_matches; m; m = m->next)
+	for (m = iptables_matches; m && m->used; m = m->next)
 		size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
 
 	mask = fw_calloc(1, size
@@ -1300,7 +1306,7 @@
 	memset(mask, 0xFF, sizeof(struct ipt_entry));
 	mptr = mask + sizeof(struct ipt_entry);
 
-	for (m = iptables_matches; m; m = m->next) {
+	for (m = iptables_matches; m && m->used; m = m->next) {
 		memset(mptr, 0xFF,
 		       IPT_ALIGN(sizeof(struct ipt_entry_match))
 		       + m->userspacesize);
@@ -1370,7 +1376,7 @@
 	return ret;
 }
 
-static int
+int
 for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
 	       int verbose, int builtinstoo, iptc_handle_t *handle)
 {
@@ -1406,7 +1412,7 @@
         return ret;
 }
 
-static int
+int
 flush_entries(const ipt_chainlabel chain, int verbose,
 	      iptc_handle_t *handle)
 {
@@ -1430,7 +1436,7 @@
 	return iptc_zero_entries(chain, handle);
 }
 
-static int
+int
 delete_chain(const ipt_chainlabel chain, int verbose,
 	     iptc_handle_t *handle)
 {
@@ -1505,7 +1511,7 @@
 	struct ipt_entry *e;
 
 	size = sizeof(struct ipt_entry);
-	for (m = matches; m; m = m->next)
+	for (m = matches; m && m->used; m = m->next)
 		size += m->m->u.match_size;
 
 	e = fw_malloc(size + target->u.target_size);
@@ -1514,7 +1520,7 @@
 	e->next_offset = size + target->u.target_size;
 
 	size = 0;
-	for (m = matches; m; m = m->next) {
+	for (m = matches; m && m->used; m = m->next) {
 		memcpy(e->elems + size, m->m, m->m->u.match_size);
 		size += m->m->u.match_size;
 	}
@@ -1538,11 +1544,28 @@
 	int ret = 1;
 	struct iptables_match *m;
 	struct iptables_target *target = NULL;
+	struct iptables_target *t;
 	const char *jumpto = "";
 	char *protocol = NULL;
 
 	memset(&fw, 0, sizeof(fw));
 
+	/* re-set optind to 0 in case do_command gets called
+	 * a second time */
+	optind = 0;
+
+	/* clear mflags in case do_command gets called a second time
+	 * (we clear the global list of all matches for security)*/
+	for (m = iptables_matches; m; m = m->next) {
+		m->mflags = 0;
+		m->used = 0;
+	}
+
+	for (t = iptables_targets; t; t = t->next) {
+		t->tflags = 0;
+		t->used = 0;
+	}
+
 	/* Suppress error messages: we may add new options if we
            demand-load a protocol. */
 	opterr = 0;
@@ -1845,7 +1868,7 @@
 					       argv, invert,
 					       &target->tflags,
 					       &fw, &target->t))) {
-				for (m = iptables_matches; m; m = m->next) {
+				for (m = iptables_matches; m && m->used; m = m->next) {
 					if (m->parse(c - m->option_offset,
 						     argv, invert,
 						     &m->mflags,
@@ -1886,7 +1909,7 @@
 		invert = FALSE;
 	}
 
-	for (m = iptables_matches; m; m = m->next)
+	for (m = iptables_matches; m && m->used; m = m->next)
 		m->final_check(m->mflags);
 	if (target)
 		target->final_check(target->tflags);
@@ -1938,7 +1961,10 @@
 			   "chain name `%s' too long (must be under %i chars)",
 			   chain, IPT_FUNCTION_MAXNAMELEN);
 
-	*handle = iptc_init(*table);
+	/* only allocate handle if we weren't called with a handle */
+	if (!*handle)
+		*handle = iptc_init(*table);
+
 	if (!*handle)
 		exit_error(VERSION_PROBLEM,
 			   "can't initialize iptables table `%s': %s",