summaryrefslogtreecommitdiffstats
path: root/iptables/xtables.c
diff options
context:
space:
mode:
Diffstat (limited to 'iptables/xtables.c')
-rw-r--r--iptables/xtables.c352
1 files changed, 136 insertions, 216 deletions
diff --git a/iptables/xtables.c b/iptables/xtables.c
index daa9b137..5c69af7e 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -36,11 +36,13 @@
#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[] = {
@@ -85,13 +87,16 @@ static struct option original_opts[] = {
};
void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
+static void printhelp(const struct xtables_rule_match *m);
struct xtables_globals xtables_globals = {
.option_offset = 0,
.program_version = PACKAGE_VERSION,
+ .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x",
.orig_opts = original_opts,
.exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
+ .print_help = printhelp,
};
#define opts xt_params->opts
@@ -223,168 +228,6 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...)
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
static int
-add_entry(const char *chain,
- const char *table,
- struct iptables_command_state *cs,
- int rulenum, int family,
- const struct addr_mask s,
- const struct addr_mask d,
- bool verbose, struct nft_handle *h, bool append)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < s.naddrs; i++) {
- if (family == AF_INET) {
- cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
- cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
- for (j = 0; j < d.naddrs; j++) {
- cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
- cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
-
- if (append) {
- ret = nft_cmd_rule_append(h, chain, table,
- cs, NULL,
- verbose);
- } else {
- ret = nft_cmd_rule_insert(h, chain, table,
- cs, rulenum,
- verbose);
- }
- }
- } else if (family == AF_INET6) {
- memcpy(&cs->fw6.ipv6.src,
- &s.addr.v6[i], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.smsk,
- &s.mask.v6[i], sizeof(struct in6_addr));
- for (j = 0; j < d.naddrs; j++) {
- memcpy(&cs->fw6.ipv6.dst,
- &d.addr.v6[j], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dmsk,
- &d.mask.v6[j], sizeof(struct in6_addr));
- if (append) {
- ret = nft_cmd_rule_append(h, chain, table,
- cs, NULL,
- verbose);
- } else {
- ret = nft_cmd_rule_insert(h, chain, table,
- cs, rulenum,
- verbose);
- }
- }
- }
- }
-
- return ret;
-}
-
-static int
-replace_entry(const char *chain, const char *table,
- struct iptables_command_state *cs,
- unsigned int rulenum,
- int family,
- const struct addr_mask s,
- const struct addr_mask d,
- bool verbose, struct nft_handle *h)
-{
- if (family == AF_INET) {
- cs->fw.ip.src.s_addr = s.addr.v4->s_addr;
- cs->fw.ip.dst.s_addr = d.addr.v4->s_addr;
- cs->fw.ip.smsk.s_addr = s.mask.v4->s_addr;
- cs->fw.ip.dmsk.s_addr = d.mask.v4->s_addr;
- } else if (family == AF_INET6) {
- memcpy(&cs->fw6.ipv6.src, s.addr.v6, sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dst, d.addr.v6, sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.smsk, s.mask.v6, sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dmsk, d.mask.v6, sizeof(struct in6_addr));
- } else
- return 1;
-
- return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
-}
-
-static int
-delete_entry(const char *chain, const char *table,
- struct iptables_command_state *cs,
- int family,
- const struct addr_mask s,
- const struct addr_mask d,
- bool verbose,
- struct nft_handle *h)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < s.naddrs; i++) {
- if (family == AF_INET) {
- cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
- cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
- for (j = 0; j < d.naddrs; j++) {
- cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
- cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_cmd_rule_delete(h, chain,
- table, cs, verbose);
- }
- } else if (family == AF_INET6) {
- memcpy(&cs->fw6.ipv6.src,
- &s.addr.v6[i], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.smsk,
- &s.mask.v6[i], sizeof(struct in6_addr));
- for (j = 0; j < d.naddrs; j++) {
- memcpy(&cs->fw6.ipv6.dst,
- &d.addr.v6[j], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dmsk,
- &d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_cmd_rule_delete(h, chain,
- table, cs, verbose);
- }
- }
- }
-
- return ret;
-}
-
-static int
-check_entry(const char *chain, const char *table,
- struct iptables_command_state *cs,
- int family,
- const struct addr_mask s,
- const struct addr_mask d,
- bool verbose, struct nft_handle *h)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < s.naddrs; i++) {
- if (family == AF_INET) {
- cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
- cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
- for (j = 0; j < d.naddrs; j++) {
- cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
- cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_cmd_rule_check(h, chain,
- table, cs, verbose);
- }
- } else if (family == AF_INET6) {
- memcpy(&cs->fw6.ipv6.src,
- &s.addr.v6[i], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.smsk,
- &s.mask.v6[i], sizeof(struct in6_addr));
- for (j = 0; j < d.naddrs; j++) {
- memcpy(&cs->fw6.ipv6.dst,
- &d.addr.v6[j], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dmsk,
- &d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_cmd_rule_check(h, chain,
- table, cs, verbose);
- }
- }
- }
-
- return ret;
-}
-
-static int
list_entries(struct nft_handle *h, const char *chain, const char *table,
int rulenum, int verbose, int numeric, int expanded,
int linenumbers)
@@ -419,6 +262,47 @@ list_rules(struct nft_handle *h, const char *chain, const char *table,
return nft_cmd_rule_list_save(h, chain, table, rulenum, counters);
}
+static void check_empty_interface(struct nft_handle *h, const char *arg)
+{
+ const char *msg = "Empty interface is likely to be undesired";
+
+ if (*arg != '\0')
+ return;
+
+ if (h->family != NFPROTO_ARP)
+ xtables_error(PARAMETER_PROBLEM, msg);
+
+ fprintf(stderr, "%s", msg);
+}
+
+static void check_inverse(struct nft_handle *h, const char option[],
+ bool *invert, int *optidx, int argc)
+{
+ switch (h->family) {
+ case NFPROTO_ARP:
+ break;
+ default:
+ return;
+ }
+
+ if (!option || strcmp(option, "!"))
+ return;
+
+ fprintf(stderr, "Using intrapositioned negation (`--option ! this`) "
+ "is deprecated in favor of extrapositioned (`! --option this`).\n");
+
+ if (*invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "Multiple `!' flags not allowed");
+ *invert = true;
+ if (optidx) {
+ *optidx = *optidx + 1;
+ if (argc && *optidx > argc)
+ xtables_error(PARAMETER_PROBLEM,
+ "no argument following `!'");
+ }
+}
+
void do_parse(struct nft_handle *h, int argc, char *argv[],
struct nft_xt_cmd_parse *p, struct iptables_command_state *cs,
struct xtables_args *args)
@@ -432,10 +316,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
bool invert = false;
int wait = 0;
- memset(cs, 0, sizeof(*cs));
- cs->jumpto = "";
- cs->argv = argv;
-
/* re-set optind to 0 in case do_command4 gets called
* a second time */
optind = 0;
@@ -455,8 +335,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
opterr = 0;
opts = xt_params->orig_opts;
- while ((cs->c = getopt_long(argc, argv,
- "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
+ while ((cs->c = getopt_long(argc, argv, xt_params->optstring,
opts, NULL)) != -1) {
switch (cs->c) {
/*
@@ -601,7 +480,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
xtables_find_match(cs->protocol,
XTF_TRY_LOAD, &cs->matches);
- printhelp(cs->matches);
+ xt_params->print_help(cs->matches);
p->command = CMD_NONE;
return;
@@ -609,14 +488,16 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
* Option selection
*/
case 'p':
+ check_inverse(h, optarg, &invert, &optind, argc);
set_option(&cs->options, OPT_PROTOCOL,
&args->invflags, invert);
/* Canonicalize into lower case */
- for (cs->protocol = optarg; *cs->protocol; cs->protocol++)
+ for (cs->protocol = argv[optind - 1];
+ *cs->protocol; cs->protocol++)
*cs->protocol = tolower(*cs->protocol);
- cs->protocol = optarg;
+ cs->protocol = argv[optind - 1];
args->proto = xtables_parse_protocol(cs->protocol);
if (args->proto == 0 &&
@@ -625,19 +506,22 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
"rule would never match protocol");
/* This needs to happen here to parse extensions */
- h->ops->proto_parse(cs, args);
+ if (h->ops->proto_parse)
+ h->ops->proto_parse(cs, args);
break;
case 's':
+ check_inverse(h, optarg, &invert, &optind, argc);
set_option(&cs->options, OPT_SOURCE,
&args->invflags, invert);
- args->shostnetworkmask = optarg;
+ args->shostnetworkmask = argv[optind - 1];
break;
case 'd':
+ check_inverse(h, optarg, &invert, &optind, argc);
set_option(&cs->options, OPT_DESTINATION,
&args->invflags, invert);
- args->dhostnetworkmask = optarg;
+ args->dhostnetworkmask = argv[optind - 1];
break;
#ifdef IPT_F_GOTO
@@ -649,33 +533,72 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
break;
#endif
+ case 2:/* src-mac */
+ check_inverse(h, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_S_MAC, &args->invflags,
+ invert);
+ args->src_mac = argv[optind - 1];
+ break;
+
+ case 3:/* dst-mac */
+ check_inverse(h, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_D_MAC, &args->invflags,
+ invert);
+ args->dst_mac = argv[optind - 1];
+ break;
+
+ case 'l':/* hardware length */
+ check_inverse(h, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_H_LENGTH, &args->invflags,
+ invert);
+ args->arp_hlen = argv[optind - 1];
+ break;
+
+ case 8: /* was never supported, not even in arptables-legacy */
+ xtables_error(PARAMETER_PROBLEM, "not supported");
+ case 4:/* opcode */
+ check_inverse(h, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_OPCODE, &args->invflags,
+ invert);
+ args->arp_opcode = argv[optind - 1];
+ break;
+
+ case 5:/* h-type */
+ check_inverse(h, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_H_TYPE, &args->invflags,
+ invert);
+ args->arp_htype = argv[optind - 1];
+ break;
+
+ case 6:/* proto-type */
+ check_inverse(h, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_P_TYPE, &args->invflags,
+ invert);
+ args->arp_ptype = argv[optind - 1];
+ break;
+
case 'j':
set_option(&cs->options, OPT_JUMP, &args->invflags,
invert);
- command_jump(cs, optarg);
+ command_jump(cs, argv[optind - 1]);
break;
-
case 'i':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
+ check_empty_interface(h, optarg);
+ check_inverse(h, optarg, &invert, &optind, argc);
set_option(&cs->options, OPT_VIANAMEIN,
&args->invflags, invert);
- xtables_parse_interface(optarg,
+ xtables_parse_interface(argv[optind - 1],
args->iniface,
args->iniface_mask);
break;
case 'o':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
+ check_empty_interface(h, optarg);
+ check_inverse(h, optarg, &invert, &optind, argc);
set_option(&cs->options, OPT_VIANAMEOUT,
&args->invflags, invert);
- xtables_parse_interface(optarg,
+ xtables_parse_interface(argv[optind - 1],
args->outiface,
args->outiface_mask);
break;
@@ -823,7 +746,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
exit_tryhelp(2);
default:
- if (command_default(cs, &xtables_globals, invert))
+ if (command_default(cs, xt_params, invert))
/* cf. ip6tables.c */
continue;
break;
@@ -912,42 +835,46 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
.table = *table,
.restore = restore,
};
- struct iptables_command_state cs;
+ 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(h, argc, argv, &p, &cs, &args);
switch (p.command) {
case CMD_APPEND:
- ret = add_entry(p.chain, p.table, &cs, 0, h->family,
- args.s, args.d,
- cs.options & OPT_VERBOSE, h, true);
+ 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 = delete_entry(p.chain, p.table, &cs, h->family,
- args.s, args.d,
- cs.options & OPT_VERBOSE, h);
+ 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 = check_entry(p.chain, p.table, &cs, h->family,
- args.s, args.d,
- cs.options & OPT_VERBOSE, h);
+ ret = h->ops->check_entry(h, p.chain, p.table, &cs, &args,
+ cs.options & OPT_VERBOSE);
break;
case CMD_REPLACE:
- ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1,
- h->family, args.s, args.d,
- cs.options & OPT_VERBOSE, h);
+ ret = h->ops->replace_entry(h, p.chain, p.table, &cs, &args,
+ cs.options & OPT_VERBOSE,
+ p.rulenum - 1);
break;
case CMD_INSERT:
- ret = add_entry(p.chain, p.table, &cs, p.rulenum - 1,
- h->family, args.s, args.d,
- cs.options&OPT_VERBOSE, h, false);
+ 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,
@@ -998,8 +925,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
ret = nft_cmd_chain_user_add(h, p.chain, p.table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_cmd_chain_user_del(h, p.chain, p.table,
- cs.options & OPT_VERBOSE);
+ 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);
@@ -1019,17 +946,10 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
nft_clear_iptables_command_state(&cs);
- 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);
- }
+ 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;