/*
- * (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
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
+#include <netdb.h>
#include <xtables.h>
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,
.post_parse = nft_ipv4_post_parse,
.parse_target = nft_ipv4_parse_target,
.rule_find = nft_ipv4_rule_find,
+ .xlate = nft_ipv4_xlate,
};
/*
- * (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
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip6.h>
+#include <netdb.h>
#include <xtables.h>
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,
.post_parse = nft_ipv6_post_parse,
.parse_target = nft_ipv6_parse_target,
.rule_find = nft_ipv6_rule_find,
+ .xlate = nft_ipv6_xlate,
};
--- /dev/null
+/*
+ * (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);
+}