[netfilter-cvslog] r6695 - trunk/iptables

kaber at netfilter.org kaber at netfilter.org
Mon Nov 13 21:23:36 CET 2006


Author: kaber at netfilter.org
Date: 2006-11-13 21:23:36 +0100 (Mon, 13 Nov 2006)
New Revision: 6695

Added:
   trunk/iptables/iptables-xml.c
   trunk/iptables/iptables.xslt
Modified:
   trunk/iptables/Makefile
Log:
Add iptables-xml tool (Amin Azez <azez at ufomechanic.net>)


Modified: trunk/iptables/Makefile
===================================================================
--- trunk/iptables/Makefile	2006-11-13 20:19:08 UTC (rev 6694)
+++ trunk/iptables/Makefile	2006-11-13 20:23:36 UTC (rev 6695)
@@ -48,9 +48,9 @@
 
 # No longer experimental.
 ifneq ($(DO_MULTI), 1)
-EXTRAS+=iptables-save iptables-restore
+EXTRAS+=iptables-save iptables-restore iptables-xml
 endif
-EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore $(DESTDIR)$(MANDIR)/man8/iptables-restore.8 $(DESTDIR)$(MANDIR)/man8/iptables-save.8
+EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore $(DESTDIR)$(BINDIR)/iptables-xml $(DESTDIR)$(MANDIR)/man8/iptables-restore.8 $(DESTDIR)$(MANDIR)/man8/iptables-save.8
 
 ifeq ($(DO_IPV6), 1)
 EXTRAS+=ip6tables ip6tables.o ip6tables.8
@@ -129,7 +129,7 @@
 	$(CC) $(CFLAGS) -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" -c -o $@ $<
 
 ifeq ($(DO_MULTI), 1)
-iptables: iptables-multi.c iptables-save.c iptables-restore.c iptables-standalone.c iptables.o $(STATIC_LIBS) libiptc/libiptc.a
+iptables: iptables-multi.c iptables-save.c iptables-restore.c iptables-xml.c iptables-standalone.c iptables.o $(STATIC_LIBS) libiptc/libiptc.a
 	$(CC) $(CFLAGS) -DIPTABLES_MULTI -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" $(LDFLAGS) -o $@ $^ $(LDLIBS)
 else
 iptables: iptables-standalone.c iptables.o $(STATIC_LIBS) libiptc/libiptc.a
@@ -166,6 +166,19 @@
 	cp $< $@
 endif
 
