]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
xtables: implement ebtables-{save,restore}
authorPhil Sutter <phil@nwl.cc>
Thu, 19 Jul 2018 16:32:09 +0000 (18:32 +0200)
committerFlorian Westphal <fw@strlen.de>
Thu, 19 Jul 2018 21:13:02 +0000 (23:13 +0200)
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>
include/xtables.h
iptables/Makefile.am
iptables/nft-bridge.c
iptables/nft.h
iptables/xtables-eb.c
iptables/xtables-multi.h
iptables/xtables-nft-multi.c
iptables/xtables-restore.c
iptables/xtables-save.c

index 743906bf1ffefe6be9f0ef367118e9e092faf64f..e4d235028deeaea3a3ee8359cbf89b5eada6d3f9 100644 (file)
@@ -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)
index 800dd13a4f29a9ae4914d9cd44b161171be56300..a950d9fd691129fb18b59c3d50037f9435b6a729 100644 (file)
@@ -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
 
index b3bb3666511556dfacd62cfa3640feb8e0b373c6..bbcecd825f8ceed144af409a864550a387d90f24 100644 (file)
@@ -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,
index f73a61c521b12932445c997c40b9b6e497838bff..a479cf072089deaaf37442b03f24061d94cc2243 100644 (file)
@@ -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);
 
 /*
index 44235347f60fe76787cb48af7f118e1b35a6d181..ab0539c8a54f3f02591603e107a206a0294716c8 100644 (file)
@@ -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') {
index 82ee9c9dbcab1904f9430098966ce5b722ed339e..8445761849aa190d0ac21a028b656a541221f5e6 100644 (file)
@@ -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
index 03690a56edb72ac15f05e1f08c444a6d625bb7e2..6fb8bd29e6ae4a53a8d6f8669b2941a0ca125dff 100644 (file)
@@ -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},
 };
index f93924579fe4f0aed2b687de8f549d5f4eee3a50..5c0ae98e8821a49bfb2d5eb5239e4cca1d79e44d 100644 (file)
@@ -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;
+}
index e6bad32fa0b8128936804c8e44ef81766ea90e96..c9df51d55327feb3ac0c3e20efa437f3da258b7f 100644 (file)
@@ -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;
+}