summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2018-07-19 18:32:09 +0200
committerFlorian Westphal <fw@strlen.de>2018-07-19 23:13:02 +0200
commit922508e9156327ccb8e35243781cf85f5787ee40 (patch)
treeba9f497f248cb16216ae69972b694f162d602424
parent25ef90814a991e80384d4369565c6decadfcd409 (diff)
xtables: implement ebtables-{save,restore}
The code for ebtables-restore was derived from legacy code, ebtables-save is actually a new implementation using the existing infrastructure and trying to adhere to legacy perl script output formatting as much as possible. This introduces a new format flag (FMT_EBT_SAVE) to allow nft_bridge_save_rule() to distinguish between ruleset listing (i.e., ebtables -L) and saving via ebtables-save - the two differ in how counters are being formatted. Odd, but that's how it is. Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: Florian Westphal <fw@strlen.de>
-rw-r--r--include/xtables.h1
-rw-r--r--iptables/Makefile.am1
-rw-r--r--iptables/nft-bridge.c85
-rw-r--r--iptables/nft.h1
-rw-r--r--iptables/xtables-eb.c4
-rw-r--r--iptables/xtables-multi.h2
-rw-r--r--iptables/xtables-nft-multi.c2
-rw-r--r--iptables/xtables-restore.c114
-rw-r--r--iptables/xtables-save.c67
9 files changed, 246 insertions, 31 deletions
diff --git a/include/xtables.h b/include/xtables.h
index 743906bf..e4d23502 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -536,6 +536,7 @@ extern void xtables_save_string(const char *value);
#define FMT_VIA 0x0040
#define FMT_NONEWLINE 0x0080
#define FMT_LINENUMBERS 0x0100
+#define FMT_EBT_SAVE 0x0200
#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \
| FMT_NUMERIC | FMT_NOTABLE)
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index 800dd13a..a950d9fd 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -82,6 +82,7 @@ x_sbin_links = iptables-nft iptables-nft-restore iptables-nft-save \
iptables-restore-translate ip6tables-restore-translate \
arptables-nft arptables \
ebtables-nft ebtables \
+ ebtables-nft-restore ebtables-nft-save \
xtables-monitor
endif
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index b3bb3666..bbcecd82 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -435,52 +435,78 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
printf("%s ", ent->e_name);
}
-static void nft_bridge_print_rule(struct nftnl_rule *r, unsigned int num,
- unsigned int format)
+static void nft_bridge_save_rule(const void *data, unsigned int format)
{
- struct iptables_command_state cs = {};
-
- nft_rule_to_ebtables_command_state(r, &cs);
-
- if (format & FMT_LINENUMBERS)
- printf("%d ", num);
+ const struct iptables_command_state *cs = data;
- print_protocol(cs.eb.ethproto, cs.eb.invflags & EBT_IPROTO, cs.eb.bitmask);
- if (cs.eb.bitmask & EBT_ISOURCE)
- print_mac('s', cs.eb.sourcemac, cs.eb.sourcemsk,
- cs.eb.invflags & EBT_ISOURCE);
- if (cs.eb.bitmask & EBT_IDEST)
- print_mac('d', cs.eb.destmac, cs.eb.destmsk,
- cs.eb.invflags & EBT_IDEST);
+ if (cs->eb.ethproto)
+ print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO,
+ cs->eb.bitmask);
+ if (cs->eb.bitmask & EBT_ISOURCE)
+ print_mac('s', cs->eb.sourcemac, cs->eb.sourcemsk,
+ cs->eb.invflags & EBT_ISOURCE);
+ if (cs->eb.bitmask & EBT_IDEST)
+ print_mac('d', cs->eb.destmac, cs->eb.destmsk,
+ cs->eb.invflags & EBT_IDEST);
- print_iface("-i", cs.eb.in, cs.eb.invflags & EBT_IIN);
- print_iface("--logical-in", cs.eb.logical_in, cs.eb.invflags & EBT_ILOGICALIN);
- print_iface("-o", cs.eb.out, cs.eb.invflags & EBT_IOUT);
- print_iface("--logical-out", cs.eb.logical_out, cs.eb.invflags & EBT_ILOGICALOUT);
+ print_iface("-i", cs->eb.in, cs->eb.invflags & EBT_IIN);
+ print_iface("--logical-in", cs->eb.logical_in,
+ cs->eb.invflags & EBT_ILOGICALIN);
+ print_iface("-o", cs->eb.out, cs->eb.invflags & EBT_IOUT);
+ print_iface("--logical-out", cs->eb.logical_out,
+ cs->eb.invflags & EBT_ILOGICALOUT);
- print_matches_and_watchers(&cs, format);
+ print_matches_and_watchers(cs, format);
printf("-j ");
- if (cs.jumpto != NULL) {
- if (strcmp(cs.jumpto, "") != 0)
- printf("%s", cs.jumpto);
+ if (cs->jumpto != NULL) {
+ if (strcmp(cs->jumpto, "") != 0)
+ printf("%s", cs->jumpto);
else
printf("CONTINUE");
}
- else if (cs.target != NULL && cs.target->print != NULL)
- cs.target->print(&cs.fw, cs.target->t, format & FMT_NUMERIC);
+ else if (cs->target != NULL && cs->target->print != NULL)
+ cs->target->print(&cs->fw, cs->target->t, format & FMT_NUMERIC);
+
+ if (!(format & FMT_NOCOUNTS)) {
+ const char *counter_fmt;
- if (!(format & FMT_NOCOUNTS))
- printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"",
- (uint64_t)cs.counters.pcnt, (uint64_t)cs.counters.bcnt);
+ if (format & FMT_EBT_SAVE)
+ counter_fmt = " -c %"PRIu64" %"PRIu64"";
+ else
+ counter_fmt = " , pcnt = %"PRIu64" -- bcnt = %"PRIu64"";
+
+ printf(counter_fmt,
+ (uint64_t)cs->counters.pcnt,
+ (uint64_t)cs->counters.bcnt);
+ }
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
+}
+
+static void nft_bridge_print_rule(struct nftnl_rule *r, unsigned int num,
+ unsigned int format)
+{
+ struct iptables_command_state cs = {};
+
+ if (format & FMT_LINENUMBERS)
+ printf("%d ", num);
+ nft_rule_to_ebtables_command_state(r, &cs);
+ nft_bridge_save_rule(&cs, format);
ebt_cs_clean(&cs);
}
+static void nft_bridge_save_chain(const struct nftnl_chain *c,
+ const char *policy)
+{
+ const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+
+ printf(":%s %s\n", chain, policy ?: "ACCEPT");
+}
+
static bool nft_bridge_is_same(const void *data_a, const void *data_b)
{
const struct ebt_entry *a = data_a;
@@ -730,8 +756,9 @@ struct nft_family_ops nft_family_ops_bridge = {
.print_table_header = nft_bridge_print_table_header,
.print_header = nft_bridge_print_header,
.print_rule = nft_bridge_print_rule,
- .save_rule = NULL,
+ .save_rule = nft_bridge_save_rule,
.save_counters = NULL,
+ .save_chain = nft_bridge_save_chain,
.post_parse = NULL,
.rule_to_cs = nft_rule_to_ebtables_command_state,
.clear_cs = ebt_cs_clean,
diff --git a/iptables/nft.h b/iptables/nft.h
index f73a61c5..a479cf07 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -146,6 +146,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, bool
int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table);
/* For xtables-eb.c */
int nft_init_eb(struct nft_handle *h);
+int ebt_get_current_chain(const char *chain);
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table);
/*
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 44235347..ab0539c8 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -203,7 +203,7 @@ delete_entry(struct nft_handle *h,
return ret;
}
-static int get_current_chain(const char *chain)
+int ebt_get_current_chain(const char *chain)
{
if (!chain)
return -1;
@@ -846,7 +846,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table)
if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!")))
xtables_error(PARAMETER_PROBLEM, "No chain name specified");
chain = optarg;
- selected_chain = get_current_chain(chain);
+ selected_chain = ebt_get_current_chain(chain);
flags |= OPT_COMMAND;
if (c == 'N') {
diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h
index 82ee9c9d..84457618 100644
--- a/iptables/xtables-multi.h
+++ b/iptables/xtables-multi.h
@@ -16,6 +16,8 @@ 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_eb_main(int, char **);
+extern int xtables_eb_restore_main(int, char **);
+extern int xtables_eb_save_main(int, char **);
extern int xtables_config_main(int, char **);
extern int xtables_monitor_main(int, char **);
#endif
diff --git a/iptables/xtables-nft-multi.c b/iptables/xtables-nft-multi.c
index 03690a56..6fb8bd29 100644
--- a/iptables/xtables-nft-multi.c
+++ b/iptables/xtables-nft-multi.c
@@ -35,6 +35,8 @@ static const struct subcommand multi_subcommands[] = {
{"ebtables-translate", xtables_eb_xlate_main},
{"ebtables", xtables_eb_main},
{"ebtables-nft", xtables_eb_main},
+ {"ebtables-restore", xtables_eb_restore_main},
+ {"ebtables-save", xtables_eb_save_main},
{"xtables-monitor", xtables_monitor_main},
{NULL},
};
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index f9392457..5c0ae98e 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -16,6 +16,7 @@
#include "libiptc/libiptc.h"
#include "xtables-multi.h"
#include "nft.h"
+#include "nft-bridge.h"
#include <libnftnl/chain.h>
#ifdef DEBUG
@@ -581,3 +582,116 @@ int xtables_ip6_restore_main(int argc, char *argv[])
return xtables_restore_main(NFPROTO_IPV6, "ip6tables-restore",
argc, argv);
}
+
+static const char *ebt_parse_table_name(const char *input)
+{
+ if (!strcmp(input, "broute"))
+ xtables_error(PARAMETER_PROBLEM, "broute table not supported");
+ else if (!strcmp(input, "filter"))
+ return "filter";
+ else if (!strcmp(input, "nat"))
+ return "nat";
+
+ xtables_error(PARAMETER_PROBLEM, "table '%s' not recognized", input);
+}
+
+static const char *ebt_parse_policy_name(const char *input)
+{
+ int i;
+
+ for (i = 0; i < NUM_STANDARD_TARGETS; i++) {
+ if (!strcmp(input, ebt_standard_targets[i])) {
+ int policy = -i - 1;
+
+ if (policy == EBT_CONTINUE)
+ i = NUM_STANDARD_TARGETS;
+ break;
+ }
+ }
+ if (i == NUM_STANDARD_TARGETS)
+ xtables_error(PARAMETER_PROBLEM, "invalid policy specified");
+ return ebt_standard_targets[i];
+}
+
+static const struct option ebt_restore_options[] = {
+ {.name = "noflush", .has_arg = 0, .val = 'n'},
+ { 0 }
+};
+
+int xtables_eb_restore_main(int argc, char *argv[])
+{
+ char buffer[10240];
+ int i, ret, c, flush = 1;
+ const char *table = NULL;
+ struct nft_handle h;
+
+ nft_init_eb(&h);
+
+ while ((c = getopt_long(argc, argv, "n",
+ ebt_restore_options, NULL)) != -1) {
+ switch(c) {
+ case 'n':
+ flush = 0;
+ break;
+ default:
+ fprintf(stderr,
+ "Usage: ebtables-restore [ --noflush ]\n");
+ exit(1);
+ break;
+ }
+ }
+
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ if (buffer[0] == '#' || buffer[0] == '\n')
+ continue;
+ if (buffer[0] == '*') {
+ table = ebt_parse_table_name(buffer + 1);
+ if (flush)
+ nft_table_flush(&h, table);
+ continue;
+ } else if (!table) {
+ xtables_error(PARAMETER_PROBLEM, "no table specified");
+ }
+ if (buffer[0] == ':') {
+ char *ch, *chain = buffer;
+ const char *policy;
+
+ if (!(ch = strchr(buffer, ' ')))
+ xtables_error(PARAMETER_PROBLEM, "no policy specified");
+ *ch = '\0';
+ policy = ebt_parse_policy_name(ch + 1);
+
+ /* No need to check chain name for consistency, since
+ * we're supposed to be reading an automatically generated
+ * file. */
+ if (ebt_get_current_chain(chain) < 0)
+ nft_chain_user_add(&h, chain, table);
+ ret = nft_chain_set(&h, table, chain, policy, NULL);
+ if (ret < 0)
+ xtables_error(PARAMETER_PROBLEM, "Wrong policy");
+ continue;
+ }
+
+ newargc = 0;
+ add_argv("ebtables");
+ add_argv("-t");
+ add_argv(table);
+ add_param_to_argv(buffer);
+
+ DEBUGP("calling do_commandeb(%u, argv, &%s, handle):\n",
+ newargc, table);
+
+ for (i = 0; i < newargc; i++)
+ DEBUGP("argv[%u]: %s\n", i, newargv[i]);
+
+ optind = 0; /* Setting optind = 1 causes serious annoyances */
+ if (!do_commandeb(&h, newargc, newargv, &newargv[2]))
+ return 1;
+ }
+
+ if (!nft_commit(&h)) {
+ fprintf(stderr, "%s\n", nft_strerror(errno));
+ return 1;
+ }
+ return 0;
+}
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index e6bad32f..c9df51d5 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -220,3 +220,70 @@ int xtables_ip6_save_main(int argc, char *argv[])
{
return xtables_save_main(NFPROTO_IPV6, "ip6tables-save", argc, argv);
}
+
+static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters)
+{
+ struct nftnl_chain_list *chain_list;
+ static bool first = true;
+ time_t now;
+
+ if (!nft_table_find(h, tablename)) {
+ printf("Table `%s' does not exist\n", tablename);
+ return 1;
+ }
+
+ if (!nft_is_table_compatible(h, tablename)) {
+ printf("# Table `%s' is incompatible, use 'nft' tool.\n", tablename);
+ return 0;
+ }
+
+ chain_list = nft_chain_dump(h);
+
+ if (first) {
+ now = time(NULL);
+ printf("# Generated by ebtables-save v%s on %s",
+ IPTABLES_VERSION, ctime(&now));
+ first = false;
+ }
+ printf("*%s\n", tablename);
+
+ /* Dump out chain names first,
+ * thereby preventing dependency conflicts */
+ nft_chain_save(h, chain_list, tablename);
+ nft_rule_save(h, tablename,
+ FMT_EBT_SAVE | (counters ? 0 : FMT_NOCOUNTS));
+ printf("\n");
+ return 0;
+}
+
+int xtables_eb_save_main(int argc_, char *argv_[])
+{
+ const char *ctr = getenv("EBTABLES_SAVE_COUNTER");
+ struct nft_handle h = {
+ .family = NFPROTO_BRIDGE,
+ };
+ int c;
+
+ if (ctr && strcmp(ctr, "yes"))
+ ctr = NULL;
+
+ xtables_globals.program_name = "ebtables-save";
+ c = xtables_init_all(&xtables_globals, h.family);
+ if (c < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize xtables\n",
+ xtables_globals.program_name,
+ xtables_globals.program_version);
+ exit(1);
+ }
+
+ if (nft_init(&h, xtables_bridge) < 0) {
+ fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
+ xtables_globals.program_name,
+ xtables_globals.program_version,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ nft_for_each_table(&h, __ebt_save, !!ctr);
+ return 0;
+}