* new code; iptables-xml for iptables package.
@ 2006-11-09 11:32 Amin Azez
2006-11-09 18:34 ` Patrick McHardy
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: Amin Azez @ 2006-11-09 11:32 UTC (permalink / raw)
To: Netfilter Development Mailinglist; +Cc: Harald Welte, Patrick McHardy
[-- 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("&");
else if (*text=='<') printf("<");
else if (*text=='>') printf(">");
else if (*text=='"') printf(""");
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(""");
// if argv[arg] contains a space, enclose in quotes
xmlEncode(argv[arg]);
if (spaces || argvattr[arg]) printf(""");
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 --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-09 11:32 new code; iptables-xml for iptables package Amin Azez
@ 2006-11-09 18:34 ` Patrick McHardy
2006-11-10 10:43 ` Amin Azez
2006-11-10 14:43 ` Pablo Neira Ayuso
2006-11-22 17:37 ` Glen Turner
2 siblings, 1 reply; 16+ messages in thread
From: Patrick McHardy @ 2006-11-09 18:34 UTC (permalink / raw)
To: Amin Azez; +Cc: Harald Welte, Netfilter Development Mailinglist
Amin Azez wrote:
> (I hope these can be added to the standard iptables package)
We can do that, but the code needs some serious coding style
cleanup before that. Please look at Documentation/CodingStyle
from the kernel source, it pretty much applies to iptables as
well.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-09 18:34 ` Patrick McHardy
@ 2006-11-10 10:43 ` Amin Azez
2006-11-10 13:07 ` Patrick McHardy
0 siblings, 1 reply; 16+ messages in thread
From: Amin Azez @ 2006-11-10 10:43 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Harald Welte, Netfilter Development Mailinglist
[-- Attachment #1: Type: text/plain, Size: 402 bytes --]
* Patrick McHardy wrote, On 09/11/06 18:34:
> Amin Azez wrote:
>
>> (I hope these can be added to the standard iptables package)
>>
>
> We can do that, but the code needs some serious coding style
> cleanup before that. Please look at Documentation/CodingStyle
> from the kernel source, it pretty much applies to iptables as
> well.
>
Thanks for the tip.
Does this meet with approval?
Sam
[-- Attachment #2: iptables-xml.c --]
[-- Type: text/x-csrc, Size: 19666 bytes --]
/* Code to convert iptables-save format to xml format,
* (C) 2006 Ufo Mechanic <azez@ufomechanic.net>
* based on iptables-restor (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 ("&");
else if (*text == '<')
printf ("<");
else if (*text == '>')
printf (">");
else if (*text == '"')
printf (""");
else
putchar (*text);
*text++;
}
}
/* Output text as a comment, avoiding a double hyphen */
static void
xmlCommentEscape (char *comment)
{
int h_count = 0;
while (comment && *comment) {
if (*comment == '-') {
h_count++;
if (h_count >= 2) {
h_count = 0;
putchar (' ');
}
putchar ('*');
}
/* strip trailing newline */
if (*comment == '\n' && *(comment + 1) == 0);
else
putchar (*comment);
comment++;
}
}
static void
xmlComment (char *comment)
{
printf ("<!-- ");
xmlCommentEscape (comment);
printf (" -->\n");
}
static void
xmlAttrS (char *name, char *value)
{
printf ("%s=\"", name);
xmlEncode (value);
printf ("\" ");
}
static void
xmlAttrI (char *name, long long int num)
{
printf ("%s=\"%lld\" ", name, num);
}
static void
closeChain ()
{
if (curChain[0] == 0)
return;
if (closeActionTag[0])
printf ("%s\n", closeActionTag);
closeActionTag[0] = 0;
if (closeRuleTag[0])
printf ("%s\n", closeRuleTag);
closeRuleTag[0] = 0;
if (curChain[0])
printf (" </chain>\n");
curChain[0] = 0;
//lastRule[0]=0;
}
static void
openChain (char *chain, char *policy, struct ipt_counters *ctr, char close)
{
closeChain ();
strncpy (curChain, chain, IPT_CHAIN_MAXNAMELEN);
curChain[IPT_CHAIN_MAXNAMELEN] = '\0';
printf (" <chain ");
xmlAttrS ("name", curChain);
if (strcmp (policy, "-") != 0)
xmlAttrS ("policy", policy);
xmlAttrI ("packet-count", (unsigned long long) ctr->pcnt);
xmlAttrI ("byte-count", (unsigned long long) ctr->bcnt);
if (close) {
printf ("%c", close);
curChain[0] = 0;
}
printf (">\n");
}
static int
existsChain (char *chain)
{
/* open a saved chain */
int c = 0;
if (0 == strcmp (curChain, chain))
return 1;
for (c = 0; c < nextChain; c++)
if (chains[c].chain && strcmp (chains[c].chain, chain) == 0)
return 1;
return 0;
}
static void
needChain (char *chain)
{
/* open a saved chain */
int c = 0;
if (0 == strcmp (curChain, chain))
return;
for (c = 0; c < nextChain; c++)
if (chains[c].chain && strcmp (chains[c].chain, chain) == 0) {
openChain (chains[c].chain, chains[c].policy,
&(chains[c].count), '\0');
/* And, mark it as done so we don't create
an empty chain at table-end time */
chains[c].created = 1;
}
}
static void
saveChain (char *chain, char *policy, struct ipt_counters *ctr)
{
if (nextChain >= maxChains) {
exit_error (PARAMETER_PROBLEM,
"%s: line %u chain name invalid\n",
program_name, line);
exit (1);
};
chains[nextChain].chain = strdup (chain);
chains[nextChain].policy = strdup (policy);
chains[nextChain].count = *ctr;
chains[nextChain].created = 0;
nextChain++;
}
static void
finishChains ()
{
int c;
for (c = 0; c < nextChain; c++)
if (!chains[c].created) {
openChain (chains[c].chain, chains[c].policy,
&(chains[c].count), '/');
free (chains[c].chain);
free (chains[c].policy);
}
nextChain = 0;
}
static void
closeTable ()
{
closeChain ();
finishChains ();
if (curTable[0])
printf (" </table>\n");
curTable[0] = 0;
}
static void
openTable (char *table)
{
closeTable ();
strncpy (curTable, table, IPT_TABLE_MAXNAMELEN);
curTable[IPT_TABLE_MAXNAMELEN] = '\0';
printf (" <table ");
xmlAttrS ("name", curTable);
printf (">\n");
}
// is char* -j --jump -g or --goto
static int
isTarget (char *arg)
{
return ((arg)
&& (strcmp ((arg), "-j") == 0 || strcmp ((arg), "--jump") == 0
|| strcmp ((arg), "-g") == 0
|| strcmp ((arg), "--goto") == 0));
}
// part=-1 means do conditions, part=1 means do rules, part=0 means do both
static void
do_rule_part (char *leveltag1, char *leveltag2, int part, int argc,
char *argv[], int argvattr[])
{
int arg = 1; // ignore leading -A
char invert_next = 0;
char *thisChain = NULL;
char *spacer = ""; // space when needed to assemble arguments
char *level1 = NULL;
char *level2 = NULL;
char *leveli1 = " ";
char *leveli2 = " ";
#define CLOSE_LEVEL(LEVEL) \
do { \
if (level ## LEVEL) printf("</%s>\n", \
(leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \
level ## LEVEL=NULL;\
} while(0)
#define OPEN_LEVEL(LEVEL,TAG) \
do {\
level ## LEVEL=TAG;\
if (leveltag ## LEVEL) {\
printf("%s<%s ", (leveli ## LEVEL), \
(leveltag ## LEVEL));\
xmlAttrS("type", (TAG)); \
} else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \
} while(0)
thisChain = argv[arg++];
if (part == 1) { /* skip */
/* use argvattr to tell which arguments were quoted
to avoid comparing quoted arguments, like comments, to -j, */
while (arg < argc && (argvattr[arg] || !isTarget (argv[arg])))
arg++;
}
/* Before we start, if the first arg is -[^-] and not -m or -j or -g
then start a dummy <match> tag for old style built-in matches.
We would do this in any case, but no need if it would be empty */
if (arg < argc && argv[arg][0] == '-' && !isTarget (argv[arg])
&& strcmp (argv[arg], "-m") != 0) {
OPEN_LEVEL (1, "match");
printf (">\n");
}
while (arg < argc) {
// If ! is followed by -* then apply to that else output as data
// Stop, if we need to
if (part == -1 && !argvattr[arg] && (isTarget (argv[arg]))) {
break;
} else if (!argvattr[arg] && strcmp (argv[arg], "!") == 0) {
if ((arg + 1) < argc && argv[arg + 1][0] == '-')
invert_next = '!';
else
printf ("%s%s", spacer, argv[arg]);
spacer = " ";
} else if (!argvattr[arg] && isTarget (argv[arg])
&& existsChain (argv[arg + 1])
&& (2 + arg >= argc)) {
if (!((1 + arg) < argc))
// no args to -j, -m or -g, ignore & finish loop
break;
CLOSE_LEVEL (2);
if (level1)
printf ("%s", leveli1);
CLOSE_LEVEL (1);
spacer = "";
invert_next = 0;
if (strcmp (argv[arg], "-g") == 0
|| strcmp (argv[arg], "--goto") == 0) {
/* goto user chain */
OPEN_LEVEL (1, "goto");
printf (">\n");
arg++;
OPEN_LEVEL (2, argv[arg]);
printf ("/>\n");
level2 = NULL;
} else {
/* call user chain */
OPEN_LEVEL (1, "call");
printf (">\n");
arg++;
OPEN_LEVEL (2, argv[arg]);
printf ("/>\n");
level2 = NULL;
}
} else if (!argvattr[arg]
&& (isTarget (argv[arg])
|| strcmp (argv[arg], "-m") == 0
|| strcmp (argv[arg], "--module") == 0)) {
if (!((1 + arg) < argc))
// no args to -j, -m or -g, ignore & finish loop
break;
CLOSE_LEVEL (2);
if (level1)
printf ("%s", leveli1);
CLOSE_LEVEL (1);
spacer = "";
invert_next = 0;
arg++;
OPEN_LEVEL (1, (argv[arg]));
// Optimize case, can we close this tag already?
if ((arg + 1) >= argc
|| (!argvattr[arg + 1]
&& (isTarget (argv[arg + 1])
|| strcmp (argv[arg + 1], "-m") == 0
|| strcmp (argv[arg + 1],
"--module") == 0))) {
printf (" />\n");
level1 = NULL;
} else {
printf (">\n");
}
} else if (!argvattr[arg] && argv[arg][0] == '-') {
char *tag;
CLOSE_LEVEL (2);
// Skip past any -
tag = argv[arg];
while (*tag == '-' && *tag)
tag++;
spacer = "";
OPEN_LEVEL (2, tag);
if (invert_next)
printf (" invert=\"1\"");
invert_next = 0;
// Optimize case, can we close this tag already?
if (!((arg + 1) < argc)
|| (argv[arg + 1][0] == '-' /* NOT QUOTED */ )) {
printf (" />\n");
level2 = NULL;
} else {
printf (">");
}
} else { // regular data
char *spaces = strchr (argv[arg], ' ');
printf ("%s", spacer);
if (spaces || argvattr[arg])
printf (""");
// if argv[arg] contains a space, enclose in quotes
xmlEncode (argv[arg]);
if (spaces || argvattr[arg])
printf (""");
spacer = " ";
}
arg++;
}
CLOSE_LEVEL (2);
if (level1)
printf ("%s", leveli1);
CLOSE_LEVEL (1);
return;
}
static int
compareRules ()
{
/* compare arguments up to -j or -g for match.
NOTE: We don't want to combine actions if there were no criteria
in each rule, or rules didn't have an action
NOTE: Depends on arguments being in some kind of "normal" order which
is the case when processing the ACTUAL output of actual iptables-save
rather than a file merely in a compatable format */
int old = 0;
int new = 0;
int compare = 0;
while (new < newargc && old < oldargc) {
if (isTarget (oldargv[old]) && isTarget (newargv[new])) {
compare = 1;
break;
}
// break when old!=new
if (strcmp (oldargv[old], newargv[new]) != 0) {
compare = 0;
break;
}
old++;
new++;
}
// We won't match unless both rules had a target.
// This means we don't combine target-less rules, which is good
return compare == 1;
}
/* has a nice parsed rule starting with -A */
static void
do_rule (char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
{
/* are these conditions the same as the previous rule?
* If so, skip arg straight to -j or -g */
if (combine && argc > 2 && !isTarget (argv[2]) && compareRules ()) {
xmlComment ("Combine action from next rule");
} else {
if (closeActionTag[0]) {
printf ("%s\n", closeActionTag);
closeActionTag[0] = 0;
}
if (closeRuleTag[0]) {
printf ("%s\n", closeRuleTag);
closeRuleTag[0] = 0;
}
printf (" <rule ");
//xmlAttrS("table",curTable); // not needed in full mode
//xmlAttrS("chain",argv[1]); // not needed in full mode
if (pcnt)
xmlAttrS ("packet-count", pcnt);
if (bcnt)
xmlAttrS ("byte-count", bcnt);
printf (">\n");
strncpy (closeRuleTag, " </rule>\n", IPT_TABLE_MAXNAMELEN);
closeRuleTag[IPT_TABLE_MAXNAMELEN] = '\0';
/* no point in writing out condition if there isn't one */
if (argc >= 3 && !isTarget (argv[2])) {
printf (" <conditions>\n");
do_rule_part (NULL, NULL, -1, argc, argv, argvattr);
printf (" </conditions>\n");
}
}
/* Write out the action */
//do_rule_part("action","arg",1,argc,argv,argvattr);
if (!closeActionTag[0]) {
printf (" <actions>\n");
strncpy (closeActionTag, " </actions>\n",
IPT_TABLE_MAXNAMELEN);
closeActionTag[IPT_TABLE_MAXNAMELEN] = '\0';
}
do_rule_part (NULL, NULL, 1, argc, argv, argvattr);
}
#ifdef IPTABLES_MULTI
int
iptables_restore_main (int argc, char *argv[])
#else
int
main (int argc, char *argv[])
#endif
{
char buffer[10240];
int c;
FILE *in;
program_name = "iptables-xml";
program_version = IPTABLES_VERSION;
line = 0;
while ((c = getopt_long (argc, argv, "cvh", options, NULL)) != -1) {
switch (c) {
case 'c':
combine = 1;
break;
case 'v':
printf ("xptables-xml\n");
verbose = 1;
break;
case 'h':
print_usage ("iptables-xml", IPTABLES_VERSION);
break;
}
}
if (optind == argc - 1) {
in = fopen (argv[optind], "r");
if (!in) {
fprintf (stderr, "Can't open %s: %s", argv[optind],
strerror (errno));
exit (1);
}
} else if (optind < argc) {
fprintf (stderr, "Unknown arguments found on commandline");
exit (1);
} else
in = stdin;
printf ("<iptables-rules version=\"1.0\">\n");
/* Grab standard input. */
while (fgets (buffer, sizeof (buffer), in)) {
int ret = 0;
line++;
if (buffer[0] == '\n')
continue;
else if (buffer[0] == '#') {
xmlComment (buffer);
continue;
}
if (verbose) {
printf ("<!-- line %d ", line);
xmlCommentEscape (buffer);
printf (" -->\n");
}
if ((strcmp (buffer, "COMMIT\n") == 0) && (curTable[0])) {
DEBUGP ("Calling commit\n");
closeTable ();
ret = 1;
} else if ((buffer[0] == '*')) {
/* New table */
char *table;
table = strtok (buffer + 1, " \t\n");
DEBUGP ("line %u, table '%s'\n", line, table);
if (!table) {
exit_error (PARAMETER_PROBLEM,
"%s: line %u table name invalid\n",
program_name, line);
exit (1);
}
openTable (table);
ret = 1;
} else if ((buffer[0] == ':') && (curTable[0])) {
/* New chain. */
char *policy, *chain;
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 --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 10:43 ` Amin Azez
@ 2006-11-10 13:07 ` Patrick McHardy
2006-11-10 13:28 ` Amin Azez
0 siblings, 1 reply; 16+ messages in thread
From: Patrick McHardy @ 2006-11-10 13:07 UTC (permalink / raw)
To: Amin Azez; +Cc: Harald Welte, Netfilter Development Mailinglist
Amin Azez wrote:
> * Patrick McHardy wrote, On 09/11/06 18:34:
>>
>>We can do that, but the code needs some serious coding style
>>cleanup before that. Please look at Documentation/CodingStyle
>>from the kernel source, it pretty much applies to iptables as
>>well.
>>
>
> Thanks for the tip.
>
> Does this meet with approval?
Much better, thanks. Two minor nitpicks: return is not a function,
so I prefer return x to return (x). Functions and function calls
should have their opening parens directly following the function
name (unlike loops etc. where we use a space). But don't bother
changing it unless you feel really motivated :)
One real comment below ..
> } 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;
This doesn't compile with old gcc versions. Unlike the kernel we still
support gcc-2.95 (I think), so please make sure you have no declarations
after statements.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 13:07 ` Patrick McHardy
@ 2006-11-10 13:28 ` Amin Azez
2006-11-10 13:51 ` Patrick McHardy
0 siblings, 1 reply; 16+ messages in thread
From: Amin Azez @ 2006-11-10 13:28 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Harald Welte, Netfilter Development Mailinglist
[-- Attachment #1: Type: text/plain, Size: 1200 bytes --]
* Patrick McHardy wrote, On 10/11/06 13:07:
>
>> Does this meet with approval?
>>
>
> Much better, thanks. Two minor nitpicks: return is not a function,
> so I prefer return x to return (x). Functions and function calls
> should have their opening parens directly following the function
> name (unlike loops etc. where we use a space). But don't bother
> changing it unless you feel really motivated :)
>
Aye; the parenthesis existed when returning the result of an expression,
not for simple values.
As for the spacing - guilt - I used the wrong indent options obviously
:-) fixed now
> One real comment below ..
>
>
...
>> if (!policy) {
>> exit_error (PARAMETER_PROBLEM,
>> "%s: line %u policy invalid\n",
>> program_name, line);
>> exit (1);
>> }
>>
>> struct ipt_counters count;
>>
>> char *ctrs;
>>
>
> This doesn't compile with old gcc versions. Unlike the kernel we still
> support gcc-2.95 (I think), so please make sure you have no declarations
> after statements.
>
ekk, thats horrible! Guilty as charged!
Thanks for taking the time to look at it and caring enough to point out
ugliness.
Another submission attempt now...
Sam
[-- Attachment #2: iptables-xml.c --]
[-- Type: text/x-csrc, Size: 19444 bytes --]
/* Code to convert iptables-save format to xml format,
* (C) 2006 Ufo Mechanic <azez@ufomechanic.net>
* based on iptables-restor (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("&");
else if (*text == '<')
printf("<");
else if (*text == '>')
printf(">");
else if (*text == '"')
printf(""");
else
putchar(*text);
*text++;
}
}
/* Output text as a comment, avoiding a double hyphen */
static void
xmlCommentEscape(char *comment)
{
int h_count = 0;
while (comment && *comment) {
if (*comment == '-') {
h_count++;
if (h_count >= 2) {
h_count = 0;
putchar(' ');
}
putchar('*');
}
/* strip trailing newline */
if (*comment == '\n' && *(comment + 1) == 0);
else
putchar(*comment);
comment++;
}
}
static void
xmlComment(char *comment)
{
printf("<!-- ");
xmlCommentEscape(comment);
printf(" -->\n");
}
static void
xmlAttrS(char *name, char *value)
{
printf("%s=\"", name);
xmlEncode(value);
printf("\" ");
}
static void
xmlAttrI(char *name, long long int num)
{
printf("%s=\"%lld\" ", name, num);
}
static void
closeChain()
{
if (curChain[0] == 0)
return;
if (closeActionTag[0])
printf("%s\n", closeActionTag);
closeActionTag[0] = 0;
if (closeRuleTag[0])
printf("%s\n", closeRuleTag);
closeRuleTag[0] = 0;
if (curChain[0])
printf(" </chain>\n");
curChain[0] = 0;
//lastRule[0]=0;
}
static void
openChain(char *chain, char *policy, struct ipt_counters *ctr, char close)
{
closeChain();
strncpy(curChain, chain, IPT_CHAIN_MAXNAMELEN);
curChain[IPT_CHAIN_MAXNAMELEN] = '\0';
printf(" <chain ");
xmlAttrS("name", curChain);
if (strcmp(policy, "-") != 0)
xmlAttrS("policy", policy);
xmlAttrI("packet-count", (unsigned long long) ctr->pcnt);
xmlAttrI("byte-count", (unsigned long long) ctr->bcnt);
if (close) {
printf("%c", close);
curChain[0] = 0;
}
printf(">\n");
}
static int
existsChain(char *chain)
{
/* open a saved chain */
int c = 0;
if (0 == strcmp(curChain, chain))
return 1;
for (c = 0; c < nextChain; c++)
if (chains[c].chain && strcmp(chains[c].chain, chain) == 0)
return 1;
return 0;
}
static void
needChain(char *chain)
{
/* open a saved chain */
int c = 0;
if (0 == strcmp(curChain, chain))
return;
for (c = 0; c < nextChain; c++)
if (chains[c].chain && strcmp(chains[c].chain, chain) == 0) {
openChain(chains[c].chain, chains[c].policy,
&(chains[c].count), '\0');
/* And, mark it as done so we don't create
an empty chain at table-end time */
chains[c].created = 1;
}
}
static void
saveChain(char *chain, char *policy, struct ipt_counters *ctr)
{
if (nextChain >= maxChains) {
exit_error(PARAMETER_PROBLEM,
"%s: line %u chain name invalid\n",
program_name, line);
exit(1);
};
chains[nextChain].chain = strdup(chain);
chains[nextChain].policy = strdup(policy);
chains[nextChain].count = *ctr;
chains[nextChain].created = 0;
nextChain++;
}
static void
finishChains()
{
int c;
for (c = 0; c < nextChain; c++)
if (!chains[c].created) {
openChain(chains[c].chain, chains[c].policy,
&(chains[c].count), '/');
free(chains[c].chain);
free(chains[c].policy);
}
nextChain = 0;
}
static void
closeTable()
{
closeChain();
finishChains();
if (curTable[0])
printf(" </table>\n");
curTable[0] = 0;
}
static void
openTable(char *table)
{
closeTable();
strncpy(curTable, table, IPT_TABLE_MAXNAMELEN);
curTable[IPT_TABLE_MAXNAMELEN] = '\0';
printf(" <table ");
xmlAttrS("name", curTable);
printf(">\n");
}
// is char* -j --jump -g or --goto
static int
isTarget(char *arg)
{
return ((arg)
&& (strcmp((arg), "-j") == 0 || strcmp((arg), "--jump") == 0
|| strcmp((arg), "-g") == 0
|| strcmp((arg), "--goto") == 0));
}
// part=-1 means do conditions, part=1 means do rules, part=0 means do both
static void
do_rule_part(char *leveltag1, char *leveltag2, int part, int argc,
char *argv[], int argvattr[])
{
int arg = 1; // ignore leading -A
char invert_next = 0;
char *thisChain = NULL;
char *spacer = ""; // space when needed to assemble arguments
char *level1 = NULL;
char *level2 = NULL;
char *leveli1 = " ";
char *leveli2 = " ";
#define CLOSE_LEVEL(LEVEL) \
do { \
if (level ## LEVEL) printf("</%s>\n", \
(leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \
level ## LEVEL=NULL;\
} while(0)
#define OPEN_LEVEL(LEVEL,TAG) \
do {\
level ## LEVEL=TAG;\
if (leveltag ## LEVEL) {\
printf("%s<%s ", (leveli ## LEVEL), \
(leveltag ## LEVEL));\
xmlAttrS("type", (TAG)); \
} else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \
} while(0)
thisChain = argv[arg++];
if (part == 1) { /* skip */
/* use argvattr to tell which arguments were quoted
to avoid comparing quoted arguments, like comments, to -j, */
while (arg < argc && (argvattr[arg] || !isTarget(argv[arg])))
arg++;
}
/* Before we start, if the first arg is -[^-] and not -m or -j or -g
then start a dummy <match> tag for old style built-in matches.
We would do this in any case, but no need if it would be empty */
if (arg < argc && argv[arg][0] == '-' && !isTarget(argv[arg])
&& strcmp(argv[arg], "-m") != 0) {
OPEN_LEVEL(1, "match");
printf(">\n");
}
while (arg < argc) {
// If ! is followed by -* then apply to that else output as data
// Stop, if we need to
if (part == -1 && !argvattr[arg] && (isTarget(argv[arg]))) {
break;
} else if (!argvattr[arg] && strcmp(argv[arg], "!") == 0) {
if ((arg + 1) < argc && argv[arg + 1][0] == '-')
invert_next = '!';
else
printf("%s%s", spacer, argv[arg]);
spacer = " ";
} else if (!argvattr[arg] && isTarget(argv[arg])
&& existsChain(argv[arg + 1])
&& (2 + arg >= argc)) {
if (!((1 + arg) < argc))
// no args to -j, -m or -g, ignore & finish loop
break;
CLOSE_LEVEL(2);
if (level1)
printf("%s", leveli1);
CLOSE_LEVEL(1);
spacer = "";
invert_next = 0;
if (strcmp(argv[arg], "-g") == 0
|| strcmp(argv[arg], "--goto") == 0) {
/* goto user chain */
OPEN_LEVEL(1, "goto");
printf(">\n");
arg++;
OPEN_LEVEL(2, argv[arg]);
printf("/>\n");
level2 = NULL;
} else {
/* call user chain */
OPEN_LEVEL(1, "call");
printf(">\n");
arg++;
OPEN_LEVEL(2, argv[arg]);
printf("/>\n");
level2 = NULL;
}
} else if (!argvattr[arg]
&& (isTarget(argv[arg])
|| strcmp(argv[arg], "-m") == 0
|| strcmp(argv[arg], "--module") == 0)) {
if (!((1 + arg) < argc))
// no args to -j, -m or -g, ignore & finish loop
break;
CLOSE_LEVEL(2);
if (level1)
printf("%s", leveli1);
CLOSE_LEVEL(1);
spacer = "";
invert_next = 0;
arg++;
OPEN_LEVEL(1, (argv[arg]));
// Optimize case, can we close this tag already?
if ((arg + 1) >= argc || (!argvattr[arg + 1]
&& (isTarget(argv[arg + 1])
|| strcmp(argv[arg + 1],
"-m") == 0
|| strcmp(argv[arg + 1],
"--module") ==
0))) {
printf(" />\n");
level1 = NULL;
} else {
printf(">\n");
}
} else if (!argvattr[arg] && argv[arg][0] == '-') {
char *tag;
CLOSE_LEVEL(2);
// Skip past any -
tag = argv[arg];
while (*tag == '-' && *tag)
tag++;
spacer = "";
OPEN_LEVEL(2, tag);
if (invert_next)
printf(" invert=\"1\"");
invert_next = 0;
// Optimize case, can we close this tag already?
if (!((arg + 1) < argc)
|| (argv[arg + 1][0] == '-' /* NOT QUOTED */ )) {
printf(" />\n");
level2 = NULL;
} else {
printf(">");
}
} else { // regular data
char *spaces = strchr(argv[arg], ' ');
printf("%s", spacer);
if (spaces || argvattr[arg])
printf(""");
// if argv[arg] contains a space, enclose in quotes
xmlEncode(argv[arg]);
if (spaces || argvattr[arg])
printf(""");
spacer = " ";
}
arg++;
}
CLOSE_LEVEL(2);
if (level1)
printf("%s", leveli1);
CLOSE_LEVEL(1);
return;
}
static int
compareRules()
{
/* compare arguments up to -j or -g for match.
NOTE: We don't want to combine actions if there were no criteria
in each rule, or rules didn't have an action
NOTE: Depends on arguments being in some kind of "normal" order which
is the case when processing the ACTUAL output of actual iptables-save
rather than a file merely in a compatable format */
int old = 0;
int new = 0;
int compare = 0;
while (new < newargc && old < oldargc) {
if (isTarget(oldargv[old]) && isTarget(newargv[new])) {
compare = 1;
break;
}
// break when old!=new
if (strcmp(oldargv[old], newargv[new]) != 0) {
compare = 0;
break;
}
old++;
new++;
}
// We won't match unless both rules had a target.
// This means we don't combine target-less rules, which is good
return compare == 1;
}
/* has a nice parsed rule starting with -A */
static void
do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
{
/* are these conditions the same as the previous rule?
* If so, skip arg straight to -j or -g */
if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) {
xmlComment("Combine action from next rule");
} else {
if (closeActionTag[0]) {
printf("%s\n", closeActionTag);
closeActionTag[0] = 0;
}
if (closeRuleTag[0]) {
printf("%s\n", closeRuleTag);
closeRuleTag[0] = 0;
}
printf(" <rule ");
//xmlAttrS("table",curTable); // not needed in full mode
//xmlAttrS("chain",argv[1]); // not needed in full mode
if (pcnt)
xmlAttrS("packet-count", pcnt);
if (bcnt)
xmlAttrS("byte-count", bcnt);
printf(">\n");
strncpy(closeRuleTag, " </rule>\n", IPT_TABLE_MAXNAMELEN);
closeRuleTag[IPT_TABLE_MAXNAMELEN] = '\0';
/* no point in writing out condition if there isn't one */
if (argc >= 3 && !isTarget(argv[2])) {
printf(" <conditions>\n");
do_rule_part(NULL, NULL, -1, argc, argv, argvattr);
printf(" </conditions>\n");
}
}
/* Write out the action */
//do_rule_part("action","arg",1,argc,argv,argvattr);
if (!closeActionTag[0]) {
printf(" <actions>\n");
strncpy(closeActionTag, " </actions>\n",
IPT_TABLE_MAXNAMELEN);
closeActionTag[IPT_TABLE_MAXNAMELEN] = '\0';
}
do_rule_part(NULL, NULL, 1, argc, argv, argvattr);
}
#ifdef IPTABLES_MULTI
int
iptables_restore_main(int argc, char *argv[])
#else
int
main(int argc, char *argv[])
#endif
{
char buffer[10240];
int c;
FILE *in;
program_name = "iptables-xml";
program_version = IPTABLES_VERSION;
line = 0;
while ((c = getopt_long(argc, argv, "cvh", options, NULL)) != -1) {
switch (c) {
case 'c':
combine = 1;
break;
case 'v':
printf("xptables-xml\n");
verbose = 1;
break;
case 'h':
print_usage("iptables-xml", IPTABLES_VERSION);
break;
}
}
if (optind == argc - 1) {
in = fopen(argv[optind], "r");
if (!in) {
fprintf(stderr, "Can't open %s: %s", argv[optind],
strerror(errno));
exit(1);
}
} else if (optind < argc) {
fprintf(stderr, "Unknown arguments found on commandline");
exit(1);
} else
in = stdin;
printf("<iptables-rules version=\"1.0\">\n");
/* Grab standard input. */
while (fgets(buffer, sizeof(buffer), in)) {
int ret = 0;
line++;
if (buffer[0] == '\n')
continue;
else if (buffer[0] == '#') {
xmlComment(buffer);
continue;
}
if (verbose) {
printf("<!-- line %d ", line);
xmlCommentEscape(buffer);
printf(" -->\n");
}
if ((strcmp(buffer, "COMMIT\n") == 0) && (curTable[0])) {
DEBUGP("Calling commit\n");
closeTable();
ret = 1;
} else if ((buffer[0] == '*')) {
/* New table */
char *table;
table = strtok(buffer + 1, " \t\n");
DEBUGP("line %u, table '%s'\n", line, table);
if (!table) {
exit_error(PARAMETER_PROBLEM,
"%s: line %u table name invalid\n",
program_name, line);
exit(1);
}
openTable(table);
ret = 1;
} else if ((buffer[0] == ':') && (curTable[0])) {
/* New chain. */
char *policy, *chain;
struct ipt_counters count;
char *ctrs;
chain = strtok(buffer + 1, " \t\n");
DEBUGP("line %u, chain '%s'\n", line, chain);
if (!chain) {
exit_error(PARAMETER_PROBLEM,
"%s: line %u chain name invalid\n",
program_name, line);
exit(1);
}
DEBUGP("Creating new chain '%s'\n", chain);
policy = strtok(NULL, " \t\n");
DEBUGP("line %u, policy '%s'\n", line, policy);
if (!policy) {
exit_error(PARAMETER_PROBLEM,
"%s: line %u policy invalid\n",
program_name, line);
exit(1);
}
ctrs = strtok(NULL, " \t\n");
parse_counters(ctrs, &count);
saveChain(chain, policy, &count);
ret = 1;
} else if (curTable[0]) {
int a;
char *ptr = buffer;
char *pcnt = NULL;
char *bcnt = NULL;
char *parsestart;
char *chain = NULL;
/* the parser */
char *param_start, *curchar;
int quote_open, quoted;
/* reset the newargv */
newargc = 0;
if (buffer[0] == '[') {
/* we have counters in our input */
ptr = strchr(buffer, ']');
if (!ptr)
exit_error(PARAMETER_PROBLEM,
"Bad line %u: need ]\n",
line);
pcnt = strtok(buffer + 1, ":");
if (!pcnt)
exit_error(PARAMETER_PROBLEM,
"Bad line %u: need :\n",
line);
bcnt = strtok(NULL, "]");
if (!bcnt)
exit_error(PARAMETER_PROBLEM,
"Bad line %u: need ]\n",
line);
/* start command parsing after counter */
parsestart = ptr + 1;
} else {
/* start command parsing at start of line */
parsestart = buffer;
}
/* This is a 'real' parser crafted in artist mode
* not hacker mode. If the author can live with that
* then so can everyone else */
quote_open = 0;
/* We need to know which args were quoted so we
can preserve quote */
quoted = 0;
param_start = parsestart;
for (curchar = parsestart; *curchar; curchar++) {
if (*curchar == '"') {
/* quote_open cannot be true if there
* was no previous character. Thus,
* curchar-1 has to be within bounds */
if (quote_open &&
*(curchar - 1) != '\\') {
quote_open = 0;
*curchar = ' ';
} else {
quote_open = 1;
quoted = 1;
param_start++;
}
}
if (*curchar == ' '
|| *curchar == '\t' || *curchar == '\n') {
char param_buffer[1024];
int param_len = curchar - param_start;
if (quote_open)
continue;
if (!param_len) {
/* two spaces? */
param_start++;
continue;
}
/* end of one parameter */
strncpy(param_buffer, param_start,
param_len);
*(param_buffer + param_len) = '\0';
/* check if table name specified */
if (!strncmp(param_buffer, "-t", 3)
|| !strncmp(param_buffer,
"--table", 8)) {
exit_error(PARAMETER_PROBLEM,
"Line %u seems to have a "
"-t table option.\n",
line);
exit(1);
}
add_argv(param_buffer, quoted);
if (newargc >= 2
&& 0 ==
strcmp(newargv[newargc - 2], "-A"))
chain = newargv[newargc - 1];
quoted = 0;
param_start += param_len + 1;
} else {
/* regular character, skip */
}
}
DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
newargc, curTable);
for (a = 0; a < newargc; a++)
DEBUGP("argv[%u]: %s\n", a, newargv[a]);
needChain(chain);// Should we explicitly look for -A
do_rule(pcnt, bcnt, newargc, newargv, newargvattr);
save_argv();
ret = 1;
}
if (!ret) {
fprintf(stderr, "%s: line %u failed\n",
program_name, line);
exit(1);
}
}
if (curTable[0]) {
fprintf(stderr, "%s: COMMIT expected at line %u\n",
program_name, line + 1);
exit(1);
}
printf("</iptables-rules>\n");
free_argv();
return 0;
}
[-- Attachment #3: iptables.xslt --]
[-- Type: application/xslt+xml, Size: 5938 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 13:28 ` Amin Azez
@ 2006-11-10 13:51 ` Patrick McHardy
2006-11-10 14:29 ` Amin Azez
0 siblings, 1 reply; 16+ messages in thread
From: Patrick McHardy @ 2006-11-10 13:51 UTC (permalink / raw)
To: Amin Azez; +Cc: Harald Welte, Netfilter Development Mailinglist
Amin Azez wrote:
> As for the spacing - guilt - I used the wrong indent options obviously
> :-) fixed now
Thanks, now all I need is a patch to the Makefile to actually compile
this thing :)
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 13:51 ` Patrick McHardy
@ 2006-11-10 14:29 ` Amin Azez
2006-11-10 14:42 ` Patrick McHardy
0 siblings, 1 reply; 16+ messages in thread
From: Amin Azez @ 2006-11-10 14:29 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Harald Welte, Netfilter Development Mailinglist
[-- Attachment #1: Type: text/plain, Size: 273 bytes --]
* Patrick McHardy wrote, On 10/11/06 13:51:
> Amin Azez wrote:
>> As for the spacing - guilt - I used the wrong indent options obviously
>> :-) fixed now
>
> Thanks, now all I need is a patch to the Makefile to actually compile
> this thing :)
>
>
:-)
Here 'tis.
Sam
[-- Attachment #2: iptables-xml-makefile.patch --]
[-- Type: text/x-patch, Size: 1824 bytes --]
--- Makefile.noxml 2006-04-10 16:14:39.000000000 +0100
+++ Makefile 2006-04-10 16:19:38.000000000 +0100
@@ -43,9 +43,9 @@
# No longer experimental.
ifneq ($(DO_MULTI), 1)
-EXTRAS+=iptables-save iptables-restore
+EXTRAS+=iptables-save iptables-restore iptables-xml
endif
-EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore $(DESTDIR)$(MANDIR)/man8/iptables-restore.8 $(DESTDIR)$(MANDIR)/man8/iptables-save.8
+EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore $(DESTDIR)$(BINDIR)/iptables-xml $(DESTDIR)$(MANDIR)/man8/iptables-restore.8 $(DESTDIR)$(MANDIR)/man8/iptables-save.8
ifeq ($(DO_IPV6), 1)
EXTRAS+=ip6tables ip6tables.o ip6tables.8
@@ -117,7 +117,7 @@
$(CC) $(CFLAGS) -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" -c -o $@ $<
ifeq ($(DO_MULTI), 1)
-iptables: iptables-multi.c iptables-save.c iptables-restore.c iptables-standalone.c iptables.o $(STATIC_LIBS) libiptc/libiptc.a
+iptables: iptables-multi.c iptables-save.c iptables-restore.c iptables-xml.c iptables-standalone.c iptables.o $(STATIC_LIBS) libiptc/libiptc.a
$(CC) $(CFLAGS) -DIPTABLES_MULTI -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" $(LDFLAGS) -o $@ $^ $(LDLIBS)
else
iptables: iptables-standalone.c iptables.o $(STATIC_LIBS) libiptc/libiptc.a
@@ -158,6 +158,19 @@
cp $< $@
endif
+iptables-xml: iptables-xml.c #iptables.o # $(STATIC_LIBS) libiptc/libiptc.a
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
+ifeq ($(DO_MULTI), 1)
+$(DESTDIR)$(BINDIR)/iptables-xml: iptables-xml
+ @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
+ ln -sf $< $@
+else
+$(DESTDIR)$(BINDIR)/iptables-xml: iptables-xml
+ @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
+ cp $< $@
+endif
+
ip6tables.o: ip6tables.c
$(CC) $(CFLAGS) -DIP6T_LIB_DIR=\"$(IPT_LIBDIR)\" -c -o $@ $<
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 14:29 ` Amin Azez
@ 2006-11-10 14:42 ` Patrick McHardy
2006-11-10 14:59 ` Amin Azez
0 siblings, 1 reply; 16+ messages in thread
From: Patrick McHardy @ 2006-11-10 14:42 UTC (permalink / raw)
To: Amin Azez; +Cc: Harald Welte, Netfilter Development Mailinglist
Amin Azez wrote:
> * Patrick McHardy wrote, On 10/11/06 13:51:
>
>>Amin Azez wrote:
>>
>>>As for the spacing - guilt - I used the wrong indent options obviously
>>>:-) fixed now
>>
>>Thanks, now all I need is a patch to the Makefile to actually compile
>>this thing :)
Thanks. Compiling gives me a warning about an unused result of this
expression:
static void
xmlEncode(char *text)
{
...
*text++;
}
I assume this should be "text++"?
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-09 11:32 new code; iptables-xml for iptables package Amin Azez
2006-11-09 18:34 ` Patrick McHardy
@ 2006-11-10 14:43 ` Pablo Neira Ayuso
2006-11-10 15:13 ` Amin Azez
2006-11-22 17:37 ` Glen Turner
2 siblings, 1 reply; 16+ messages in thread
From: Pablo Neira Ayuso @ 2006-11-10 14:43 UTC (permalink / raw)
To: Amin Azez
Cc: Harald Welte, Netfilter Development Mailinglist, Patrick McHardy
Amin Azez wrote:
> (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 -
Just a wild thought, why not go further and provide a native XML
interface instead of a converter?
BTW, could you also provide a DTD (Document Type Definition)? It can be
interesting to check for well-formed documents.
--
The dawn of the fourth age of Linux firewalling is coming; a time of
great struggle and heroic deeds -- J.Kadlecsik got inspired by J.Morris
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 14:42 ` Patrick McHardy
@ 2006-11-10 14:59 ` Amin Azez
2006-11-10 15:11 ` Patrick McHardy
0 siblings, 1 reply; 16+ messages in thread
From: Amin Azez @ 2006-11-10 14:59 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Harald Welte, Netfilter Development Mailinglist
* Patrick McHardy wrote, On 10/11/06 14:42:
> Amin Azez wrote:
>> * Patrick McHardy wrote, On 10/11/06 13:51:
>>
>>> Amin Azez wrote:
>>>
>>>> As for the spacing - guilt - I used the wrong indent options obviously
>>>> :-) fixed now
>>> Thanks, now all I need is a patch to the Makefile to actually compile
>>> this thing :)
>
> Thanks. Compiling gives me a warning about an unused result of this
> expression:
>
> static void
> xmlEncode(char *text)
> {
> ...
> *text++;
>
> }
>
> I assume this should be "text++"?
Oh! Certainly!
In trying to work out why it works at all, I discover that
*text++ is not the same as (*text)++; both of which are wrong in this case.
While we are at it we should make that compare at the top of the same
function be >=127 not >127
Sam
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 14:59 ` Amin Azez
@ 2006-11-10 15:11 ` Patrick McHardy
2006-11-10 15:57 ` Amin Azez
0 siblings, 1 reply; 16+ messages in thread
From: Patrick McHardy @ 2006-11-10 15:11 UTC (permalink / raw)
To: Amin Azez; +Cc: Harald Welte, Netfilter Development Mailinglist
Amin Azez wrote:
> In trying to work out why it works at all, I discover that
> *text++ is not the same as (*text)++; both of which are wrong in this case.
>
> While we are at it we should make that compare at the top of the same
> function be >=127 not >127
OK, both fixed and applied. Please send potential fixes or changes as
patches against current SVN.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 14:43 ` Pablo Neira Ayuso
@ 2006-11-10 15:13 ` Amin Azez
0 siblings, 0 replies; 16+ messages in thread
From: Amin Azez @ 2006-11-10 15:13 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: Harald Welte, Netfilter Development Mailinglist, Patrick McHardy
* Pablo Neira Ayuso wrote, On 10/11/06 14:43:
> Amin Azez wrote:
>> (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 -
>
> Just a wild thought, why not go further and provide a native XML
> interface instead of a converter?
There are some considerations.
Small changes must be made to the save- output of every module.
If instead of using printf, a slightly more semantic function were used,
then we would get xml output nearly for-free.
Most modules would just output like this:
iptables_arg_output("source-address",souce_address,0);
which for xml output would be
<source-address>1.1.1.1</source-address>
or text output:
--source-address 1.1.1.1
(the final 0 is the invert flag, for matches).
However if iptables could save in xmlformat natively, then there is a
strong argment that it should be able to load xmlformat natively,
instead of using xsltproc or xsl converter of the day.
- nothing very wrong in this but it would be a bigger decision and one
which would be easier to make (and justify the time for) when we see how
this settles in.
> BTW, could you also provide a DTD (Document Type Definition)? It can be
> interesting to check for well-formed documents.
Yes.... it may require a new xml format as the current format is perhaps
too free-form, with each module or argument being converted directly to
a new tag. The disadvantage is that the DTD will depend on "knowing"
precisely which iptables modules are available.
Perhaps it's an advantage if the DTD were also generated as part of the
iptables build system, but it would then require that each module more
formally declare the semantics of the arguments in order to support such
generation.
In other words to do it that way is ideal but not a small change.
I would support working towards that.
I had toyed with output like:
<action type="SNAT"><arg name="source-address">1.1.1.1</arg></action>
but it was too sterile and void of meaning. Although it would be easy to
FIX a DTD for it to verify against,the verification would mean very little.
If we keep to the current format and can generated a DTD at compile
time, then DTD verification would be quite meaningful.
Sam
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 15:11 ` Patrick McHardy
@ 2006-11-10 15:57 ` Amin Azez
2006-11-13 19:43 ` Patrick McHardy
0 siblings, 1 reply; 16+ messages in thread
From: Amin Azez @ 2006-11-10 15:57 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Harald Welte, Netfilter Development Mailinglist
* Patrick McHardy wrote, On 10/11/06 15:11:
> Amin Azez wrote:
>> In trying to work out why it works at all, I discover that
>> *text++ is not the same as (*text)++; both of which are wrong in this case.
>>
>> While we are at it we should make that compare at the top of the same
>> function be >=127 not >127
>
> OK, both fixed and applied. Please send potential fixes or changes as
> patches against current SVN.
OK, Thanks.
To what were they applied? They're not in current SVN according to:
http://svn.netfilter.org/cgi-bin/viewcvs.cgi/trunk/iptables/
Sam
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-10 15:57 ` Amin Azez
@ 2006-11-13 19:43 ` Patrick McHardy
0 siblings, 0 replies; 16+ messages in thread
From: Patrick McHardy @ 2006-11-13 19:43 UTC (permalink / raw)
To: Amin Azez; +Cc: Harald Welte, Netfilter Development Mailinglist
Amin Azez wrote:
> To what were they applied? They're not in current SVN according to:
> http://svn.netfilter.org/cgi-bin/viewcvs.cgi/trunk/iptables/
Ups sorry, apparently I made a mistake. I've committed it now.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-09 11:32 new code; iptables-xml for iptables package Amin Azez
2006-11-09 18:34 ` Patrick McHardy
2006-11-10 14:43 ` Pablo Neira Ayuso
@ 2006-11-22 17:37 ` Glen Turner
2006-11-23 12:55 ` Amin Azez
2 siblings, 1 reply; 16+ messages in thread
From: Glen Turner @ 2006-11-22 17:37 UTC (permalink / raw)
To: Netfilter Development Mailinglist
Amin Azez wrote:
> 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>
Folks,
Before committing stuff which generates XML output it might be
worthwhile checking if a DTD has also been supplied so that
third-party tools can use and generate the XML with some
assurance. If the use of the XML is private to Netfilter
then then XML format offers no advantages over the standard
format.
In particular, folks will want something to use as a target
when converting to/from Tivoli XML/Juniper XML/Cisco XML/
OASIS XACML/IETF PCM (as you can see there's no shortage of
XML ACL formats, and still no real standardisation in sight
despite consistent ACLs between devices being a boon to network
operations).
Thanks, Glen
--
Glen Turner Tel: (08) 8303 3936 or +61 8 8303 3936
Australia's Academic & Research Network www.aarnet.edu.au
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: new code; iptables-xml for iptables package.
2006-11-22 17:37 ` Glen Turner
@ 2006-11-23 12:55 ` Amin Azez
0 siblings, 0 replies; 16+ messages in thread
From: Amin Azez @ 2006-11-23 12:55 UTC (permalink / raw)
To: netfilter-devel
* Glen Turner wrote, On 22/11/06 17:37:
> Amin Azez wrote:
>
>> 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>
>
> Folks,
>
> Before committing stuff which generates XML output it might be
> worthwhile checking if a DTD has also been supplied so that
> third-party tools can use and generate the XML with some
> assurance. If the use of the XML is private to Netfilter
> then then XML format offers no advantages over the standard
> format.
Well it does offer advantages over the standard format, in that any xslt
processor can manipulate the rules as opposed to er.... sed and grep...
and perl...
> In particular, folks will want something to use as a target
> when converting to/from Tivoli XML/Juniper XML/Cisco XML/
> OASIS XACML/IETF PCM
A DTD would help there, but this is -devel and you are looking at a new
work, in progress. Useful suggestions such as you have made were
anticipated when the xml stuff was offered. Thanks for this suggestion.
There has been discussion in this thread covering how a DTD might be
generated as part of the build process. It would require the
author/maintainer of each module to express semantically the arguments
they parse. No doubt this would have re-factorable benefits for the
options parsing which may be useful tool. In short, the work involved is
significant and would requires significant changes, and it is perhaps
better to see how useful the current format is, in order to get
direction for what should come next.
I would be interested to hear what use you are able to make of this xml
format and stylesheet. If you are familiar with iptables rules then lack
of a DTD should not be a practical obstacle.
> (as you can see there's no shortage of
> XML ACL formats, and still no real standardisation in sight
> despite consistent ACLs between devices being a boon to network
> operations).
Yeah; I don't think standardization of XML formats is desirable, each
format is expressive to it's purpose. XML allows recipe based conversion
between formats in many cases, or specific generation from a single
general purpose abstract format.
As the first part of a work in progress tools have been supplied to
convert between an iptables biased xml format and iptables native form.
I'm using these tools heavily (as might be expected) and find them
extremely useful.
I hope for feedback from others; no doubt I have to write a man page next.
Sam
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2006-11-23 12:55 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-09 11:32 new code; iptables-xml for iptables package Amin Azez
2006-11-09 18:34 ` 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
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.