iptables-xml.c revision 4dcdc9b3f8f42eb3b5a1d12e1b3d2fc1e2675725
18d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* Code to convert iptables-save format to xml format,
28d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez * (C) 2006 Ufo Mechanic <azez@ufomechanic.net>
38d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez * based on iptables-restor (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
48d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez * based on previous code from Rusty Russell <rusty@linuxcare.com.au>
58d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez *
68d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez * This code is distributed under the terms of GNU GPL v2
78d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez *
88d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez * $Id: iptables-xml.c,v 1.4 2006/11/09 12:02:17 azez Exp $
98d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez */
108d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
118d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#include <getopt.h>
128d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#include <sys/errno.h>
138d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#include <string.h>
148d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#include <stdio.h>
158d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#include <stdlib.h>
168d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#include <stdarg.h>
178d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#include "iptables.h"
188d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#include "libiptc/libiptc.h"
1933690a1aec0b6309ff90066ca56285b6e43013f2Jan Engelhardt#include "iptables-multi.h"
204dcdc9b3f8f42eb3b5a1d12e1b3d2fc1e2675725Jamal Hadi Salim#include <xtables.h>
218d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
228d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#ifdef DEBUG
238d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
248d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#else
258d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#define DEBUGP(x, args...)
268d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#endif
278d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
288d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* no need to link with iptables.o */
298d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezconst char *program_name;
308d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezconst char *program_version;
318d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
32e78c69c8146c5dcd096ba13ac03d7a7bb90e3ea7Lutz Jaenicke#ifndef IPTABLES_MULTI
33e78c69c8146c5dcd096ba13ac03d7a7bb90e3ea7Lutz Jaenickeint line = 0;
34a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardtvoid exit_error(enum xtables_exittype status, const char *msg, ...)
358d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
368d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	va_list args;
378d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
388d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	va_start(args, msg);
398d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	fprintf(stderr, "%s v%s: ", program_name, program_version);
408d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	vfprintf(stderr, msg, args);
418d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	va_end(args);
428d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	fprintf(stderr, "\n");
438d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	/* On error paths, make sure that we don't leak memory */
448d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	exit(status);
458d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
46e78c69c8146c5dcd096ba13ac03d7a7bb90e3ea7Lutz Jaenicke#endif
478d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
488d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void print_usage(const char *name, const char *version)
498d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	    __attribute__ ((noreturn));
508d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
518d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic int verbose = 0;
528d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* Whether to combine actions of sequential rules with identical conditions */
538d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic int combine = 0;
548d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* Keeping track of external matches and targets.  */
558d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic struct option options[] = {
56ddffcfbe3c97d1eb81d497261ff376cd336974b3Patrick McHardy	{"verbose", 0, NULL, 'v'},
57ddffcfbe3c97d1eb81d497261ff376cd336974b3Patrick McHardy	{"combine", 0, NULL, 'c'},
58ddffcfbe3c97d1eb81d497261ff376cd336974b3Patrick McHardy	{"help", 0, NULL, 'h'},
599ee386a1b6d7704b259460152c959ab0e79e02aaMax Kellermann	{ .name = NULL }
608d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez};
618d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
628d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
638d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezprint_usage(const char *name, const char *version)
648d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
658d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	fprintf(stderr, "Usage: %s [-c] [-v] [-h]\n"
668d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		"          [--combine ]\n"
678d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		"	   [ --verbose ]\n" "	   [ --help ]\n", name);
688d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
698d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	exit(1);
708d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
718d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
72e78c69c8146c5dcd096ba13ac03d7a7bb90e3ea7Lutz Jaenickestatic int
738d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezparse_counters(char *string, struct ipt_counters *ctr)
748d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
75b73691f9e67149deefbc2d2115d66dfc62264333Patrick McHardy	u_int64_t *pcnt, *bcnt;
76b73691f9e67149deefbc2d2115d66dfc62264333Patrick McHardy
77b73691f9e67149deefbc2d2115d66dfc62264333Patrick McHardy	if (string != NULL) {
78b73691f9e67149deefbc2d2115d66dfc62264333Patrick McHardy		pcnt = &ctr->pcnt;
79b73691f9e67149deefbc2d2115d66dfc62264333Patrick McHardy		bcnt = &ctr->bcnt;
808d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		return (sscanf
818d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			(string, "[%llu:%llu]",
82b73691f9e67149deefbc2d2115d66dfc62264333Patrick McHardy			 (unsigned long long *)pcnt,
83b73691f9e67149deefbc2d2115d66dfc62264333Patrick McHardy			 (unsigned long long *)bcnt) == 2);
84b73691f9e67149deefbc2d2115d66dfc62264333Patrick McHardy	} else
858d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		return (0 == 2);
868d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
878d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
888d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* global new argv and argc */
898d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic char *newargv[255];
907a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardtstatic unsigned int newargc = 0;
918d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
928d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic char *oldargv[255];
937a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardtstatic unsigned int oldargc = 0;
948d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
958d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* arg meta data, were they quoted, frinstance */
968d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic int newargvattr[255];
978d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
988d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#define IPT_CHAIN_MAXNAMELEN IPT_TABLE_MAXNAMELEN
99ddffcfbe3c97d1eb81d497261ff376cd336974b3Patrick McHardystatic char closeActionTag[IPT_TABLE_MAXNAMELEN + 1];
100ddffcfbe3c97d1eb81d497261ff376cd336974b3Patrick McHardystatic char closeRuleTag[IPT_TABLE_MAXNAMELEN + 1];
101ddffcfbe3c97d1eb81d497261ff376cd336974b3Patrick McHardystatic char curTable[IPT_TABLE_MAXNAMELEN + 1];
102ddffcfbe3c97d1eb81d497261ff376cd336974b3Patrick McHardystatic char curChain[IPT_CHAIN_MAXNAMELEN + 1];
1038d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
104dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardtstruct chain {
1058d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char *chain;
1068d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char *policy;
1078d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	struct ipt_counters count;
1088d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	int created;
109dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt};
1108d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1118d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#define maxChains 10240		/* max chains per table */
112dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardtstatic struct chain chains[maxChains];
1138d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic int nextChain = 0;
1148d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1158d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* funCtion adding one argument to newargv, updating newargc
1168d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez * returns true if argument added, false otherwise */
1178d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic int
1188d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezadd_argv(char *what, int quoted)
1198d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
1208d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	DEBUGP("add_argv: %d %s\n", newargc, what);
1218d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (what && ((newargc + 1) < sizeof(newargv) / sizeof(char *))) {
1228d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		newargv[newargc] = strdup(what);
1238d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		newargvattr[newargc] = quoted;
1248d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		newargc++;
1258d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		return 1;
1268d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	} else
1278d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		return 0;
1288d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
1298d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1308d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
1318d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezfree_argv(void)
1328d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
1337a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int i;
1348d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1358d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	for (i = 0; i < newargc; i++) {
1368d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		free(newargv[i]);
1378d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		newargv[i] = NULL;
1388d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
1398d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	newargc = 0;
1408d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1418d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	for (i = 0; i < oldargc; i++) {
1428d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		free(oldargv[i]);
1438d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		oldargv[i] = NULL;
1448d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
1458d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	oldargc = 0;
1468d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
1478d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1488d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* save parsed rule for comparison with next rule
1498d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez   to perform action agregation on duplicate conditions */
1508d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
1518d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezsave_argv(void)
1528d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
1537a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int i;
1548d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1558d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	for (i = 0; i < oldargc; i++)
1568d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		free(oldargv[i]);
1578d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	oldargc = newargc;
1588d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	newargc = 0;
1598d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	for (i = 0; i < oldargc; i++) {
1608d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		oldargv[i] = newargv[i];
1618d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		newargv[i] = NULL;
1628d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
1638d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
1648d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1658d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* like puts but with xml encoding */
1668d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
1678d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezxmlEncode(char *text)
1688d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
1698d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	while (text && *text) {
1708d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if ((unsigned char) (*text) >= 127)
1718d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("&#%d;", (unsigned char) (*text));
1728d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		else if (*text == '&')
1738d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("&amp;");
1748d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		else if (*text == '<')
1758d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("&lt;");
1768d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		else if (*text == '>')
1778d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("&gt;");
1788d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		else if (*text == '"')
1798d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("&quot;");
1808d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		else
1818d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			putchar(*text);
1828d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		text++;
1838d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
1848d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
1858d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1868d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* Output text as a comment, avoiding a double hyphen */
1878d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
1888d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezxmlCommentEscape(char *comment)
1898d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
1908d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	int h_count = 0;
1918d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
1928d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	while (comment && *comment) {
1938d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (*comment == '-') {
1948d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			h_count++;
1958d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (h_count >= 2) {
1968d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				h_count = 0;
1978d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				putchar(' ');
1988d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			}
1998d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			putchar('*');
2008d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
2018d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		/* strip trailing newline */
2028d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (*comment == '\n' && *(comment + 1) == 0);
2038d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		else
2048d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			putchar(*comment);
2058d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		comment++;
2068d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
2078d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
2088d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2098d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
2108d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezxmlComment(char *comment)
2118d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
2128d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf("<!-- ");
2138d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	xmlCommentEscape(comment);
2148d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf(" -->\n");
2158d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
2168d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2178d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
2188d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezxmlAttrS(char *name, char *value)
2198d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
2208d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf("%s=\"", name);
2218d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	xmlEncode(value);
2228d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf("\" ");
2238d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
2248d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2258d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
2268d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezxmlAttrI(char *name, long long int num)
2278d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
2288d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf("%s=\"%lld\" ", name, num);
2298d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
2308d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2318d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
2329ee386a1b6d7704b259460152c959ab0e79e02aaMax KellermanncloseChain(void)
2338d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
2348d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (curChain[0] == 0)
2358d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		return;
2368d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2378d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (closeActionTag[0])
2388d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf("%s\n", closeActionTag);
2398d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	closeActionTag[0] = 0;
2408d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (closeRuleTag[0])
2418d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf("%s\n", closeRuleTag);
2428d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	closeRuleTag[0] = 0;
2438d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (curChain[0])
2448d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf("    </chain>\n");
2458d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	curChain[0] = 0;
2468d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	//lastRule[0]=0;
2478d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
2488d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2498d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
2508d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezopenChain(char *chain, char *policy, struct ipt_counters *ctr, char close)
2518d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
2528d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	closeChain();
2538d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2548d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	strncpy(curChain, chain, IPT_CHAIN_MAXNAMELEN);
2558d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	curChain[IPT_CHAIN_MAXNAMELEN] = '\0';
2568d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2578d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf("    <chain ");
2588d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	xmlAttrS("name", curChain);
2598d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (strcmp(policy, "-") != 0)
2608d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		xmlAttrS("policy", policy);
2618d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	xmlAttrI("packet-count", (unsigned long long) ctr->pcnt);
2628d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	xmlAttrI("byte-count", (unsigned long long) ctr->bcnt);
2638d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (close) {
2648d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf("%c", close);
2658d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		curChain[0] = 0;
2668d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
2678d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf(">\n");
2688d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
2698d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2708d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic int
2718d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezexistsChain(char *chain)
2728d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
2738d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	/* open a saved chain */
2748d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	int c = 0;
2758d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2768d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (0 == strcmp(curChain, chain))
2778d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		return 1;
2788d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	for (c = 0; c < nextChain; c++)
2798d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (chains[c].chain && strcmp(chains[c].chain, chain) == 0)
2808d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			return 1;
2818d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	return 0;
2828d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
2838d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2848d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
2858d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezneedChain(char *chain)
2868d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
2878d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	/* open a saved chain */
2888d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	int c = 0;
2898d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2908d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (0 == strcmp(curChain, chain))
2918d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		return;
2928d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
2938d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	for (c = 0; c < nextChain; c++)
2948d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (chains[c].chain && strcmp(chains[c].chain, chain) == 0) {
2958d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			openChain(chains[c].chain, chains[c].policy,
2968d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				  &(chains[c].count), '\0');
2978d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			/* And, mark it as done so we don't create
2988d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			   an empty chain at table-end time */
2998d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			chains[c].created = 1;
3008d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
3018d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
3028d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3038d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
3048d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezsaveChain(char *chain, char *policy, struct ipt_counters *ctr)
3058d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
3068d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (nextChain >= maxChains) {
3078d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		exit_error(PARAMETER_PROBLEM,
3088d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			   "%s: line %u chain name invalid\n",
3098d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			   program_name, line);
3108d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		exit(1);
3118d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	};
3128d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	chains[nextChain].chain = strdup(chain);
3138d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	chains[nextChain].policy = strdup(policy);
3148d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	chains[nextChain].count = *ctr;
3158d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	chains[nextChain].created = 0;
3168d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	nextChain++;
3178d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
3188d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3198d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
3209ee386a1b6d7704b259460152c959ab0e79e02aaMax KellermannfinishChains(void)
3218d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
3228d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	int c;
3238d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3248d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	for (c = 0; c < nextChain; c++)
3258d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (!chains[c].created) {
3268d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			openChain(chains[c].chain, chains[c].policy,
3278d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				  &(chains[c].count), '/');
3288d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			free(chains[c].chain);
3298d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			free(chains[c].policy);
3308d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
3318d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	nextChain = 0;
3328d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
3338d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3348d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
3359ee386a1b6d7704b259460152c959ab0e79e02aaMax KellermanncloseTable(void)
3368d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
3378d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	closeChain();
3388d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	finishChains();
3398d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (curTable[0])
3408d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf("  </table>\n");
3418d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	curTable[0] = 0;
3428d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
3438d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3448d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
3458d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezopenTable(char *table)
3468d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
3478d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	closeTable();
3488d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3498d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	strncpy(curTable, table, IPT_TABLE_MAXNAMELEN);
3508d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	curTable[IPT_TABLE_MAXNAMELEN] = '\0';
3518d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3528d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf("  <table ");
3538d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	xmlAttrS("name", curTable);
3548d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf(">\n");
3558d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
3568d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3578d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez// is char* -j --jump -g or --goto
3588d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic int
3598d3eccb19a9c6fc006193d633b985205e350b9c5Amin AzezisTarget(char *arg)
3608d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
3618d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	return ((arg)
3628d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		&& (strcmp((arg), "-j") == 0 || strcmp((arg), "--jump") == 0
3638d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		    || strcmp((arg), "-g") == 0
3648d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		    || strcmp((arg), "--goto") == 0));
3658d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
3668d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3678e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott// is it a terminating target like -j ACCEPT, etc
3688e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott// (or I guess -j SNAT in nat table, but we don't check for that yet
3698e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicottstatic int
3708e52815a55692d657aeca7f8ecf656cd65dcfce0Sam LiddicottisTerminatingTarget(char *arg)
3718e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott{
3728e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott	return ((arg)
3738e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott		&& (strcmp((arg), "ACCEPT") == 0
3748e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott		    || strcmp((arg), "DROP") == 0
3758e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott		    || strcmp((arg), "QUEUE") == 0
3768e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott		    || strcmp((arg), "RETURN") == 0));
3778e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott}
3788e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott
3798d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez// part=-1 means do conditions, part=1 means do rules, part=0 means do both
3808d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
3818d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezdo_rule_part(char *leveltag1, char *leveltag2, int part, int argc,
3828d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	     char *argv[], int argvattr[])
3838d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
3848d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	int arg = 1;		// ignore leading -A
3858d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char invert_next = 0;
3868d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char *thisChain = NULL;
3878d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char *spacer = "";	// space when needed to assemble arguments
3888d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char *level1 = NULL;
3898d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char *level2 = NULL;
3908d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char *leveli1 = "        ";
3918d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char *leveli2 = "          ";
3928d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
3938d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#define CLOSE_LEVEL(LEVEL) \
3948d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	do { \
3958d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (level ## LEVEL) printf("</%s>\n", \
3968d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		(leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \
3978d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		level ## LEVEL=NULL;\
3988d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	} while(0)
3998d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
4008d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#define OPEN_LEVEL(LEVEL,TAG) \
4018d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	do {\
4028d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		level ## LEVEL=TAG;\
4038d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (leveltag ## LEVEL) {\
4048d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("%s<%s ", (leveli ## LEVEL), \
4058d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				(leveltag ## LEVEL));\
4068d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			xmlAttrS("type", (TAG)); \
4078d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		} else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \
4088d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	} while(0)
4098d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
4108d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	thisChain = argv[arg++];
4118d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
4128d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (part == 1) {	/* skip */
4138d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		/* use argvattr to tell which arguments were quoted
4148d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		   to avoid comparing quoted arguments, like comments, to -j, */
4158d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		while (arg < argc && (argvattr[arg] || !isTarget(argv[arg])))
4168d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			arg++;
4178d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
4188d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
4198d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	/* Before we start, if the first arg is -[^-] and not -m or -j or -g
4208d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	   then start a dummy <match> tag for old style built-in matches.
4218d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	   We would do this in any case, but no need if it would be empty */
4228d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (arg < argc && argv[arg][0] == '-' && !isTarget(argv[arg])
4238d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	    && strcmp(argv[arg], "-m") != 0) {
4248d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		OPEN_LEVEL(1, "match");
4258d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf(">\n");
4268d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
4278d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	while (arg < argc) {
4288d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		// If ! is followed by -* then apply to that else output as data
4298d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		// Stop, if we need to
4308d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (part == -1 && !argvattr[arg] && (isTarget(argv[arg]))) {
4318d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			break;
4328d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		} else if (!argvattr[arg] && strcmp(argv[arg], "!") == 0) {
4338d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if ((arg + 1) < argc && argv[arg + 1][0] == '-')
4348d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				invert_next = '!';
4358d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			else
4368d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf("%s%s", spacer, argv[arg]);
4378d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			spacer = " ";
4388d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		} else if (!argvattr[arg] && isTarget(argv[arg])
4398d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			   && existsChain(argv[arg + 1])
4408d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			   && (2 + arg >= argc)) {
4418d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (!((1 + arg) < argc))
4428d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				// no args to -j, -m or -g, ignore & finish loop
4438d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				break;
4448d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			CLOSE_LEVEL(2);
4458d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (level1)
4468d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf("%s", leveli1);
4478d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			CLOSE_LEVEL(1);
4488d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			spacer = "";
4498d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			invert_next = 0;
4508d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (strcmp(argv[arg], "-g") == 0
4518d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			    || strcmp(argv[arg], "--goto") == 0) {
4528d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				/* goto user chain */
4538d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				OPEN_LEVEL(1, "goto");
4548d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf(">\n");
4558d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				arg++;
4568d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				OPEN_LEVEL(2, argv[arg]);
4578d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf("/>\n");
4588d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				level2 = NULL;
4598d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			} else {
4608d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				/* call user chain */
4618d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				OPEN_LEVEL(1, "call");
4628d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf(">\n");
4638d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				arg++;
4648d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				OPEN_LEVEL(2, argv[arg]);
4658d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf("/>\n");
4668d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				level2 = NULL;
4678d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			}
4688d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		} else if (!argvattr[arg]
4698d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			   && (isTarget(argv[arg])
4708d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			       || strcmp(argv[arg], "-m") == 0
4718d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			       || strcmp(argv[arg], "--module") == 0)) {
4728d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (!((1 + arg) < argc))
4738d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				// no args to -j, -m or -g, ignore & finish loop
4748d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				break;
4758d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			CLOSE_LEVEL(2);
4768d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (level1)
4778d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf("%s", leveli1);
4788d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			CLOSE_LEVEL(1);
4798d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			spacer = "";
4808d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			invert_next = 0;
4818d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			arg++;
4828d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			OPEN_LEVEL(1, (argv[arg]));
4838d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			// Optimize case, can we close this tag already?
4848d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if ((arg + 1) >= argc || (!argvattr[arg + 1]
4858d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						  && (isTarget(argv[arg + 1])
4868d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						      || strcmp(argv[arg + 1],
4878d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez								"-m") == 0
4888d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						      || strcmp(argv[arg + 1],
4898d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez								"--module") ==
4908d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						      0))) {
4918d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf(" />\n");
4928d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				level1 = NULL;
4938d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			} else {
4948d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf(">\n");
4958d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			}
4968d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		} else if (!argvattr[arg] && argv[arg][0] == '-') {
4978d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *tag;
4988d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			CLOSE_LEVEL(2);
4998d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			// Skip past any -
5008d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			tag = argv[arg];
5018d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			while (*tag == '-' && *tag)
5028d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				tag++;
5038d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5048d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			spacer = "";
5058d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			OPEN_LEVEL(2, tag);
5068d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (invert_next)
5078d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf(" invert=\"1\"");
5088d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			invert_next = 0;
5098d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5108d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			// Optimize case, can we close this tag already?
5118d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (!((arg + 1) < argc)
5128d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			    || (argv[arg + 1][0] == '-' /* NOT QUOTED */ )) {
5138d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf(" />\n");
5148d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				level2 = NULL;
5158d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			} else {
5168d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf(">");
5178d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			}
5188d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		} else {	// regular data
5198d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *spaces = strchr(argv[arg], ' ');
5208d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("%s", spacer);
5218d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (spaces || argvattr[arg])
5228d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf("&quot;");
5238d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			// if argv[arg] contains a space, enclose in quotes
5248d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			xmlEncode(argv[arg]);
5258d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (spaces || argvattr[arg])
5268d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				printf("&quot;");
5278d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			spacer = " ";
5288d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
5298d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		arg++;
5308d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
5318d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	CLOSE_LEVEL(2);
5328d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (level1)
5338d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf("%s", leveli1);
5348d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	CLOSE_LEVEL(1);
5358d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
5368d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5378d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic int
5389ee386a1b6d7704b259460152c959ab0e79e02aaMax KellermanncompareRules(void)
5398d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
5408d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	/* compare arguments up to -j or -g for match.
5418d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	   NOTE: We don't want to combine actions if there were no criteria
5428d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	   in each rule, or rules didn't have an action
5438d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	   NOTE: Depends on arguments being in some kind of "normal" order which
5448d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	   is the case when processing the ACTUAL output of actual iptables-save
5458d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	   rather than a file merely in a compatable format */
5468d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5477a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int old = 0;
5487a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt	unsigned int new = 0;
5498d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5508d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	int compare = 0;
5518d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5528d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	while (new < newargc && old < oldargc) {
5538d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (isTarget(oldargv[old]) && isTarget(newargv[new])) {
5548e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott			/* if oldarg was a terminating action then it makes no sense
5558e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott			 * to combine further actions into the same xml */
5568e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott			if (((strcmp((oldargv[old]), "-j") == 0
5578e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott					|| strcmp((oldargv[old]), "--jump") == 0)
5588e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott				&& old+1 < oldargc
5598e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott				&& isTerminatingTarget(oldargv[old+1]) )
5608e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott			    || strcmp((oldargv[old]), "-g") == 0
5618e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott			    || strcmp((oldargv[old]), "--goto") == 0 ) {
5628e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott				/* Previous rule had terminating action */
5638e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott				compare = 0;
5648e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott			} else {
5658e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott				compare = 1;
5668e52815a55692d657aeca7f8ecf656cd65dcfce0Sam Liddicott			}
5678d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			break;
5688d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
5698d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		// break when old!=new
5708d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (strcmp(oldargv[old], newargv[new]) != 0) {
5718d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			compare = 0;
5728d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			break;
5738d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
5748d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5758d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		old++;
5768d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		new++;
5778d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
5788d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	// We won't match unless both rules had a target.
5798d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	// This means we don't combine target-less rules, which is good
5808d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5818d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	return compare == 1;
5828d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
5838d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5848d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez/* has a nice parsed rule starting with -A */
5858d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezstatic void
5868d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezdo_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
5878d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
5888d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	/* are these conditions the same as the previous rule?
5898d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	 * If so, skip arg straight to -j or -g */
5908d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) {
5918d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		xmlComment("Combine action from next rule");
5928d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	} else {
5938d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
5948d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (closeActionTag[0]) {
5958d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("%s\n", closeActionTag);
5968d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			closeActionTag[0] = 0;
5978d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
5988d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (closeRuleTag[0]) {
5998d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("%s\n", closeRuleTag);
6008d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			closeRuleTag[0] = 0;
6018d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
6028d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6038d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf("      <rule ");
6048d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		//xmlAttrS("table",curTable); // not needed in full mode
6058d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		//xmlAttrS("chain",argv[1]); // not needed in full mode
6068d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (pcnt)
6078d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			xmlAttrS("packet-count", pcnt);
6088d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (bcnt)
6098d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			xmlAttrS("byte-count", bcnt);
6108d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf(">\n");
6118d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6128d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		strncpy(closeRuleTag, "      </rule>\n", IPT_TABLE_MAXNAMELEN);
6138d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		closeRuleTag[IPT_TABLE_MAXNAMELEN] = '\0';
6148d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6158d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		/* no point in writing out condition if there isn't one */
6168d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (argc >= 3 && !isTarget(argv[2])) {
6178d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("       <conditions>\n");
6188d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			do_rule_part(NULL, NULL, -1, argc, argv, argvattr);
6198d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("       </conditions>\n");
6208d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
6218d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
6228d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	/* Write out the action */
6238d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	//do_rule_part("action","arg",1,argc,argv,argvattr);
6248d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (!closeActionTag[0]) {
6258d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		printf("       <actions>\n");
6268d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		strncpy(closeActionTag, "       </actions>\n",
6278d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			IPT_TABLE_MAXNAMELEN);
6288d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		closeActionTag[IPT_TABLE_MAXNAMELEN] = '\0';
6298d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
6308d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	do_rule_part(NULL, NULL, 1, argc, argv, argvattr);
6318d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
6328d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6334dcdc9b3f8f42eb3b5a1d12e1b3d2fc1e2675725Jamal Hadi Salimstruct xtables_globals iptables_xml_globals = {
6344dcdc9b3f8f42eb3b5a1d12e1b3d2fc1e2675725Jamal Hadi Salim	.option_offset = 0,
6354dcdc9b3f8f42eb3b5a1d12e1b3d2fc1e2675725Jamal Hadi Salim	.program_version = IPTABLES_VERSION,
6364dcdc9b3f8f42eb3b5a1d12e1b3d2fc1e2675725Jamal Hadi Salim	.program_name = "iptables-xml",
6374dcdc9b3f8f42eb3b5a1d12e1b3d2fc1e2675725Jamal Hadi Salim	.exit_error = exit_error,
6384dcdc9b3f8f42eb3b5a1d12e1b3d2fc1e2675725Jamal Hadi Salim};
6398d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6408d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#ifdef IPTABLES_MULTI
6418d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezint
642e78c69c8146c5dcd096ba13ac03d7a7bb90e3ea7Lutz Jaenickeiptables_xml_main(int argc, char *argv[])
6438d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#else
6448d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezint
6458d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azezmain(int argc, char *argv[])
6468d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez#endif
6478d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez{
6488d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	char buffer[10240];
6498d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	int c;
6508d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	FILE *in;
6518d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6528d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	program_name = "iptables-xml";
653dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt	program_version = IPTABLES_VERSION;
6548d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	line = 0;
6558d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6564dcdc9b3f8f42eb3b5a1d12e1b3d2fc1e2675725Jamal Hadi Salim	xtables_set_params(&iptables_xml_globals);
6578d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	while ((c = getopt_long(argc, argv, "cvh", options, NULL)) != -1) {
6588d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		switch (c) {
6598d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		case 'c':
6608d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			combine = 1;
6618d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			break;
6628d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		case 'v':
6638d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("xptables-xml\n");
6648d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			verbose = 1;
6658d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			break;
6668d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		case 'h':
667dacafa55379fd98212031d8c559096c91d7ce93bJan Engelhardt			print_usage("iptables-xml", IPTABLES_VERSION);
6688d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			break;
6698d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
6708d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
6718d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6728d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (optind == argc - 1) {
6738d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		in = fopen(argv[optind], "r");
6748d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (!in) {
6758d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			fprintf(stderr, "Can't open %s: %s", argv[optind],
6768d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				strerror(errno));
6778d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			exit(1);
6788d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
6798d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	} else if (optind < argc) {
6808d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		fprintf(stderr, "Unknown arguments found on commandline");
6818d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		exit(1);
6828d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	} else
6838d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		in = stdin;
6848d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6858d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf("<iptables-rules version=\"1.0\">\n");
6868d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6878d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	/* Grab standard input. */
6888d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	while (fgets(buffer, sizeof(buffer), in)) {
6898d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		int ret = 0;
6908d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6918d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		line++;
6928d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
6938d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (buffer[0] == '\n')
6948d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			continue;
6958d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		else if (buffer[0] == '#') {
6968d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			xmlComment(buffer);
6978d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			continue;
6988d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
6998d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7008d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (verbose) {
7018d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf("<!-- line %d ", line);
7028d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			xmlCommentEscape(buffer);
7038d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			printf(" -->\n");
7048d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
7058d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7068d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if ((strcmp(buffer, "COMMIT\n") == 0) && (curTable[0])) {
7078d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			DEBUGP("Calling commit\n");
7088d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			closeTable();
7098d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			ret = 1;
7108d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		} else if ((buffer[0] == '*')) {
7118d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			/* New table */
7128d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *table;
7138d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7148d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			table = strtok(buffer + 1, " \t\n");
7158d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			DEBUGP("line %u, table '%s'\n", line, table);
7168d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (!table) {
7178d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				exit_error(PARAMETER_PROBLEM,
7188d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					   "%s: line %u table name invalid\n",
7198d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					   program_name, line);
7208d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				exit(1);
7218d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			}
7228d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			openTable(table);
7238d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7248d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			ret = 1;
7258d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		} else if ((buffer[0] == ':') && (curTable[0])) {
7268d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			/* New chain. */
7278d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *policy, *chain;
7288d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			struct ipt_counters count;
7298d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *ctrs;
7308d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7318d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			chain = strtok(buffer + 1, " \t\n");
7328d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			DEBUGP("line %u, chain '%s'\n", line, chain);
7338d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (!chain) {
7348d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				exit_error(PARAMETER_PROBLEM,
7358d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					   "%s: line %u chain name invalid\n",
7368d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					   program_name, line);
7378d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				exit(1);
7388d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			}
7398d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7408d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			DEBUGP("Creating new chain '%s'\n", chain);
7418d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7428d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			policy = strtok(NULL, " \t\n");
7438d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			DEBUGP("line %u, policy '%s'\n", line, policy);
7448d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (!policy) {
7458d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				exit_error(PARAMETER_PROBLEM,
7468d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					   "%s: line %u policy invalid\n",
7478d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					   program_name, line);
7488d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				exit(1);
7498d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			}
7508d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7518d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			ctrs = strtok(NULL, " \t\n");
7528d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			parse_counters(ctrs, &count);
7538d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			saveChain(chain, policy, &count);
7548d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7558d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			ret = 1;
7568d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		} else if (curTable[0]) {
7577a236f4cc685a420c1a782a5db614a93baf37ccfJan Engelhardt			unsigned int a;
7588d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *ptr = buffer;
7598d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *pcnt = NULL;
7608d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *bcnt = NULL;
7618d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *parsestart;
7628d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *chain = NULL;
7638d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7648d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			/* the parser */
7658d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			char *param_start, *curchar;
7668d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			int quote_open, quoted;
7678d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7688d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			/* reset the newargv */
7698d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			newargc = 0;
7708d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7718d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			if (buffer[0] == '[') {
7728d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				/* we have counters in our input */
7738d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				ptr = strchr(buffer, ']');
7748d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				if (!ptr)
7758d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					exit_error(PARAMETER_PROBLEM,
7768d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						   "Bad line %u: need ]\n",
7778d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						   line);
7788d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7798d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				pcnt = strtok(buffer + 1, ":");
7808d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				if (!pcnt)
7818d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					exit_error(PARAMETER_PROBLEM,
7828d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						   "Bad line %u: need :\n",
7838d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						   line);
7848d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7858d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				bcnt = strtok(NULL, "]");
7868d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				if (!bcnt)
7878d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					exit_error(PARAMETER_PROBLEM,
7888d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						   "Bad line %u: need ]\n",
7898d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						   line);
7908d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7918d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				/* start command parsing after counter */
7928d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				parsestart = ptr + 1;
7938d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			} else {
7948d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				/* start command parsing at start of line */
7958d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				parsestart = buffer;
7968d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			}
7978d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7988d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
7998d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			/* This is a 'real' parser crafted in artist mode
8008d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			 * not hacker mode. If the author can live with that
8018d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			 * then so can everyone else */
8028d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8038d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			quote_open = 0;
8048d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			/* We need to know which args were quoted so we
8058d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			   can preserve quote */
8068d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			quoted = 0;
8078d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			param_start = parsestart;
8088d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8098d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			for (curchar = parsestart; *curchar; curchar++) {
8108d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				if (*curchar == '"') {
8118d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					/* quote_open cannot be true if there
8128d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					 * was no previous character.  Thus,
8138d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					 * curchar-1 has to be within bounds */
8148d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					if (quote_open &&
8158d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					    *(curchar - 1) != '\\') {
8168d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						quote_open = 0;
8178d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						*curchar = ' ';
8188d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					} else {
8198d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						quote_open = 1;
8208d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						quoted = 1;
8218d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						param_start++;
8228d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					}
8238d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				}
8248d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				if (*curchar == ' '
8258d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				    || *curchar == '\t' || *curchar == '\n') {
8268d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					char param_buffer[1024];
8278d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					int param_len = curchar - param_start;
8288d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8298d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					if (quote_open)
8308d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						continue;
8318d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8328d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					if (!param_len) {
8338d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						/* two spaces? */
8348d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						param_start++;
8358d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						continue;
8368d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					}
8378d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8388d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					/* end of one parameter */
8398d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					strncpy(param_buffer, param_start,
8408d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						param_len);
8418d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					*(param_buffer + param_len) = '\0';
8428d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8438d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					/* check if table name specified */
8448d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					if (!strncmp(param_buffer, "-t", 3)
8458d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					    || !strncmp(param_buffer,
8468d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez							"--table", 8)) {
8478d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						exit_error(PARAMETER_PROBLEM,
8488d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez							   "Line %u seems to have a "
8498d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez							   "-t table option.\n",
8508d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez							   line);
8518d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						exit(1);
8528d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					}
8538d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8548d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					add_argv(param_buffer, quoted);
8558d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					if (newargc >= 2
8568d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					    && 0 ==
8578d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					    strcmp(newargv[newargc - 2], "-A"))
8588d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez						chain = newargv[newargc - 1];
8598d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					quoted = 0;
8608d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					param_start += param_len + 1;
8618d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				} else {
8628d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez					/* regular character, skip */
8638d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				}
8648d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			}
8658d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8668d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
8678d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			       newargc, curTable);
8688d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8698d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			for (a = 0; a < newargc; a++)
8708d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				DEBUGP("argv[%u]: %s\n", a, newargv[a]);
8718d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8728d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			needChain(chain);// Should we explicitly look for -A
8738d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			do_rule(pcnt, bcnt, newargc, newargv, newargvattr);
8748d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8758d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			save_argv();
8768d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			ret = 1;
8778d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
8788d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		if (!ret) {
8798d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			fprintf(stderr, "%s: line %u failed\n",
8808d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez				program_name, line);
8818d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			exit(1);
8828d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		}
8838d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
8848d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	if (curTable[0]) {
8858d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		fprintf(stderr, "%s: COMMIT expected at line %u\n",
8868d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez			program_name, line + 1);
8878d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez		exit(1);
8888d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	}
8898d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8908d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	printf("</iptables-rules>\n");
8918d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	free_argv();
8928d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez
8938d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez	return 0;
8948d3eccb19a9c6fc006193d633b985205e350b9c5Amin Azez}
895