diff options
Diffstat (limited to 'iptables')
-rw-r--r-- | iptables/Makefile.am | 5 | ||||
-rw-r--r-- | iptables/nft-ipv4.c | 64 | ||||
-rw-r--r-- | iptables/nft-ipv6.c | 67 | ||||
-rw-r--r-- | iptables/nft-shared.h | 2 | ||||
-rw-r--r-- | iptables/nft.h | 10 | ||||
-rw-r--r-- | iptables/xtables-compat-multi.c | 4 | ||||
-rw-r--r-- | iptables/xtables-multi.h | 4 | ||||
-rw-r--r-- | iptables/xtables-translate.c | 463 |
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); +} |