summaryrefslogtreecommitdiffstats
path: root/iptables
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2014-04-11 12:31:39 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2016-02-16 19:30:21 +0100
commit933400b37d0966980d07d32b64403830429761ed (patch)
treea2540049b9e8c1d679bc2d8a096f0ffc629b9d36 /iptables
parentd13b60c9ddb48e651b92f13579e236c530658176 (diff)
nft: xtables: add the infrastructure to translate from iptables to nft
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>
Diffstat (limited to 'iptables')
-rw-r--r--iptables/Makefile.am5
-rw-r--r--iptables/nft-ipv4.c64
-rw-r--r--iptables/nft-ipv6.c67
-rw-r--r--iptables/nft-shared.h2
-rw-r--r--iptables/nft.h10
-rw-r--r--iptables/xtables-compat-multi.c4
-rw-r--r--iptables/xtables-multi.h4
-rw-r--r--iptables/xtables-translate.c463
8 files changed, 616 insertions, 3 deletions
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index c3eb8a81..569a739d 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -43,7 +43,8 @@ xtables_compat_multi_SOURCES += xtables-save.c xtables-restore.c \
nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \
xtables-arp-standalone.c xtables-arp.c \
getethertype.c nft-bridge.c \
- xtables-eb-standalone.c xtables-eb.c
+ xtables-eb-standalone.c xtables-eb.c \
+ xtables-translate.c
xtables_compat_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS} ${libnetfilter_conntrack_LIBS} ../extensions/libext4.a ../extensions/libext6.a ../extensions/libext_ebt.a ../extensions/libext_arpt.a
# yacc and lex generate dirty code
xtables_compat_multi-xtables-config-parser.o xtables_compat_multi-xtables-config-syntax.o: AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls
@@ -71,6 +72,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 ebtables-compat
endif
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 109c6237..ede8f176 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>
@@ -428,6 +429,66 @@ static void nft_ipv4_save_counters(const void *data)
save_counters(cs->counters.pcnt, cs->counters.bcnt);
}
+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,
@@ -442,4 +503,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 7b27d872..107a84e2 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>
@@ -376,6 +377,69 @@ static void nft_ipv6_save_counters(const void *data)
save_counters(cs->counters.pcnt, cs->counters.bcnt);
}
+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("ip saddr", &cs->fw6.ipv6.src,
+ cs->fw6.ipv6.invflags & IP6T_INV_SRCIP, buf);
+ xlate_ipv6_addr("ip daddr", &cs->fw6.ipv6.dst,
+ cs->fw6.ipv6.invflags & 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,
@@ -390,4 +454,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 56d75f82..73861833 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -37,6 +37,7 @@
#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
struct xtables_args;
+struct xt_buf;
enum {
NFT_XT_CTX_PAYLOAD = (1 << 0),
@@ -101,6 +102,7 @@ struct nft_family_ops {
void (*parse_target)(struct xtables_target *t, void *data);
bool (*rule_find)(struct nft_family_ops *ops, struct nftnl_rule *r,
void *data);
+ int (*xlate)(const void *data, struct xt_buf *buf);
};
void add_meta(struct nftnl_rule *r, uint32_t key);
diff --git a/iptables/nft.h b/iptables/nft.h
index 2cf78fda..192050a4 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -156,6 +156,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 902da524..3e24631c 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},
{"ebtables-compat", xtables_eb_main},
diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h
index 21e60b2b..7b4195c1 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_eb_main(int, char **);
extern int xtables_config_main(int, char **);
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
new file mode 100644
index 00000000..30028c35
--- /dev/null
+++ b/iptables/xtables-translate.c
@@ -0,0 +1,463 @@
+/*
+ * (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, numeric = cs->options & OPT_NUMERIC;
+
+ /* 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, numeric);
+ 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, numeric = cs->options & OPT_NUMERIC;
+
+ for (matchp = cs->matches; matchp; matchp = matchp->next) {
+ if (!matchp->match->xlate)
+ return 0;
+
+ ret = matchp->match->xlate(matchp->match->m, buf, numeric);
+ 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);
+ printf("# Completed on %s", ctime(&now));
+
+ nft_fini(&h);
+ fclose(p.in);
+ 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);
+}