+iptables-xml: iptables-xml.c #iptables.o # $(STATIC_LIBS) libiptc/libiptc.a
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
+ifeq ($(DO_MULTI), 1)
+$(DESTDIR)$(BINDIR)/iptables-xml: iptables-xml
+	@[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
+	ln -sf $< $@
+else
+$(DESTDIR)$(BINDIR)/iptables-xml: iptables-xml
+	@[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
+	cp $< $@
+endif
+
 ip6tables.o: ip6tables.c
 	$(CC) $(CFLAGS) -DIP6T_LIB_DIR=\"$(IPT_LIBDIR)\" -c -o $@ $<
 

Added: trunk/iptables/iptables-xml.c
===================================================================
--- trunk/iptables/iptables-xml.c	                        (rev 0)
+++ trunk/iptables/iptables-xml.c	2006-11-13 20:23:36 UTC (rev 6695)
@@ -0,0 +1,859 @@
+/* Code to convert iptables-save format to xml format,
+ * (C) 2006 Ufo Mechanic <azez at ufomechanic.net>
+ * based on iptables-restor (C) 2000-2002 by Harald Welte <laforge at gnumonks.org>
+ * based on previous code from Rusty Russell <rusty at linuxcare.com.au>
+ *
+ * This code is distributed under the terms of GNU GPL v2
+ *
+ * $Id: iptables-xml.c,v 1.4 2006/11/09 12:02:17 azez Exp $
+ */
+
+#include <getopt.h>
+#include <sys/errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "iptables.h"
+#include "libiptc/libiptc.h"
+
+#ifdef DEBUG
+#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args...)
+#endif
+
+/* no need to link with iptables.o */
+const char *program_name;
+const char *program_version;
+int line = 0;
+
+void
+exit_error(enum exittype status, char *msg, ...)
+{
+	va_list args;
+
+	va_start(args, msg);
+	fprintf(stderr, "%s v%s: ", program_name, program_version);
+	vfprintf(stderr, msg, args);
+	va_end(args);
+	fprintf(stderr, "\n");
+	/* On error paths, make sure that we don't leak memory */
+	exit(status);
+}
+
+static void print_usage(const char *name, const char *version)
+	    __attribute__ ((noreturn));
+
+static int verbose = 0;
+/* Whether to combine actions of sequential rules with identical conditions */
+static int combine = 0;
+/* Keeping track of external matches and targets.  */
+static struct option options[] = {
+	{"verbose", 0, 0, 'v'},
+	{"combine", 0, 0, 'c'},
+	{"help", 0, 0, 'h'},
+	{0}
+};
+
+static void
+print_usage(const char *name, const char *version)
+{
+	fprintf(stderr, "Usage: %s [-c] [-v] [-h]\n"
+		"          [--combine ]\n"
+		"	   [ --verbose ]\n" "	   [ --help ]\n", name);
+
+	exit(1);
+}
+
+int
+parse_counters(char *string, struct ipt_counters *ctr)
+{
+	if (string != NULL)
+		return (sscanf
+			(string, "[%llu:%llu]",
+			 (unsigned long long *) &ctr->pcnt,
+			 (unsigned long long *) &ctr->bcnt) == 2);
+	else
+		return (0 == 2);
+}
+
+/* global new argv and argc */
+static char *newargv[255];
+static int newargc = 0;
+
+static char *oldargv[255];
+static int oldargc = 0;
+
+/* arg meta data, were they quoted, frinstance */
+static int newargvattr[255];
+
+#define IPT_CHAIN_MAXNAMELEN IPT_TABLE_MAXNAMELEN
+char closeActionTag[IPT_TABLE_MAXNAMELEN + 1];
+char closeRuleTag[IPT_TABLE_MAXNAMELEN + 1];
+char curTable[IPT_TABLE_MAXNAMELEN + 1];
+char curChain[IPT_CHAIN_MAXNAMELEN + 1];
+
+typedef struct chain
+{
+	char *chain;
+	char *policy;
+	struct ipt_counters count;
+	int created;
+} chain;
+
+#define maxChains 10240		/* max chains per table */
+static chain chains[maxChains];
+static int nextChain = 0;
+
+/* funCtion adding one argument to newargv, updating newargc 
+ * returns true if argument added, false otherwise */
+static int
+add_argv(char *what, int quoted)
+{
+	DEBUGP("add_argv: %d %s\n", newargc, what);
+	if (what && ((newargc + 1) < sizeof(newargv) / sizeof(char *))) {
+		newargv[newargc] = strdup(what);
+		newargvattr[newargc] = quoted;
+		newargc++;
+		return 1;
+	} else
+		return 0;
+}
+
+static void
+free_argv(void)
+{
+	int i;
+
+	for (i = 0; i < newargc; i++) {
+		free(newargv[i]);
+		newargv[i] = NULL;
+	}
+	newargc = 0;
+
+	for (i = 0; i < oldargc; i++) {
+		free(oldargv[i]);
+		oldargv[i] = NULL;
+	}
+	oldargc = 0;
+}
+
+/* save parsed rule for comparison with next rule 
+   to perform action agregation on duplicate conditions */
+static void
+save_argv(void)
+{
+	int i;
+
+	for (i = 0; i < oldargc; i++)
+		free(oldargv[i]);
+	oldargc = newargc;
+	newargc = 0;
+	for (i = 0; i < oldargc; i++) {
+		oldargv[i] = newargv[i];
+		newargv[i] = NULL;
+	}
+}
+
+/* like puts but with xml encoding */
+static void
+xmlEncode(char *text)
+{
+	while (text && *text) {
+		if ((unsigned char) (*text) >= 127)
+			printf("&#%d;", (unsigned char) (*text));
+		else if (*text == '&')
+			printf("&amp;");
+		else if (*text == '<')
+			printf("&lt;");
+		else if (*text == '>')
+			printf("&gt;");
+		else if (*text == '"')
+			printf("&quot;");
+		else
+			putchar(*text);
+		text++;
+	}
+}
+
+/* Output text as a comment, avoiding a double hyphen */
+static void
+xmlCommentEscape(char *comment)
+{
+	int h_count = 0;
+
+	while (comment && *comment) {
+		if (*comment == '-') {
+			h_count++;
+			if (h_count >= 2) {
+				h_count = 0;
+				putchar(' ');
+			}
+			putchar('*');
+		}
+		/* strip trailing newline */
+		if (*comment == '\n' && *(comment + 1) == 0);
+		else
+			putchar(*comment);
+		comment++;
+	}
+}
+
+static void
+xmlComment(char *comment)
+{
+	printf("<!-- ");
+	xmlCommentEscape(comment);
+	printf(" -->\n");
+}
+
+static void
+xmlAttrS(char *name, char *value)
+{
+	printf("%s=\"", name);
+	xmlEncode(value);
+	printf("\" ");
+}
+
+static void
+xmlAttrI(char *name, long long int num)
+{
+	printf("%s=\"%lld\" ", name, num);
+}
+
+static void
+closeChain()
+{
+	if (curChain[0] == 0)
+		return;
+
+	if (closeActionTag[0])
+		printf("%s\n", closeActionTag);
+	closeActionTag[0] = 0;
+	if (closeRuleTag[0])
+		printf("%s\n", closeRuleTag);
+	closeRuleTag[0] = 0;
+	if (curChain[0])
+		printf("    </chain>\n");
+	curChain[0] = 0;
+	//lastRule[0]=0;
+}
+
+static void
+openChain(char *chain, char *policy, struct ipt_counters *ctr, char close)
+{
+	closeChain();
+
+	strncpy(curChain, chain, IPT_CHAIN_MAXNAMELEN);
+	curChain[IPT_CHAIN_MAXNAMELEN] = '\0';
+
+	printf("    <chain ");
+	xmlAttrS("name", curChain);
+	if (strcmp(policy, "-") != 0)
+		xmlAttrS("policy", policy);
+	xmlAttrI("packet-count", (unsigned long long) ctr->pcnt);
+	xmlAttrI("byte-count", (unsigned long long) ctr->bcnt);
+	if (close) {
+		printf("%c", close);
+		curChain[0] = 0;
+	}
+	printf(">\n");
+}
+
+static int
+existsChain(char *chain)
+{
+	/* open a saved chain */
+	int c = 0;
+
+	if (0 == strcmp(curChain, chain))
+		return 1;
+	for (c = 0; c < nextChain; c++)
+		if (chains[c].chain && strcmp(chains[c].chain, chain) == 0)
+			return 1;
+	return 0;
+}
+
+static void
+needChain(char *chain)
+{
+	/* open a saved chain */
+	int c = 0;
+
+	if (0 == strcmp(curChain, chain))
+		return;
+
+	for (c = 0; c < nextChain; c++)
+		if (chains[c].chain && strcmp(chains[c].chain, chain) == 0) {
+			openChain(chains[c].chain, chains[c].policy,
+				  &(chains[c].count), '\0');
+			/* And, mark it as done so we don't create 
+			   an empty chain at table-end time */
+			chains[c].created = 1;
+		}
+}
+
+static void
+saveChain(char *chain, char *policy, struct ipt_counters *ctr)
+{
+	if (nextChain >= maxChains) {
+		exit_error(PARAMETER_PROBLEM,
+			   "%s: line %u chain name invalid\n",
+			   program_name, line);
+		exit(1);
+	};
+	chains[nextChain].chain = strdup(chain);
+	chains[nextChain].policy = strdup(policy);
+	chains[nextChain].count = *ctr;
+	chains[nextChain].created = 0;
+	nextChain++;
+}
+
+static void
+finishChains()
+{
+	int c;
+
+	for (c = 0; c < nextChain; c++)
+		if (!chains[c].created) {
+			openChain(chains[c].chain, chains[c].policy,
+				  &(chains[c].count), '/');
+			free(chains[c].chain);
+			free(chains[c].policy);
+		}
+	nextChain = 0;
+}
+
+static void
+closeTable()
+{
+	closeChain();
+	finishChains();
+	if (curTable[0])
+		printf("  </table>\n");
+	curTable[0] = 0;
+}
+
+static void
+openTable(char *table)
+{
+	closeTable();
+
+	strncpy(curTable, table, IPT_TABLE_MAXNAMELEN);
+	curTable[IPT_TABLE_MAXNAMELEN] = '\0';
+
+	printf("  <table ");
+	xmlAttrS("name", curTable);
+	printf(">\n");
+}
+
+// is char* -j --jump -g or --goto
+static int
+isTarget(char *arg)
+{
+	return ((arg)
+		&& (strcmp((arg), "-j") == 0 || strcmp((arg), "--jump") == 0
+		    || strcmp((arg), "-g") == 0
+		    || strcmp((arg), "--goto") == 0));
+}
+
+// part=-1 means do conditions, part=1 means do rules, part=0 means do both
+static void
+do_rule_part(char *leveltag1, char *leveltag2, int part, int argc,
+	     char *argv[], int argvattr[])
+{
+	int arg = 1;		// ignore leading -A
+	char invert_next = 0;
+	char *thisChain = NULL;
+	char *spacer = "";	// space when needed to assemble arguments
+	char *level1 = NULL;
+	char *level2 = NULL;
+	char *leveli1 = "        ";
+	char *leveli2 = "          ";
+
+#define CLOSE_LEVEL(LEVEL) \
+	do { \
+		if (level ## LEVEL) printf("</%s>\n", \
+		(leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \
+		level ## LEVEL=NULL;\
+	} while(0)
+
+#define OPEN_LEVEL(LEVEL,TAG) \
+	do {\
+		level ## LEVEL=TAG;\
+		if (leveltag ## LEVEL) {\
+			printf("%s<%s ", (leveli ## LEVEL), \
+				(leveltag ## LEVEL));\
+			xmlAttrS("type", (TAG)); \
+		} else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \
+	} while(0)
+
+	thisChain = argv[arg++];
+
+	if (part == 1) {	/* skip */
+		/* use argvattr to tell which arguments were quoted 
+		   to avoid comparing quoted arguments, like comments, to -j, */
+		while (arg < argc && (argvattr[arg] || !isTarget(argv[arg])))
+			arg++;
+	}
+
+	/* Before we start, if the first arg is -[^-] and not -m or -j or -g 
+	   then start a dummy <match> tag for old style built-in matches.  
+	   We would do this in any case, but no need if it would be empty */
+	if (arg < argc && argv[arg][0] == '-' && !isTarget(argv[arg])
+	    && strcmp(argv[arg], "-m") != 0) {
+		OPEN_LEVEL(1, "match");
+		printf(">\n");
+	}
+	while (arg < argc) {
+		// If ! is followed by -* then apply to that else output as data
+		// Stop, if we need to
+		if (part == -1 && !argvattr[arg] && (isTarget(argv[arg]))) {
+			break;
+		} else if (!argvattr[arg] && strcmp(argv[arg], "!") == 0) {
+			if ((arg + 1) < argc && argv[arg + 1][0] == '-')
+				invert_next = '!';
+			else
+				printf("%s%s", spacer, argv[arg]);
+			spacer = " ";
+		} else if (!argvattr[arg] && isTarget(argv[arg])
+			   && existsChain(argv[arg + 1])
+			   && (2 + arg >= argc)) {
+			if (!((1 + arg) < argc))
+				// no args to -j, -m or -g, ignore & finish loop
+				break;
+			CLOSE_LEVEL(2);
+			if (level1)
+				printf("%s", leveli1);
+			CLOSE_LEVEL(1);
+			spacer = "";
+			invert_next = 0;
+			if (strcmp(argv[arg], "-g") == 0
+			    || strcmp(argv[arg], "--goto") == 0) {
+				/* goto user chain */
+				OPEN_LEVEL(1, "goto");
+				printf(">\n");
+				arg++;
+				OPEN_LEVEL(2, argv[arg]);
+				printf("/>\n");
+				level2 = NULL;
+			} else {
+				/* call user chain */
+				OPEN_LEVEL(1, "call");
+				printf(">\n");
+				arg++;
+				OPEN_LEVEL(2, argv[arg]);
+				printf("/>\n");
+				level2 = NULL;
+			}
+		} else if (!argvattr[arg]
+			   && (isTarget(argv[arg])
+			       || strcmp(argv[arg], "-m") == 0
+			       || strcmp(argv[arg], "--module") == 0)) {
+			if (!((1 + arg) < argc))
+				// no args to -j, -m or -g, ignore & finish loop
+				break;
+			CLOSE_LEVEL(2);
+			if (level1)
+				printf("%s", leveli1);
+			CLOSE_LEVEL(1);
+			spacer = "";
+			invert_next = 0;
+			arg++;
+			OPEN_LEVEL(1, (argv[arg]));
+			// Optimize case, can we close this tag already?
+			if ((arg + 1) >= argc || (!argvattr[arg + 1]
+						  && (isTarget(argv[arg + 1])
+						      || strcmp(argv[arg + 1],
+								"-m") == 0
+						      || strcmp(argv[arg + 1],
+								"--module") ==
+						      0))) {
+				printf(" />\n");
+				level1 = NULL;
+			} else {
+				printf(">\n");
+			}
+		} else if (!argvattr[arg] && argv[arg][0] == '-') {
+			char *tag;
+			CLOSE_LEVEL(2);
+			// Skip past any -
+			tag = argv[arg];
+			while (*tag == '-' && *tag)
+				tag++;
+
+			spacer = "";
+			OPEN_LEVEL(2, tag);
+			if (invert_next)
+				printf(" invert=\"1\"");
+			invert_next = 0;
+
+			// Optimize case, can we close this tag already?
+			if (!((arg + 1) < argc)
+			    || (argv[arg + 1][0] == '-' /* NOT QUOTED */ )) {
+				printf(" />\n");
+				level2 = NULL;
+			} else {
+				printf(">");
+			}
+		} else {	// regular data
+			char *spaces = strchr(argv[arg], ' ');
+			printf("%s", spacer);
+			if (spaces || argvattr[arg])
+				printf("&quot;");
+			// if argv[arg] contains a space, enclose in quotes
+			xmlEncode(argv[arg]);
+			if (spaces || argvattr[arg])
+				printf("&quot;");
+			spacer = " ";
+		}
+		arg++;
+	}
+	CLOSE_LEVEL(2);
+	if (level1)
+		printf("%s", leveli1);
+	CLOSE_LEVEL(1);
+
+	return;
+}
+
+static int
+compareRules()
+{
+	/* compare arguments up to -j or -g for match.
+	   NOTE: We don't want to combine actions if there were no criteria 
+	   in each rule, or rules didn't have an action 
+	   NOTE: Depends on arguments being in some kind of "normal" order which 
+	   is the case when processing the ACTUAL output of actual iptables-save 
+	   rather than a file merely in a compatable format */
+
+	int old = 0;
+	int new = 0;
+
+	int compare = 0;
+
+	while (new < newargc && old < oldargc) {
+		if (isTarget(oldargv[old]) && isTarget(newargv[new])) {
+			compare = 1;
+			break;
+		}
+		// break when old!=new
+		if (strcmp(oldargv[old], newargv[new]) != 0) {
+			compare = 0;
+			break;
+		}
+
+		old++;
+		new++;
+	}
+	// We won't match unless both rules had a target. 
+	// This means we don't combine target-less rules, which is good
+
+	return compare == 1;
+}
+
+/* has a nice parsed rule starting with -A */
+static void
+do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
+{
+	/* are these conditions the same as the previous rule?
+	 * If so, skip arg straight to -j or -g */
+	if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) {
+		xmlComment("Combine action from next rule");
+	} else {
+
+		if (closeActionTag[0]) {
+			printf("%s\n", closeActionTag);
+			closeActionTag[0] = 0;
+		}
+		if (closeRuleTag[0]) {
+			printf("%s\n", closeRuleTag);
+			closeRuleTag[0] = 0;
+		}
+
+		printf("      <rule ");
+		//xmlAttrS("table",curTable); // not needed in full mode 
+		//xmlAttrS("chain",argv[1]); // not needed in full mode 
+		if (pcnt)
+			xmlAttrS("packet-count", pcnt);
+		if (bcnt)
+			xmlAttrS("byte-count", bcnt);
+		printf(">\n");
+
+		strncpy(closeRuleTag, "      </rule>\n", IPT_TABLE_MAXNAMELEN);
+		closeRuleTag[IPT_TABLE_MAXNAMELEN] = '\0';
+
+		/* no point in writing out condition if there isn't one */
+		if (argc >= 3 && !isTarget(argv[2])) {
+			printf("       <conditions>\n");
+			do_rule_part(NULL, NULL, -1, argc, argv, argvattr);
+			printf("       </conditions>\n");
+		}
+	}
+	/* Write out the action */
+	//do_rule_part("action","arg",1,argc,argv,argvattr);
+	if (!closeActionTag[0]) {
+		printf("       <actions>\n");
+		strncpy(closeActionTag, "       </actions>\n",
+			IPT_TABLE_MAXNAMELEN);
+		closeActionTag[IPT_TABLE_MAXNAMELEN] = '\0';
+	}
+	do_rule_part(NULL, NULL, 1, argc, argv, argvattr);
+}
+
+
+#ifdef IPTABLES_MULTI
+int
+iptables_restore_main(int argc, char *argv[])
+#else
+int
+main(int argc, char *argv[])
+#endif
+{
+	char buffer[10240];
+	int c;
+	FILE *in;
+
+	program_name = "iptables-xml";
+	program_version = IPTABLES_VERSION;
+	line = 0;
+
+	while ((c = getopt_long(argc, argv, "cvh", options, NULL)) != -1) {
+		switch (c) {
+		case 'c':
+			combine = 1;
+			break;
+		case 'v':
+			printf("xptables-xml\n");
+			verbose = 1;
+			break;
+		case 'h':
+			print_usage("iptables-xml", IPTABLES_VERSION);
+			break;
+		}
+	}
+
+	if (optind == argc - 1) {
+		in = fopen(argv[optind], "r");
+		if (!in) {
+			fprintf(stderr, "Can't open %s: %s", argv[optind],
+				strerror(errno));
+			exit(1);
+		}
+	} else if (optind < argc) {
+		fprintf(stderr, "Unknown arguments found on commandline");
+		exit(1);
+	} else
+		in = stdin;
+
+	printf("<iptables-rules version=\"1.0\">\n");
+
+	/* Grab standard input. */
+	while (fgets(buffer, sizeof(buffer), in)) {
+		int ret = 0;
+
+		line++;
+
+		if (buffer[0] == '\n')
+			continue;
+		else if (buffer[0] == '#') {
+			xmlComment(buffer);
+			continue;
+		}
+
+		if (verbose) {
+			printf("<!-- line %d ", line);
+			xmlCommentEscape(buffer);
+			printf(" -->\n");
+		}
+
+		if ((strcmp(buffer, "COMMIT\n") == 0) && (curTable[0])) {
+			DEBUGP("Calling commit\n");
+			closeTable();
+			ret = 1;
+		} 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);
+			}
+			openTable(table);
+
+			ret = 1;
+		} else if ((buffer[0] == ':') && (curTable[0])) {
+			/* New chain. */
+			char *policy, *chain;
+			struct ipt_counters count;
+			char *ctrs;
+
+			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);
+			}
+
+			DEBUGP("Creating new chain '%s'\n", chain);
+
+			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);
+			}
+
+			ctrs = strtok(NULL, " \t\n");
+			parse_counters(ctrs, &count);
+			saveChain(chain, policy, &count);
+
+			ret = 1;
+		} else if (curTable[0]) {
+			int a;
+			char *ptr = buffer;
+			char *pcnt = NULL;
+			char *bcnt = NULL;
+			char *parsestart;
+			char *chain = NULL;
+
+			/* the parser */
+			char *param_start, *curchar;
+			int quote_open, quoted;
+
+			/* reset the newargv */
+			newargc = 0;
+
+			if (buffer[0] == '[') {
+				/* we have counters in our input */
+				ptr = strchr(buffer, ']');
+				if (!ptr)
+					exit_error(PARAMETER_PROBLEM,
+						   "Bad line %u: need ]\n",
+						   line);
+
+				pcnt = strtok(buffer + 1, ":");
+				if (!pcnt)
+					exit_error(PARAMETER_PROBLEM,
+						   "Bad line %u: need :\n",
+						   line);
+
+				bcnt = strtok(NULL, "]");
+				if (!bcnt)
+					exit_error(PARAMETER_PROBLEM,
+						   "Bad line %u: need ]\n",
+						   line);
+
+				/* start command parsing after counter */
+				parsestart = ptr + 1;
+			} else {
+				/* start command parsing at start of line */
+				parsestart = buffer;
+			}
+
+
+			/* This is a 'real' parser crafted in artist mode
+			 * not hacker mode. If the author can live with that
+			 * then so can everyone else */
+
+			quote_open = 0;
+			/* We need to know which args were quoted so we 
+			   can preserve quote */
+			quoted = 0;
+			param_start = parsestart;
+
+			for (curchar = parsestart; *curchar; curchar++) {
+				if (*curchar == '"') {
+					/* quote_open cannot be true if there
+					 * was no previous character.  Thus, 
+					 * curchar-1 has to be within bounds */
+					if (quote_open &&
+					    *(curchar - 1) != '\\') {
+						quote_open = 0;
+						*curchar = ' ';
+					} else {
+						quote_open = 1;
+						quoted = 1;
+						param_start++;
+					}
+				}
+				if (*curchar == ' '
+				    || *curchar == '\t' || *curchar == '\n') {
+					char param_buffer[1024];
+					int param_len = curchar - param_start;
+
+					if (quote_open)
+						continue;
+
+					if (!param_len) {
+						/* two spaces? */
+						param_start++;
+						continue;
+					}
+
+					/* end of one parameter */
+					strncpy(param_buffer, param_start,
+						param_len);
+					*(param_buffer + param_len) = '\0';
+
+					/* check if table name specified */
+					if (!strncmp(param_buffer, "-t", 3)
+					    || !strncmp(param_buffer,
+							"--table", 8)) {
+						exit_error(PARAMETER_PROBLEM,
+							   "Line %u seems to have a "
+							   "-t table option.\n",
+							   line);
+						exit(1);
+					}
+
+					add_argv(param_buffer, quoted);
+					if (newargc >= 2
+					    && 0 ==
+					    strcmp(newargv[newargc - 2], "-A"))
+						chain = newargv[newargc - 1];
+					quoted = 0;
+					param_start += param_len + 1;
+				} else {
+					/* regular character, skip */
+				}
+			}
+
+			DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
+			       newargc, curTable);
+
+			for (a = 0; a < newargc; a++)
+				DEBUGP("argv[%u]: %s\n", a, newargv[a]);
+
+			needChain(chain);// Should we explicitly look for -A
+			do_rule(pcnt, bcnt, newargc, newargv, newargvattr);
+
+			save_argv();
+			ret = 1;
+		}
+		if (!ret) {
+			fprintf(stderr, "%s: line %u failed\n",
+				program_name, line);
+			exit(1);
+		}
+	}
+	if (curTable[0]) {
+		fprintf(stderr, "%s: COMMIT expected at line %u\n",
+			program_name, line + 1);
+		exit(1);
+	}
+
+	printf("</iptables-rules>\n");
+	free_argv();
+
+	return 0;
+}

