/* Code to take an iptables-style command line and do it. */ /* * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au * * (C) 2000-2002 by the netfilter coreteam : * Paul 'Rusty' Russell * Marc Boucher * James Morris * Harald Welte * Jozsef Kadlecsik * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xshared.h" #include "nft-shared.h" #include "nft.h" static struct option original_opts[] = { {.name = "append", .has_arg = 1, .val = 'A'}, {.name = "delete", .has_arg = 1, .val = 'D'}, {.name = "check", .has_arg = 1, .val = 'C'}, {.name = "insert", .has_arg = 1, .val = 'I'}, {.name = "replace", .has_arg = 1, .val = 'R'}, {.name = "list", .has_arg = 2, .val = 'L'}, {.name = "list-rules", .has_arg = 2, .val = 'S'}, {.name = "flush", .has_arg = 2, .val = 'F'}, {.name = "zero", .has_arg = 2, .val = 'Z'}, {.name = "new-chain", .has_arg = 1, .val = 'N'}, {.name = "delete-chain", .has_arg = 2, .val = 'X'}, {.name = "rename-chain", .has_arg = 1, .val = 'E'}, {.name = "policy", .has_arg = 1, .val = 'P'}, {.name = "source", .has_arg = 1, .val = 's'}, {.name = "destination", .has_arg = 1, .val = 'd'}, {.name = "src", .has_arg = 1, .val = 's'}, /* synonym */ {.name = "dst", .has_arg = 1, .val = 'd'}, /* synonym */ {.name = "protocol", .has_arg = 1, .val = 'p'}, {.name = "in-interface", .has_arg = 1, .val = 'i'}, {.name = "jump", .has_arg = 1, .val = 'j'}, {.name = "table", .has_arg = 1, .val = 't'}, {.name = "match", .has_arg = 1, .val = 'm'}, {.name = "numeric", .has_arg = 0, .val = 'n'}, {.name = "out-interface", .has_arg = 1, .val = 'o'}, {.name = "verbose", .has_arg = 0, .val = 'v'}, {.name = "wait", .has_arg = 2, .val = 'w'}, {.name = "wait-interval", .has_arg = 2, .val = 'W'}, {.name = "exact", .has_arg = 0, .val = 'x'}, {.name = "fragments", .has_arg = 0, .val = 'f'}, {.name = "version", .has_arg = 0, .val = 'V'}, {.name = "help", .has_arg = 2, .val = 'h'}, {.name = "line-numbers", .has_arg = 0, .val = '0'}, {.name = "modprobe", .has_arg = 1, .val = 'M'}, {.name = "set-counters", .has_arg = 1, .val = 'c'}, {.name = "goto", .has_arg = 1, .val = 'g'}, {.name = "ipv4", .has_arg = 0, .val = '4'}, {.name = "ipv6", .has_arg = 0, .val = '6'}, {NULL}, }; struct xtables_globals xtables_globals = { .option_offset = 0, .program_version = PACKAGE_VERSION " (nf_tables)", .orig_opts = original_opts, .compat_rev = nft_compatible_revision, }; /* * All functions starting with "parse" should succeed, otherwise * the program fails. * Most routines return pointers to static data that may change * between calls to the same or other routines with a few exceptions: * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask" * return global static data. */ /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ static int list_entries(struct nft_handle *h, const char *chain, const char *table, int rulenum, int verbose, int numeric, int expanded, int linenumbers) { unsigned int format; format = FMT_OPTIONS; if (!verbose) format |= FMT_NOCOUNTS; else format |= FMT_VIA; if (numeric) format |= FMT_NUMERIC; if (!expanded) format |= FMT_KILOMEGAGIGA; if (linenumbers) format |= FMT_LINENUMBERS; return nft_cmd_rule_list(h, chain, table, rulenum, format); } static int list_rules(struct nft_handle *h, const char *chain, const char *table, int rulenum, int counters) { if (counters) counters = -1; /* iptables -c format */ return nft_cmd_rule_list_save(h, chain, table, rulenum, counters); } int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, bool restore) { int ret = 1; struct xt_cmd_parse p = { .table = *table, .restore = restore, .line = line, .ops = &h->ops->cmd_parse, }; struct iptables_command_state cs = { .jumpto = "", .argv = argv, }; struct xtables_args args = { .family = h->family, }; if (h->ops->init_cs) h->ops->init_cs(&cs); do_parse(argc, argv, &p, &cs, &args); h->verbose = p.verbose; if (!nft_table_builtin_find(h, p.table)) xtables_error(VERSION_PROBLEM, "table '%s' does not exist", p.table); switch (p.command) { case CMD_APPEND: ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args, cs.options & OPT_VERBOSE, true, p.rulenum - 1); break; case CMD_DELETE: ret = h->ops->delete_entry(h, p.chain, p.table, &cs, &args, cs.options & OPT_VERBOSE); break; case CMD_DELETE_NUM: ret = nft_cmd_rule_delete_num(h, p.chain, p.table, p.rulenum - 1, p.verbose); break; case CMD_CHECK: ret = h->ops->check_entry(h, p.chain, p.table, &cs, &args, cs.options & OPT_VERBOSE); break; case CMD_REPLACE: ret = h->ops->replace_entry(h, p.chain, p.table, &cs, &args, cs.options & OPT_VERBOSE, p.rulenum - 1); break; case CMD_INSERT: ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args, cs.options & OPT_VERBOSE, false, p.rulenum - 1); break; case CMD_FLUSH: ret = nft_cmd_rule_flush(h, p.chain, p.table, cs.options & OPT_VERBOSE); break; case CMD_ZERO: ret = nft_cmd_chain_zero_counters(h, p.chain, p.table, cs.options & OPT_VERBOSE); break; case CMD_ZERO_NUM: ret = nft_cmd_rule_zero_counters(h, p.chain, p.table, p.rulenum - 1); break; case CMD_LIST: case CMD_LIST|CMD_ZERO: case CMD_LIST|CMD_ZERO_NUM: ret = list_entries(h, p.chain, p.table, p.rulenum, cs.options & OPT_VERBOSE, cs.options & OPT_NUMERIC, cs.options & OPT_EXPANDED, cs.options & OPT_LINENUMBERS); if (ret && (p.command & CMD_ZERO)) { ret = nft_cmd_chain_zero_counters(h, p.chain, p.table, cs.options & OPT_VERBOSE); } if (ret && (p.command & CMD_ZERO_NUM)) { ret = nft_cmd_rule_zero_counters(h, p.chain, p.table, p.rulenum - 1); } nft_check_xt_legacy(h->family, false); break; case CMD_LIST_RULES: case CMD_LIST_RULES|CMD_ZERO: case CMD_LIST_RULES|CMD_ZERO_NUM: ret = list_rules(h, p.chain, p.table, p.rulenum, cs.options & OPT_VERBOSE); if (ret && (p.command & CMD_ZERO)) { ret = nft_cmd_chain_zero_counters(h, p.chain, p.table, cs.options & OPT_VERBOSE); } if (ret && (p.command & CMD_ZERO_NUM)) { ret = nft_cmd_rule_zero_counters(h, p.chain, p.table, p.rulenum - 1); } nft_check_xt_legacy(h->family, false); break; case CMD_NEW_CHAIN: ret = nft_cmd_chain_user_add(h, p.chain, p.table); break; case CMD_DELETE_CHAIN: ret = nft_cmd_chain_del(h, p.chain, p.table, cs.options & OPT_VERBOSE); break; case CMD_RENAME_CHAIN: ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname); break; case CMD_SET_POLICY: ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL); break; case CMD_NONE: /* do_parse ignored the line (eg: -4 with ip6tables-restore) */ break; default: /* We should never reach this... */ exit_tryhelp(2, line); } *table = p.table; h->ops->clear_cs(&cs); xtables_clear_args(&args); xtables_free_opts(1); return ret; }