* [PATCH 1/5] nft: xtables: add generic parsing infrastructure to interpret commands
2014-04-14 10:41 [RFC PATCH 0/5] translations from iptables to nft Pablo Neira Ayuso
@ 2014-04-14 10:41 ` Pablo Neira Ayuso
2014-04-14 10:41 ` [PATCH 2/5] nft: xtables-restore: add generic parsing infrastructure Pablo Neira Ayuso
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2014-04-14 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Split the code to parse arguments and to issue command so we reuse this
for the iptables to nft translation infrastructure.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
iptables/nft-shared.h | 15 ++
iptables/xtables.c | 445 ++++++++++++++++++++++++++-----------------------
2 files changed, 249 insertions(+), 211 deletions(-)
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 145f19d..d4bc31e 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -175,6 +175,21 @@ struct xtables_args {
#define CMD_ZERO_NUM 0x2000U
#define CMD_CHECK 0x4000U
+struct nft_xt_cmd_parse {
+ unsigned int command;
+ unsigned int rulenum;
+ char *table;
+ char *chain;
+ char *newname;
+ char *policy;
+ bool restore;
+ int verbose;
+};
+
+void do_parse(struct nft_handle *h, int argc, char *argv[],
+ struct nft_xt_cmd_parse *p, struct iptables_command_state *cs,
+ struct xtables_args *args);
+
/*
* ARP
*/
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 45a5ac6..8aa58af 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -678,25 +678,17 @@ static void command_match(struct iptables_command_state *cs)
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
}
-int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
- bool restore)
+void do_parse(struct nft_handle *h, int argc, char *argv[],
+ struct nft_xt_cmd_parse *p, struct iptables_command_state *cs,
+ struct xtables_args *args)
{
- struct iptables_command_state cs;
- int verbose = 0;
- const char *chain = NULL;
- const char *policy = NULL, *newname = NULL;
- unsigned int rulenum = 0, command = 0;
- int ret = 1;
struct xtables_match *m;
struct xtables_rule_match *matchp;
struct xtables_target *t;
- struct xtables_args args = {
- .family = h->family,
- };
- memset(&cs, 0, sizeof(cs));
- cs.jumpto = "";
- cs.argv = argv;
+ memset(cs, 0, sizeof(*cs));
+ cs->jumpto = "";
+ cs->argv = argv;
/* re-set optind to 0 in case do_command4 gets called
* a second time */
@@ -721,43 +713,43 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
xtables_error(PARAMETER_PROBLEM, "Unknown family");
opts = xt_params->orig_opts;
- while ((cs.c = getopt_long(argc, argv,
+ while ((cs->c = getopt_long(argc, argv,
"-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:46",
opts, NULL)) != -1) {
- switch (cs.c) {
+ switch (cs->c) {
/*
* Command selection
*/
case 'A':
- add_command(&command, CMD_APPEND, CMD_NONE,
- cs.invert);
- chain = optarg;
+ add_command(&p->command, CMD_APPEND, CMD_NONE,
+ cs->invert);
+ p->chain = optarg;
break;
case 'C':
- add_command(&command, CMD_CHECK, CMD_NONE,
- cs.invert);
- chain = optarg;
+ add_command(&p->command, CMD_CHECK, CMD_NONE,
+ cs->invert);
+ p->chain = optarg;
break;
case 'D':
- add_command(&command, CMD_DELETE, CMD_NONE,
- cs.invert);
- chain = optarg;
+ add_command(&p->command, CMD_DELETE, CMD_NONE,
+ cs->invert);
+ p->chain = optarg;
if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!') {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_DELETE_NUM;
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ p->command = CMD_DELETE_NUM;
}
break;
case 'R':
- add_command(&command, CMD_REPLACE, CMD_NONE,
- cs.invert);
- chain = optarg;
+ add_command(&p->command, CMD_REPLACE, CMD_NONE,
+ cs->invert);
+ p->chain = optarg;
if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- rulenum = parse_rulenumber(argv[optind++]);
+ p->rulenum = parse_rulenumber(argv[optind++]);
else
xtables_error(PARAMETER_PROBLEM,
"-%c requires a rule number",
@@ -765,59 +757,64 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
break;
case 'I':
- add_command(&command, CMD_INSERT, CMD_NONE,
- cs.invert);
- chain = optarg;
+ add_command(&p->command, CMD_INSERT, CMD_NONE,
+ cs->invert);
+ p->chain = optarg;
if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- rulenum = parse_rulenumber(argv[optind++]);
- else rulenum = 1;
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ else
+ p->rulenum = 1;
break;
case 'L':
- add_command(&command, CMD_LIST,
- CMD_ZERO | CMD_ZERO_NUM, cs.invert);
- if (optarg) chain = optarg;
+ add_command(&p->command, CMD_LIST,
+ CMD_ZERO | CMD_ZERO_NUM, cs->invert);
+ if (optarg)
+ p->chain = optarg;
else if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- chain = argv[optind++];
+ p->chain = argv[optind++];
if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- rulenum = parse_rulenumber(argv[optind++]);
+ p->rulenum = parse_rulenumber(argv[optind++]);
break;
case 'S':
- add_command(&command, CMD_LIST_RULES,
- CMD_ZERO|CMD_ZERO_NUM, cs.invert);
- if (optarg) chain = optarg;
+ add_command(&p->command, CMD_LIST_RULES,
+ CMD_ZERO|CMD_ZERO_NUM, cs->invert);
+ if (optarg)
+ p->chain = optarg;
else if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- chain = argv[optind++];
+ p->chain = argv[optind++];
if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- rulenum = parse_rulenumber(argv[optind++]);
+ p->rulenum = parse_rulenumber(argv[optind++]);
break;
case 'F':
- add_command(&command, CMD_FLUSH, CMD_NONE,
- cs.invert);
- if (optarg) chain = optarg;
+ add_command(&p->command, CMD_FLUSH, CMD_NONE,
+ cs->invert);
+ if (optarg)
+ p->chain = optarg;
else if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- chain = argv[optind++];
+ p->chain = argv[optind++];
break;
case 'Z':
- add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
- cs.invert);
- if (optarg) chain = optarg;
+ add_command(&p->command, CMD_ZERO,
+ CMD_LIST|CMD_LIST_RULES, cs->invert);
+ if (optarg)
+ p->chain = optarg;
else if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- chain = argv[optind++];
+ p->chain = argv[optind++];
if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!') {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_ZERO_NUM;
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ p->command = CMD_ZERO_NUM;
}
break;
@@ -830,27 +827,28 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
xtables_error(PARAMETER_PROBLEM,
"chain name may not clash "
"with target name\n");
- add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
- cs.invert);
- chain = optarg;
+ add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
+ cs->invert);
+ p->chain = optarg;
break;
case 'X':
- add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
- cs.invert);
- if (optarg) chain = optarg;
+ add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
+ cs->invert);
+ if (optarg)
+ p->chain = optarg;
else if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- chain = argv[optind++];
+ p->chain = argv[optind++];
break;
case 'E':
- add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
- cs.invert);
- chain = optarg;
+ add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
+ cs->invert);
+ p->chain = optarg;
if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- newname = argv[optind++];
+ p->newname = argv[optind++];
else
xtables_error(PARAMETER_PROBLEM,
"-%c requires old-chain-name and "
@@ -859,12 +857,12 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
break;
case 'P':
- add_command(&command, CMD_SET_POLICY, CMD_NONE,
- cs.invert);
- chain = optarg;
+ add_command(&p->command, CMD_SET_POLICY, CMD_NONE,
+ cs->invert);
+ p->chain = optarg;
if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
- policy = argv[optind++];
+ p->policy = argv[optind++];
else
xtables_error(PARAMETER_PROBLEM,
"-%c requires a chain and a policy",
@@ -876,57 +874,58 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
optarg = argv[optind];
/* iptables -p icmp -h */
- if (!cs.matches && cs.protocol)
- xtables_find_match(cs.protocol,
- XTF_TRY_LOAD, &cs.matches);
+ if (!cs->matches && cs->protocol)
+ xtables_find_match(cs->protocol,
+ XTF_TRY_LOAD, &cs->matches);
- exit_printhelp(cs.matches);
+ exit_printhelp(cs->matches);
/*
* Option selection
*/
case 'p':
- set_option(&cs.options, OPT_PROTOCOL, &args.invflags,
- cs.invert);
+ set_option(&cs->options, OPT_PROTOCOL,
+ &args->invflags, cs->invert);
/* Canonicalize into lower case */
- for (cs.protocol = optarg; *cs.protocol; cs.protocol++)
- *cs.protocol = tolower(*cs.protocol);
+ for (cs->protocol = optarg; *cs->protocol; cs->protocol++)
+ *cs->protocol = tolower(*cs->protocol);
- cs.protocol = optarg;
- args.proto = xtables_parse_protocol(cs.protocol);
+ cs->protocol = optarg;
+ args->proto = xtables_parse_protocol(cs->protocol);
- if (args.proto == 0 && (args.invflags & XT_INV_PROTO))
+ if (args->proto == 0 &&
+ (args->invflags & XT_INV_PROTO))
xtables_error(PARAMETER_PROBLEM,
"rule would never match protocol");
/* This needs to happen here to parse extensions */
- h->ops->proto_parse(&cs, &args);
+ h->ops->proto_parse(cs, args);
break;
case 's':
- set_option(&cs.options, OPT_SOURCE, &args.invflags,
- cs.invert);
- args.shostnetworkmask = optarg;
+ set_option(&cs->options, OPT_SOURCE,
+ &args->invflags, cs->invert);
+ args->shostnetworkmask = optarg;
break;
case 'd':
- set_option(&cs.options, OPT_DESTINATION,
- &args.invflags, cs.invert);
- args.dhostnetworkmask = optarg;
+ set_option(&cs->options, OPT_DESTINATION,
+ &args->invflags, cs->invert);
+ args->dhostnetworkmask = optarg;
break;
#ifdef IPT_F_GOTO
case 'g':
- set_option(&cs.options, OPT_JUMP, &args.invflags,
- cs.invert);
- args.goto_set = true;
- cs.jumpto = parse_target(optarg);
+ set_option(&cs->options, OPT_JUMP, &args->invflags,
+ cs->invert);
+ args->goto_set = true;
+ cs->jumpto = parse_target(optarg);
break;
#endif
case 'j':
- command_jump(&cs);
+ command_jump(cs);
break;
@@ -935,11 +934,11 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
xtables_error(PARAMETER_PROBLEM,
"Empty interface is likely to be "
"undesired");
- set_option(&cs.options, OPT_VIANAMEIN, &args.invflags,
- cs.invert);
+ set_option(&cs->options, OPT_VIANAMEIN,
+ &args->invflags, cs->invert);
xtables_parse_interface(optarg,
- args.iniface,
- args.iniface_mask);
+ args->iniface,
+ args->iniface_mask);
break;
case 'o':
@@ -947,54 +946,54 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
xtables_error(PARAMETER_PROBLEM,
"Empty interface is likely to be "
"undesired");
- set_option(&cs.options, OPT_VIANAMEOUT, &args.invflags,
- cs.invert);
+ set_option(&cs->options, OPT_VIANAMEOUT,
+ &args->invflags, cs->invert);
xtables_parse_interface(optarg,
- args.outiface,
- args.outiface_mask);
+ args->outiface,
+ args->outiface_mask);
break;
case 'f':
- if (args.family == AF_INET6) {
+ if (args->family == AF_INET6) {
xtables_error(PARAMETER_PROBLEM,
"`-f' is not supported in IPv6, "
"use -m frag instead");
}
- set_option(&cs.options, OPT_FRAGMENT, &args.invflags,
- cs.invert);
- args.flags |= IPT_F_FRAG;
+ set_option(&cs->options, OPT_FRAGMENT, &args->invflags,
+ cs->invert);
+ args->flags |= IPT_F_FRAG;
break;
case 'v':
- if (!verbose)
- set_option(&cs.options, OPT_VERBOSE,
- &args.invflags, cs.invert);
- verbose++;
+ if (!p->verbose)
+ set_option(&cs->options, OPT_VERBOSE,
+ &args->invflags, cs->invert);
+ p->verbose++;
break;
case 'm':
- command_match(&cs);
+ command_match(cs);
break;
case 'n':
- set_option(&cs.options, OPT_NUMERIC, &args.invflags,
- cs.invert);
+ set_option(&cs->options, OPT_NUMERIC, &args->invflags,
+ cs->invert);
break;
case 't':
- if (cs.invert)
+ if (cs->invert)
xtables_error(PARAMETER_PROBLEM,
"unexpected ! flag before --table");
- *table = optarg;
+ p->table = optarg;
break;
case 'x':
- set_option(&cs.options, OPT_EXPANDED, &args.invflags,
- cs.invert);
+ set_option(&cs->options, OPT_EXPANDED, &args->invflags,
+ cs->invert);
break;
case 'V':
- if (cs.invert)
+ if (cs->invert)
printf("Not %s ;-)\n", prog_vers);
else
printf("%s v%s\n",
@@ -1002,7 +1001,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
exit(0);
case 'w':
- if (restore) {
+ if (p->restore) {
xtables_error(PARAMETER_PROBLEM,
"You cannot use `-w' from "
"iptables-restore");
@@ -1010,8 +1009,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
break;
case '0':
- set_option(&cs.options, OPT_LINENUMBERS,
- &args.invflags, cs.invert);
+ set_option(&cs->options, OPT_LINENUMBERS,
+ &args->invflags, cs->invert);
break;
case 'M':
@@ -1019,45 +1018,44 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
break;
case 'c':
-
- set_option(&cs.options, OPT_COUNTERS, &args.invflags,
- cs.invert);
- args.pcnt = optarg;
- args.bcnt = strchr(args.pcnt + 1, ',');
- if (args.bcnt)
- args.bcnt++;
- if (!args.bcnt && optind < argc &&
+ set_option(&cs->options, OPT_COUNTERS, &args->invflags,
+ cs->invert);
+ args->pcnt = optarg;
+ args->bcnt = strchr(args->pcnt + 1, ',');
+ if (args->bcnt)
+ args->bcnt++;
+ if (!args->bcnt && optind < argc &&
argv[optind][0] != '-' &&
argv[optind][0] != '!')
- args.bcnt = argv[optind++];
- if (!args.bcnt)
+ args->bcnt = argv[optind++];
+ if (!args->bcnt)
xtables_error(PARAMETER_PROBLEM,
"-%c requires packet and byte counter",
opt2char(OPT_COUNTERS));
- if (sscanf(args.pcnt, "%llu", &args.pcnt_cnt) != 1)
+ if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
xtables_error(PARAMETER_PROBLEM,
"-%c packet counter not numeric",
opt2char(OPT_COUNTERS));
- if (sscanf(args.bcnt, "%llu", &args.bcnt_cnt) != 1)
+ if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
xtables_error(PARAMETER_PROBLEM,
"-%c byte counter not numeric",
opt2char(OPT_COUNTERS));
break;
case '4':
- if (args.family != AF_INET)
+ if (args->family != AF_INET)
exit_tryhelp(2);
- h->ops = nft_family_ops_lookup(args.family);
+ h->ops = nft_family_ops_lookup(args->family);
break;
case '6':
- args.family = AF_INET6;
+ args->family = AF_INET6;
xtables_set_nfproto(AF_INET6);
- h->ops = nft_family_ops_lookup(args.family);
+ h->ops = nft_family_ops_lookup(args->family);
if (h->ops == NULL)
xtables_error(PARAMETER_PROBLEM,
"Unknown family");
@@ -1065,11 +1063,11 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
case 1: /* non option */
if (optarg[0] == '!' && optarg[1] == '\0') {
- if (cs.invert)
+ if (cs->invert)
xtables_error(PARAMETER_PROBLEM,
"multiple consecutive ! not"
" allowed");
- cs.invert = TRUE;
+ cs->invert = TRUE;
optarg[0] = '\0';
continue;
}
@@ -1077,78 +1075,78 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
exit_tryhelp(2);
default:
- if (command_default(&cs, &xtables_globals) == 1)
+ if (command_default(cs, &xtables_globals) == 1)
/* cf. ip6tables.c */
continue;
break;
}
- cs.invert = FALSE;
+ cs->invert = FALSE;
}
- if (strcmp(*table, "nat") == 0 &&
- ((policy != NULL && strcmp(policy, "DROP") == 0) ||
- (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
+ if (strcmp(p->table, "nat") == 0 &&
+ ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
+ (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
xtables_error(PARAMETER_PROBLEM,
"\nThe \"nat\" table is not intended for filtering, "
"the use of DROP is therefore inhibited.\n\n");
- for (matchp = cs.matches; matchp; matchp = matchp->next)
+ for (matchp = cs->matches; matchp; matchp = matchp->next)
xtables_option_mfcall(matchp->match);
- if (cs.target != NULL)
- xtables_option_tfcall(cs.target);
+ if (cs->target != NULL)
+ xtables_option_tfcall(cs->target);
/* Fix me: must put inverse options checking here --MN */
if (optind < argc)
xtables_error(PARAMETER_PROBLEM,
"unknown arguments found on commandline");
- if (!command)
+ if (!p->command)
xtables_error(PARAMETER_PROBLEM, "no command specified");
- if (cs.invert)
+ if (cs->invert)
xtables_error(PARAMETER_PROBLEM,
"nothing appropriate following !");
/* Set only if required, needed by xtables-restore */
if (h->family == AF_UNSPEC)
- h->family = args.family;
+ h->family = args->family;
- h->ops->post_parse(command, &cs, &args);
+ h->ops->post_parse(p->command, cs, args);
- if (command == CMD_REPLACE &&
- (args.s.naddrs != 1 || args.d.naddrs != 1))
+ if (p->command == CMD_REPLACE &&
+ (args->s.naddrs != 1 || args->d.naddrs != 1))
xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
"specify a unique address");
- generic_opt_check(command, cs.options);
+ generic_opt_check(p->command, cs->options);
- if (chain != NULL && strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
+ if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
"chain name `%s' too long (must be under %u chars)",
- chain, XT_EXTENSION_MAXNAMELEN);
-
- if (command == CMD_APPEND
- || command == CMD_DELETE
- || command == CMD_CHECK
- || command == CMD_INSERT
- || command == CMD_REPLACE) {
- if (strcmp(chain, "PREROUTING") == 0
- || strcmp(chain, "INPUT") == 0) {
+ p->chain, XT_EXTENSION_MAXNAMELEN);
+
+ if (p->command == CMD_APPEND ||
+ p->command == CMD_DELETE ||
+ p->command == CMD_CHECK ||
+ p->command == CMD_INSERT ||
+ p->command == CMD_REPLACE) {
+ if (strcmp(p->chain, "PREROUTING") == 0
+ || strcmp(p->chain, "INPUT") == 0) {
/* -o not valid with incoming packets. */
- if (cs.options & OPT_VIANAMEOUT)
+ if (cs->options & OPT_VIANAMEOUT)
xtables_error(PARAMETER_PROBLEM,
"Can't use -%c with %s\n",
opt2char(OPT_VIANAMEOUT),
- chain);
+ p->chain);
}
- if (strcmp(chain, "POSTROUTING") == 0
- || strcmp(chain, "OUTPUT") == 0) {
+ if (strcmp(p->chain, "POSTROUTING") == 0
+ || strcmp(p->chain, "OUTPUT") == 0) {
/* -i not valid with outgoing packets */
- if (cs.options & OPT_VIANAMEIN)
+ if (cs->options & OPT_VIANAMEIN)
xtables_error(PARAMETER_PROBLEM,
"Can't use -%c with %s\n",
opt2char(OPT_VIANAMEIN),
- chain);
+ p->chain);
}
/*
@@ -1157,90 +1155,115 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
* nf_table will spot the error if the chain does not exists.
*/
}
+}
+
+int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
+ bool restore)
+{
+ int ret = 1;
+ struct nft_xt_cmd_parse p = {
+ .table = *table,
+ .restore = restore,
+ };
+ struct iptables_command_state cs;
+ struct xtables_args args = {
+ .family = h->family,
+ };
+
+ do_parse(h, argc, argv, &p, &cs, &args);
- switch (command) {
+ switch (p.command) {
case CMD_APPEND:
- ret = add_entry(chain, *table, &cs, 0, h->family,
- args.s, args.d, cs.options&OPT_VERBOSE,
- h, true);
+ ret = add_entry(p.chain, p.table, &cs, 0, h->family,
+ args.s, args.d,
+ cs.options & OPT_VERBOSE, h, true);
break;
case CMD_DELETE:
- ret = delete_entry(chain, *table, &cs, h->family,
- args.s, args.d, cs.options&OPT_VERBOSE, h);
+ ret = delete_entry(p.chain, p.table, &cs, h->family,
+ args.s, args.d,
+ cs.options & OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
- ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
+ ret = nft_rule_delete_num(h, p.chain, p.table,
+ p.rulenum - 1, p.verbose);
break;
case CMD_CHECK:
- ret = check_entry(chain, *table, &cs, h->family,
- args.s, args.d, cs.options&OPT_VERBOSE, h);
+ ret = check_entry(p.chain, p.table, &cs, h->family,
+ args.s, args.d,
+ cs.options & OPT_VERBOSE, h);
break;
case CMD_REPLACE:
- ret = replace_entry(chain, *table, &cs, rulenum - 1,
+ ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1,
h->family, args.s, args.d,
- cs.options&OPT_VERBOSE, h);
+ cs.options & OPT_VERBOSE, h);
break;
case CMD_INSERT:
- ret = add_entry(chain, *table, &cs, rulenum - 1, h->family,
- args.s, args.d, cs.options&OPT_VERBOSE, h,
- false);
+ ret = add_entry(p.chain, p.table, &cs, p.rulenum - 1,
+ h->family, args.s, args.d,
+ cs.options&OPT_VERBOSE, h, false);
break;
case CMD_FLUSH:
- ret = nft_rule_flush(h, chain, *table);
+ ret = nft_rule_flush(h, p.chain, p.table);
break;
case CMD_ZERO:
- ret = nft_chain_zero_counters(h, chain, *table);
+ ret = nft_chain_zero_counters(h, p.chain, p.table);
break;
case CMD_ZERO_NUM:
- ret = nft_rule_zero_counters(h, chain, *table, rulenum - 1);
+ ret = nft_rule_zero_counters(h, p.chain, p.table,
+ p.rulenum - 1);
break;
case CMD_LIST:
case CMD_LIST|CMD_ZERO:
case CMD_LIST|CMD_ZERO_NUM:
- ret = list_entries(h, chain, *table,
- rulenum,
- cs.options&OPT_VERBOSE,
- cs.options&OPT_NUMERIC,
- cs.options&OPT_EXPANDED,
- cs.options&OPT_LINENUMBERS);
- if (ret && (command & CMD_ZERO))
- ret = nft_chain_zero_counters(h, chain, *table);
- if (ret && (command & CMD_ZERO_NUM))
- ret = nft_rule_zero_counters(h, chain, *table,
- rulenum - 1);
+ ret = list_entries(h, p.chain, p.table, p.rulenum,
+ cs.options & OPT_VERBOSE,
+ cs.options & OPT_NUMERIC,
+ cs.options & OPT_EXPANDED,
+ cs.options & OPT_LINENUMBERS);
+ if (ret && (p.command & CMD_ZERO)) {
+ ret = nft_chain_zero_counters(h, p.chain,
+ p.table);
+ }
+ if (ret && (p.command & CMD_ZERO_NUM)) {
+ ret = nft_rule_zero_counters(h, p.chain, p.table,
+ p.rulenum - 1);
+ }
break;
case CMD_LIST_RULES:
case CMD_LIST_RULES|CMD_ZERO:
case CMD_LIST_RULES|CMD_ZERO_NUM:
- ret = list_rules(h, chain, *table, rulenum, cs.options&OPT_VERBOSE);
- if (ret && (command & CMD_ZERO))
- ret = nft_chain_zero_counters(h, chain, *table);
- if (ret && (command & CMD_ZERO_NUM))
- ret = nft_rule_zero_counters(h, chain, *table,
- rulenum - 1);
+ ret = list_rules(h, p.chain, p.table, p.rulenum,
+ cs.options & OPT_VERBOSE);
+ if (ret && (p.command & CMD_ZERO)) {
+ ret = nft_chain_zero_counters(h, p.chain,
+ p.table);
+ }
+ if (ret && (p.command & CMD_ZERO_NUM)) {
+ ret = nft_rule_zero_counters(h, p.chain, p.table,
+ p.rulenum - 1);
+ }
break;
case CMD_NEW_CHAIN:
- ret = nft_chain_user_add(h, chain, *table);
+ ret = nft_chain_user_add(h, p.chain, p.table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_chain_user_del(h, chain, *table);
+ ret = nft_chain_user_del(h, p.chain, p.table);
break;
case CMD_RENAME_CHAIN:
- ret = nft_chain_user_rename(h, chain, *table, newname);
+ ret = nft_chain_user_rename(h, p.chain, p.table, p.newname);
break;
case CMD_SET_POLICY:
- ret = nft_chain_set(h, *table, chain, policy, NULL);
+ ret = nft_chain_set(h, p.table, p.chain, p.policy, NULL);
if (ret < 0)
xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
- policy);
+ p.policy);
break;
default:
/* We should never reach this... */
exit_tryhelp(2);
}
-/* if (verbose > 1)
- dump_entries(*handle); */
+ *table = p.table;
xtables_rule_matches_free(&cs.matches);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/5] nft: xtables-restore: add generic parsing infrastructure
2014-04-14 10:41 [RFC PATCH 0/5] translations from iptables to nft Pablo Neira Ayuso
2014-04-14 10:41 ` [PATCH 1/5] nft: xtables: add generic parsing infrastructure to interpret commands Pablo Neira Ayuso
@ 2014-04-14 10:41 ` Pablo Neira Ayuso
2014-04-14 10:41 ` [PATCH 3/5] nft: xtables: add the infrastructure to translate from iptables to nft Pablo Neira Ayuso
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2014-04-14 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
This allows us to reuse the xtables-restore parser code in the
translation infrastructure.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
iptables/nft-shared.h | 35 ++++++
iptables/xtables-restore.c | 271 ++++++++++++++++++++++++++------------------
2 files changed, 195 insertions(+), 111 deletions(-)
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index d4bc31e..584cd5f 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -190,6 +190,41 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
struct nft_xt_cmd_parse *p, struct iptables_command_state *cs,
struct xtables_args *args);
+struct nft_xt_restore_parse {
+ FILE *in;
+ int testing;
+ const char *tablename;
+};
+
+struct nft_chain_list;
+
+struct nft_xt_restore_cb {
+ void (*table_new)(struct nft_handle *h, const char *table);
+ struct nft_chain_list *(*chain_list)(struct nft_handle *h);
+ int (*chains_purge)(struct nft_handle *h, const char *table,
+ struct nft_chain_list *clist);
+ void (*chain_del)(struct nft_chain_list *clist, const char *curtable,
+ const char *chain);
+ int (*chain_set)(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy,
+ const struct xt_counters *counters);
+ int (*chain_user_add)(struct nft_handle *h, const char *chain,
+ const char *table);
+
+ int (*rule_flush)(struct nft_handle *h, const char *chain, const char *table);
+
+ int (*do_command)(struct nft_handle *h, int argc, char *argv[],
+ char **table, bool restore);
+
+ int (*commit)(struct nft_handle *h);
+ int (*abort)(struct nft_handle *h);
+};
+
+void xtables_restore_parse(struct nft_handle *h,
+ struct nft_xt_restore_parse *p,
+ struct nft_xt_restore_cb *cb,
+ int argc, char *argv[]);
+
/*
* ARP
*/
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 3cb095f..f5e4553 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -159,107 +159,62 @@ static void add_param_to_argv(char *parsestart)
}
}
+static struct nft_chain_list *get_chain_list(struct nft_handle *h)
+{
+ struct nft_chain_list *chain_list;
+
+ chain_list = nft_chain_dump(h);
+ if (chain_list == NULL)
+ xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n");
+
+ return chain_list;
+}
+
+static void chain_delete(struct nft_chain_list *clist, const char *curtable,
+ const char *chain)
+{
+ struct nft_chain *chain_obj;
+
+ chain_obj = nft_chain_list_find(clist, curtable, chain);
+ /* This chain has been found, delete from list. Later
+ * on, unvisited chains will be purged out.
+ */
+ if (chain_obj != NULL)
+ nft_chain_list_del(chain_obj);
+}
+
+struct nft_xt_restore_cb restore_cb = {
+ .chain_list = get_chain_list,
+ .commit = nft_commit,
+ .abort = nft_abort,
+ .chains_purge = nft_table_purge_chains,
+ .rule_flush = nft_rule_flush,
+ .chain_del = chain_delete,
+ .do_command = do_commandx,
+ .chain_set = nft_chain_set,
+ .chain_user_add = nft_chain_user_add,
+};
+
static const struct xtc_ops xtc_ops = {
.strerror = nft_strerror,
};
-static int
-xtables_restore_main(int family, const char *progname, int argc, char *argv[])
+void xtables_restore_parse(struct nft_handle *h,
+ struct nft_xt_restore_parse *p,
+ struct nft_xt_restore_cb *cb,
+ int argc, char *argv[])
{
- struct nft_handle h = {
- .family = family,
- .restore = true,
- };
char buffer[10240];
- int c;
+ int in_table = 0;
char curtable[XT_TABLE_MAXNAMELEN + 1];
- FILE *in;
- int in_table = 0, testing = 0;
- const char *tablename = NULL;
const struct xtc_ops *ops = &xtc_ops;
- struct nft_chain_list *chain_list;
- struct nft_chain *chain_obj;
-
- line = 0;
-
- xtables_globals.program_name = progname;
- c = xtables_init_all(&xtables_globals, family);
- if (c < 0) {
- fprintf(stderr, "%s/%s Failed to initialize xtables\n",
- xtables_globals.program_name,
- xtables_globals.program_version);
- exit(1);
- }
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
- init_extensions4();
-#endif
-
- if (nft_init(&h, xtables_ipv4) < 0) {
- fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
- xtables_globals.program_name,
- xtables_globals.program_version,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
+ struct nft_chain_list *chain_list = NULL;
- while ((c = getopt_long(argc, argv, "bcvthnM:T:46", options, NULL)) != -1) {
- switch (c) {
- case 'b':
- fprintf(stderr, "-b/--binary option is not implemented\n");
- break;
- case 'c':
- counters = 1;
- break;
- case 'v':
- verbose = 1;
- break;
- case 't':
- testing = 1;
- break;
- case 'h':
- print_usage("xtables-restore",
- IPTABLES_VERSION);
- break;
- case 'n':
- noflush = 1;
- break;
- case 'M':
- xtables_modprobe_program = optarg;
- break;
- case 'T':
- tablename = optarg;
- break;
- case '4':
- h.family = AF_INET;
- break;
- case '6':
- h.family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
- break;
- }
- }
-
- if (optind == argc - 1) {
- in = fopen(argv[optind], "re");
- if (!in) {
- fprintf(stderr, "Can't open %s: %s\n", argv[optind],
- strerror(errno));
- exit(1);
- }
- }
- else if (optind < argc) {
- fprintf(stderr, "Unknown arguments found on commandline\n");
- exit(1);
- }
- else in = stdin;
-
- chain_list = nft_chain_dump(&h);
- if (chain_list == NULL)
- xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n");
+ if (cb->chain_list)
+ chain_list = cb->chain_list(h);
/* Grab standard input. */
- while (fgets(buffer, sizeof(buffer), in)) {
+ while (fgets(buffer, sizeof(buffer), p->in)) {
int ret = 0;
line++;
@@ -270,22 +225,24 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
fputs(buffer, stdout);
continue;
} else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
- if (!testing) {
+ if (!p->testing) {
/* Commit per table, although we support
* global commit at once, stick by now to
* the existing behaviour.
*/
DEBUGP("Calling commit\n");
- ret = nft_commit(&h);
+ if (cb->commit)
+ ret = cb->commit(h);
} else {
DEBUGP("Not calling commit, testing\n");
- ret = nft_abort(&h);
+ if (cb->abort)
+ ret = cb->abort(h);
}
in_table = 0;
/* Purge out unused chains in this table */
- if (!testing)
- nft_table_purge_chains(&h, curtable, chain_list);
+ if (!p->testing && cb->chains_purge)
+ cb->chains_purge(h, curtable, chain_list);
} else if ((buffer[0] == '*') && (!in_table)) {
/* New table */
@@ -302,18 +259,22 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
strncpy(curtable, table, XT_TABLE_MAXNAMELEN);
curtable[XT_TABLE_MAXNAMELEN] = '\0';
- if (tablename && (strcmp(tablename, table) != 0))
+ if (p->tablename && (strcmp(p->tablename, table) != 0))
continue;
if (noflush == 0) {
DEBUGP("Cleaning all chains of table '%s'\n",
table);
- nft_rule_flush(&h, NULL, table);
+ if (cb->rule_flush)
+ cb->rule_flush(h, NULL, table);
}
ret = 1;
in_table = 1;
+ if (cb->table_new)
+ cb->table_new(h, table);
+
} else if ((buffer[0] == ':') && (in_table)) {
/* New chain. */
char *policy, *chain = NULL;
@@ -328,13 +289,8 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
exit(1);
}
- chain_obj = nft_chain_list_find(chain_list,
- curtable, chain);
- /* This chain has been found, delete from list. Later
- * on, unvisited chains will be purged out.
- */
- if (chain_obj != NULL)
- nft_chain_list_del(chain_obj);
+ if (cb->chain_del)
+ cb->chain_del(chain_list, curtable, chain);
if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
@@ -362,7 +318,8 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
"for chain '%s'\n", chain);
}
- if (nft_chain_set(&h, curtable, chain, policy, &count) < 0) {
+ if (cb->chain_set &&
+ cb->chain_set(h, curtable, chain, policy, &count) < 0) {
xtables_error(OTHER_PROBLEM,
"Can't set policy `%s'"
" on `%s' line %u: %s\n",
@@ -374,7 +331,8 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
ret = 1;
} else {
- if (nft_chain_user_add(&h, chain, curtable) < 0) {
+ if (cb->chain_user_add &&
+ cb->chain_user_add(h, chain, curtable) < 0) {
if (errno == EEXIST)
continue;
@@ -441,10 +399,14 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
for (a = 0; a < newargc; a++)
DEBUGP("argv[%u]: %s\n", a, newargv[a]);
- ret = do_commandx(&h, newargc, newargv,
- &newargv[2], true);
+ ret = cb->do_command(h, newargc, newargv,
+ &newargv[2], true);
if (ret < 0) {
- ret = nft_abort(&h);
+ if (cb->abort)
+ ret = cb->abort(h);
+ else
+ ret = 0;
+
if (ret < 0) {
fprintf(stderr, "failed to abort "
"commit operation\n");
@@ -455,7 +417,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
free_argv();
fflush(stdout);
}
- if (tablename && (strcmp(tablename, curtable) != 0))
+ if (p->tablename && (strcmp(p->tablename, curtable) != 0))
continue;
if (!ret) {
fprintf(stderr, "%s: line %u failed\n",
@@ -468,8 +430,95 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
xt_params->program_name, line + 1);
exit(1);
}
+}
+
+static int
+xtables_restore_main(int family, const char *progname, int argc, char *argv[])
+{
+ struct nft_handle h = {
+ .family = family,
+ .restore = true,
+ };
+ int c;
+ struct nft_xt_restore_parse p = {};
+
+ line = 0;
+
+ xtables_globals.program_name = progname;
+ c = xtables_init_all(&xtables_globals, family);
+ if (c < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize xtables\n",
+ xtables_globals.program_name,
+ xtables_globals.program_version);
+ exit(1);
+ }
+#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
+ init_extensions4();
+#endif
+
+ if (nft_init(&h, xtables_ipv4) < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
+ xtables_globals.program_name,
+ xtables_globals.program_version,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ while ((c = getopt_long(argc, argv, "bcvthnM:T:46", options, NULL)) != -1) {
+ switch (c) {
+ case 'b':
+ fprintf(stderr, "-b/--binary option is not implemented\n");
+ break;
+ case 'c':
+ counters = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 't':
+ p.testing = 1;
+ break;
+ case 'h':
+ print_usage("xtables-restore",
+ IPTABLES_VERSION);
+ break;
+ case 'n':
+ noflush = 1;
+ break;
+ case 'M':
+ xtables_modprobe_program = optarg;
+ break;
+ case 'T':
+ p.tablename = optarg;
+ break;
+ case '4':
+ h.family = AF_INET;
+ break;
+ case '6':
+ h.family = AF_INET6;
+ xtables_set_nfproto(AF_INET6);
+ break;
+ }
+ }
+
+ if (optind == argc - 1) {
+ p.in = fopen(argv[optind], "re");
+ if (!p.in) {
+ fprintf(stderr, "Can't open %s: %s\n", argv[optind],
+ strerror(errno));
+ exit(1);
+ }
+ } else if (optind < argc) {
+ fprintf(stderr, "Unknown arguments found on commandline\n");
+ exit(1);
+ } else {
+ p.in = stdin;
+ }
+
+ xtables_restore_parse(&h, &p, &restore_cb, argc, argv);
- fclose(in);
+ fclose(p.in);
return 0;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/5] nft: xtables: add the infrastructure to translate from iptables to nft
2014-04-14 10:41 [RFC PATCH 0/5] translations from iptables to nft Pablo Neira Ayuso
2014-04-14 10:41 ` [PATCH 1/5] nft: xtables: add generic parsing infrastructure to interpret commands Pablo Neira Ayuso
2014-04-14 10:41 ` [PATCH 2/5] nft: xtables-restore: add generic parsing infrastructure Pablo Neira Ayuso
@ 2014-04-14 10:41 ` Pablo Neira Ayuso
2014-04-14 10:41 ` [PATCH 4/5] extensions: libxt_tcp: add translation " Pablo Neira Ayuso
2014-04-14 10:41 ` [PATCH 5/5] extensions: libxt_state: " Pablo Neira Ayuso
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2014-04-14 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
This patch provides the infrastructure and two new utilities to
translate iptables commands to nft, they are:
1) iptables-restore-translate which basically takes a file that contains
the ruleset in iptables-restore format and converts it to the nft
syntax, eg.
% iptables-restore-translate -f ipt-ruleset > nft-ruleset
% cat nft-ruleset
# Translated by iptables-restore-translate v1.4.21 on Mon Apr 14 12:18:14 2014
add table ip filter
add chain ip filter INPUT { type filter hook input priority 0; }
add chain ip filter FORWARD { type filter hook forward priority 0; }
add chain ip filter OUTPUT { type filter hook output priority 0; }
add rule ip filter INPUT iifname lo counter accept
# -t filter -A INPUT -m state --state INVALID -j LOG --log-prefix invalid:
...
The rules that cannot be translated are left commented. Users should be able
to run this to track down the nft progress to see at what point it can fully
replace iptables and their filtering policy.
2) iptables-translate which suggests a translation for an iptables
command:
$ iptables-translate -I OUTPUT -p udp -d 8.8.8.8 -j ACCEPT
nft add rule filter OUTPUT ip protocol udp ip dst 8.8.8.8 counter accept
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/xtables.h | 14 ++
iptables/Makefile.am | 3 +
iptables/nft-ipv4.c | 64 +++++-
iptables/nft-ipv6.c | 65 +++++-
iptables/nft-shared.h | 2 +
iptables/nft.h | 10 +
iptables/xtables-compat-multi.c | 4 +
iptables/xtables-multi.h | 4 +
iptables/xtables-translate.c | 459 +++++++++++++++++++++++++++++++++++++++
libxtables/xtables.c | 51 +++++
10 files changed, 674 insertions(+), 2 deletions(-)
create mode 100644 iptables/xtables-translate.c
diff --git a/include/xtables.h b/include/xtables.h
index bad11a8..2d78cbf 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -205,6 +205,8 @@ enum xtables_ext_flags {
XTABLES_EXT_ALIAS = 1 << 0,
};
+struct xt_buf;
+
/* Include file for additions: new matches and targets. */
struct xtables_match
{
@@ -269,6 +271,9 @@ struct xtables_match
void (*x6_fcheck)(struct xt_fcheck_call *);
const struct xt_option_entry *x6_options;
+ /* Translate iptables to nft */
+ int (*xlate)(const struct xt_entry_match *match, struct xt_buf *buf);
+
/* Size of per-extension instance extra "global" scratch space */
size_t udata_size;
@@ -346,6 +351,9 @@ struct xtables_target
void (*x6_fcheck)(struct xt_fcheck_call *);
const struct xt_option_entry *x6_options;
+ /* Translate iptables to nft */
+ int (*xlate)(const struct xt_entry_target *target, struct xt_buf *buf);
+
size_t udata_size;
/* Ignore these men behind the curtain: */
@@ -548,6 +556,12 @@ extern void xtables_lmap_free(struct xtables_lmap *);
extern int xtables_lmap_name2id(const struct xtables_lmap *, const char *);
extern const char *xtables_lmap_id2name(const struct xtables_lmap *, int);
+/* generic buffer */
+struct xt_buf *xt_buf_alloc(int size);
+void xt_buf_free(struct xt_buf *buf);
+void xt_buf_add(struct xt_buf *buf, const char *fmt, ...);
+const char *xt_buf_get(struct xt_buf *buf);
+
#ifdef XTABLES_INTERNAL
/* Shipped modules rely on this... */
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index 41bca7c..5ede3fc 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -38,6 +38,7 @@ xtables_compat_multi_SOURCES += xtables-config-parser.y xtables-config-syntax.l
xtables_compat_multi_SOURCES += xtables-save.c xtables-restore.c \
xtables-standalone.c xtables.c nft.c \
nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \
+ xtables-translate.c \
xtables-config.c xtables-events.c \
xtables-arp-standalone.c xtables-arp.c
xtables_compat_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS}
@@ -67,6 +68,8 @@ endif
if ENABLE_NFTABLES
x_sbin_links = iptables-compat iptables-compat-restore iptables-compat-save \
ip6tables-compat ip6tables-compat-restore ip6tables-compat-save \
+ iptables-translate ip6tables-translate \
+ iptables-restore-translate ip6tables-restore-translate \
arptables-compat xtables-config xtables-events
endif
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index d05e80e..f59f630 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -1,5 +1,5 @@
/*
- * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org>
* (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,6 +17,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
+#include <netdb.h>
#include <xtables.h>
@@ -409,6 +410,66 @@ static bool nft_ipv4_rule_find(struct nft_family_ops *ops,
return nft_ipv46_rule_find(ops, r, cs);
}
+static int nft_ipv4_xlate(const void *data, struct xt_buf *buf)
+{
+ const struct iptables_command_state *cs = data;
+ int ret;
+
+ if (cs->fw.ip.iniface[0] != '\0') {
+ xt_buf_add(buf, "iifname %s%s ",
+ cs->fw.ip.invflags & IPT_INV_VIA_IN ? "!= " : "",
+ cs->fw.ip.iniface);
+ }
+ if (cs->fw.ip.outiface[0] != '\0') {
+ xt_buf_add(buf, "oifname %s%s ",
+ cs->fw.ip.invflags & IPT_INV_VIA_OUT? "!= " : "",
+ cs->fw.ip.outiface);
+ }
+
+ if (cs->fw.ip.flags & IPT_F_FRAG) {
+ xt_buf_add(buf, "ip frag-off %s%x ",
+ cs->fw.ip.invflags & IPT_INV_FRAG? "" : "!= ", 0);
+ }
+
+ if (cs->fw.ip.proto != 0) {
+ const struct protoent *pent =
+ getprotobynumber(cs->fw.ip.proto);
+ char protonum[strlen("255") + 1];
+
+ if (!xlate_find_match(cs, pent->p_name)) {
+ snprintf(protonum, sizeof(protonum), "%u",
+ cs->fw.ip.proto);
+ protonum[sizeof(protonum) - 1] = '\0';
+ xt_buf_add(buf, "ip protocol %s%s ",
+ cs->fw.ip.invflags & IPT_INV_PROTO ?
+ "!= " : "",
+ pent ? pent->p_name : protonum);
+ }
+ }
+
+ if (cs->fw.ip.src.s_addr != 0) {
+ xt_buf_add(buf, "ip saddr %s%s ",
+ cs->fw.ip.invflags & IPT_INV_SRCIP ? "!= " : "",
+ inet_ntoa(cs->fw.ip.src));
+ }
+ if (cs->fw.ip.dst.s_addr != 0) {
+ xt_buf_add(buf, "ip daddr %s%s ",
+ cs->fw.ip.invflags & IPT_INV_DSTIP ? "!= " : "",
+ inet_ntoa(cs->fw.ip.dst));
+ }
+
+ ret = xlate_matches(cs, buf);
+ if (!ret)
+ return ret;
+
+ /* Always add counters per rule, as in iptables */
+ xt_buf_add(buf, "counter ");
+
+ ret = xlate_action(cs, !!(cs->fw.ip.flags & IPT_F_GOTO), buf);
+
+ return ret;
+}
+
struct nft_family_ops nft_family_ops_ipv4 = {
.add = nft_ipv4_add,
.is_same = nft_ipv4_is_same,
@@ -421,4 +482,5 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.post_parse = nft_ipv4_post_parse,
.parse_target = nft_ipv4_parse_target,
.rule_find = nft_ipv4_rule_find,
+ .xlate = nft_ipv4_xlate,
};
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index f08598a..3890848 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -1,5 +1,5 @@
/*
- * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org>
* (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,6 +17,7 @@
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip6.h>
+#include <netdb.h>
#include <xtables.h>
@@ -330,6 +331,67 @@ static bool nft_ipv6_rule_find(struct nft_family_ops *ops,
return nft_ipv46_rule_find(ops, r, cs);
}
+static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr,
+ int invert, struct xt_buf *buf)
+{
+ char addr_str[INET6_ADDRSTRLEN];
+
+ if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr))
+ return;
+
+ inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
+ xt_buf_add(buf, "%s %s%s ", selector, invert ? "!= " : "", addr_str);
+}
+
+static int nft_ipv6_xlate(const void *data, struct xt_buf *buf)
+{
+ const struct iptables_command_state *cs = data;
+ int ret;
+
+ if (cs->fw6.ipv6.iniface[0] != '\0') {
+ xt_buf_add(buf, "iifname %s%s ",
+ cs->fw6.ipv6.invflags & IP6T_INV_VIA_IN ?
+ "!= " : "",
+ cs->fw6.ipv6.iniface);
+ }
+ if (cs->fw6.ipv6.outiface[0] != '\0') {
+ xt_buf_add(buf, "oifname %s%s ",
+ cs->fw6.ipv6.invflags & IP6T_INV_VIA_OUT ?
+ "!= " : "",
+ cs->fw6.ipv6.outiface);
+ }
+
+ if (cs->fw6.ipv6.proto != 0) {
+ const struct protoent *pent =
+ getprotobynumber(cs->fw6.ipv6.proto);
+ char protonum[strlen("255") + 1];
+
+ if (!xlate_find_match(cs, pent->p_name)) {
+ snprintf(protonum, sizeof(protonum), "%u",
+ cs->fw6.ipv6.proto);
+ protonum[sizeof(protonum) - 1] = '\0';
+ xt_buf_add(buf, "ip protocol %s%s ",
+ cs->fw6.ipv6.invflags & IP6T_INV_PROTO ?
+ "!= " : "",
+ pent ? pent->p_name : protonum);
+ }
+ }
+
+ xlate_ipv6_addr("saddr", &cs->fw6.ipv6.src, IP6T_INV_SRCIP, buf);
+ xlate_ipv6_addr("daddr", &cs->fw6.ipv6.dst, IP6T_INV_DSTIP, buf);
+
+ ret = xlate_matches(cs, buf);
+ if (!ret)
+ return ret;
+
+ /* Always add counters per rule, as in iptables */
+ xt_buf_add(buf, "counter ");
+
+ ret = xlate_action(cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO), buf);
+
+ return ret;
+}
+
struct nft_family_ops nft_family_ops_ipv6 = {
.add = nft_ipv6_add,
.is_same = nft_ipv6_is_same,
@@ -342,4 +404,5 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.post_parse = nft_ipv6_post_parse,
.parse_target = nft_ipv6_parse_target,
.rule_find = nft_ipv6_rule_find,
+ .xlate = nft_ipv6_xlate,
};
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 584cd5f..8d2faf2 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -35,6 +35,7 @@
#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
struct xtables_args;
+struct xt_buf;
struct nft_family_ops {
int (*add)(struct nft_rule *r, void *data);
@@ -57,6 +58,7 @@ struct nft_family_ops {
void (*parse_target)(struct xtables_target *t, void *data);
bool (*rule_find)(struct nft_family_ops *ops, struct nft_rule *r,
void *data);
+ int (*xlate)(const void *data, struct xt_buf *buf);
};
void add_meta(struct nft_rule *r, uint32_t key);
diff --git a/iptables/nft.h b/iptables/nft.h
index c31371c..31c04f3 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -158,6 +158,16 @@ enum {
int nft_xtables_config_load(struct nft_handle *h, const char *filename, uint32_t flags);
/*
+ * Translation from iptables to nft
+ */
+struct xt_buf;
+
+bool xlate_find_match(const struct iptables_command_state *cs, const char *p_name);
+int xlate_matches(const struct iptables_command_state *cs, struct xt_buf *buf);
+int xlate_action(const struct iptables_command_state *cs, bool goto_set,
+ struct xt_buf *buf);
+
+/*
* ARP
*/
diff --git a/iptables/xtables-compat-multi.c b/iptables/xtables-compat-multi.c
index 4781052..bb21e69 100644
--- a/iptables/xtables-compat-multi.c
+++ b/iptables/xtables-compat-multi.c
@@ -26,6 +26,10 @@ static const struct subcommand multi_subcommands[] = {
{"ip6tables-restore", xtables_ip6_restore_main},
{"ip6tables-compat-save", xtables_ip6_save_main},
{"ip6tables-compat-restore", xtables_ip6_restore_main},
+ {"iptables-translate", xtables_ip4_xlate_main},
+ {"ip6tables-translate", xtables_ip6_xlate_main},
+ {"iptables-restore-translate", xtables_ip4_xlate_restore_main},
+ {"ip6tables-restore-translate", xtables_ip6_xlate_restore_main},
{"arptables", xtables_arp_main},
{"arptables-compat", xtables_arp_main},
{"xtables-config", xtables_config_main},
diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h
index e706894..022b2ad 100644
--- a/iptables/xtables-multi.h
+++ b/iptables/xtables-multi.h
@@ -9,6 +9,10 @@ extern int xtables_ip4_restore_main(int, char **);
extern int xtables_ip6_main(int, char **);
extern int xtables_ip6_save_main(int, char **);
extern int xtables_ip6_restore_main(int, char **);
+extern int xtables_ip4_xlate_main(int, char **);
+extern int xtables_ip6_xlate_main(int, char **);
+extern int xtables_ip4_xlate_restore_main(int, char **);
+extern int xtables_ip6_xlate_restore_main(int, char **);
extern int xtables_arp_main(int, char **);
extern int xtables_config_main(int, char **);
extern int xtables_events_main(int, char **);
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
new file mode 100644
index 0000000..c7fb2df
--- /dev/null
+++ b/iptables/xtables-translate.c
@@ -0,0 +1,459 @@
+/*
+ * (C) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <iptables.h>
+#include <time.h>
+#include "xtables-multi.h"
+#include "nft.h"
+
+#include <string.h>
+#include <netdb.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <unistd.h>
+#include <iptables.h>
+#include <xtables.h>
+#include <libiptc/libxtc.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include "xshared.h"
+#include "nft-shared.h"
+
+int xlate_action(const struct iptables_command_state *cs, bool goto_set,
+ struct xt_buf *buf)
+{
+ int ret = 1;
+
+ /* If no target at all, add nothing (default to continue) */
+ if (cs->target != NULL) {
+ /* Standard target? */
+ if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
+ xt_buf_add(buf, "accept");
+ else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
+ xt_buf_add(buf, "drop");
+ else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
+ xt_buf_add(buf, "return");
+ else if (cs->target->xlate)
+ ret = cs->target->xlate(cs->target->t, buf);
+ else
+ return 0;
+ } else if (strlen(cs->jumpto) > 0) {
+ /* Not standard, then it's a go / jump to chain */
+ if (goto_set)
+ xt_buf_add(buf, "goto %s", cs->jumpto);
+ else
+ xt_buf_add(buf, "jump %s", cs->jumpto);
+ }
+
+ return ret;
+}
+
+int xlate_matches(const struct iptables_command_state *cs, struct xt_buf *buf)
+{
+ struct xtables_rule_match *matchp;
+ int ret = 1;
+
+ for (matchp = cs->matches; matchp; matchp = matchp->next) {
+ if (!matchp->match->xlate)
+ return 0;
+
+ ret = matchp->match->xlate(matchp->match->m, buf);
+ if (!ret)
+ break;
+ }
+ return ret;
+}
+
+bool xlate_find_match(const struct iptables_command_state *cs, const char *p_name)
+{
+ struct xtables_rule_match *matchp;
+
+ /* Skip redundant protocol, eg. ip protocol tcp tcp dport */
+ for (matchp = cs->matches; matchp; matchp = matchp->next) {
+ if (strcmp(matchp->match->name, p_name) == 0)
+ return true;
+ }
+ return false;
+}
+
+const char *family2str[] = {
+ [NFPROTO_IPV4] = "ip",
+ [NFPROTO_IPV6] = "ip6",
+};
+
+static int nft_rule_xlate_add(struct nft_handle *h,
+ const struct nft_xt_cmd_parse *p,
+ const struct iptables_command_state *cs,
+ bool append)
+{
+ struct xt_buf *buf = xt_buf_alloc(10240);
+ int ret;
+
+ if (append) {
+ xt_buf_add(buf, "add rule %s %s %s ",
+ family2str[h->family], p->table, p->chain);
+ } else {
+ xt_buf_add(buf, "insert rule %s %s %s ",
+ family2str[h->family], p->table, p->chain);
+ }
+
+ ret = h->ops->xlate(cs, buf);
+ if (ret)
+ printf("%s\n", xt_buf_get(buf));
+
+ xt_buf_free(buf);
+ return ret;
+}
+
+static int xlate(struct nft_handle *h, struct nft_xt_cmd_parse *p,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool append,
+ int (*cb)(struct nft_handle *h,
+ const struct nft_xt_cmd_parse *p,
+ const struct iptables_command_state *cs,
+ bool append))
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ switch (h->family) {
+ case AF_INET:
+ cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->fw.ip.dst.s_addr =
+ args->d.addr.v4[j].s_addr;
+ cs->fw.ip.dmsk.s_addr =
+ args->d.mask.v4[j].s_addr;
+ ret = cb(h, p, cs, append);
+ }
+ break;
+ case AF_INET6:
+ memcpy(&cs->fw6.ipv6.src,
+ &args->s.addr.v6[i], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk,
+ &args->s.mask.v6[i], sizeof(struct in6_addr));
+ for (j = 0; j < args->d.naddrs; j++) {
+ memcpy(&cs->fw6.ipv6.dst,
+ &args->d.addr.v6[j],
+ sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk,
+ &args->d.mask.v6[j],
+ sizeof(struct in6_addr));
+ ret = cb(h, p, cs, append);
+ }
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void print_ipt_cmd(int argc, char *argv[])
+{
+ int i;
+
+ printf("# ");
+ for (i = 1; i < argc; i++)
+ printf("%s ", argv[i]);
+
+ printf("\n");
+}
+
+static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
+ char **table, bool restore)
+{
+ int ret = 0;
+ struct nft_xt_cmd_parse p = {
+ .table = *table,
+ .restore = restore,
+ };
+ struct iptables_command_state cs;
+ struct xtables_args args = {
+ .family = h->family,
+ };
+
+ do_parse(h, argc, argv, &p, &cs, &args);
+
+ switch (p.command) {
+ case CMD_APPEND:
+ ret = 1;
+ if (!xlate(h, &p, &cs, &args, true, nft_rule_xlate_add))
+ print_ipt_cmd(argc, argv);
+ break;
+ case CMD_DELETE:
+ break;
+ case CMD_DELETE_NUM:
+ break;
+ case CMD_CHECK:
+ break;
+ case CMD_REPLACE:
+ break;
+ case CMD_INSERT:
+ ret = 1;
+ if (!xlate(h, &p, &cs, &args, false, nft_rule_xlate_add))
+ print_ipt_cmd(argc, argv);
+ break;
+ case CMD_FLUSH:
+ break;
+ case CMD_ZERO:
+ break;
+ case CMD_ZERO_NUM:
+ break;
+ case CMD_LIST:
+ case CMD_LIST|CMD_ZERO:
+ case CMD_LIST|CMD_ZERO_NUM:
+ printf("list table %s %s\n",
+ family2str[h->family], p.table);
+ ret = 1;
+ break;
+ case CMD_LIST_RULES:
+ case CMD_LIST_RULES|CMD_ZERO:
+ case CMD_LIST_RULES|CMD_ZERO_NUM:
+ break;
+ case CMD_NEW_CHAIN:
+ printf("add chain %s %s %s\n",
+ family2str[h->family], p.table, p.chain);
+ ret = 1;
+ break;
+ case CMD_DELETE_CHAIN:
+ printf("delete chain %s %s %s\n",
+ family2str[h->family], p.table, p.chain);
+ ret = 1;
+ break;
+ case CMD_RENAME_CHAIN:
+ break;
+ case CMD_SET_POLICY:
+ break;
+ default:
+ /* We should never reach this... */
+ printf("Unsupported command?\n");
+ exit(1);
+ }
+
+ xtables_rule_matches_free(&cs.matches);
+
+ if (h->family == AF_INET) {
+ free(args.s.addr.v4);
+ free(args.s.mask.v4);
+ free(args.d.addr.v4);
+ free(args.d.mask.v4);
+ } else if (h->family == AF_INET6) {
+ free(args.s.addr.v6);
+ free(args.s.mask.v6);
+ free(args.d.addr.v6);
+ free(args.d.mask.v6);
+ }
+ xtables_free_opts(1);
+
+ return ret;
+}
+
+static void print_usage(const char *name, const char *version)
+{
+ fprintf(stderr, "%s %s "
+ "(c) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>\n"
+ "Usage: %s [-h] [-f]\n"
+ " [ --help ]\n"
+ " [ --file=<FILE> ]\n", name, version, name);
+ exit(1);
+}
+
+static const struct option options[] = {
+ { .name = "help", .has_arg = false, .val = 'h' },
+ { .name = "file", .has_arg = true, .val = 'f' },
+ { NULL },
+};
+
+static int xlate_chain_user_add(struct nft_handle *h, const char *chain,
+ const char *table)
+{
+ printf("add chain %s %s %s\n", family2str[h->family], chain, table);
+ return 0;
+}
+
+static int commit(struct nft_handle *h)
+{
+ return 1;
+}
+
+static void xlate_table_new(struct nft_handle *h, const char *table)
+{
+ printf("add table %s %s\n", family2str[h->family], table);
+}
+
+static int xlate_chain_set(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy,
+ const struct xt_counters *counters)
+{
+ printf("add chain %s %s %s ", family2str[h->family], table, chain);
+ if (strcmp(chain, "PREROUTING") == 0)
+ printf("{ type filter hook prerouting priority 0; }\n");
+ else if (strcmp(chain, "INPUT") == 0)
+ printf("{ type filter hook input priority 0; }\n");
+ else if (strcmp(chain, "FORWARD") == 0)
+ printf("{ type filter hook forward priority 0; }\n");
+ else if (strcmp(chain, "OUTPUT") == 0)
+ printf("{ type filter hook output priority 0; }\n");
+ else if (strcmp(chain, "POSTROUTING") == 0)
+ printf("{ type filter hook postrouting priority 0; }\n");
+
+ return 1;
+}
+
+static struct nft_xt_restore_cb cb_xlate = {
+ .table_new = xlate_table_new,
+ .chain_set = xlate_chain_set,
+ .chain_user_add = xlate_chain_user_add,
+ .do_command = do_command_xlate,
+ .commit = commit,
+ .abort = commit,
+};
+
+static int xtables_xlate_main(int family, const char *progname, int argc,
+ char *argv[])
+{
+ int ret;
+ char *table = "filter";
+ struct nft_handle h = {
+ .family = family,
+ };
+
+ xtables_globals.program_name = progname;
+ ret = xtables_init_all(&xtables_globals, family);
+ if (ret < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize xtables\n",
+ xtables_globals.program_name,
+ xtables_globals.program_version);
+ exit(1);
+ }
+#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
+ init_extensions4();
+#endif
+
+ if (nft_init(&h, xtables_ipv4) < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
+ xtables_globals.program_name,
+ xtables_globals.program_version,
+ strerror(errno));
+ nft_fini(&h);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("nft ");
+ ret = do_command_xlate(&h, argc, argv, &table, false);
+ if (!ret)
+ fprintf(stderr, "Translation not implemented\n");
+
+ nft_fini(&h);
+ exit(!ret);
+}
+
+static int xtables_restore_xlate_main(int family, const char *progname,
+ int argc, char *argv[])
+{
+ int ret;
+ struct nft_handle h = {
+ .family = family,
+ };
+ const char *file = NULL;
+ struct nft_xt_restore_parse p = {};
+ time_t now = time(NULL);
+ int c;
+
+ xtables_globals.program_name = progname;
+ ret = xtables_init_all(&xtables_globals, family);
+ if (ret < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize xtables\n",
+ xtables_globals.program_name,
+ xtables_globals.program_version);
+ exit(1);
+ }
+#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
+ init_extensions4();
+#endif
+
+ if (nft_init(&h, xtables_ipv4) < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
+ xtables_globals.program_name,
+ xtables_globals.program_version,
+ strerror(errno));
+ nft_fini(&h);
+ exit(EXIT_FAILURE);
+ }
+
+ opterr = 0;
+ while ((c = getopt_long(argc, argv, "hf:", options, NULL)) != -1) {
+ switch (c) {
+ case 'h':
+ print_usage(argv[0], IPTABLES_VERSION);
+ exit(0);
+ case 'f':
+ file = optarg;
+ break;
+ }
+ }
+
+ if (file == NULL) {
+ fprintf(stderr, "ERROR: missing file name\n");
+ print_usage(argv[0], IPTABLES_VERSION);
+ exit(0);
+ }
+
+ p.in = fopen(file, "r");
+ if (p.in == NULL) {
+ fprintf(stderr, "Cannot open file %s\n", file);
+ exit(1);
+ }
+
+ printf("# Translated by %s v%s on %s",
+ argv[0], IPTABLES_VERSION, ctime(&now));
+ xtables_restore_parse(&h, &p, &cb_xlate, argc, argv);
+
+ nft_fini(&h);
+ exit(0);
+}
+
+int xtables_ip4_xlate_main(int argc, char *argv[])
+{
+ return xtables_xlate_main(NFPROTO_IPV4, "iptables-translate",
+ argc, argv);
+}
+
+int xtables_ip6_xlate_main(int argc, char *argv[])
+{
+ return xtables_xlate_main(NFPROTO_IPV6, "ip6tables-translate",
+ argc, argv);
+}
+
+int xtables_ip4_xlate_restore_main(int argc, char *argv[])
+{
+ return xtables_restore_xlate_main(NFPROTO_IPV4,
+ "iptables-translate-restore",
+ argc, argv);
+}
+
+int xtables_ip6_xlate_restore_main(int argc, char *argv[])
+{
+ return xtables_restore_xlate_main(NFPROTO_IPV6,
+ "ip6tables-translate-restore",
+ argc, argv);
+}
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 1ab86d5..3cf09e0 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -1959,3 +1959,54 @@ void get_kernel_version(void)
sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
kernel_version = LINUX_VERSION(x, y, z);
}
+
+struct xt_buf {
+ char *data;
+ int size;
+ int rem;
+ int off;
+};
+
+struct xt_buf *xt_buf_alloc(int size)
+{
+ struct xt_buf *buf;
+
+ buf = malloc(sizeof(struct xt_buf));
+ if (buf == NULL)
+ xtables_error(RESOURCE_PROBLEM, "OOM");
+
+ buf->data = malloc(size);
+ if (buf->data == NULL)
+ xtables_error(RESOURCE_PROBLEM, "OOM");
+
+ buf->size = size;
+ buf->rem = size;
+ buf->off = 0;
+
+ return buf;
+}
+
+void xt_buf_free(struct xt_buf *buf)
+{
+ free(buf);
+}
+
+void xt_buf_add(struct xt_buf *buf, const char *fmt, ...)
+{
+ va_list ap;
+ int len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(buf->data + buf->off, buf->rem, fmt, ap);
+ if (len < 0 || len >= buf->rem)
+ xtables_error(RESOURCE_PROBLEM, "OOM");
+
+ va_end(ap);
+ buf->rem -= len;
+ buf->off += len;
+}
+
+const char *xt_buf_get(struct xt_buf *buf)
+{
+ return buf->data;
+}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/5] extensions: libxt_tcp: add translation to nft
2014-04-14 10:41 [RFC PATCH 0/5] translations from iptables to nft Pablo Neira Ayuso
` (2 preceding siblings ...)
2014-04-14 10:41 ` [PATCH 3/5] nft: xtables: add the infrastructure to translate from iptables to nft Pablo Neira Ayuso
@ 2014-04-14 10:41 ` Pablo Neira Ayuso
2014-04-14 10:41 ` [PATCH 5/5] extensions: libxt_state: " Pablo Neira Ayuso
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2014-04-14 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Translation for the TCP option matching is not yet implemented as we
don't have a way to match this yet.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
extensions/libxt_tcp.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c
index bbdec45..dddefb4 100644
--- a/extensions/libxt_tcp.c
+++ b/extensions/libxt_tcp.c
@@ -362,6 +362,85 @@ static void tcp_save(const void *ip, const struct xt_entry_match *match)
}
}
+static const struct tcp_flag_names tcp_flag_names_xlate[] = {
+ { "fin", 0x01 },
+ { "syn", 0x02 },
+ { "rst", 0x04 },
+ { "psh", 0x08 },
+ { "ack", 0x10 },
+ { "urg", 0x20 },
+};
+
+static void print_tcp_xlate(struct xt_buf *buf, uint8_t flags)
+{
+ int have_flag = 0;
+
+ while (flags) {
+ unsigned int i;
+
+ for (i = 0; (flags & tcp_flag_names_xlate[i].flag) == 0; i++);
+
+ if (have_flag)
+ xt_buf_add(buf, "|");
+
+ xt_buf_add(buf, "%s", tcp_flag_names_xlate[i].name);
+ have_flag = 1;
+
+ flags &= ~tcp_flag_names_xlate[i].flag;
+ }
+
+ if (!have_flag)
+ xt_buf_add(buf, "none");
+}
+
+static int tcp_xlate(const struct xt_entry_match *match, struct xt_buf *buf)
+{
+ const struct xt_tcp *tcpinfo = (const struct xt_tcp *)match->data;
+
+ if (tcpinfo->spts[0] != 0 || tcpinfo->spts[1] != 0xffff) {
+ if (tcpinfo->spts[0] != tcpinfo->spts[1]) {
+ xt_buf_add(buf, "tcp sport %s%u-%u ",
+ tcpinfo->invflags & XT_TCP_INV_SRCPT ?
+ "!= " : "",
+ tcpinfo->spts[0], tcpinfo->spts[1]);
+ } else {
+ xt_buf_add(buf, "tcp sport %s%u ",
+ tcpinfo->invflags & XT_TCP_INV_SRCPT ?
+ "!= " : "",
+ tcpinfo->spts[0]);
+ }
+ }
+
+ if (tcpinfo->dpts[0] != 0 || tcpinfo->dpts[1] != 0xffff) {
+ if (tcpinfo->dpts[0] != tcpinfo->dpts[1]) {
+ xt_buf_add(buf, "tcp dport %s%u-%u ",
+ tcpinfo->invflags & XT_TCP_INV_DSTPT ?
+ "!= " : "",
+ tcpinfo->dpts[0], tcpinfo->dpts[1]);
+ } else {
+ xt_buf_add(buf, "tcp dport %s%u ",
+ tcpinfo->invflags & XT_TCP_INV_DSTPT ?
+ "!= " : "",
+ tcpinfo->dpts[0]);
+ }
+ }
+
+ /* XXX not yet implemented */
+ if (tcpinfo->option || (tcpinfo->invflags & XT_TCP_INV_OPTION))
+ return 0;
+
+ if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) {
+ xt_buf_add(buf, "tcp flags & ");
+ print_tcp_xlate(buf, tcpinfo->flg_mask);
+ xt_buf_add(buf, " %s ",
+ tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!= ": "==");
+ print_tcp_xlate(buf, tcpinfo->flg_cmp);
+ xt_buf_add(buf, " ");
+ }
+
+ return 1;
+}
+
static struct xtables_match tcp_match = {
.family = NFPROTO_UNSPEC,
.name = "tcp",
@@ -374,6 +453,7 @@ static struct xtables_match tcp_match = {
.print = tcp_print,
.save = tcp_save,
.extra_opts = tcp_opts,
+ .xlate = tcp_xlate,
};
void
--
1.7.10.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 5/5] extensions: libxt_state: add translation to nft
2014-04-14 10:41 [RFC PATCH 0/5] translations from iptables to nft Pablo Neira Ayuso
` (3 preceding siblings ...)
2014-04-14 10:41 ` [PATCH 4/5] extensions: libxt_tcp: add translation " Pablo Neira Ayuso
@ 2014-04-14 10:41 ` Pablo Neira Ayuso
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2014-04-14 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
extensions/libxt_conntrack.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 128bbd2..4154464 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -1156,6 +1156,43 @@ static void state_save(const void *ip, const struct xt_entry_match *match)
state_print_state(sinfo->statemask);
}
+static void state_xlate_print(struct xt_buf *buf, unsigned int statemask)
+{
+ const char *sep = "";
+
+ if (statemask & XT_CONNTRACK_STATE_INVALID) {
+ xt_buf_add(buf, "%s%s", sep, "invalid");
+ sep = ",";
+ }
+ if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
+ xt_buf_add(buf, "%s%s", sep, "new");
+ sep = ",";
+ }
+ if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
+ xt_buf_add(buf, "%s%s", sep, "related");
+ sep = ",";
+ }
+ if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
+ xt_buf_add(buf, "%s%s", sep, "established");
+ sep = ",";
+ }
+ if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
+ xt_buf_add(buf, "%s%s", sep, "untracked");
+ sep = ",";
+ }
+}
+
+static int state_xlate(const struct xt_entry_match *match, struct xt_buf *buf)
+{
+ const struct xt_conntrack_mtinfo3 *sinfo = (const void *)match->data;
+
+ xt_buf_add(buf, "ct state %s", sinfo->invert_flags & XT_CONNTRACK_STATE ?
+ "!= " : "");
+ state_xlate_print(buf, sinfo->state_mask);
+ xt_buf_add(buf, " ");
+ return 1;
+}
+
static struct xtables_match conntrack_mt_reg[] = {
{
.version = XTABLES_VERSION,
@@ -1306,6 +1343,7 @@ static struct xtables_match conntrack_mt_reg[] = {
.save = state_save,
.x6_parse = state_ct23_parse,
.x6_options = state_opts,
+ .xlate = state_xlate,
},
{
.family = NFPROTO_UNSPEC,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 6+ messages in thread