Blame bootstrap_ver/iptables/iptables-xml.c

Packit Service dd8e2b
/* Code to convert iptables-save format to xml format,
Packit Service dd8e2b
 * (C) 2006 Ufo Mechanic <azez@ufomechanic.net>
Packit Service dd8e2b
 * based on iptables-restore (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
Packit Service dd8e2b
 * based on previous code from Rusty Russell <rusty@linuxcare.com.au>
Packit Service dd8e2b
 *
Packit Service dd8e2b
 * This code is distributed under the terms of GNU GPL v2
Packit Service dd8e2b
 */
Packit Service dd8e2b
Packit Service dd8e2b
#include <getopt.h>
Packit Service dd8e2b
#include <errno.h>
Packit Service dd8e2b
#include <string.h>
Packit Service dd8e2b
#include <stdio.h>
Packit Service dd8e2b
#include <stdlib.h>
Packit Service dd8e2b
#include <stdarg.h>
Packit Service dd8e2b
#include "iptables.h"
Packit Service dd8e2b
#include "libiptc/libiptc.h"
Packit Service dd8e2b
#include "xtables-multi.h"
Packit Service dd8e2b
#include <xtables.h>
Packit Service dd8e2b
#include "xshared.h"
Packit Service dd8e2b
Packit Service dd8e2b
struct xtables_globals iptables_xml_globals = {
Packit Service dd8e2b
	.option_offset = 0,
Packit Service dd8e2b
	.program_version = IPTABLES_VERSION,
Packit Service dd8e2b
	.program_name = "iptables-xml",
Packit Service dd8e2b
};
Packit Service dd8e2b
#define prog_name iptables_xml_globals.program_name
Packit Service dd8e2b
#define prog_vers iptables_xml_globals.program_version
Packit Service dd8e2b
Packit Service dd8e2b
static void print_usage(const char *name, const char *version)
Packit Service dd8e2b
	    __attribute__ ((noreturn));
