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