blob: 051d5c7b7f98be18d361861c13ef55d54525d182 [file] [log] [blame]
/* 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 <coreteam@netfilter.org>:
* Paul 'Rusty' Russell <rusty@rustcorp.com.au>
* Marc Boucher <marc+nf@mbsi.ca>
* James Morris <jmorris@intercode.com.au>
* Harald Welte <laforge@gnumonks.org>
* Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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 <getopt.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 <netinet/ether.h>
#include <iptables.h>
#include <xtables.h>
#include <fcntl.h>
#include "xshared.h"
#include "nft-shared.h"
#include "nft-arp.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)",
.optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x",
.orig_opts = original_opts,
.compat_rev = nft_compatible_revision,
.print_help = xtables_printhelp,
};
/*
* 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);
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;
nft_clear_iptables_command_state(&cs);
free(args.s.addr.ptr);
free(args.s.mask.ptr);
free(args.d.addr.ptr);
free(args.d.mask.ptr);
xtables_free_opts(1);
return ret;
}