reorganized tree after kernel merge
diff --git a/iptables-save.c b/iptables-save.c
new file mode 100644
index 0000000..40e9d6a
--- /dev/null
+++ b/iptables-save.c
@@ -0,0 +1,260 @@
+/* Code to save the iptables state, in human readable-form. */
+#include <getopt.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <time.h>
+#include "packet-match/userspace/libiptc/libiptc.h"
+#include "packet-match/userspace/iptables.h"
+
+/* Keeping track of external matches and targets.  */
+static struct option options[] = {
+	{ "binary", 1, 0, 'b' },
+	{ "counters", 1, 0, 'c' },
+	{ "dump", 1, 0, 'd' },
+	{ 0 }
+};
+
+#define IP_PARTS_NATIVE(n)			\
+(unsigned int)((n)>>24)&0xFF,			\
+(unsigned int)((n)>>16)&0xFF,			\
+(unsigned int)((n)>>8)&0xFF,			\
+(unsigned int)((n)&0xFF)
+
+#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
+
+/* This assumes that mask is contiguous, and byte-bounded. */
+static void
+print_iface(char letter, const char *iface, const unsigned char *mask,
+	    int invert)
+{
+	unsigned int i;
+
+	if (mask[0] == 0)
+		return;
+	
+	printf("-%c %s", letter, invert ? "! " : "");
+
+	for (i = 0; i < IFNAMSIZ; i++) {
+		if (mask[i] != 0) {
+			if (iface[i] != '\0')
+				printf("%c", iface[i]);
+		} else {
+			if (iface[i] != '\0')
+				printf("+");
+			break;
+		}
+	}
+}
+
+/* These are hardcoded backups in iptables.c, so they are safe */
+struct pprot {
+	char *name;
+	u_int8_t num;
+};
+
+static const struct pprot chain_protos[] = {
+	{ "tcp", IPPROTO_TCP },
+	{ "udp", IPPROTO_UDP },
+	{ "icmp", IPPROTO_ICMP },
+};
+
+static void print_proto(u_int16_t proto, int invert)
+{
+	if (proto) {
+		unsigned int i;
+		const char *invertstr = invert ? "! " : "";
+
+		for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
+			if (chain_protos[i].num == proto) {
+				printf("-p %s%s ",
+				       invertstr, chain_protos[i].name);
+				return;
+			}
+
+		printf("-p %s%u ", invertstr, proto);
+	}
+}
+
+static int non_zero(const void *ptr, size_t size)
+{
+	unsigned int i;
+
+	for (i = 0; i < size; i++)
+		if (((char *)ptr)[i])
+			return 0;
+
+	return 1;
+}
+
+/* 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)
+{
+	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_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, 1);
+
+		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);
+			}
+		}
+	}
+
+	/* Print targinfo part */
+	if (e->target_name[0]) {
+		struct iptables_target *target
+			= find_target(e->target_name, 1);
+
+		if (target)
+			target->save(e);
+		else {
+			/* If some bits are non-zero, it implies we *need*
+			   to understand it */
+			if (non_zero(&e->targinfo, sizeof(e->targinfo))) {
+				fprintf(stderr,
+					"Can't find library for target `%s'\n",
+					e->target_name);
+				exit(1);
+			}
+		}
+	}
+	printf("\n");
+}
+
+/* Debugging prototype. */
+extern void dump_entries(iptc_handle_t handle);
+
+/* Format:
+ * :Chain name POLICY packets bytes
+ * rule
+ */
+int main(int argc, char *argv[])
+{
+	iptc_handle_t h;
+	const char *chain = NULL;
+	int c;
+	int binary = 0, counters = 0;
+
+	program_name = "iptables-save";
+	program_version = NETFILTER_VERSION;
+
+	while ((c = getopt_long(argc, argv, "bc", options, NULL)) != -1) {
+		switch (c) {
+		case 'b':
+			binary = 1;
+			break;
+
+		case 'c':
+			counters = 1;
+			break;
+
+		case 'd':
+			/* Debugging dump. */
+			h = iptc_init();
+			if (!h)
+				exit_error(OTHER_PROBLEM, "iptc_init: %s\n",
+					   iptc_strerror(errno));
+			dump_entries(h);
+			exit(0);
+		}
+	}
+
+	if (optind < argc) {
+		fprintf(stderr, "Unknown arguments found on commandline");
+		exit(1);
+	}
+
+	h = iptc_init();
+	if (!h) {
+		fprintf(stderr, "Can't initialize: %s\n",
+			iptc_strerror(errno));
+		exit(1);
+	}
+
+	if (!binary) {
+		time_t now = time(NULL);
+
+		printf("# Generated by iptables-save v%s on %s",
+		       NETFILTER_VERSION, ctime(&now));
+
+		/* Dump out chain names */
+		while ((chain = iptc_next_chain(chain, &h)) != NULL) {
+			printf(":%s ", chain);
+			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);
+			} else {
+				printf("- 0 0\n");
+			}
+		}
+
+		/* Dump out rules */
+		while ((chain = iptc_next_chain(chain, &h)) != NULL) {
+			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) {
+					fprintf(stderr,
+						"Can't read rule %u of chain %s: %s\n",
+						i, chain, iptc_strerror(errno));
+					exit(1);
+				}
+				print_rule(e, counters);
+			}
+		}
+
+		now = time(NULL);
+		printf("COMMIT\n");
+		printf("# Completed on %s", ctime(&now));
+	} else {
+		/* Binary, huh?  OK. */
+		fprintf(stderr, "Binary NYI\n");
+		exit(1);
+	}
+
+	return 0;
+}