diff options
Diffstat (limited to 'iptables/xtables-translate.c')
-rw-r--r-- | iptables/xtables-translate.c | 463 |
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); +} |