Blame iptables/iptables-xml.c

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