summaryrefslogtreecommitdiffstats
path: root/iptables/xtables-translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'iptables/xtables-translate.c')
-rw-r--r--iptables/xtables-translate.c463
1 files changed, 463 insertions, 0 deletions
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);
+}