This adds C implementations for arptables-save and -restore in compat
layer based on the two perl scripts in legacy arptables repository.

To share common code, introduce nft_init_arp() analogous to
nft_init_eb() introduced earlier.

Signed-off-by: Phil Sutter <[email protected]>
---
 iptables/Makefile.am              |   2 +
 iptables/nft-arp.c                |  49 +++++++++-----
 iptables/nft.h                    |   1 +
 iptables/xtables-arp-standalone.c |  17 +----
 iptables/xtables-arp.c            |  36 ++++++++---
 iptables/xtables-multi.h          |   2 +
 iptables/xtables-nft-multi.c      |   4 ++
 iptables/xtables-restore.c        | 104 ++++++++++++++++++++++++++++++
 iptables/xtables-save.c           |  39 +++++++++++
 9 files changed, 214 insertions(+), 40 deletions(-)

diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index 2cbd586128140..d0218ddc80487 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -81,6 +81,8 @@ x_sbin_links  = iptables-nft iptables-nft-restore 
iptables-nft-save \
                iptables-translate ip6tables-translate \
                iptables-restore-translate ip6tables-restore-translate \
                arptables-nft arptables \
+               arptables-nft-restore arptables-restore \
+               arptables-nft-save arptables-save \
                ebtables-nft ebtables \
                ebtables-nft-restore ebtables-restore \
                ebtables-nft-save ebtables-save \
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 5cabb93e4a9bc..f5b05f864963a 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -436,7 +436,7 @@ static void nft_arp_print_header(unsigned int format, const 
char *chain,
        }
 }
 
