All of lore.kernel.org
 help / color / mirror / Atom feed
From: Amin Azez <azez@ufomechanic.net>
To: Netfilter Development Mailinglist <netfilter-devel@lists.netfilter.org>
Cc: Harald Welte <laforge@netfilter.org>, Patrick McHardy <kaber@trash.net>
Subject: new code; iptables-xml for iptables package.
Date: Thu, 09 Nov 2006 11:32:05 +0000	[thread overview]
Message-ID: <455311B5.5000600@ufomechanic.net> (raw)

[-- Attachment #1: Type: text/plain, Size: 2355 bytes --]

(I hope these can be added to the standard iptables package)

Here is iptables-xml based on iptables-restore (as it knows how to parse
iptables-save format), along with some xslt that converts back to
iptables-save format.

A typical null use would be:

  iptables-save -c | iptables-xml -c | xsltproc iptables.xslt -

iptables-xml does a mechanistic conversion to a very expressive xml
format; the only semantic considerations are for -g and -j targets in
order to discriminate between <call> <goto> and <nane-of-target> as it
helps xml processing scripts if they can tell the difference between a
target like SNAT and another chain.

The software is released under the GPL2 (naturally, being derived from
iptables-restore). I'm happy to "or later version" if/when iptables ever
does.

the -c argument means "combine"; it looks for sequential rules with
actions whose conditions are non-null and identical, and combines those
into a single xml rule with multiple actions. The test is rather basic
and thus suited to processing the ACTUAL output of iptables-save as this
does some (accidental) argument re-ordering making the test more likely
to succeed. This option is only to help people whose native format is
iptables-save move to xml; those who use xml as the native format will
not be bothered by this.

The accomanying xslt does a reverse translation back to iptables-save
format, and is released under the same license.

The xslt is not very strict; maybe if you give it bad xml it will
produce a bad output file. It's sole purpose is not to syntax or sanity
check the iptables rules, but to provide an alternative representation
of these rules.

It would be trivial to alter the multiple-actions code in the xslt to
generate sub-chains instead of repeating the conditions; I intend to do
this soon, but current behaviour is required by my current projects in
the short term.

A sample of the xml format
<iptables-rules>
  <table name="mangle" >
    <chain name="PREROUTING" policy="ACCEPT" packet-count="63436"
byte-count="7137573" >
      <rule >
       <conditions>
        <match >
          <p >tcp</p>
        </match>
        <tcp >
          <sport >8443</sport>
        </tcp>
       </conditions>
       <actions>
        <call >
          <check_ip />
        </call>
       </actions>
      </rule>
    </chain>
</iptables-rules>

Sam

[-- Attachment #2: iptables-xml.c --]
[-- Type: text/x-csrc, Size: 19487 bytes --]

/* Code to convert iptables-save format to xml format,
 * (C) 2006 Ufo Mechanic <azez@ufomechanic.net>
 * based on iptables-restore (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
 * based on previous code from Rusty Russell <rusty@linuxcare.com.au>
 *
 * This code is distributed under the terms of GNU GPL v2
 *
 * $Id: iptables-xml.c,v 1.4 2006/11/09 12:02:17 azez Exp $
 */

#include <getopt.h>
#include <sys/errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "iptables.h"
#include "libiptc/libiptc.h"

#ifdef DEBUG
#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
#else
#define DEBUGP(x, args...) 
#endif

/* no need to link with iptables.o */
const char* program_name;
const char* program_version;
int line=0;

void exit_error(enum exittype status, char *msg, ...)
{
        va_list args;

        va_start(args, msg);
        fprintf(stderr, "%s v%s: ", program_name, program_version);
        vfprintf(stderr, msg, args);
        va_end(args);
        fprintf(stderr, "\n");
        /* On error paths, make sure that we don't leak memory */
        exit(status);
}

static void print_usage(const char *name, const char *version) __attribute__((noreturn));

static int verbose = 0;
/* Whether to combine actions of sequential rules with identical conditions */
static int combine = 0;
/* Keeping track of external matches and targets.  */
static struct option options[] = {
	{ "verbose", 0, 0, 'v' },
	{ "combine", 0, 0, 'c' },
	{ "help", 0, 0, 'h' },
	{ 0 }
};

static void print_usage(const char *name, const char *version)
{
	fprintf(stderr, "Usage: %s [-c] [-v] [-h]\n"
                        "          [--combine ]\n"
			"	   [ --verbose ]\n"
			"	   [ --help ]\n",
			name);
		
	exit(1);
}

int parse_counters(char *string, struct ipt_counters *ctr)
{
	if (string != NULL)
		return (sscanf(string, "[%llu:%llu]", (unsigned long long *)&ctr->pcnt, (unsigned long long *)&ctr->bcnt) == 2);
	else
		return (0 == 2);
}

/* global new argv and argc */
static char *newargv[255];
static int newargc=0;

static char *oldargv[255];
static int oldargc=0;

/* arg meta data, were they quoted, frinstance */
static int newargvattr[255];
static int oldargvattr[255];

#define IPT_CHAIN_MAXNAMELEN IPT_TABLE_MAXNAMELEN
char closeActionTag[IPT_TABLE_MAXNAMELEN+1];
char closeRuleTag[IPT_TABLE_MAXNAMELEN+1];
char curTable[IPT_TABLE_MAXNAMELEN+1];
char curChain[IPT_CHAIN_MAXNAMELEN+1];

typedef struct chain {
	char *chain;
	char *policy;
	struct ipt_counters count;
	int created;
} chain;

#define maxChains 10240 /* max chains per table */
static chain chains[maxChains];
static int nextChain=0;

/* funCtion adding one argument to newargv, updating newargc 
 * returns true if argument added, false otherwise */
static int add_argv(char *what,int quoted) {
	DEBUGP("add_argv: %d %s\n", newargc, what);
	if (what && ((newargc + 1) < sizeof(newargv)/sizeof(char *))) {
		newargv[newargc] = strdup(what);
		newargvattr[newargc]=quoted;
		newargc++;
		return 1;
	} else 
		return 0;
}

static void free_argv(void) {
	int i;

	for (i = 0; i < newargc; i++) {
		free(newargv[i]);
		newargv[i]=NULL;
	}
	newargc=0;

	for (i = 0; i < oldargc; i++) {
		free(oldargv[i]);
		oldargv[i]=NULL;
	}
	oldargc=0;
}

/* save parsed rule for comparison with next rule 
   to perform action agregation on duplicate conditions */
static void save_argv(void) {
	int i;

	for (i = 0; i < oldargc; i++)
		free(oldargv[i]);
	oldargc=newargc;
	newargc=0;
	for (i = 0; i < oldargc; i++) {
		oldargv[i]=newargv[i];
		newargv[i]=NULL;
	}
}

/* like puts but with xml encoding */
static void xmlEncode(char* text) {
	while(text && *text) {
		if ((unsigned char)(*text)>127) printf("&#%d;",(unsigned char)(*text));
		else if (*text=='&') printf("&amp;");
		else if (*text=='<') printf("&lt;");
		else if (*text=='>') printf("&gt;");
		else if (*text=='"') printf("&quot;");
		else putchar(*text);
		*text++;
	}
}

/* Output text as a comment, avoiding a double hyphen */
static void xmlCommentEscape(char* comment) {
  int h_count=0;

  while(comment && *comment) {
    if (*comment=='-') {
      h_count++;
      if (h_count>=2) {
        h_count=0;
        putchar(' ');
      }
      putchar('*');
    }
    /* strip trailing newline */
    if (*comment=='\n' && *(comment+1)==0);
    else putchar(*comment);
    comment++;
  }
}

static void xmlComment(char *comment) {
  printf("<!-- ");
  xmlCommentEscape(comment);
  printf(" -->\n");
}

static void xmlAttrS(char* name, char* value) {
  printf("%s=\"",name);
  xmlEncode(value);
  printf("\" ");
}

static void xmlAttrI(char* name, long long int num) {
  printf("%s=\"%lld\" ",name,num);
}

static void closeChain() {
	if (curChain[0]==0) return;

	if (closeActionTag[0]) printf("%s\n",closeActionTag);
	closeActionTag[0]=0;
	if (closeRuleTag[0]) printf("%s\n",closeRuleTag);
	closeRuleTag[0]=0;
	if (curChain[0]) printf("    </chain>\n");
	curChain[0]=0;
	//lastRule[0]=0;
}

static void openChain(char* chain, char* policy, struct ipt_counters *ctr, char close) {
	closeChain();
	
	strncpy(curChain, chain, IPT_CHAIN_MAXNAMELEN);
	curChain[IPT_CHAIN_MAXNAMELEN] = '\0';

	printf("    <chain ");
	xmlAttrS("name",curChain);
	if (strcmp(policy,"-")!=0) xmlAttrS("policy",policy);
	xmlAttrI("packet-count",(unsigned long long)ctr->pcnt);
	xmlAttrI("byte-count",(unsigned long long)ctr->bcnt);
	if (close) {
		printf("%c",close);
		curChain[0]=0;
	}
	printf(">\n");
}

static int existsChain(char *chain) {
	/* open a saved chain */
	int c=0;

	if (0==strcmp(curChain,chain)) return 1;
	for(c=0;c<nextChain;c++) if (chains[c].chain && strcmp(chains[c].chain,chain)==0) return 1;
	return 0;
}

static void needChain(char *chain) {
	/* open a saved chain */
	int c=0;

	if (0==strcmp(curChain,chain)) return;
	
	for(c=0;c<nextChain;c++) if (chains[c].chain && strcmp(chains[c].chain,chain)==0) {
		openChain(chains[c].chain, chains[c].policy, &(chains[c].count),'\0');
		// And, mark it as done so we don't create an empty chain at table-end time
		chains[c].created=1;
	}
}

static void saveChain(char* chain, char* policy, struct ipt_counters *ctr) {
	if (nextChain>=maxChains) {
		exit_error(PARAMETER_PROBLEM,
			"%s: line %u chain name invalid\n",
			program_name, line);
		exit(1);
	};
	chains[nextChain].chain=strdup(chain);
	chains[nextChain].policy=strdup(policy);
	chains[nextChain].count=*ctr;
	chains[nextChain].created=0;
	nextChain++;
}

static void finishChains() {
	int c;

	for(c=0;c<nextChain;c++) if (! chains[c].created) {
		openChain(chains[c].chain, chains[c].policy, &(chains[c].count),'/');
		free(chains[c].chain);
		free(chains[c].policy);
	}
	nextChain=0;
}

static void closeTable() {
	closeChain();
	finishChains();
	if (curTable[0]) printf("  </table>\n");
	curTable[0]=0;
}

static void openTable(char* table) {
	closeTable();

	strncpy(curTable, table, IPT_TABLE_MAXNAMELEN);
	curTable[IPT_TABLE_MAXNAMELEN] = '\0';

	printf("  <table ");
	xmlAttrS("name",curTable);
	printf(">\n");
}

// is char* -j --jump -g or --goto
static int isTarget(char* arg) {
  return ((arg) && ( strcmp((arg),"-j")==0 || strcmp((arg),"--jump")==0 || strcmp((arg),"-g")==0 || strcmp((arg),"--goto")==0));
}

// part=-1 means do conditions, part=1 means do rules, part=0 means do both
static void do_rule_part(char* leveltag1,char *leveltag2,int part, int argc, char* argv[], int argvattr[]) {
	int arg=1; // ignore leading -A
	char invert_next=0;
	char* thisChain=NULL;
	char* spacer=""; // space when needed to assemble arguments
	char* level1=NULL;
	char* level2=NULL;
	char* leveli1="        ";
	char* leveli2="          ";

#define CLOSE_LEVEL(LEVEL) \
	do { \
		if (level ## LEVEL) printf("</%s>\n", (leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \
		level ## LEVEL=NULL;\
	} while(0)

#define OPEN_LEVEL(LEVEL,TAG) \
	do {\
		level ## LEVEL=TAG;\
		if (leveltag ## LEVEL) {\
			printf("%s<%s ", (leveli ## LEVEL), (leveltag ## LEVEL));\
			xmlAttrS("type", (TAG)); \
		} else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \
	} while(0)

	thisChain=argv[arg++];

	if (part==1) { /* skip */
		/* use argvattr to tell which arguments were quoted 
                   to avoid comparing quoted arguments, like comments, to -j,*/
		while(arg<argc && (argvattr[arg] || !isTarget(argv[arg])) ) arg++;
	}
	
	/* Before we start, if the first arg is -[^-] and not -m or -j or -g then start a dummy <match> tag 
	 * for old style built-in matches.  We would do this in any case, but no need if it would be empty */
	if (arg<argc && argv[arg][0]=='-' && ! isTarget(argv[arg]) && strcmp(argv[arg],"-m")!=0) {
		OPEN_LEVEL(1,"match");
		printf(">\n");
	}
	while(arg<argc) {
		// If ! is followed by -* then apply to that, else output as data
                // Stop, if we need to
		if (part==-1 && ! argvattr[arg] && (isTarget(argv[arg]))) {
			break;
		} else if (! argvattr[arg] && strcmp(argv[arg],"!")==0) { 
			if ((arg+1)<argc && argv[arg+1][0]=='-') invert_next='!';
			else printf("%s%s",spacer,argv[arg]);
			spacer=" ";
		} else if (! argvattr[arg] && isTarget(argv[arg]) && existsChain(argv[arg+1]) && (2+arg>=argc)) {
			if (! ((1+arg)<argc)) break; // no args to -j, -m or -g, just ignore it and finish loop
			CLOSE_LEVEL(2);
			if (level1) printf("%s",leveli1);
			CLOSE_LEVEL(1);
			spacer="";
			invert_next=0;
			if (strcmp(argv[arg],"-g")==0 || strcmp(argv[arg],"--goto")==0) {
				/* goto user chain */
				OPEN_LEVEL(1,"goto");
				printf(">\n");
				arg++;
				OPEN_LEVEL(2,argv[arg]);
				printf("/>\n");
				level2=NULL;
			} else {
				/* call user chain */
				OPEN_LEVEL(1,"call");
				printf(">\n");
				arg++;
				OPEN_LEVEL(2,argv[arg]);
				printf("/>\n");
				level2=NULL;
			}
 		} else if (! argvattr[arg] && (isTarget(argv[arg]) || strcmp(argv[arg],"-m")==0 || strcmp(argv[arg],"--module")==0)) {
			if (! ((1+arg)<argc)) break; // no args to -j, -m or -g, just ignore it and finish loop
			CLOSE_LEVEL(2);
			if (level1) printf("%s",leveli1);
			CLOSE_LEVEL(1);
			spacer="";
			invert_next=0;
			arg++;
			OPEN_LEVEL(1,(argv[arg]));
			// Optimize case, can we close this tag already?
			if ( (arg+1)>=argc || (! argvattr[arg+1] && ( isTarget(argv[arg+1]) || strcmp(argv[arg+1],"-m")==0 || strcmp(argv[arg+1],"--module")==0 ) ) ) {
				printf(" />\n");
				level1=NULL;
			} else {
				printf(">\n");
			}
		} else if (! argvattr[arg] && argv[arg][0]=='-') {
			char* tag;
			CLOSE_LEVEL(2);
			// Skip past any -
			tag=argv[arg];
			while(*tag=='-' && *tag) tag++;

			spacer="";
			OPEN_LEVEL(2,tag);
			if (invert_next) printf(" invert=\"1\"");
			invert_next=0;

			// Optimize case, can we close this tag already?
			if (! ((arg+1)<argc) || (argv[arg+1][0]=='-' /* NOT QUOTED */)) {
				printf(" />\n");
				level2=NULL;
			} else {
				printf(">");
			}
		} else { // regular data
			char* spaces=strchr(argv[arg],' ');
			printf("%s",spacer);
			if (spaces || argvattr[arg]) printf("&quot;");
			// if argv[arg] contains a space, enclose in quotes
			xmlEncode(argv[arg]);
			if (spaces || argvattr[arg]) printf("&quot;");
			spacer=" ";
		}
		arg++;
	}
	CLOSE_LEVEL(2);
	if (level1) printf("%s",leveli1);
	CLOSE_LEVEL(1);

	return;
}

static int compareRules() {
  /* compare arguments up to -j or -g for match.
     NOTE: We don't want to combine actions if there were no criteria in each rule,
           or rules didn't have an action 
     NOTE: Depends on arguments being in some kind of "normal" order which is 
           the case when processing the ACTUAL output of actual iptables-save 
           rather than a file merely in a compatable format */

  int old=0;
  int new=0;

  int compare=0;

  while (new<newargc && old<oldargc) {
    if (isTarget(oldargv[old]) && isTarget(newargv[new])) { 
      compare=1;
      break;
    }
    // break when old!=new
    if (strcmp(oldargv[old],newargv[new])!=0) {
      compare=0;
      break;
    }

    old++;
    new++;
  }
  // We won't match unless both rules had a target. 
  // This means we don't combine target-less rules, which is good

  /* If we don't insist that they both have -j, then if compare may be still -1 if one of them ran out of space cos had no -j
     This is OK, if the other is at -j, e.g. */
  //NOTE:NOTE:These two lines were commented out so I did NOT add the -g code to match the -j code
  //if (compare==-1 && ( (old<oldargc && oldargv[old]=="-j") || (new<newargc && newargv[new]=="-j") ) ) compare=1;
  //else if (compare==-1) compare=0;

  return compare==1;
}

/* has a nice parsed rule starting with -A */
static void do_rule(char* pcnt, char* bcnt, int argc, char *argv[], int argvattr[]) {
	/* are these conditions the same as the previous rule?
 	 * If so, skip arg straight to -j or -g */
	if (combine && argc>2 && ! isTarget(argv[2]) && compareRules()) {
		xmlComment("Combine action from next rule");
	} else {

		if (closeActionTag[0]) {
			printf("%s\n",closeActionTag);
			closeActionTag[0]=0;
		}
		if (closeRuleTag[0]) {
			printf("%s\n",closeRuleTag);
			closeRuleTag[0]=0;
		}

		printf("      <rule ");
		//xmlAttrS("table",curTable); // not needed in full mode 
		//xmlAttrS("chain",argv[1]); // not needed in full mode 
		if (pcnt) xmlAttrS("packet-count",pcnt);
		if (bcnt) xmlAttrS("byte-count",bcnt);
		printf(">\n");

		strncpy(closeRuleTag, "      </rule>\n", IPT_TABLE_MAXNAMELEN);
		closeRuleTag[IPT_TABLE_MAXNAMELEN] = '\0';

		/* no point in writing out condition if we can see there isn't one */
		if (argc>=3 && !isTarget(argv[2]) ) {
			printf("       <conditions>\n");
			do_rule_part(NULL,NULL,-1,argc,argv,argvattr);
			printf("       </conditions>\n");
		}
	}
	/* Write out the action */
	//do_rule_part("action","arg",1,argc,argv,argvattr);
	if (! closeActionTag[0]) {
	  printf("       <actions>\n");
	  strncpy(closeActionTag, "       </actions>\n", IPT_TABLE_MAXNAMELEN);
	  closeActionTag[IPT_TABLE_MAXNAMELEN] = '\0';
	}
	do_rule_part(NULL,NULL,1,argc,argv,argvattr);
}


#ifdef IPTABLES_MULTI
int
iptables_restore_main(int argc, char *argv[])
#else
int
main(int argc, char *argv[])
#endif
{
	char buffer[10240];
	int c;
	FILE *in;

	program_name = "iptables-xml";
	program_version = IPTABLES_VERSION;
	line = 0;

	while ((c = getopt_long(argc, argv, "bcvthnM:", options, NULL)) != -1) {
		switch (c) {
			case 'c':
				combine = 1;
				break;
			case 'v':
				printf("xptables-xml\n");
				verbose = 1;
				break;
			case 'h':
				print_usage("iptables-xml",
					    IPTABLES_VERSION);
				break;
		}
	}
	
	if (optind == argc - 1) {
		in = fopen(argv[optind], "r");
		if (!in) {
			fprintf(stderr, "Can't open %s: %s", argv[optind],
				strerror(errno));
			exit(1);
		}
	}
	else if (optind < argc) {
		fprintf(stderr, "Unknown arguments found on commandline");
		exit(1);
	}
	else in = stdin;

	printf("<iptables-rules version=\"1.0\">\n");

	/* Grab standard input. */
	while (fgets(buffer, sizeof(buffer), in)) {
		int ret = 0;

		line++;

		if (buffer[0] == '\n')
			continue;
		else if (buffer[0] == '#') {
			xmlComment(buffer);
			continue;
		}

		if (verbose) {	
			printf("<!-- line %d ",line);
			xmlCommentEscape(buffer);
			printf(" -->\n");
		}

		if ((strcmp(buffer, "COMMIT\n") == 0) && (curTable[0])) {
			DEBUGP("Calling commit\n");
			closeTable();
			ret=1;
		} else if ((buffer[0] == '*')) {
			/* New table */
			char *table;

			table = strtok(buffer+1, " \t\n");
			DEBUGP("line %u, table '%s'\n", line, table);
			if (!table) {
				exit_error(PARAMETER_PROBLEM, 
					"%s: line %u table name invalid\n",
					program_name, line);
				exit(1);
			}
			openTable(table);

			ret=1;
		} else if ((buffer[0] == ':') && (curTable[0])) {
			/* New chain. */
			char *policy, *chain;

			chain = strtok(buffer+1, " \t\n");
			DEBUGP("line %u, chain '%s'\n", line, chain);
			if (!chain) {
				exit_error(PARAMETER_PROBLEM,
					   "%s: line %u chain name invalid\n",
					   program_name, line);
				exit(1);
			}

			DEBUGP("Creating new chain '%s'\n", chain);

			policy = strtok(NULL, " \t\n");
			DEBUGP("line %u, policy '%s'\n", line, policy);
			if (!policy) {
				exit_error(PARAMETER_PROBLEM,
					   "%s: line %u policy invalid\n",
					   program_name, line);
				exit(1);
			}

			struct ipt_counters count;

			char *ctrs;
			ctrs = strtok(NULL, " \t\n");

			parse_counters(ctrs, &count);
			
			saveChain(chain, policy, &count);

			ret=1;
		} else if (curTable[0]) {
			int a;
			char *ptr = buffer;
			char *pcnt = NULL;
			char *bcnt = NULL;
			char *parsestart;
			char *chain = NULL;

			/* the parser */
			char *param_start, *curchar;
			int quote_open, quoted;

			/* reset the newargv */
			newargc = 0;

			if (buffer[0] == '[') {
				/* we have counters in our input */
				ptr = strchr(buffer, ']');
				if (!ptr)
					exit_error(PARAMETER_PROBLEM,
						   "Bad line %u: need ]\n",
						   line);

				pcnt = strtok(buffer+1, ":");
				if (!pcnt)
					exit_error(PARAMETER_PROBLEM,
						   "Bad line %u: need :\n",
						   line);

				bcnt = strtok(NULL, "]");
				if (!bcnt)
					exit_error(PARAMETER_PROBLEM,
						   "Bad line %u: need ]\n",
						   line);

				/* start command parsing after counter */
				parsestart = ptr + 1;
			} else {
				/* start command parsing at start of line */
				parsestart = buffer;
			}


			/* This is a 'real' parser crafted in artist mode
			 * not hacker mode. If the author can live with that
			 * then so can everyone else */

			quote_open = 0;
			/* We need to know which args were quoted so we can preserve quote */
			quoted = 0; 
			param_start = parsestart;
			
			for (curchar = parsestart; *curchar; curchar++) {
				if (*curchar == '"') {
					/* quote_open cannot be true if there
					 * was no previous character.  Thus, 
					 * curchar-1 has to be within bounds */
					if (quote_open && 
					    *(curchar-1) != '\\') {
						quote_open = 0;
						*curchar = ' ';
					} else {
						quote_open = 1;
						quoted = 1;
						param_start++;
					}
				} 
				if (*curchar == ' '
				    || *curchar == '\t'
				    || * curchar == '\n') {
					char param_buffer[1024];
					int param_len = curchar-param_start;

					if (quote_open)
						continue;

					if (!param_len) {
						/* two spaces? */
						param_start++;
						continue;
					}
					
					/* end of one parameter */
					strncpy(param_buffer, param_start,
						param_len);
					*(param_buffer+param_len) = '\0';

					/* check if table name specified */
					if (!strncmp(param_buffer, "-t", 3)
                                            || !strncmp(param_buffer, "--table", 8)) {
						exit_error(PARAMETER_PROBLEM, 
						   "Line %u seems to have a "
						   "-t table option.\n", line);
						exit(1);
					}

					add_argv(param_buffer,quoted);
					if (newargc>=2 && 0==strcmp(newargv[newargc-2],"-A")) chain=newargv[newargc-1];
					quoted = 0;
					param_start += param_len + 1;
				} else {
					/* regular character, skip */
				}
			}

			DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
				newargc, curTable);

			for (a = 0; a < newargc; a++)
				DEBUGP("argv[%u]: %s\n", a, newargv[a]);

			needChain(chain); // Should we explicitly look for -A
			do_rule(pcnt, bcnt, newargc, newargv, newargvattr);

			save_argv();
			ret=1;
		}
		if (!ret) {
			fprintf(stderr, "%s: line %u failed\n",
					program_name, line);
			exit(1);
		}
	}
	if (curTable[0]) {
		fprintf(stderr, "%s: COMMIT expected at line %u\n",
				program_name, line + 1);
		exit(1);
	}

	printf("</iptables-rules>\n");
	free_argv();

	return 0;
}

[-- Attachment #3: iptables.xslt --]
[-- Type: application/xslt+xml, Size: 5938 bytes --]

             reply	other threads:[~2006-11-09 11:32 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-11-09 11:32 Amin Azez [this message]
2006-11-09 18:34 ` new code; iptables-xml for iptables package Patrick McHardy
2006-11-10 10:43   ` Amin Azez
2006-11-10 13:07     ` Patrick McHardy
2006-11-10 13:28       ` Amin Azez
2006-11-10 13:51         ` Patrick McHardy
2006-11-10 14:29           ` Amin Azez
2006-11-10 14:42             ` Patrick McHardy
2006-11-10 14:59               ` Amin Azez
2006-11-10 15:11                 ` Patrick McHardy
2006-11-10 15:57                   ` Amin Azez
2006-11-13 19:43                     ` Patrick McHardy
2006-11-10 14:43 ` Pablo Neira Ayuso
2006-11-10 15:13   ` Amin Azez
2006-11-22 17:37 ` Glen Turner
2006-11-23 12:55   ` Amin Azez

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=455311B5.5000600@ufomechanic.net \
    --to=azez@ufomechanic.net \
    --cc=kaber@trash.net \
    --cc=laforge@netfilter.org \
    --cc=netfilter-devel@lists.netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.