Packit Service dd8e2b
Packit Service dd8e2b
static int verbose;
Packit Service dd8e2b
/* Whether to combine actions of sequential rules with identical conditions */
Packit Service dd8e2b
static int combine;
Packit Service dd8e2b
/* Keeping track of external matches and targets.  */
Packit Service dd8e2b
static const struct option options[] = {
Packit Service dd8e2b
	{"verbose", 0, NULL, 'v'},
Packit Service dd8e2b
	{"combine", 0, NULL, 'c'},
Packit Service dd8e2b
	{"help", 0, NULL, 'h'},
Packit Service dd8e2b
	{ .name = NULL }
Packit Service dd8e2b
};
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
print_usage(const char *name, const char *version)
Packit Service dd8e2b
{
Packit Service dd8e2b
	fprintf(stderr, "Usage: %s [-c] [-v] [-h]\n"
Packit Service dd8e2b
		"          [--combine ]\n"
Packit Service dd8e2b
		"	   [ --verbose ]\n" "	   [ --help ]\n", name);
Packit Service dd8e2b
Packit Service dd8e2b
	exit(1);
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
#define XT_CHAIN_MAXNAMELEN XT_TABLE_MAXNAMELEN
Packit Service dd8e2b
static char closeActionTag[XT_TABLE_MAXNAMELEN + 1];
Packit Service dd8e2b
static char closeRuleTag[XT_TABLE_MAXNAMELEN + 1];
Packit Service dd8e2b
static char curTable[XT_TABLE_MAXNAMELEN + 1];
Packit Service dd8e2b
static char curChain[XT_CHAIN_MAXNAMELEN + 1];
Packit Service dd8e2b
Packit Service dd8e2b
struct chain {
Packit Service dd8e2b
	char *chain;
Packit Service dd8e2b
	char *policy;
Packit Service dd8e2b
	struct xt_counters count;
Packit Service dd8e2b
	int created;
Packit Service dd8e2b
};
Packit Service dd8e2b
Packit Service dd8e2b
#define maxChains 10240		/* max chains per table */
Packit Service dd8e2b
static struct chain chains[maxChains];
Packit Service dd8e2b
static int nextChain;
Packit Service dd8e2b
Packit Service dd8e2b
/* like puts but with xml encoding */
Packit Service dd8e2b
static void
Packit Service dd8e2b
xmlEncode(char *text)
Packit Service dd8e2b
{
Packit Service dd8e2b
	while (text && *text) {
Packit Service dd8e2b
		if ((unsigned char) (*text) >= 127)
Packit Service dd8e2b
			printf("&#%d;", (unsigned char) (*text));
Packit Service dd8e2b
		else if (*text == '&')
Packit Service dd8e2b
			printf("&");
Packit Service dd8e2b
		else if (*text == '<')
Packit Service dd8e2b
			printf("<");
Packit Service dd8e2b
		else if (*text == '>')
Packit Service dd8e2b
			printf(">");
Packit Service dd8e2b
		else if (*text == '"')
Packit Service dd8e2b
			printf(""");
Packit Service dd8e2b
		else
Packit Service dd8e2b
			putchar(*text);
Packit Service dd8e2b
		text++;
Packit Service dd8e2b
	}
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
/* Output text as a comment, avoiding a double hyphen */
Packit Service dd8e2b
static void
Packit Service dd8e2b
xmlCommentEscape(char *comment)
Packit Service dd8e2b
{
Packit Service dd8e2b
	int h_count = 0;
Packit Service dd8e2b
Packit Service dd8e2b
	while (comment && *comment) {
Packit Service dd8e2b
		if (*comment == '-') {
Packit Service dd8e2b
			h_count++;
Packit Service dd8e2b
			if (h_count >= 2) {
Packit Service dd8e2b
				h_count = 0;
Packit Service dd8e2b
				putchar(' ');
Packit Service dd8e2b
			}
Packit Service dd8e2b
			putchar('*');
Packit Service dd8e2b
		}
Packit Service dd8e2b
		/* strip trailing newline */
Packit Service dd8e2b
		if (*comment == '\n' && *(comment + 1) == 0);
Packit Service dd8e2b
		else
Packit Service dd8e2b
			putchar(*comment);
Packit Service dd8e2b
		comment++;
Packit Service dd8e2b
	}
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
xmlComment(char *comment)
Packit Service dd8e2b
{
Packit Service dd8e2b
	printf("
Packit Service dd8e2b
	xmlCommentEscape(comment);
Packit Service dd8e2b
	printf(" -->\n");
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
xmlAttrS(char *name, char *value)
Packit Service dd8e2b
{
Packit Service dd8e2b
	printf("%s=\"", name);
Packit Service dd8e2b
	xmlEncode(value);
Packit Service dd8e2b
	printf("\" ");
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
xmlAttrI(char *name, long long int num)
Packit Service dd8e2b
{
Packit Service dd8e2b
	printf("%s=\"%lld\" ", name, num);
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
closeChain(void)
Packit Service dd8e2b
{
Packit Service dd8e2b
	if (curChain[0] == 0)
Packit Service dd8e2b
		return;
Packit Service dd8e2b
Packit Service dd8e2b
	if (closeActionTag[0])
Packit Service dd8e2b
		printf("%s\n", closeActionTag);
Packit Service dd8e2b
	closeActionTag[0] = 0;
Packit Service dd8e2b
	if (closeRuleTag[0])
Packit Service dd8e2b
		printf("%s\n", closeRuleTag);
Packit Service dd8e2b
	closeRuleTag[0] = 0;
Packit Service dd8e2b
	if (curChain[0])
Packit Service dd8e2b
		printf("    </chain>\n");
Packit Service dd8e2b
	curChain[0] = 0;
Packit Service dd8e2b
	//lastRule[0]=0;
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
openChain(char *chain, char *policy, struct xt_counters *ctr, char close)
Packit Service dd8e2b
{
Packit Service dd8e2b
	closeChain();
Packit Service dd8e2b
Packit Service dd8e2b
	strncpy(curChain, chain, XT_CHAIN_MAXNAMELEN);
Packit Service dd8e2b
	curChain[XT_CHAIN_MAXNAMELEN] = '\0';
Packit Service dd8e2b
Packit Service dd8e2b
	printf("    
Packit Service dd8e2b
	xmlAttrS("name", curChain);
Packit Service dd8e2b
	if (strcmp(policy, "-") != 0)
Packit Service dd8e2b
		xmlAttrS("policy", policy);
Packit Service dd8e2b
	xmlAttrI("packet-count", (unsigned long long) ctr->pcnt);
Packit Service dd8e2b
	xmlAttrI("byte-count", (unsigned long long) ctr->bcnt);
Packit Service dd8e2b
	if (close) {
Packit Service dd8e2b
		printf("%c", close);
Packit Service dd8e2b
		curChain[0] = 0;
Packit Service dd8e2b
	}
Packit Service dd8e2b
	printf(">\n");
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static int
Packit Service dd8e2b
existsChain(char *chain)
Packit Service dd8e2b
{
Packit Service dd8e2b
	/* open a saved chain */
Packit Service dd8e2b
	int c = 0;
Packit Service dd8e2b
Packit Service dd8e2b
	if (0 == strcmp(curChain, chain))
Packit Service dd8e2b
		return 1;
Packit Service dd8e2b
	for (c = 0; c < nextChain; c++)
Packit Service dd8e2b
		if (chains[c].chain && strcmp(chains[c].chain, chain) == 0)
Packit Service dd8e2b
			return 1;
Packit Service dd8e2b
	return 0;
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
needChain(char *chain)
Packit Service dd8e2b
{
Packit Service dd8e2b
	/* open a saved chain */
Packit Service dd8e2b
	int c = 0;
Packit Service dd8e2b
Packit Service dd8e2b
	if (0 == strcmp(curChain, chain))
Packit Service dd8e2b
		return;
Packit Service dd8e2b
Packit Service dd8e2b
	for (c = 0; c < nextChain; c++)
Packit Service dd8e2b
		if (chains[c].chain && strcmp(chains[c].chain, chain) == 0) {
Packit Service dd8e2b
			openChain(chains[c].chain, chains[c].policy,
Packit Service dd8e2b
				  &(chains[c].count), '\0');
Packit Service dd8e2b
			/* And, mark it as done so we don't create 
Packit Service dd8e2b
			   an empty chain at table-end time */
Packit Service dd8e2b
			chains[c].created = 1;
Packit Service dd8e2b
		}
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
saveChain(char *chain, char *policy, struct xt_counters *ctr)
Packit Service dd8e2b
{
Packit Service dd8e2b
	if (nextChain >= maxChains) {
Packit Service dd8e2b
		xtables_error(PARAMETER_PROBLEM,
Packit Service dd8e2b
			   "%s: line %u chain name invalid\n",
Packit Service dd8e2b
			   prog_name, line);
Packit Service dd8e2b
		exit(1);
Packit Service dd8e2b
	};
Packit Service dd8e2b
	chains[nextChain].chain = strdup(chain);
Packit Service dd8e2b
	chains[nextChain].policy = strdup(policy);
Packit Service dd8e2b
	chains[nextChain].count = *ctr;
Packit Service dd8e2b
	chains[nextChain].created = 0;
Packit Service dd8e2b
	nextChain++;
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
finishChains(void)
Packit Service dd8e2b
{
Packit Service dd8e2b
	int c;
Packit Service dd8e2b
Packit Service dd8e2b
	for (c = 0; c < nextChain; c++)
Packit Service dd8e2b
		if (!chains[c].created) {
Packit Service dd8e2b
			openChain(chains[c].chain, chains[c].policy,
Packit Service dd8e2b
				  &(chains[c].count), '/');
Packit Service dd8e2b
			free(chains[c].chain);
Packit Service dd8e2b
			free(chains[c].policy);
Packit Service dd8e2b
		}
Packit Service dd8e2b
	nextChain = 0;
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
closeTable(void)
Packit Service dd8e2b
{
Packit Service dd8e2b
	closeChain();
Packit Service dd8e2b
	finishChains();
Packit Service dd8e2b
	if (curTable[0])
Packit Service dd8e2b
		printf("  \n");
Packit Service dd8e2b
	curTable[0] = 0;
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static void
Packit Service dd8e2b
openTable(char *table)
Packit Service dd8e2b
{
Packit Service dd8e2b
	closeTable();
Packit Service dd8e2b
Packit Service dd8e2b
	strncpy(curTable, table, XT_TABLE_MAXNAMELEN);
Packit Service dd8e2b
	curTable[XT_TABLE_MAXNAMELEN] = '\0';
Packit Service dd8e2b
Packit Service dd8e2b
	printf("  
Packit Service dd8e2b
	xmlAttrS("name", curTable);
Packit Service dd8e2b
	printf(">\n");
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
// is char* -j --jump -g or --goto
Packit Service dd8e2b
static int
Packit Service dd8e2b
isTarget(char *arg)
Packit Service dd8e2b
{
Packit Service dd8e2b
	return ((arg)
Packit Service dd8e2b
		&& (strcmp((arg), "-j") == 0 || strcmp((arg), "--jump") == 0
Packit Service dd8e2b
		    || strcmp((arg), "-g") == 0
Packit Service dd8e2b
		    || strcmp((arg), "--goto") == 0));
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
// is it a terminating target like -j ACCEPT, etc
Packit Service dd8e2b
// (or I guess -j SNAT in nat table, but we don't check for that yet
Packit Service dd8e2b
static int
Packit Service dd8e2b
isTerminatingTarget(char *arg)
Packit Service dd8e2b
{
Packit Service dd8e2b
	return ((arg)
Packit Service dd8e2b
		&& (strcmp((arg), "ACCEPT") == 0
Packit Service dd8e2b
		    || strcmp((arg), "DROP") == 0
Packit Service dd8e2b
		    || strcmp((arg), "QUEUE") == 0
Packit Service dd8e2b
		    || strcmp((arg), "RETURN") == 0));
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
// part=-1 means do conditions, part=1 means do rules, part=0 means do both
Packit Service dd8e2b
static void
Packit Service dd8e2b
do_rule_part(char *leveltag1, char *leveltag2, int part, int argc,
Packit Service dd8e2b
	     char *argv[], int argvattr[])
Packit Service dd8e2b
{
Packit Service dd8e2b
	int i;
Packit Service dd8e2b
	int arg = 2;		// ignore leading -A <chain>
Packit Service dd8e2b
	char invert_next = 0;
Packit Service dd8e2b
	char *spacer = "";	// space when needed to assemble arguments
Packit Service dd8e2b
	char *level1 = NULL;
Packit Service dd8e2b
	char *level2 = NULL;
Packit Service dd8e2b
	char *leveli1 = "        ";
Packit Service dd8e2b
	char *leveli2 = "          ";
Packit Service dd8e2b
Packit Service dd8e2b
#define CLOSE_LEVEL(LEVEL) \
Packit Service dd8e2b
	do { \
Packit Service dd8e2b
		if (level ## LEVEL) printf("</%s>\n", \
Packit Service dd8e2b
		(leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \
Packit Service dd8e2b
		level ## LEVEL=NULL;\
Packit Service dd8e2b
	} while(0)
Packit Service dd8e2b
Packit Service dd8e2b
#define OPEN_LEVEL(LEVEL,TAG) \
Packit Service dd8e2b
	do {\
Packit Service dd8e2b
		level ## LEVEL=TAG;\
Packit Service dd8e2b
		if (leveltag ## LEVEL) {\
Packit Service dd8e2b
			printf("%s<%s ", (leveli ## LEVEL), \
Packit Service dd8e2b
				(leveltag ## LEVEL));\
Packit Service dd8e2b
			xmlAttrS("type", (TAG)); \
Packit Service dd8e2b
		} else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \
Packit Service dd8e2b
	} while(0)
Packit Service dd8e2b
Packit Service dd8e2b
	if (part == 1) {	/* skip */
Packit Service dd8e2b
		/* use argvattr to tell which arguments were quoted 
Packit Service dd8e2b
		   to avoid comparing quoted arguments, like comments, to -j, */
Packit Service dd8e2b
		while (arg < argc && (argvattr[arg] || !isTarget(argv[arg])))
Packit Service dd8e2b
			arg++;
Packit Service dd8e2b
	}
Packit Service dd8e2b
Packit Service dd8e2b
	/* Before we start, if the first arg is -[^-] and not -m or -j or -g
Packit Service dd8e2b
	 * then start a dummy <match> tag for old style built-in matches.
Packit Service dd8e2b
	 * We would do this in any case, but no need if it would be empty.
Packit Service dd8e2b
	 * In the case of negation, we need to look at arg+1
Packit Service dd8e2b
	 */
Packit Service dd8e2b
	if (arg < argc && strcmp(argv[arg], "!") == 0)
Packit Service dd8e2b
		i = arg + 1;
Packit Service dd8e2b
	else
Packit Service dd8e2b
		i = arg;
Packit Service dd8e2b
	if (i < argc && argv[i][0] == '-' && !isTarget(argv[i])
Packit Service dd8e2b
	    && strcmp(argv[i], "-m") != 0) {
Packit Service dd8e2b
		OPEN_LEVEL(1, "match");
Packit Service dd8e2b
		printf(">\n");
Packit Service dd8e2b
	}
Packit Service dd8e2b
	while (arg < argc) {
Packit Service dd8e2b
		// If ! is followed by -* then apply to that else output as data
Packit Service dd8e2b
		// Stop, if we need to
Packit Service dd8e2b
		if (part == -1 && !argvattr[arg] && (isTarget(argv[arg]))) {
Packit Service dd8e2b
			break;
Packit Service dd8e2b
		} else if (!argvattr[arg] && strcmp(argv[arg], "!") == 0) {
Packit Service dd8e2b
			if ((arg + 1) < argc && argv[arg + 1][0] == '-')
Packit Service dd8e2b
				invert_next = '!';
Packit Service dd8e2b
			else
Packit Service dd8e2b
				printf("%s%s", spacer, argv[arg]);
Packit Service dd8e2b
			spacer = " ";
Packit Service dd8e2b
		} else if (!argvattr[arg] && isTarget(argv[arg]) &&
Packit Service dd8e2b
			   (arg + 1 < argc) &&
Packit Service dd8e2b
			   existsChain(argv[arg + 1])) {
Packit Service dd8e2b
			CLOSE_LEVEL(2);
Packit Service dd8e2b
			if (level1)
Packit Service dd8e2b
				printf("%s", leveli1);
Packit Service dd8e2b
			CLOSE_LEVEL(1);
Packit Service dd8e2b
			spacer = "";
Packit Service dd8e2b
			invert_next = 0;
Packit Service dd8e2b
			if (strcmp(argv[arg], "-g") == 0
Packit Service dd8e2b
			    || strcmp(argv[arg], "--goto") == 0) {
Packit Service dd8e2b
				/* goto user chain */
Packit Service dd8e2b
				OPEN_LEVEL(1, "goto");
Packit Service dd8e2b
				printf(">\n");
Packit Service dd8e2b
				arg++;
Packit Service dd8e2b
				OPEN_LEVEL(2, argv[arg]);
Packit Service dd8e2b
				printf("/>\n");
Packit Service dd8e2b
				level2 = NULL;
Packit Service dd8e2b
			} else {
Packit Service dd8e2b
				/* call user chain */
Packit Service dd8e2b
				OPEN_LEVEL(1, "call");
Packit Service dd8e2b
				printf(">\n");
Packit Service dd8e2b
				arg++;
Packit Service dd8e2b
				OPEN_LEVEL(2, argv[arg]);
Packit Service dd8e2b
				printf("/>\n");
Packit Service dd8e2b
				level2 = NULL;
Packit Service dd8e2b
			}
Packit Service dd8e2b
		} else if (!argvattr[arg]
Packit Service dd8e2b
			   && (isTarget(argv[arg])
Packit Service dd8e2b
			       || strcmp(argv[arg], "-m") == 0
Packit Service dd8e2b
			       || strcmp(argv[arg], "--module") == 0)) {
Packit Service dd8e2b
			if (!((1 + arg) < argc))
Packit Service dd8e2b
				// no args to -j, -m or -g, ignore & finish loop
Packit Service dd8e2b
				break;
Packit Service dd8e2b
			CLOSE_LEVEL(2);
Packit Service dd8e2b
			if (level1)
Packit Service dd8e2b
				printf("%s", leveli1);
Packit Service dd8e2b
			CLOSE_LEVEL(1);
Packit Service dd8e2b
			spacer = "";
Packit Service dd8e2b
			invert_next = 0;
Packit Service dd8e2b
			arg++;
Packit Service dd8e2b
			OPEN_LEVEL(1, (argv[arg]));
Packit Service dd8e2b
			// Optimize case, can we close this tag already?
Packit Service dd8e2b
			if ((arg + 1) >= argc || (!argvattr[arg + 1]
Packit Service dd8e2b
						  && (isTarget(argv[arg + 1])
Packit Service dd8e2b
						      || strcmp(argv[arg + 1],
Packit Service dd8e2b
								"-m") == 0
Packit Service dd8e2b
						      || strcmp(argv[arg + 1],
Packit Service dd8e2b
								"--module") ==
Packit Service dd8e2b
						      0))) {
Packit Service dd8e2b
				printf(" />\n");
Packit Service dd8e2b
				level1 = NULL;
Packit Service dd8e2b
			} else {
Packit Service dd8e2b
				printf(">\n");
Packit Service dd8e2b
			}
Packit Service dd8e2b
		} else if (!argvattr[arg] && argv[arg][0] == '-') {
Packit Service dd8e2b
			char *tag;
Packit Service dd8e2b
			CLOSE_LEVEL(2);
Packit Service dd8e2b
			// Skip past any -
Packit Service dd8e2b
			tag = argv[arg];
Packit Service dd8e2b
			while (*tag == '-' && *tag)
Packit Service dd8e2b
				tag++;
Packit Service dd8e2b
Packit Service dd8e2b
			spacer = "";
Packit Service dd8e2b
			OPEN_LEVEL(2, tag);
Packit Service dd8e2b
			if (invert_next)
Packit Service dd8e2b
				printf(" invert=\"1\"");
Packit Service dd8e2b
			invert_next = 0;
Packit Service dd8e2b
Packit Service dd8e2b
			// Optimize case, can we close this tag already?
Packit Service dd8e2b
			if (!((arg + 1) < argc)
Packit Service dd8e2b
			    || (argv[arg + 1][0] == '-' /* NOT QUOTED */ )) {
Packit Service dd8e2b
				printf(" />\n");
Packit Service dd8e2b
				level2 = NULL;
Packit Service dd8e2b
			} else {
Packit Service dd8e2b
				printf(">");
Packit Service dd8e2b
			}
Packit Service dd8e2b
		} else {	// regular data
Packit Service dd8e2b
			char *spaces = strchr(argv[arg], ' ');
Packit Service dd8e2b
			printf("%s", spacer);
Packit Service dd8e2b
			if (spaces || argvattr[arg])
Packit Service dd8e2b
				printf(""");
Packit Service dd8e2b
			// if argv[arg] contains a space, enclose in quotes
Packit Service dd8e2b
			xmlEncode(argv[arg]);
Packit Service dd8e2b
			if (spaces || argvattr[arg])
Packit Service dd8e2b
				printf(""");
Packit Service dd8e2b
			spacer = " ";
Packit Service dd8e2b
		}
Packit Service dd8e2b
		arg++;
Packit Service dd8e2b
	}
Packit Service dd8e2b
	CLOSE_LEVEL(2);
Packit Service dd8e2b
	if (level1)
Packit Service dd8e2b
		printf("%s", leveli1);
Packit Service dd8e2b
	CLOSE_LEVEL(1);
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
static int
Packit Service dd8e2b
compareRules(void)
Packit Service dd8e2b
{
Packit Service dd8e2b
	/* Compare arguments up to -j or -g for match.
Packit Service dd8e2b
	 * NOTE: We don't want to combine actions if there were no criteria
Packit Service dd8e2b
	 * in each rule, or rules didn't have an action.
Packit Service dd8e2b
	 * NOTE: Depends on arguments being in some kind of "normal" order which
Packit Service dd8e2b
	 * is the case when processing the ACTUAL output of actual iptables-save
Packit Service dd8e2b
	 * rather than a file merely in a compatible format.
Packit Service dd8e2b
	 */
Packit Service dd8e2b
Packit Service dd8e2b
	unsigned int old = 0;
Packit Service dd8e2b
	unsigned int new = 0;
Packit Service dd8e2b
Packit Service dd8e2b
	int compare = 0;
Packit Service dd8e2b
Packit Service dd8e2b
	while (new < newargc && old < oldargc) {
Packit Service dd8e2b
		if (isTarget(oldargv[old]) && isTarget(newargv[new])) {
Packit Service dd8e2b
			/* if oldarg was a terminating action then it makes no sense
Packit Service dd8e2b
			 * to combine further actions into the same xml */
Packit Service dd8e2b
			if (((strcmp((oldargv[old]), "-j") == 0 
Packit Service dd8e2b
					|| strcmp((oldargv[old]), "--jump") == 0) 
Packit Service dd8e2b
				&& old+1 < oldargc
Packit Service dd8e2b
				&& isTerminatingTarget(oldargv[old+1]) )
Packit Service dd8e2b
			    || strcmp((oldargv[old]), "-g") == 0 
Packit Service dd8e2b
			    || strcmp((oldargv[old]), "--goto") == 0 ) {
Packit Service dd8e2b
				/* Previous rule had terminating action */	
Packit Service dd8e2b
				compare = 0;
Packit Service dd8e2b
			} else {
Packit Service dd8e2b
				compare = 1;
Packit Service dd8e2b
			}
Packit Service dd8e2b
			break;
Packit Service dd8e2b
		}
Packit Service dd8e2b
		// break when old!=new
Packit Service dd8e2b
		if (strcmp(oldargv[old], newargv[new]) != 0) {
Packit Service dd8e2b
			compare = 0;
Packit Service dd8e2b
			break;
Packit Service dd8e2b
		}
Packit Service dd8e2b
Packit Service dd8e2b
		old++;
Packit Service dd8e2b
		new++;
Packit Service dd8e2b
	}
Packit Service dd8e2b
	// We won't match unless both rules had a target. 
Packit Service dd8e2b
	// This means we don't combine target-less rules, which is good
Packit Service dd8e2b
Packit Service dd8e2b
	return compare == 1;
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
/* has a nice parsed rule starting with -A */
Packit Service dd8e2b
static void
Packit Service dd8e2b
do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
Packit Service dd8e2b
{
Packit Service dd8e2b
	/* are these conditions the same as the previous rule?
Packit Service dd8e2b
	 * If so, skip arg straight to -j or -g */
Packit Service dd8e2b
	if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) {
Packit Service dd8e2b
		xmlComment("Combine action from next rule");
Packit Service dd8e2b
	} else {
Packit Service dd8e2b
Packit Service dd8e2b
		if (closeActionTag[0]) {
Packit Service dd8e2b
			printf("%s\n", closeActionTag);
Packit Service dd8e2b
			closeActionTag[0] = 0;
Packit Service dd8e2b
		}
Packit Service dd8e2b
		if (closeRuleTag[0]) {
Packit Service dd8e2b
			printf("%s\n", closeRuleTag);
Packit Service dd8e2b
			closeRuleTag[0] = 0;
Packit Service dd8e2b
		}
Packit Service dd8e2b
Packit Service dd8e2b
		printf("      
Packit Service dd8e2b
		//xmlAttrS("table",curTable); // not needed in full mode 
Packit Service dd8e2b
		//xmlAttrS("chain",argv[1]); // not needed in full mode 
Packit Service dd8e2b
		if (pcnt)
Packit Service dd8e2b
			xmlAttrS("packet-count", pcnt);
Packit Service dd8e2b
		if (bcnt)
Packit Service dd8e2b
			xmlAttrS("byte-count", bcnt);
Packit Service dd8e2b
		printf(">\n");
Packit Service dd8e2b
Packit Service dd8e2b
		strncpy(closeRuleTag, "      </rule>\n", XT_TABLE_MAXNAMELEN);
Packit Service dd8e2b
		closeRuleTag[XT_TABLE_MAXNAMELEN] = '\0';
Packit Service dd8e2b
Packit Service dd8e2b
		/* no point in writing out condition if there isn't one */
Packit Service dd8e2b
		if (argc >= 3 && !isTarget(argv[2])) {
Packit Service dd8e2b
			printf("       <conditions>\n");
Packit Service dd8e2b
			do_rule_part(NULL, NULL, -1, argc, argv, argvattr);
Packit Service dd8e2b
			printf("       </conditions>\n");
Packit Service dd8e2b
		}
Packit Service dd8e2b
	}
Packit Service dd8e2b
	/* Write out the action */
Packit Service dd8e2b
	//do_rule_part("action","arg",1,argc,argv,argvattr);
Packit Service dd8e2b
	if (!closeActionTag[0]) {
Packit Service dd8e2b
		printf("       <actions>\n");
Packit Service dd8e2b
		strncpy(closeActionTag, "       </actions>\n",
Packit Service dd8e2b
			XT_TABLE_MAXNAMELEN);
Packit Service dd8e2b
		closeActionTag[XT_TABLE_MAXNAMELEN] = '\0';
Packit Service dd8e2b
	}
Packit Service dd8e2b
	do_rule_part(NULL, NULL, 1, argc, argv, argvattr);
Packit Service dd8e2b
}
Packit Service dd8e2b
Packit Service dd8e2b
int
Packit Service dd8e2b
iptables_xml_main(int argc, char *argv[])
Packit Service dd8e2b
{
Packit Service dd8e2b
	char buffer[10240];
Packit Service dd8e2b
	int c;
Packit Service dd8e2b
	FILE *in;
Packit Service dd8e2b
Packit Service dd8e2b
	line = 0;
Packit Service dd8e2b
Packit Service dd8e2b
	xtables_set_params(&iptables_xml_globals);
Packit Service dd8e2b
	while ((c = getopt_long(argc, argv, "cvh", options, NULL)) != -1) {
Packit Service dd8e2b
		switch (c) {
Packit Service dd8e2b
		case 'c':
Packit Service dd8e2b
			combine = 1;
Packit Service dd8e2b
			break;
Packit Service dd8e2b
		case 'v':
Packit Service dd8e2b
			printf("xptables-xml\n");
Packit Service dd8e2b
			verbose = 1;
Packit Service dd8e2b
			break;
Packit Service dd8e2b
		case 'h':
Packit Service dd8e2b
			print_usage("iptables-xml", IPTABLES_VERSION);
Packit Service dd8e2b
			break;
Packit Service dd8e2b
		}
Packit Service dd8e2b
	}
Packit Service dd8e2b
Packit Service dd8e2b
	if (optind == argc - 1) {
Packit Service dd8e2b
		in = fopen(argv[optind], "re");
Packit Service dd8e2b
		if (!in) {
Packit Service dd8e2b
			fprintf(stderr, "Can't open %s: %s", argv[optind],
Packit Service dd8e2b
				strerror(errno));
Packit Service dd8e2b
			exit(1);
Packit Service dd8e2b
		}
Packit Service dd8e2b
	} else if (optind < argc) {
Packit Service dd8e2b
		fprintf(stderr, "Unknown arguments found on commandline");
Packit Service dd8e2b
		exit(1);
Packit Service dd8e2b
	} else
Packit Service dd8e2b
		in = stdin;
Packit Service dd8e2b
Packit Service dd8e2b
	printf("<iptables-rules version=\"1.0\">\n");
Packit Service dd8e2b
Packit Service dd8e2b
	/* Grab standard input. */
Packit Service dd8e2b
	while (fgets(buffer, sizeof(buffer), in)) {
Packit Service dd8e2b
		int ret = 0;
Packit Service dd8e2b
Packit Service dd8e2b
		line++;
Packit Service dd8e2b
Packit Service dd8e2b
		if (buffer[0] == '\n')
Packit Service dd8e2b
			continue;
Packit Service dd8e2b
		else if (buffer[0] == '#') {
Packit Service dd8e2b
			xmlComment(buffer);
Packit Service dd8e2b
			continue;
Packit Service dd8e2b
		}
Packit Service dd8e2b
Packit Service dd8e2b
		if (verbose) {
Packit Service dd8e2b
			printf("
Packit Service dd8e2b
			xmlCommentEscape(buffer);
Packit Service dd8e2b
			printf(" -->\n");
Packit Service dd8e2b
		}
Packit Service dd8e2b
Packit Service dd8e2b
		if ((strcmp(buffer, "COMMIT\n") == 0) && (curTable[0])) {
Packit Service dd8e2b
			DEBUGP("Calling commit\n");
Packit Service dd8e2b
			closeTable();
Packit Service dd8e2b
			ret = 1;
Packit Service dd8e2b
		} else if ((buffer[0] == '*')) {
Packit Service dd8e2b
			/* New table */
Packit Service dd8e2b
			char *table;
Packit Service dd8e2b
Packit Service dd8e2b
			table = strtok(buffer + 1, " \t\n");
Packit Service dd8e2b
			DEBUGP("line %u, table '%s'\n", line, table);
Packit Service dd8e2b
			if (!table) {
Packit Service dd8e2b
				xtables_error(PARAMETER_PROBLEM,
Packit Service dd8e2b
					   "%s: line %u table name invalid\n",
Packit Service dd8e2b
					   prog_name, line);
Packit Service dd8e2b
				exit(1);
Packit Service dd8e2b
			}
Packit Service dd8e2b
			openTable(table);
Packit Service dd8e2b
Packit Service dd8e2b
			ret = 1;
Packit Service dd8e2b
		} else if ((buffer[0] == ':') && (curTable[0])) {
Packit Service dd8e2b
			/* New chain. */
Packit Service dd8e2b
			char *policy, *chain;
Packit Service dd8e2b
			struct xt_counters count;
Packit Service dd8e2b
			char *ctrs;
Packit Service dd8e2b
Packit Service dd8e2b
			chain = strtok(buffer + 1, " \t\n");
Packit Service dd8e2b
			DEBUGP("line %u, chain '%s'\n", line, chain);
Packit Service dd8e2b
			if (!chain) {
Packit Service dd8e2b
				xtables_error(PARAMETER_PROBLEM,
Packit Service dd8e2b
					   "%s: line %u chain name invalid\n",
Packit Service dd8e2b
					   prog_name, line);
Packit Service dd8e2b
				exit(1);
Packit Service dd8e2b
			}
Packit Service dd8e2b
Packit Service dd8e2b
			DEBUGP("Creating new chain '%s'\n", chain);
Packit Service dd8e2b
Packit Service dd8e2b
			policy = strtok(NULL, " \t\n");
Packit Service dd8e2b
			DEBUGP("line %u, policy '%s'\n", line, policy);
Packit Service dd8e2b
			if (!policy) {
Packit Service dd8e2b
				xtables_error(PARAMETER_PROBLEM,
Packit Service dd8e2b
					   "%s: line %u policy invalid\n",
Packit Service dd8e2b
					   prog_name, line);
Packit Service dd8e2b
				exit(1);
Packit Service dd8e2b
			}
Packit Service dd8e2b
Packit Service dd8e2b
			ctrs = strtok(NULL, " \t\n");
Packit Service dd8e2b
			parse_counters(ctrs, &count);
Packit Service dd8e2b
			saveChain(chain, policy, &count);
Packit Service dd8e2b
Packit Service dd8e2b
			ret = 1;
Packit Service dd8e2b
		} else if (curTable[0]) {
Packit Service dd8e2b
			unsigned int a;
Packit Service dd8e2b
			char *pcnt = NULL;
Packit Service dd8e2b
			char *bcnt = NULL;
Packit Service dd8e2b
			char *parsestart;
Packit Service dd8e2b
			char *chain = NULL;
Packit Service dd8e2b
Packit Service dd8e2b
			/* the parser */
Packit Service dd8e2b
			char *param_start, *curchar;
Packit Service dd8e2b
			int quote_open, quoted;
Packit Service dd8e2b
			char param_buffer[1024];
Packit Service dd8e2b
Packit Service dd8e2b
			if (buffer[0] == '[') {
Packit Service dd8e2b
				/* we have counters in our input */
Packit Service dd8e2b
				char *ptr = strchr(buffer, ']');
Packit Service dd8e2b
Packit Service dd8e2b
				if (!ptr)
Packit Service dd8e2b
					xtables_error(PARAMETER_PROBLEM,
Packit Service dd8e2b
						   "Bad line %u: need ]\n",
Packit Service dd8e2b
						   line);
Packit Service dd8e2b
Packit Service dd8e2b
				pcnt = strtok(buffer + 1, ":");
Packit Service dd8e2b
				if (!pcnt)
Packit Service dd8e2b
					xtables_error(PARAMETER_PROBLEM,
Packit Service dd8e2b
						   "Bad line %u: need :\n",
Packit Service dd8e2b
						   line);
Packit Service dd8e2b
Packit Service dd8e2b
				bcnt = strtok(NULL, "]");
Packit Service dd8e2b
				if (!bcnt)
Packit Service dd8e2b
					xtables_error(PARAMETER_PROBLEM,
Packit Service dd8e2b
						   "Bad line %u: need ]\n",
Packit Service dd8e2b
						   line);
Packit Service dd8e2b
Packit Service dd8e2b
				/* start command parsing after counter */
Packit Service dd8e2b
				parsestart = ptr + 1;
Packit Service dd8e2b
			} else {
Packit Service dd8e2b
				/* start command parsing at start of line */
Packit Service dd8e2b
				parsestart = buffer;
Packit Service dd8e2b
			}
Packit Service dd8e2b
Packit Service dd8e2b
Packit Service dd8e2b
			/* This is a 'real' parser crafted in artist mode
Packit Service dd8e2b
			 * not hacker mode. If the author can live with that
Packit Service dd8e2b
			 * then so can everyone else */
Packit Service dd8e2b
Packit Service dd8e2b
			quote_open = 0;
Packit Service dd8e2b
			/* We need to know which args were quoted so we 
Packit Service dd8e2b
			   can preserve quote */
Packit Service dd8e2b
			quoted = 0;
Packit Service dd8e2b
			param_start = parsestart;
Packit Service dd8e2b
Packit Service dd8e2b
			for (curchar = parsestart; *curchar; curchar++) {
Packit Service dd8e2b
				if (*curchar == '"') {
Packit Service dd8e2b
					/* quote_open cannot be true if there
Packit Service dd8e2b
					 * was no previous character.  Thus, 
Packit Service dd8e2b
					 * curchar-1 has to be within bounds */
Packit Service dd8e2b
					if (quote_open &&
Packit Service dd8e2b
					    *(curchar - 1) != '\\') {
Packit Service dd8e2b
						quote_open = 0;
Packit Service dd8e2b
						*curchar = ' ';
Packit Service dd8e2b
					} else {
Packit Service dd8e2b
						quote_open = 1;
Packit Service dd8e2b
						quoted = 1;
Packit Service dd8e2b
						param_start++;
Packit Service dd8e2b
					}
Packit Service dd8e2b
				}
Packit Service dd8e2b
				if (*curchar == ' '
Packit Service dd8e2b
				    || *curchar == '\t' || *curchar == '\n') {
Packit Service dd8e2b
					int param_len = curchar - param_start;
Packit Service dd8e2b
Packit Service dd8e2b
					if (quote_open)
Packit Service dd8e2b
						continue;
Packit Service dd8e2b
Packit Service dd8e2b
					if (!param_len) {
Packit Service dd8e2b
						/* two spaces? */
Packit Service dd8e2b
						param_start++;
Packit Service dd8e2b
						continue;
Packit Service dd8e2b
					}
Packit Service dd8e2b
Packit Service dd8e2b
					/* end of one parameter */
Packit Service dd8e2b
					strncpy(param_buffer, param_start,
Packit Service dd8e2b
						param_len);
Packit Service dd8e2b
					*(param_buffer + param_len) = '\0';
Packit Service dd8e2b
Packit Service dd8e2b
					/* check if table name specified */
Packit Service dd8e2b
					if ((param_buffer[0] == '-' &&
Packit Service dd8e2b
					     param_buffer[1] != '-' &&
Packit Service dd8e2b
					     strchr(param_buffer, 't')) ||
Packit Service dd8e2b
					    (!strncmp(param_buffer, "--t", 3) &&
Packit Service dd8e2b
					     !strncmp(param_buffer, "--table", strlen(param_buffer)))) {
Packit Service dd8e2b
						xtables_error(PARAMETER_PROBLEM,
Packit Service dd8e2b
							   "Line %u seems to have a "
Packit Service dd8e2b
							   "-t table option.\n",
Packit Service dd8e2b
							   line);
Packit Service dd8e2b
						exit(1);
Packit Service dd8e2b
					}
Packit Service dd8e2b
Packit Service dd8e2b
					add_argv(param_buffer, quoted);
Packit Service dd8e2b
					if (newargc >= 2
Packit Service dd8e2b
					    && 0 ==
Packit Service dd8e2b
					    strcmp(newargv[newargc - 2], "-A"))
Packit Service dd8e2b
						chain = newargv[newargc - 1];
Packit Service dd8e2b
					quoted = 0;
Packit Service dd8e2b
					param_start += param_len + 1;
Packit Service dd8e2b
				} else {
Packit Service dd8e2b
					/* regular character, skip */
Packit Service dd8e2b
				}
Packit Service dd8e2b
			}
Packit Service dd8e2b
Packit Service dd8e2b
			DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
Packit Service dd8e2b
			       newargc, curTable);
Packit Service dd8e2b
Packit Service dd8e2b
			for (a = 0; a < newargc; a++)
Packit Service dd8e2b
				DEBUGP("argv[%u]: %s\n", a, newargv[a]);
Packit Service dd8e2b
Packit Service dd8e2b
			if (!chain) {
Packit Service dd8e2b
				fprintf(stderr, "%s: line %u failed - no chain found\n",
Packit Service dd8e2b
					prog_name, line);
Packit Service dd8e2b
				exit(1);
Packit Service dd8e2b
			}
Packit Service dd8e2b
			needChain(chain);// Should we explicitly look for -A
Packit Service dd8e2b
			do_rule(pcnt, bcnt, newargc, newargv, newargvattr);
Packit Service dd8e2b
Packit Service dd8e2b
			save_argv();
Packit Service dd8e2b
			ret = 1;
Packit Service dd8e2b
		}
Packit Service dd8e2b
		if (!ret) {
Packit Service dd8e2b
			fprintf(stderr, "%s: line %u failed\n",
Packit Service dd8e2b
				prog_name, line);
Packit Service dd8e2b
			exit(1);
Packit Service dd8e2b
		}
Packit Service dd8e2b
	}
Packit Service dd8e2b
	if (curTable[0]) {
Packit Service dd8e2b
		fprintf(stderr, "%s: COMMIT expected at line %u\n",
Packit Service dd8e2b
			prog_name, line + 1);
Packit Service dd8e2b
		exit(1);
Packit Service dd8e2b
	}
Packit Service dd8e2b
Packit Service dd8e2b
	fclose(in);
Packit Service dd8e2b
	printf("</iptables-rules>\n");
Packit Service dd8e2b
	free_argv();
Packit Service dd8e2b
Packit Service dd8e2b
	return 0;
Packit Service dd8e2b
}