-static void nft_arp_print_rule_details(struct arpt_entry *fw,
+static void nft_arp_print_rule_details(const struct arpt_entry *fw,
                                       unsigned int format)
 {
        char buf[BUFSIZ];
@@ -579,35 +579,42 @@ after_devdst:
 }
 
 static void
-nft_arp_print_rule(struct nftnl_rule *r, unsigned int num, unsigned int format)
+nft_arp_save_rule(const void *data, unsigned int format)
 {
-       struct iptables_command_state cs = {};
-
-       nft_arp_rule_to_cs(r, &cs);
-
-       if (format & FMT_LINENUMBERS)
-               printf("%u ", num);
+       const struct iptables_command_state *cs = data;
 
-       nft_arp_print_rule_details(&cs.arp, format);
+       nft_arp_print_rule_details(&cs->arp, format);
 
-       if (cs.jumpto != NULL && strcmp(cs.jumpto, "") != 0) {
-               printf("-j %s", cs.jumpto);
-       } else if (cs.target) {
-               printf("-j %s", cs.target->name);
-               cs.target->print(&cs.arp, cs.target->t, format & FMT_NUMERIC);
+       if (cs->jumpto != NULL && strcmp(cs->jumpto, "") != 0) {
+               printf("-j %s", cs->jumpto);
+       } else if (cs->target) {
+               printf("-j %s", cs->target->name);
+               cs->target->print(&cs->arp, cs->target->t, format & 
FMT_NUMERIC);
        }
 
        if (!(format & FMT_NOCOUNTS)) {
                printf(", pcnt=");
-               xtables_print_num(cs.arp.counters.pcnt, format);
+               xtables_print_num(cs->arp.counters.pcnt, format);
                printf("-- bcnt=");
-               xtables_print_num(cs.arp.counters.bcnt, format);
+               xtables_print_num(cs->arp.counters.bcnt, format);
        }
 
        if (!(format & FMT_NONEWLINE))
                fputc('\n', stdout);
 }
 
+static void
+nft_arp_print_rule(struct nftnl_rule *r, unsigned int num, unsigned int format)
+{
+       struct iptables_command_state cs = {};
+
+       if (format & FMT_LINENUMBERS)
+               printf("%u ", num);
+
+       nft_arp_rule_to_cs(r, &cs);
+       nft_arp_save_rule(&cs, format);
+}
+
 static bool nft_arp_is_same(const void *data_a,
                            const void *data_b)
 {
@@ -655,6 +662,13 @@ static bool nft_arp_rule_find(struct nft_family_ops *ops, 
struct nftnl_rule *r,
        return true;
 }
 
+static void nft_arp_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 ?: "-");
+}
+
 struct nft_family_ops nft_family_ops_arp = {
        .add                    = nft_arp_add,
        .is_same                = nft_arp_is_same,
@@ -664,8 +678,9 @@ struct nft_family_ops nft_family_ops_arp = {
        .parse_immediate        = nft_arp_parse_immediate,
        .print_header           = nft_arp_print_header,
        .print_rule             = nft_arp_print_rule,
-       .save_rule              = NULL,
+       .save_rule              = nft_arp_save_rule,
        .save_counters          = NULL,
+       .save_chain             = nft_arp_save_chain,
        .post_parse             = NULL,
        .rule_to_cs             = nft_arp_rule_to_cs,
        .clear_cs               = NULL,
diff --git a/iptables/nft.h b/iptables/nft.h
index a479cf072089d..491076081adf3 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -143,6 +143,7 @@ const char *nft_strerror(int err);
 /* For xtables.c */
 int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, 
bool restore);
 /* For xtables-arptables.c */
+int nft_init_arp(struct nft_handle *h);
 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);
diff --git a/iptables/xtables-arp-standalone.c 
b/iptables/xtables-arp-standalone.c
index 6553d28f6d95d..b3ade3eaaebec 100644
--- a/iptables/xtables-arp-standalone.c
+++ b/iptables/xtables-arp-standalone.c
@@ -47,22 +47,9 @@ int xtables_arp_main(int argc, char *argv[])
 {
        int ret;
        char *table = "filter";
-       struct nft_handle h = {
-               .family = NFPROTO_ARP,
-       };
+       struct nft_handle h;
 
-       arptables_globals.program_name = "arptables";
-       ret = xtables_init_all(&arptables_globals, NFPROTO_ARP);
-       if (ret < 0) {
-               fprintf(stderr, "%s/%s Failed to initialize arptables-compat\n",
-                       arptables_globals.program_name,
-                       arptables_globals.program_version);
-               exit(1);
-       }
-
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
-       init_extensionsa();
-#endif
+       nft_init_arp(&h);
 
        ret = do_commandarp(&h, argc, argv, &table);
        if (ret)
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index ce9e618b7049b..d73856f5c66b1 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -929,6 +929,34 @@ delete_entry(const char *chain,
        return ret;
 }
 
+int nft_init_arp(struct nft_handle *h)
+{
+       arptables_globals.program_name = "arptables";
+       if (xtables_init_all(&arptables_globals, NFPROTO_ARP) < 0) {
+               fprintf(stderr, "%s/%s Failed to initialize arptables-compat\n",
+                       arptables_globals.program_name,
+                       arptables_globals.program_version);
+               exit(1);
+       }
+
+#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+       init_extensionsa();
+#endif
+
+       memset(h, 0, sizeof(*h));
+       h->family = NFPROTO_ARP;
+
+       if (nft_init(h, xtables_arp) < 0)
+               xtables_error(OTHER_PROBLEM,
+                             "Could not initialize nftables layer.");
+
+       h->ops = nft_family_ops_lookup(h->family);
+       if (h->ops == NULL)
+               xtables_error(PARAMETER_PROBLEM, "Unknown family");
+
+       return 0;
+}
+
 int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
 {
        struct iptables_command_state cs = {
@@ -1361,14 +1389,6 @@ int do_commandarp(struct nft_handle *h, int argc, char 
*argv[], char **table)
                                "chain name `%s' too long (must be under %i 
chars)",
                                chain, ARPT_FUNCTION_MAXNAMELEN);
 
-       if (nft_init(h, xtables_arp) < 0)
-               xtables_error(OTHER_PROBLEM,
-                             "Could not initialize nftables layer.");
-
-       h->ops = nft_family_ops_lookup(h->family);
-       if (h->ops == NULL)
-               xtables_error(PARAMETER_PROBLEM, "Unknown family");
-
        if (command == CMD_APPEND
            || command == CMD_DELETE
            || command == CMD_INSERT
diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h
index 8445761849aa1..0fedb430e1a28 100644
--- a/iptables/xtables-multi.h
+++ b/iptables/xtables-multi.h
@@ -15,6 +15,8 @@ extern int xtables_eb_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_arp_restore_main(int, char **);
+extern int xtables_arp_save_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 **);
diff --git a/iptables/xtables-nft-multi.c b/iptables/xtables-nft-multi.c
index d9cca088f27a8..e2b7c641f85dd 100644
--- a/iptables/xtables-nft-multi.c
+++ b/iptables/xtables-nft-multi.c
@@ -32,6 +32,10 @@ static const struct subcommand multi_subcommands[] = {
        {"ip6tables-restore-translate", xtables_ip6_xlate_restore_main},
        {"arptables",                   xtables_arp_main},
        {"arptables-nft",               xtables_arp_main},
+       {"arptables-restore",           xtables_arp_restore_main},
+       {"arptables-nft-restore",       xtables_arp_restore_main},
+       {"arptables-save",              xtables_arp_save_main},
+       {"arptables-nft-save",          xtables_arp_save_main},
        {"ebtables-translate",          xtables_eb_xlate_main},
        {"ebtables",                    xtables_eb_main},
        {"ebtables-restore",            xtables_eb_restore_main},
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index ead61842bc360..17d4bc75e92de 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -710,3 +710,107 @@ int xtables_eb_restore_main(int argc, char *argv[])
                fprintf(stderr, "%s\n", nft_strerror(errno));
        return !ret;
 }
+
+static const char *arp_parse_policy_name(const char *input)
+{
+       const char *policy_names[] = {
+               "ACCEPT",
+               "DROP",
+               "RETURN",
+               "-",
+               NULL,
+       };
+       int i;
+
+       for (i = 0; policy_names[i]; i++) {
+               if (!strcmp(input, policy_names[i]))
+                       return policy_names[i];
+       }
+       xtables_error(PARAMETER_PROBLEM, "invalid policy '%s'", input);
+}
+
+int xtables_arp_restore_main(int argc, char *argv[])
+{
+       const char *table = NULL;
+       struct nft_handle h;
+       char buffer[10240];
+       int i, ret = 1;
+
+       nft_init_arp(&h);
+
+       if (!nft_table_flush(&h, "filter") || !nft_commit(&h)) {
+               xtables_error(OTHER_PROBLEM, "initial table flush failed");
+               goto out;
+       }
+
+       while (fgets(buffer, sizeof(buffer), stdin)) {
+               if (buffer[0] == '#' || buffer[0] == '\n')
+                       continue;
+               if (buffer[0] == '*') {
+                       *strchr(buffer, '\n') = '\0';
+                       if (strcmp(buffer + 1, "filter"))
+                               xtables_error(PARAMETER_PROBLEM,
+                                             "table '%s' not recognized",
+                                             buffer + 1);
+                       table = "filter";
+                       /* this is strictly not necessary, but ensures default
+                        * chains are created before later attempts are made to
+                        * change policies */
+                       nft_table_new(&h, table);
+                       continue;
+               } else if (!table) {
+                       xtables_error(PARAMETER_PROBLEM, "no table specified");
+               }
+               if (buffer[0] == ':') {
+                       char *ch, *chain = buffer + 1;
+                       const char *policy;
+
+                       if (!(ch = strchr(buffer, ' ')))
+                               xtables_error(PARAMETER_PROBLEM,
+                                             "no policy specified");
+                       *ch = '\0';
+                       *strchr(ch + 1, '\n') = '\0';
+                       policy = arp_parse_policy_name(ch + 1);
+
+                       if (!strcmp(policy, "-")) {
+                               nft_chain_user_add(&h, chain, table);
+                       } else {
+                               ret = nft_chain_set(&h, table,
+                                                   chain, policy, NULL);
+                               if (ret < 0)
+                                       xtables_error(PARAMETER_PROBLEM,
+                                                     "Wrong policy");
+                       }
+                       continue;
+               }
+
+               newargc = 0;
+               add_argv("arptables");
+               add_argv("-t");
+               add_argv(table);
+               add_param_to_argv(buffer);
+
+               DEBUGP("calling do_commandarp(handle, %u, argv, &%s):\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 */
+               ret = do_commandarp(&h, newargc, newargv, &newargv[2]);
+
+               free_argv();
+
+               if (!ret)
+                       break;
+       }
+
+       if (ret)
+               ret = nft_commit(&h);
+out:
+       nft_fini(&h);
+
+       if (!ret)
+               fprintf(stderr, "%s\n", nft_strerror(errno));
+       return !ret;
+}
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index c9df51d55327f..fc51fcfeb5815 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -287,3 +287,42 @@ int xtables_eb_save_main(int argc_, char *argv_[])
        nft_for_each_table(&h, __ebt_save, !!ctr);
        return 0;
 }
+
+int xtables_arp_save_main(int argc, char **argv)
+{
+       struct nft_handle h = {
+               .family = NFPROTO_ARP,
+       };
+       int c;
+
+       xtables_globals.program_name = "arptables-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_arp) < 0) {
+               fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
+                               xtables_globals.program_name,
+                               xtables_globals.program_version,
+                               strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       if (!nft_table_find(&h, "filter"))
+               return 0;
+
+       if (!nft_is_table_compatible(&h, "filter")) {
+               printf("# Table `filter' is incompatible, use 'nft' tool.\n");
+               return 0;
+       }
+
+       printf("*filter\n");
+       nft_chain_save(&h, nft_chain_dump(&h), "filter");
+       nft_rule_save(&h, "filter", FMT_NOCOUNTS);
+       printf("\n");
+       return 0;
+}
-- 
2.18.0

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to