Added: trunk/iptables/iptables.xslt
===================================================================
--- trunk/iptables/iptables.xslt	                        (rev 0)
+++ trunk/iptables/iptables.xslt	2006-11-13 20:23:36 UTC (rev 6695)
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- Converts from simple xml iptables format to iptables-save format  
+     Copyright 2006 UfoMechanic 
+     Author: azez at ufomechanic.net 
+     This code is distributed and licensed under the terms of GNU GPL v2
+     
+     This sample usage outputs roughly want goes in
+       iptables-save | iptables-xml -c | xsltproc iptables.xslt -
+     -->
+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:output method = "text" />
+  <xsl:strip-space elements="*" />
+
+  <!-- output conditions of a rule but not an action -->
+  <xsl:template match="iptables-rules/table/chain/rule/conditions/*">
+    <!-- <match> is the psuedo module when a match module doesn't need to be loaded
+         and when -m does not need to be inserted -->
+    <xsl:if test="name() != 'match'">
+      <xsl:text> -m </xsl:text><xsl:value-of select="name()"/>
+    </xsl:if>
+    <xsl:apply-templates select="node()"/>
+  </xsl:template>
+
+  <!-- delete the actions or conditions containers, and process child nodes -->
+  <xsl:template match="iptables-rules/table/chain/rule/actions|table/chain/rule/conditions">
+    <xsl:apply-templates select="*"/>
+  </xsl:template>
+
+  <xsl:template match="iptables-rules/table/chain/rule/actions/goto">
+    <xsl:text> -g </xsl:text>
+    <xsl:apply-templates select="*"/>
+    <xsl:text>&#xA;</xsl:text>
+  </xsl:template>
+  <xsl:template match="iptables-rules/table/chain/rule/actions/call">
+    <xsl:text> -j </xsl:text>
+    <xsl:apply-templates select="*"/>
+    <xsl:text>&#xA;</xsl:text>
+  </xsl:template>
+  <!-- all other actions are module actions -->
+  <xsl:template match="iptables-rules/table/chain/rule/actions/*">
+    <xsl:text> -j </xsl:text><xsl:value-of select="name()"/>
+    <xsl:apply-templates select="*"/>
+    <xsl:text>&#xA;</xsl:text>
+  </xsl:template>
+  
+  <!-- all child action nodes -->
+  <xsl:template match="iptables-rules/table/chain/rule/actions/*/*|iptables-rules/table/chain/rule/actions/*//*|iptables-rules/table/chain/rule/conditions/*/*|iptables-rules/table/chain/rule/conditions/*//*">
+    <xsl:if test="@invert=1"><xsl:text> !</xsl:text></xsl:if>
+    <xsl:text> -</xsl:text>
+    <!-- if length of name is 1 character, then only do 1 - not 2 -->
+    <xsl:if test="string-length(name())&gt;1">
+      <xsl:text>-</xsl:text>
+    </xsl:if>
+    <xsl:value-of select="name()"/>
+    <xsl:text> </xsl:text><xsl:value-of select="."/>
+  </xsl:template>
+
+  <xsl:template match="iptables-rules/table/chain/rule/actions/call/*|iptables-rules/table/chain/rule/actions/goto/*">
+    <xsl:value-of select="name()"/>
+    <!-- I bet there are no child nodes, should we risk it? -->
+    <xsl:apply-templates select="node()"/>
+  </xsl:template>
+
+  <!-- output the head of the rule, and any conditions -->
+  <xsl:template name="rule-head">
+    <xsl:if test="string-length(@packet-count)+string-length(@byte-count)">
+      <xsl:call-template name="counters"><xsl:with-param name="node" select="."/></xsl:call-template>
+      <xsl:text> </xsl:text>
+    </xsl:if>
+    <xsl:text>-A </xsl:text><!-- a rule must be under a chain -->
+    <xsl:value-of select="../@name" />
+    <xsl:apply-templates select="conditions"/>
+  </xsl:template>
+
+  <!-- Output a single rule, perhaps as multiple rules if we have more than one action -->
+  <xsl:template match="iptables-rules/table/chain/rule">
+    <xsl:choose>
+      <xsl:when test="count(actions/*)&gt;0">
+        <xsl:for-each select="actions/*">
+          <!-- and a for-each to re-select the rule as the current node, to write the rule-head -->
+          <xsl:for-each select="../..">
+            <xsl:call-template name="rule-head"/>
+          </xsl:for-each>
+          <!-- now write the this action -->
+          <xsl:apply-templates select="."/>
+        </xsl:for-each>
+      </xsl:when>
+      <xsl:otherwise>
+        <!-- no need to loop if there are no actions, just output conditions -->
+        <xsl:call-template name="rule-head"/>
+        <xsl:text>&#xA;</xsl:text>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="iptables-rules/table">
+    <xsl:text># Generated by iptables.xslt&#xA;</xsl:text>
+    <xsl:text>*</xsl:text><xsl:value-of select="@name"/><xsl:text>&#xA;</xsl:text>
+    <!-- Loop through each chain and output the chain header -->
+    <xsl:for-each select="chain">
+      <xsl:text>:</xsl:text>
+      <xsl:value-of select="@name"/>
+      <xsl:text> </xsl:text>
+      <xsl:choose>
+        <xsl:when test="not(string-length(@policy))"><xsl:text>-</xsl:text></xsl:when>
+        <xsl:otherwise><xsl:value-of select="@policy"/></xsl:otherwise>
+      </xsl:choose>
+      <xsl:text> </xsl:text>
+      <xsl:call-template name="counters"><xsl:with-param name="node" select="."/></xsl:call-template>
+      <xsl:text>&#xA;</xsl:text>
+    </xsl:for-each>
+    <!-- Loop through each chain and output the rules -->
+    <xsl:apply-templates select="node()"/>
+    <xsl:text>COMMIT&#xA;# Completed&#xA;</xsl:text>
+  </xsl:template>
+  
+  <xsl:template name="counters">
+    <xsl:param name="$node"/>
+    <xsl:text>[</xsl:text>
+    <xsl:if test="string-length($node/@packet-count)"><xsl:value-of select="$node/@packet-count"/></xsl:if>
+    <xsl:if test="string-length($node/@packet-count)=0">0</xsl:if>
+    <xsl:text>:</xsl:text>
+    <xsl:if test="string-length($node/@byte-count)"><xsl:value-of select="$node/@byte-count"/></xsl:if>
+    <xsl:if test="string-length($node/@byte-count)=0">0</xsl:if>
+    <xsl:text>]</xsl:text>
+  </xsl:template>  
+  
+  <!-- the bit that automatically recurses for us, NOTE: we use * not node(), we don't want to copy every white space text -->
+  <xsl:template match="@*|node()">
+    <xsl:copy>
+      <!-- with libxslt xsltproc we can't do @*|node() or the nodes may get processed before the attributes -->
+      <xsl:apply-templates select="@*"/>
+      <xsl:apply-templates select="node()"/>
+    </xsl:copy>
+  </xsl:template>
+
+</xsl:transform>




More information about the netfilter-cvslog mailing list