summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac3
-rw-r--r--extensions/libipt_DNAT.c138
-rw-r--r--extensions/libipt_SNAT.c158
-rw-r--r--extensions/libxt_DNAT.man6
-rw-r--r--extensions/libxt_NFLOG.c8
-rw-r--r--extensions/libxt_NFLOG.t16
-rw-r--r--extensions/libxt_SNAT.man6
-rw-r--r--extensions/libxt_hashlimit.t4
-rw-r--r--extensions/libxt_tcpmss.c16
-rw-r--r--extensions/libxt_tcpmss.txlate11
-rw-r--r--include/xtables.h2
-rwxr-xr-xiptables-test.py18
-rw-r--r--iptables/Makefile.am2
-rw-r--r--iptables/ip6tables.c844
-rw-r--r--iptables/iptables-restore.c2
-rw-r--r--iptables/iptables-save.c2
-rw-r--r--iptables/iptables.c842
-rw-r--r--iptables/nft-arp.c262
-rw-r--r--iptables/nft-bridge.c13
-rw-r--r--iptables/nft-ipv4.c229
-rw-r--r--iptables/nft-ipv6.c219
-rw-r--r--iptables/nft-shared.c214
-rw-r--r--iptables/nft-shared.h86
-rw-r--r--iptables/nft.c103
-rw-r--r--iptables/nft.h3
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0007-chain-policies_02
-rw-r--r--iptables/xshared.c1058
-rw-r--r--iptables/xshared.h99
-rw-r--r--iptables/xtables-arp-standalone.c65
-rw-r--r--iptables/xtables-arp.c753
-rw-r--r--iptables/xtables-eb-translate.c5
-rw-r--r--iptables/xtables-eb.c17
-rw-r--r--iptables/xtables-monitor.c2
-rw-r--r--iptables/xtables-multi.h3
-rw-r--r--iptables/xtables-restore.c11
-rw-r--r--iptables/xtables-save.c8
-rw-r--r--iptables/xtables-standalone.c54
-rw-r--r--iptables/xtables-translate.c28
-rw-r--r--iptables/xtables.c836
-rw-r--r--libxtables/xtables.c12
-rwxr-xr-xxlate-test.py18
41 files changed, 2245 insertions, 3933 deletions
diff --git a/configure.ac b/configure.ac
index 00ae60c5..86c67194 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,9 +12,8 @@ AC_PROG_INSTALL
AM_INIT_AUTOMAKE([-Wall])
AC_PROG_CC
AM_PROG_CC_C_O
-AC_DISABLE_STATIC
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
-AM_PROG_LIBTOOL
+LT_INIT([disable-static])
AC_ARG_WITH([kernel],
AS_HELP_STRING([--with-kernel=PATH],
diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c
index 5b33fd23..eefa95eb 100644
--- a/extensions/libipt_DNAT.c
+++ b/extensions/libipt_DNAT.c
@@ -18,14 +18,6 @@ enum {
F_X_TO_DEST = 1 << O_X_TO_DEST,
};
-/* Dest NAT data consists of a multi-range, indicating where to map
- to. */
-struct ipt_natinfo
-{
- struct xt_entry_target t;
- struct nf_nat_ipv4_multi_range_compat mr;
-};
-
static void DNAT_help(void)
{
printf(
@@ -46,41 +38,20 @@ static void DNAT_help_v2(void)
static const struct xt_option_entry DNAT_opts[] = {
{.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_MULTI},
+ .flags = XTOPT_MAND},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
-static struct ipt_natinfo *
-append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range)
-{
- unsigned int size;
-
- /* One rangesize already in struct ipt_natinfo */
- size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
-
- info = realloc(info, size);
- if (!info)
- xtables_error(OTHER_PROBLEM, "Out of memory\n");
-
- info->t.u.target_size = size;
- info->mr.range[info->mr.rangesize] = *range;
- info->mr.rangesize++;
-
- return info;
-}
-
/* Ranges expected in network order. */
-static struct xt_entry_target *
-parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
+static void
+parse_to(const char *orig_arg, int portok, struct nf_nat_ipv4_range *range)
{
- struct nf_nat_ipv4_range range;
char *arg, *colon, *dash, *error;
const struct in_addr *ip;
arg = xtables_strdup(orig_arg);
- memset(&range, 0, sizeof(range));
colon = strchr(arg, ':');
if (colon) {
@@ -90,7 +61,7 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
- range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
+ range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
port = atoi(colon+1);
if (port <= 0 || port > 65535)
@@ -104,8 +75,8 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
dash = strchr(colon, '-');
if (!dash) {
- range.min.tcp.port
- = range.max.tcp.port
+ range->min.tcp.port
+ = range->max.tcp.port
= htons(port);
} else {
int maxport;
@@ -118,18 +89,18 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
/* People are stupid. */
xtables_error(PARAMETER_PROBLEM,
"Port range `%s' funky\n", colon+1);
- range.min.tcp.port = htons(port);
- range.max.tcp.port = htons(maxport);
+ range->min.tcp.port = htons(port);
+ range->max.tcp.port = htons(maxport);
}
/* Starts with a colon? No IP info...*/
if (colon == arg) {
free(arg);
- return &(append_range(info, &range)->t);
+ return;
}
*colon = '\0';
}
- range.flags |= NF_NAT_RANGE_MAP_IPS;
+ range->flags |= NF_NAT_RANGE_MAP_IPS;
dash = strchr(arg, '-');
if (colon && dash && dash > colon)
dash = NULL;
@@ -141,24 +112,24 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
arg);
- range.min_ip = ip->s_addr;
+ range->min_ip = ip->s_addr;
if (dash) {
ip = xtables_numeric_to_ipaddr(dash+1);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
dash+1);
- range.max_ip = ip->s_addr;
+ range->max_ip = ip->s_addr;
} else
- range.max_ip = range.min_ip;
+ range->max_ip = range->min_ip;
free(arg);
- return &(append_range(info, &range)->t);
+ return;
}
static void DNAT_parse(struct xt_option_call *cb)
{
+ struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data;
const struct ipt_entry *entry = cb->xt_entry;
- struct ipt_natinfo *info = (void *)(*cb->target);
int portok;
if (entry->ip.proto == IPPROTO_TCP
@@ -173,18 +144,11 @@ static void DNAT_parse(struct xt_option_call *cb)
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TO_DEST:
- if (cb->xflags & F_X_TO_DEST) {
- if (!kernel_version)
- get_kernel_version();
- if (kernel_version > LINUX_VERSION(2, 6, 10))
- xtables_error(PARAMETER_PROBLEM,
- "DNAT: Multiple --to-destination not supported");
- }
- *cb->target = parse_to(cb->arg, portok, info);
+ parse_to(cb->arg, portok, mr->range);
cb->xflags |= F_X_TO_DEST;
break;
case O_PERSISTENT:
- info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT;
+ mr->range->flags |= NF_NAT_RANGE_PERSISTENT;
break;
}
}
@@ -196,6 +160,8 @@ static void DNAT_fcheck(struct xt_fcheck_call *cb)
if ((cb->xflags & f) == f)
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
+
+ mr->rangesize = 1;
}
static void print_range(const struct nf_nat_ipv4_range *r)
@@ -221,32 +187,28 @@ static void print_range(const struct nf_nat_ipv4_range *r)
static void DNAT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
- const struct ipt_natinfo *info = (const void *)target;
- unsigned int i = 0;
+ const struct nf_nat_ipv4_multi_range_compat *mr =
+ (const void *)target->data;
printf(" to:");
- for (i = 0; i < info->mr.rangesize; i++) {
- print_range(&info->mr.range[i]);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
- printf(" persistent");
- }
+ print_range(mr->range);
+ if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ printf(" random");
+ if (mr->range->flags & NF_NAT_RANGE_PERSISTENT)
+ printf(" persistent");
}
static void DNAT_save(const void *ip, const struct xt_entry_target *target)
{
- const struct ipt_natinfo *info = (const void *)target;
- unsigned int i = 0;
-
- for (i = 0; i < info->mr.rangesize; i++) {
- printf(" --to-destination ");
- print_range(&info->mr.range[i]);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
- printf(" --persistent");
- }
+ const struct nf_nat_ipv4_multi_range_compat *mr =
+ (const void *)target->data;
+
+ printf(" --to-destination ");
+ print_range(mr->range);
+ if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ printf(" --random");
+ if (mr->range->flags & NF_NAT_RANGE_PERSISTENT)
+ printf(" --persistent");
}
static void print_range_xlate(const struct nf_nat_ipv4_range *r,
@@ -272,23 +234,21 @@ static void print_range_xlate(const struct nf_nat_ipv4_range *r,
static int DNAT_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
- const struct ipt_natinfo *info = (const void *)params->target;
- unsigned int i = 0;
+ const struct nf_nat_ipv4_multi_range_compat *mr =
+ (const void *)params->target->data;
bool sep_need = false;
const char *sep = " ";
- for (i = 0; i < info->mr.rangesize; i++) {
- xt_xlate_add(xl, "dnat to ");
- print_range_xlate(&info->mr.range[i], xl);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) {
- xt_xlate_add(xl, " random");
- sep_need = true;
- }
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%spersistent", sep);
- }
+ xt_xlate_add(xl, "dnat to ");
+ print_range_xlate(mr->range, xl);
+ if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
+ xt_xlate_add(xl, " random");
+ sep_need = true;
+ }
+ if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%spersistent", sep);
}
return 1;
@@ -406,10 +366,6 @@ static void DNAT_parse_v2(struct xt_option_call *cb)
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TO_DEST:
- if (cb->xflags & F_X_TO_DEST) {
- xtables_error(PARAMETER_PROBLEM,
- "DNAT: Multiple --to-destination not supported");
- }
parse_to_v2(cb->arg, portok, range);
cb->xflags |= F_X_TO_DEST;
break;
diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c
index c655439e..bd36830a 100644
--- a/extensions/libipt_SNAT.c
+++ b/extensions/libipt_SNAT.c
@@ -20,14 +20,6 @@ enum {
F_X_TO_SRC = 1 << O_X_TO_SRC,
};
-/* Source NAT data consists of a multi-range, indicating where to map
- to. */
-struct ipt_natinfo
-{
- struct xt_entry_target t;
- struct nf_nat_ipv4_multi_range_compat mr;
-};
-
static void SNAT_help(void)
{
printf(
@@ -39,42 +31,21 @@ static void SNAT_help(void)
static const struct xt_option_entry SNAT_opts[] = {
{.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_MULTI},
+ .flags = XTOPT_MAND},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
{.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
-static struct ipt_natinfo *
-append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range)
-{
- unsigned int size;
-
- /* One rangesize already in struct ipt_natinfo */
- size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
-
- info = realloc(info, size);
- if (!info)
- xtables_error(OTHER_PROBLEM, "Out of memory\n");
-
- info->t.u.target_size = size;
- info->mr.range[info->mr.rangesize] = *range;
- info->mr.rangesize++;
-
- return info;
-}
-
/* Ranges expected in network order. */
-static struct xt_entry_target *
-parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
+static void
+parse_to(const char *orig_arg, int portok, struct nf_nat_ipv4_range *range)
{
- struct nf_nat_ipv4_range range;
char *arg, *colon, *dash, *error;
const struct in_addr *ip;
arg = xtables_strdup(orig_arg);
- memset(&range, 0, sizeof(range));
colon = strchr(arg, ':');
if (colon) {
@@ -84,7 +55,7 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
- range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
+ range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
port = atoi(colon+1);
if (port <= 0 || port > 65535)
@@ -98,8 +69,8 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
dash = strchr(colon, '-');
if (!dash) {
- range.min.tcp.port
- = range.max.tcp.port
+ range->min.tcp.port
+ = range->max.tcp.port
= htons(port);
} else {
int maxport;
@@ -112,18 +83,18 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
/* People are stupid. */
xtables_error(PARAMETER_PROBLEM,
"Port range `%s' funky\n", colon+1);
- range.min.tcp.port = htons(port);
- range.max.tcp.port = htons(maxport);
+ range->min.tcp.port = htons(port);
+ range->max.tcp.port = htons(maxport);
}
/* Starts with a colon? No IP info...*/
if (colon == arg) {
free(arg);
- return &(append_range(info, &range)->t);
+ return;
}
*colon = '\0';
}
- range.flags |= NF_NAT_RANGE_MAP_IPS;
+ range->flags |= NF_NAT_RANGE_MAP_IPS;
dash = strchr(arg, '-');
if (colon && dash && dash > colon)
dash = NULL;
@@ -135,24 +106,24 @@ parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
arg);
- range.min_ip = ip->s_addr;
+ range->min_ip = ip->s_addr;
if (dash) {
ip = xtables_numeric_to_ipaddr(dash+1);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
dash+1);
- range.max_ip = ip->s_addr;
+ range->max_ip = ip->s_addr;
} else
- range.max_ip = range.min_ip;
+ range->max_ip = range->min_ip;
free(arg);
- return &(append_range(info, &range)->t);
+ return;
}
static void SNAT_parse(struct xt_option_call *cb)
{
+ struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
const struct ipt_entry *entry = cb->xt_entry;
- struct ipt_natinfo *info = (void *)(*cb->target);
int portok;
if (entry->ip.proto == IPPROTO_TCP
@@ -167,18 +138,11 @@ static void SNAT_parse(struct xt_option_call *cb)
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TO_SRC:
- if (cb->xflags & F_X_TO_SRC) {
- if (!kernel_version)
- get_kernel_version();
- if (kernel_version > LINUX_VERSION(2, 6, 10))
- xtables_error(PARAMETER_PROBLEM,
- "SNAT: Multiple --to-source not supported");
- }
- *cb->target = parse_to(cb->arg, portok, info);
+ parse_to(cb->arg, portok, mr->range);
cb->xflags |= F_X_TO_SRC;
break;
case O_PERSISTENT:
- info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT;
+ mr->range->flags |= NF_NAT_RANGE_PERSISTENT;
break;
}
}
@@ -190,9 +154,11 @@ static void SNAT_fcheck(struct xt_fcheck_call *cb)
struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
if ((cb->xflags & f) == f)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
+ mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
if ((cb->xflags & r) == r)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
+ mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
+
+ mr->rangesize = 1;
}
static void print_range(const struct nf_nat_ipv4_range *r)
@@ -218,36 +184,32 @@ static void print_range(const struct nf_nat_ipv4_range *r)
static void SNAT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
- const struct ipt_natinfo *info = (const void *)target;
- unsigned int i = 0;
+ const struct nf_nat_ipv4_multi_range_compat *mr =
+ (const void *)target->data;
printf(" to:");
- for (i = 0; i < info->mr.rangesize; i++) {
- print_range(&info->mr.range[i]);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" random-fully");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
- printf(" persistent");
- }
+ print_range(mr->range);
+ if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ printf(" random");
+ if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ printf(" random-fully");
+ if (mr->range->flags & NF_NAT_RANGE_PERSISTENT)
+ printf(" persistent");
}
static void SNAT_save(const void *ip, const struct xt_entry_target *target)
{
- const struct ipt_natinfo *info = (const void *)target;
- unsigned int i = 0;
-
- for (i = 0; i < info->mr.rangesize; i++) {
- printf(" --to-source ");
- print_range(&info->mr.range[i]);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" --random-fully");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
- printf(" --persistent");
- }
+ const struct nf_nat_ipv4_multi_range_compat *mr =
+ (const void *)target->data;
+
+ printf(" --to-source ");
+ print_range(mr->range);
+ if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ printf(" --random");
+ if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ printf(" --random-fully");
+ if (mr->range->flags & NF_NAT_RANGE_PERSISTENT)
+ printf(" --persistent");
}
static void print_range_xlate(const struct nf_nat_ipv4_range *r,
@@ -274,29 +236,27 @@ static void print_range_xlate(const struct nf_nat_ipv4_range *r,
static int SNAT_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
- const struct ipt_natinfo *info = (const void *)params->target;
- unsigned int i = 0;
+ const struct nf_nat_ipv4_multi_range_compat *mr =
+ (const void *)params->target->data;
bool sep_need = false;
const char *sep = " ";
- for (i = 0; i < info->mr.rangesize; i++) {
- xt_xlate_add(xl, "snat to ");
- print_range_xlate(&info->mr.range[i], xl);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) {
- xt_xlate_add(xl, " random");
- sep_need = true;
- }
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%sfully-random", sep);
- sep_need = true;
- }
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%spersistent", sep);
- }
+ xt_xlate_add(xl, "snat to ");
+ print_range_xlate(mr->range, xl);
+ if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
+ xt_xlate_add(xl, " random");
+ sep_need = true;
+ }
+ if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%sfully-random", sep);
+ sep_need = true;
+ }
+ if (mr->range->flags & NF_NAT_RANGE_PERSISTENT) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%spersistent", sep);
}
return 1;
diff --git a/extensions/libxt_DNAT.man b/extensions/libxt_DNAT.man
index 225274ff..c3daea9a 100644
--- a/extensions/libxt_DNAT.man
+++ b/extensions/libxt_DNAT.man
@@ -18,12 +18,6 @@ if the rule also specifies one of the following protocols:
If no port range is specified, then the destination port will never be
modified. If no IP address is specified then only the destination port
will be modified.
-In Kernels up to 2.6.10 you can add several \-\-to\-destination options. For
-those kernels, if you specify more than one destination address, either via an
-address range or multiple \-\-to\-destination options, a simple round-robin (one
-after another in cycle) load balancing takes place between these addresses.
-Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges
-anymore.
.TP
\fB\-\-random\fP
If option
diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c
index 02a1b4aa..6137a68f 100644
--- a/extensions/libxt_NFLOG.c
+++ b/extensions/libxt_NFLOG.c
@@ -5,6 +5,7 @@
#include <getopt.h>
#include <xtables.h>
+#include <linux/netfilter/nf_log.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_NFLOG.h>
@@ -53,12 +54,16 @@ static void NFLOG_init(struct xt_entry_target *t)
static void NFLOG_parse(struct xt_option_call *cb)
{
+ char *nf_log_prefix = cb->udata;
+
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_PREFIX:
if (strchr(cb->arg, '\n') != NULL)
xtables_error(PARAMETER_PROBLEM,
"Newlines not allowed in --log-prefix");
+
+ snprintf(nf_log_prefix, NF_LOG_PREFIXLEN, "%s", cb->arg);
break;
}
}
@@ -78,7 +83,7 @@ static void NFLOG_check(struct xt_fcheck_call *cb)
static void nflog_print(const struct xt_nflog_info *info, char *prefix)
{
if (info->prefix[0] != '\0') {
- printf(" %snflog-prefix ", prefix);
+ printf(" %snflog-prefix", prefix);
xtables_save_string(info->prefix);
}
if (info->group)
@@ -149,6 +154,7 @@ static struct xtables_target nflog_target = {
.save = NFLOG_save,
.x6_options = NFLOG_opts,
.xlate = NFLOG_xlate,
+ .udata_size = NF_LOG_PREFIXLEN
};
void _init(void)
diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t
index 933fa221..561ec8c7 100644
--- a/extensions/libxt_NFLOG.t
+++ b/extensions/libxt_NFLOG.t
@@ -3,19 +3,19 @@
-j NFLOG --nflog-group 65535;=;OK
-j NFLOG --nflog-group 65536;;FAIL
-j NFLOG --nflog-group 0;-j NFLOG;OK
--j NFLOG --nflog-range 1;=;OK
--j NFLOG --nflog-range 4294967295;=;OK
--j NFLOG --nflog-range 4294967296;;FAIL
--j NFLOG --nflog-range -1;;FAIL
+# `--nflog-range` is broken and only supported by xtables-legacy. It
+# has been superseded by `--nflog--group`.
+# -j NFLOG --nflog-range 1;=;OK
+# -j NFLOG --nflog-range 4294967295;=;OK
+# -j NFLOG --nflog-range 4294967296;;FAIL
+# -j NFLOG --nflog-range -1;;FAIL
-j NFLOG --nflog-size 0;=;OK
-j NFLOG --nflog-size 1;=;OK
-j NFLOG --nflog-size 4294967295;=;OK
-j NFLOG --nflog-size 4294967296;;FAIL
-j NFLOG --nflog-size -1;;FAIL
-# ERROR: cannot find: iptables -I INPUT -j NFLOG --nflog-prefix xxxxxx [...]
-# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
-# ERROR: should fail: iptables -A INPUT -j NFLOG --nflog-prefix xxxxxxx [...]
-# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
+-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
+-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;OK
-j NFLOG --nflog-threshold 1;=;OK
# ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0
# -j NFLOG --nflog-threshold 0;;FAIL
diff --git a/extensions/libxt_SNAT.man b/extensions/libxt_SNAT.man
index 8cd0b80e..08766447 100644
--- a/extensions/libxt_SNAT.man
+++ b/extensions/libxt_SNAT.man
@@ -19,12 +19,6 @@ If no port range is specified, then source ports below 512 will be
mapped to other ports below 512: those between 512 and 1023 inclusive
will be mapped to ports below 1024, and other ports will be mapped to
1024 or above. Where possible, no port alteration will occur.
-In Kernels up to 2.6.10, you can add several \-\-to\-source options. For those
-kernels, if you specify more than one source address, either via an address
-range or multiple \-\-to\-source options, a simple round-robin (one after another
-in cycle) takes place between these addresses.
-Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges
-anymore.
.TP
\fB\-\-random\fP
If option
diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t
index 83699337..206d9293 100644
--- a/extensions/libxt_hashlimit.t
+++ b/extensions/libxt_hashlimit.t
@@ -3,12 +3,12 @@
-m hashlimit --hashlimit-above 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
--m hashlimit --hashlimit-above 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-above 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
--m hashlimit --hashlimit-upto 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode srcip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
diff --git a/extensions/libxt_tcpmss.c b/extensions/libxt_tcpmss.c
index bcd357aa..61b853d1 100644
--- a/extensions/libxt_tcpmss.c
+++ b/extensions/libxt_tcpmss.c
@@ -60,6 +60,21 @@ static void tcpmss_save(const void *ip, const struct xt_entry_match *match)
printf("%u:%u", info->mss_min, info->mss_max);
}
+static int tcpmss_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_tcpmss_match_info *info = (void *)params->match->data;
+
+ xt_xlate_add(xl, "tcp option maxseg size %s", info->invert ? "!= " : "");
+
+ if (info->mss_min == info->mss_max)
+ xt_xlate_add(xl, "%u", info->mss_min);
+ else
+ xt_xlate_add(xl, "%u-%u", info->mss_min, info->mss_max);
+
+ return 1;
+}
+
static struct xtables_match tcpmss_match = {
.family = NFPROTO_UNSPEC,
.name = "tcpmss",
@@ -71,6 +86,7 @@ static struct xtables_match tcpmss_match = {
.save = tcpmss_save,
.x6_parse = tcpmss_parse,
.x6_options = tcpmss_opts,
+ .xlate = tcpmss_xlate,
};
void _init(void)
diff --git a/extensions/libxt_tcpmss.txlate b/extensions/libxt_tcpmss.txlate
new file mode 100644
index 00000000..d3f1b27d
--- /dev/null
+++ b/extensions/libxt_tcpmss.txlate
@@ -0,0 +1,11 @@
+iptables-translate -A INPUT -m tcpmss --mss 42
+nft add rule ip filter INPUT tcp option maxseg size 42 counter
+
+iptables-translate -A INPUT -m tcpmss ! --mss 42
+nft add rule ip filter INPUT tcp option maxseg size != 42 counter
+
+iptables-translate -A INPUT -m tcpmss --mss 42:1024
+nft add rule ip filter INPUT tcp option maxseg size 42-1024 counter
+
+iptables-translate -A INPUT -m tcpmss ! --mss 1461:65535
+nft add rule ip filter INPUT tcp option maxseg size != 1461-65535 counter
diff --git a/include/xtables.h b/include/xtables.h
index e51f4bfd..ca674c26 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -420,10 +420,12 @@ struct xtables_globals
{
unsigned int option_offset;
const char *program_name, *program_version;
+ const char *optstring;
struct option *orig_opts;
struct option *opts;
void (*exit_err)(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
int (*compat_rev)(const char *name, uint8_t rev, int opt);
+ void (*print_help)(const struct xtables_rule_match *m);
};
#define XT_GETOPT_TABLEEND {.name = NULL, .has_arg = false}
diff --git a/iptables-test.py b/iptables-test.py
index 0ba3d368..95fa11b1 100755
--- a/iptables-test.py
+++ b/iptables-test.py
@@ -84,7 +84,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
cmd = iptables + " -A " + rule
if netns:
- cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + cmd
+ cmd = "ip netns exec ____iptables-container-test " + EXECUTABLE + " " + cmd
ret = execute_cmd(cmd, filename, lineno)
@@ -123,7 +123,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
elif splitted[0] == EBTABLES:
command = EBTABLES_SAVE
- command = EXECUTEABLE + " " + command
+ command = EXECUTABLE + " " + command
if netns:
command = "ip netns exec ____iptables-container-test " + command
@@ -168,7 +168,7 @@ def execute_cmd(cmd, filename, lineno):
'''
global log_file
if cmd.startswith('iptables ') or cmd.startswith('ip6tables ') or cmd.startswith('ebtables ') or cmd.startswith('arptables '):
- cmd = EXECUTEABLE + " " + cmd
+ cmd = EXECUTABLE + " " + cmd
print("command: {}".format(cmd), file=log_file)
ret = subprocess.call(cmd, shell=True, universal_newlines=True,
@@ -202,12 +202,12 @@ def run_test_file(filename, netns):
iptables = IPTABLES
elif "libarpt_" in filename:
# only supported with nf_tables backend
- if EXECUTEABLE != "xtables-nft-multi":
+ if EXECUTABLE != "xtables-nft-multi":
return 0, 0
iptables = ARPTABLES
elif "libebt_" in filename:
# only supported with nf_tables backend
- if EXECUTEABLE != "xtables-nft-multi":
+ if EXECUTABLE != "xtables-nft-multi":
return 0, 0
iptables = EBTABLES
else:
@@ -245,7 +245,7 @@ def run_test_file(filename, netns):
if line[0] == "%":
external_cmd = line.rstrip()[1:]
if netns:
- external_cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + external_cmd
+ external_cmd = "ip netns exec ____iptables-container-test " + EXECUTABLE + " " + external_cmd
execute_cmd(external_cmd, filename, lineno)
continue
@@ -366,10 +366,10 @@ def main():
show_missing()
return
- global EXECUTEABLE
- EXECUTEABLE = "xtables-legacy-multi"
+ global EXECUTABLE
+ EXECUTABLE = "xtables-legacy-multi"
if args.nftables:
- EXECUTEABLE = "xtables-nft-multi"
+ EXECUTABLE = "xtables-nft-multi"
if os.getuid() != 0:
print("You need to be root to run this, sorry", file=sys.stderr)
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index f7895210..0258264c 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -37,7 +37,7 @@ xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \
xtables-standalone.c xtables.c nft.c \
nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \
xtables-monitor.c nft-cache.c \
- xtables-arp-standalone.c xtables-arp.c \
+ xtables-arp.c \
nft-bridge.c nft-cmd.c nft-chain.c \
xtables-eb-standalone.c xtables-eb.c \
xtables-eb-translate.c \
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index e967c040..560b6ed0 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -87,134 +87,15 @@ static struct option original_opts[] = {
{NULL},
};
-void ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
struct xtables_globals ip6tables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (legacy)",
+ .optstring = OPTSTRING_COMMON "R:S::W::" "46bg:h::m:nvw::x",
.orig_opts = original_opts,
- .exit_err = ip6tables_exit_error,
.compat_rev = xtables_compatible_revision,
+ .print_help = xtables_printhelp,
};
-#define opts ip6tables_globals.opts
-#define prog_name ip6tables_globals.program_name
-#define prog_vers ip6tables_globals.program_version
-
-static void __attribute__((noreturn))
-exit_tryhelp(int status)
-{
- if (line != -1)
- fprintf(stderr, "Error occurred at line: %d\n", line);
- fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
- prog_name, prog_name);
- xtables_free_opts(1);
- exit(status);
-}
-
-static void
-exit_printhelp(const struct xtables_rule_match *matches)
-{
- printf("%s v%s\n\n"
-"Usage: %s -[ACD] chain rule-specification [options]\n"
-" %s -I chain [rulenum] rule-specification [options]\n"
-" %s -R chain rulenum rule-specification [options]\n"
-" %s -D chain rulenum [options]\n"
-" %s -[LS] [chain [rulenum]] [options]\n"
-" %s -[FZ] [chain] [options]\n"
-" %s -[NX] chain\n"
-" %s -E old-chain-name new-chain-name\n"
-" %s -P chain target [options]\n"
-" %s -h (print this help information)\n\n",
- prog_name, prog_vers, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name);
-
- printf(
-"Commands:\n"
-"Either long or short options are allowed.\n"
-" --append -A chain Append to chain\n"
-" --check -C chain Check for the existence of a rule\n"
-" --delete -D chain Delete matching rule from chain\n"
-" --delete -D chain rulenum\n"
-" Delete rule rulenum (1 = first) from chain\n"
-" --insert -I chain [rulenum]\n"
-" Insert in chain as rulenum (default 1=first)\n"
-" --replace -R chain rulenum\n"
-" Replace rule rulenum (1 = first) in chain\n"
-" --list -L [chain [rulenum]]\n"
-" List the rules in a chain or all chains\n"
-" --list-rules -S [chain [rulenum]]\n"
-" Print the rules in a chain or all chains\n"
-" --flush -F [chain] Delete all rules in chain or all chains\n"
-" --zero -Z [chain [rulenum]]\n"
-" Zero counters in chain or all chains\n"
-" --new -N chain Create a new user-defined chain\n"
-" --delete-chain\n"
-" -X [chain] Delete a user-defined chain\n"
-" --policy -P chain target\n"
-" Change policy on chain to target\n"
-" --rename-chain\n"
-" -E old-chain new-chain\n"
-" Change chain name, (moving any references)\n"
-
-"Options:\n"
-" --ipv4 -4 Error (line is ignored by ip6tables-restore)\n"
-" --ipv6 -6 Nothing (line is ignored by iptables-restore)\n"
-"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n"
-"[!] --source -s address[/mask][,...]\n"
-" source specification\n"
-"[!] --destination -d address[/mask][,...]\n"
-" destination specification\n"
-"[!] --in-interface -i input name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --jump -j target\n"
-" target for rule (may load target extension)\n"
-#ifdef IP6T_F_GOTO
-" --goto -g chain\n"
-" jump to chain with no return\n"
-#endif
-" --match -m match\n"
-" extended match (may load extension)\n"
-" --numeric -n numeric output of addresses and ports\n"
-"[!] --out-interface -o output name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --table -t table table to manipulate (default: `filter')\n"
-" --verbose -v verbose mode\n"
-" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
-" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n"
-" interval to wait for xtables lock\n"
-" default is 1 second\n"
-" --line-numbers print line numbers when listing\n"
-" --exact -x expand numbers (display exact values)\n"
-/*"[!] --fragment -f match second or further fragments only\n"*/
-" --modprobe=<command> try to insert modules using this command\n"
-" --set-counters PKTS BYTES set the counter during insert/append\n"
-"[!] --version -V print package version.\n");
-
- print_extension_helps(xtables_targets, matches);
- exit(0);
-}
-
-void
-ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...)
-{
- va_list args;
-
- va_start(args, msg);
- fprintf(stderr, "%s v%s (legacy): ", prog_name, prog_vers);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, "\n");
- if (status == PARAMETER_PROBLEM)
- exit_tryhelp(status);
- if (status == VERSION_PROBLEM)
- fprintf(stderr,
- "Perhaps ip6tables or your kernel needs to be upgraded.\n");
- /* On error paths, make sure that we don't leak memory */
- xtables_free_opts(1);
- exit(status);
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
@@ -224,91 +105,6 @@ ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...)
* return global static data.
*/
-/* These are invalid numbers as upper layer protocol */
-static int is_exthdr(uint16_t proto)
-{
- return (proto == IPPROTO_ROUTING ||
- proto == IPPROTO_FRAGMENT ||
- proto == IPPROTO_AH ||
- proto == IPPROTO_DSTOPTS);
-}
-
-static void
-parse_chain(const char *chainname)
-{
- const char *ptr;
-
- if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %u chars)",
- chainname, XT_EXTENSION_MAXNAMELEN);
-
- if (*chainname == '-' || *chainname == '!')
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `%c'\n", *chainname);
-
- if (xtables_find_target(chainname, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
-
- for (ptr = chainname; *ptr; ptr++)
- if (isspace(*ptr))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s'", chainname);
-}
-
-static void
-print_header(unsigned int format, const char *chain, struct xtc_handle *handle)
-{
- struct xt_counters counters;
- const char *pol = ip6tc_get_policy(chain, &counters, handle);
- printf("Chain %s", chain);
- if (pol) {
- printf(" (policy %s", pol);
- if (!(format & FMT_NOCOUNTS)) {
- fputc(' ', stdout);
- xtables_print_num(counters.pcnt, (format|FMT_NOTABLE));
- fputs("packets, ", stdout);
- xtables_print_num(counters.bcnt, (format|FMT_NOTABLE));
- fputs("bytes", stdout);
- }
- printf(")\n");
- } else {
- unsigned int refs;
- if (!ip6tc_get_references(&refs, chain, handle))
- printf(" (ERROR obtaining refs)\n");
- else
- printf(" (%u references)\n", refs);
- }
-
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4s ", "%s "), "num");
- if (!(format & FMT_NOCOUNTS)) {
- if (format & FMT_KILOMEGAGIGA) {
- printf(FMT("%5s ","%s "), "pkts");
- printf(FMT("%5s ","%s "), "bytes");
- } else {
- printf(FMT("%8s ","%s "), "pkts");
- printf(FMT("%10s ","%s "), "bytes");
- }
- }
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ","%s "), "target");
- fputs(" prot ", stdout);
- if (format & FMT_OPTIONS)
- fputs("opt", stdout);
- if (format & FMT_VIA) {
- printf(FMT(" %-6s ","%s "), "in");
- printf(FMT("%-6s ","%s "), "out");
- }
- printf(FMT(" %-19s ","%s "), "source");
- printf(FMT(" %-19s "," %s "), "destination");
- printf("\n");
-}
-
-
static int
print_match(const struct xt_entry_match *m,
const struct ip6t_ip6 *ip,
@@ -355,33 +151,10 @@ print_firewall(const struct ip6t_entry *fw,
t = ip6t_get_target((struct ip6t_entry *)fw);
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4u ", "%u "), num);
+ print_rule_details(num, &fw->counters, targname, fw->ipv6.proto,
+ fw->ipv6.flags, fw->ipv6.invflags, format);
- if (!(format & FMT_NOCOUNTS)) {
- xtables_print_num(fw->counters.pcnt, format);
- xtables_print_num(fw->counters.bcnt, format);
- }
-
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ", "%s "), targname);
-
- fputc(fw->ipv6.invflags & XT_INV_PROTO ? '!' : ' ', stdout);
- {
- const char *pname = proto_to_name(fw->ipv6.proto, format&FMT_NUMERIC);
- if (pname)
- printf(FMT("%-5s", "%s "), pname);
- else
- printf(FMT("%-5hu", "%hu "), fw->ipv6.proto);
- }
-
- if (format & FMT_OPTIONS) {
- if (format & FMT_NOTABLE)
- fputs("opt ", stdout);
- fputc(' ', stdout); /* Invert flag of FRAG */
- fputc(' ', stdout); /* -f */
- fputc(' ', stdout);
- }
+ print_fragment(fw->ipv6.flags, fw->ipv6.invflags, format, true);
print_ifaces(fw->ipv6.iniface, fw->ipv6.outiface,
fw->ipv6.invflags, format);
@@ -711,8 +484,18 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
if (found) printf("\n");
- if (!rulenum)
- print_header(format, this, handle);
+ if (!rulenum) {
+ struct xt_counters counters;
+ unsigned int urefs;
+ const char *pol;
+ int refs = - 1;
+
+ pol = ip6tc_get_policy(this, &counters, handle);
+ if (!pol && ip6tc_get_references(&urefs, this, handle))
+ refs = urefs;
+
+ print_header(format, this, pol, &counters, refs, 0);
+ }
i = ip6tc_first_rule(this, handle);
num = 0;
@@ -733,97 +516,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
return found;
}
-/* This assumes that mask is contiguous, and byte-bounded. */
-static void
-print_iface(char letter, const char *iface, const unsigned char *mask,
- int invert)
-{
- unsigned int i;
-
- if (mask[0] == 0)
- return;
-
- printf("%s -%c ", invert ? " !" : "", letter);
-
- for (i = 0; i < IFNAMSIZ; i++) {
- if (mask[i] != 0) {
- if (iface[i] != '\0')
- printf("%c", iface[i]);
- } else {
- /* we can access iface[i-1] here, because
- * a few lines above we make sure that mask[0] != 0 */
- if (iface[i-1] != '\0')
- printf("+");
- break;
- }
- }
-}
-
-static void print_proto(uint16_t proto, int invert)
-{
- if (proto) {
- const char *pname = proto_to_name(proto, 0);
- const char *invertstr = invert ? " !" : "";
-
- if (pname)
- printf("%s -p %s", invertstr, pname);
- else
- printf("%s -p %u", invertstr, proto);
- }
-}
-
-static int print_match_save(const struct xt_entry_match *e,
- const struct ip6t_ip6 *ip)
-{
- const char *name = e->u.user.name;
- const int revision = e->u.user.revision;
- struct xtables_match *match, *mt, *mt2;
-
- match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
- if (match) {
- mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD,
- match, revision);
- if (!mt2)
- mt2 = match;
- printf(" -m %s", mt2->alias ? mt2->alias(e) : name);
-
- /* some matches don't provide a save function */
- if (mt && mt->save)
- mt->save(ip, e);
- else if (match->save)
- printf(unsupported_rev);
- } else {
- if (e->u.match_size) {
- fprintf(stderr,
- "Can't find library for match `%s'\n",
- name);
- exit(1);
- }
- }
- return 0;
-}
-
-/* Print a given ip including mask if necessary. */
-static void print_ip(const char *prefix, const struct in6_addr *ip,
- const struct in6_addr *mask, int invert)
-{
- char buf[51];
- int l = xtables_ip6mask_to_cidr(mask);
-
- if (l == 0 && !invert)
- return;
-
- printf("%s %s %s",
- invert ? " !" : "",
- prefix,
- inet_ntop(AF_INET6, ip, buf, sizeof buf));
-
- if (l == -1)
- printf("/%s", inet_ntop(AF_INET6, mask, buf, sizeof buf));
- else
- printf("/%d", l);
-}
-
/* We want this to be readable, so only print out necessary fields.
* Because that's the kind of world I want to live in.
*/
@@ -841,19 +533,15 @@ void print_rule6(const struct ip6t_entry *e,
printf("-A %s", chain);
/* Print IP part. */
- print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk),
- e->ipv6.invflags & IP6T_INV_SRCIP);
-
- print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk),
- e->ipv6.invflags & IP6T_INV_DSTIP);
-
- print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask,
- e->ipv6.invflags & IP6T_INV_VIA_IN);
+ save_ipv6_addr('s', &e->ipv6.src, &e->ipv6.smsk,
+ e->ipv6.invflags & IP6T_INV_SRCIP);
- print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask,
- e->ipv6.invflags & IP6T_INV_VIA_OUT);
+ save_ipv6_addr('d', &e->ipv6.dst, &e->ipv6.dmsk,
+ e->ipv6.invflags & IP6T_INV_DSTIP);
- print_proto(e->ipv6.proto, e->ipv6.invflags & XT_INV_PROTO);
+ save_rule_details(e->ipv6.iniface, e->ipv6.iniface_mask,
+ e->ipv6.outiface, e->ipv6.outiface_mask,
+ e->ipv6.proto, 0, e->ipv6.invflags);
#if 0
/* not definied in ipv6
@@ -1008,10 +696,24 @@ generate_entry(const struct ip6t_entry *fw,
int do_command6(int argc, char *argv[], char **table,
struct xtc_handle **handle, bool restore)
{
+ struct xt_cmd_parse_ops cmd_parse_ops = {
+ .proto_parse = ipv6_proto_parse,
+ .post_parse = ipv6_post_parse,
+ };
+ struct xt_cmd_parse p = {
+ .table = *table,
+ .restore = restore,
+ .line = line,
+ .ops = &cmd_parse_ops,
+ };
struct iptables_command_state cs = {
.jumpto = "",
.argv = argv,
};
+ struct xtables_args args = {
+ .family = AF_INET6,
+ .wait_interval.tv_sec = 1,
+ };
struct ip6t_entry *e = NULL;
unsigned int nsaddrs = 0, ndaddrs = 0;
struct in6_addr *saddrs = NULL, *daddrs = NULL;
@@ -1022,437 +724,28 @@ int do_command6(int argc, char *argv[], char **table,
struct timeval wait_interval = {
.tv_sec = 1,
};
- bool wait_interval_set = false;
const char *chain = NULL;
- const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
const char *policy = NULL, *newname = NULL;
unsigned int rulenum = 0, command = 0;
- const char *pcnt = NULL, *bcnt = NULL;
int ret = 1;
- struct xtables_match *m;
- struct xtables_rule_match *matchp;
- struct xtables_target *t;
- unsigned long long cnt;
- bool table_set = false;
- uint16_t invflags = 0;
- bool invert = false;
-
- /* re-set optind to 0 in case do_command6 gets called
- * a second time */
- optind = 0;
-
- /* clear mflags in case do_command6 gets called a second time
- * (we clear the global list of all matches for security)*/
- for (m = xtables_matches; m; m = m->next)
- m->mflags = 0;
-
- for (t = xtables_targets; t; t = t->next) {
- t->tflags = 0;
- t->used = 0;
- }
-
- /* Suppress error messages: we may add new options if we
- demand-load a protocol. */
- 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:bvw::W::nt:m:xc:g:46",
- opts, NULL)) != -1) {
- switch (cs.c) {
- /*
- * Command selection
- */
- case 'A':
- add_command(&command, CMD_APPEND, CMD_NONE, invert);
- chain = optarg;
- break;
-
- case 'C':
- add_command(&command, CMD_CHECK, CMD_NONE, invert);
- chain = optarg;
- break;
-
- case 'D':
- add_command(&command, CMD_DELETE, CMD_NONE, invert);
- chain = optarg;
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_DELETE_NUM;
- }
- break;
-
- case 'R':
- add_command(&command, CMD_REPLACE, CMD_NONE, invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a rule number",
- cmd2char(CMD_REPLACE));
- break;
-
- case 'I':
- add_command(&command, CMD_INSERT, CMD_NONE, invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else rulenum = 1;
- break;
-
- case 'L':
- add_command(&command, CMD_LIST,
- CMD_ZERO | CMD_ZERO_NUM, invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'S':
- add_command(&command, CMD_LIST_RULES,
- CMD_ZERO | CMD_ZERO_NUM, invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'F':
- add_command(&command, CMD_FLUSH, CMD_NONE, invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'Z':
- add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_ZERO_NUM;
- }
- break;
-
- case 'N':
- parse_chain(optarg);
- add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert);
- chain = optarg;
- break;
-
- case 'X':
- add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'E':
- add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- newname = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires old-chain-name and "
- "new-chain-name",
- cmd2char(CMD_RENAME_CHAIN));
- break;
-
- case 'P':
- add_command(&command, CMD_SET_POLICY, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- policy = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a chain and a policy",
- cmd2char(CMD_SET_POLICY));
- break;
-
- case 'h':
- if (!optarg)
- optarg = argv[optind];
-
- /* ip6tables -p icmp -h */
- if (!cs.matches && cs.protocol)
- xtables_find_match(cs.protocol, XTF_TRY_LOAD,
- &cs.matches);
-
- exit_printhelp(cs.matches);
-
- /*
- * Option selection
- */
- case 'p':
- set_option(&cs.options, OPT_PROTOCOL, &invflags,
- invert);
-
- /* Canonicalize into lower case */
- for (cs.protocol = optarg; *cs.protocol; cs.protocol++)
- *cs.protocol = tolower(*cs.protocol);
-
- cs.protocol = optarg;
- cs.fw6.ipv6.proto = xtables_parse_protocol(cs.protocol);
- cs.fw6.ipv6.flags |= IP6T_F_PROTO;
-
- if (cs.fw6.ipv6.proto == 0 && (invflags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM,
- "rule would never match protocol");
-
- if (is_exthdr(cs.fw6.ipv6.proto)
- && (invflags & XT_INV_PROTO) == 0)
- fprintf(stderr,
- "Warning: never matched protocol: %s. "
- "use extension match instead.\n",
- cs.protocol);
- break;
-
- case 's':
- set_option(&cs.options, OPT_SOURCE, &invflags, invert);
- shostnetworkmask = optarg;
- break;
-
- case 'd':
- set_option(&cs.options, OPT_DESTINATION, &invflags,
- invert);
- dhostnetworkmask = optarg;
- break;
-
-#ifdef IP6T_F_GOTO
- case 'g':
- set_option(&cs.options, OPT_JUMP, &invflags, invert);
- cs.fw6.ipv6.flags |= IP6T_F_GOTO;
- cs.jumpto = xt_parse_target(optarg);
- break;
-#endif
- case 'j':
- set_option(&cs.options, OPT_JUMP, &invflags, invert);
- command_jump(&cs, optarg);
- break;
-
-
- case 'i':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs.options, OPT_VIANAMEIN, &invflags,
- invert);
- xtables_parse_interface(optarg,
- cs.fw6.ipv6.iniface,
- cs.fw6.ipv6.iniface_mask);
- break;
-
- case 'o':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs.options, OPT_VIANAMEOUT, &invflags,
- invert);
- xtables_parse_interface(optarg,
- cs.fw6.ipv6.outiface,
- cs.fw6.ipv6.outiface_mask);
- break;
-
- case 'v':
- if (!verbose)
- set_option(&cs.options, OPT_VERBOSE,
- &invflags, invert);
- verbose++;
- break;
-
- case 'w':
- if (restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-w' from "
- "ip6tables-restore");
- }
- wait = parse_wait_time(argc, argv);
- break;
-
- case 'W':
- if (restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-W' from "
- "ip6tables-restore");
- }
- parse_wait_interval(argc, argv, &wait_interval);
- wait_interval_set = true;
- break;
-
- case 'm':
- command_match(&cs, invert);
- break;
-
- case 'n':
- set_option(&cs.options, OPT_NUMERIC, &invflags, invert);
- break;
-
- case 't':
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "unexpected ! flag before --table");
- if (restore && table_set)
- xtables_error(PARAMETER_PROBLEM,
- "The -t option (seen in line %u) cannot be used in %s.\n",
- line, xt_params->program_name);
- *table = optarg;
- table_set = true;
- break;
-
- case 'x':
- set_option(&cs.options, OPT_EXPANDED, &invflags,
- invert);
- break;
-
- case 'V':
- if (invert)
- printf("Not %s ;-)\n", prog_vers);
- else
- printf("%s v%s (legacy)\n",
- prog_name, prog_vers);
- exit(0);
-
- case '0':
- set_option(&cs.options, OPT_LINENUMBERS, &invflags,
- invert);
- break;
-
- case 'M':
- xtables_modprobe_program = optarg;
- break;
-
- case 'c':
-
- set_option(&cs.options, OPT_COUNTERS, &invflags,
- invert);
- pcnt = optarg;
- bcnt = strchr(pcnt + 1, ',');
- if (bcnt)
- bcnt++;
- if (!bcnt && xs_has_arg(argc, argv))
- bcnt = argv[optind++];
- if (!bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires packet and byte counter",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(pcnt, "%llu", &cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c packet counter not numeric",
- opt2char(OPT_COUNTERS));
- cs.fw6.counters.pcnt = cnt;
-
- if (sscanf(bcnt, "%llu", &cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c byte counter not numeric",
- opt2char(OPT_COUNTERS));
- cs.fw6.counters.bcnt = cnt;
- break;
-
- case '4':
- /* This is not the IPv4 iptables */
- if (line != -1)
- return 1; /* success: line ignored */
- fprintf(stderr, "This is the IPv6 version of ip6tables.\n");
- exit_tryhelp(2);
-
- case '6':
- /* This is indeed the IPv6 ip6tables */
- break;
-
- case 1: /* non option */
- if (optarg[0] == '!' && optarg[1] == '\0') {
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- invert = true;
- optarg[0] = '\0';
- continue;
- }
- fprintf(stderr, "Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (command_default(&cs, &ip6tables_globals, invert))
- /*
- * If new options were loaded, we must retry
- * getopt immediately and not allow
- * invert=false to be executed.
- */
- continue;
- break;
- }
- invert = false;
- }
-
- if (!wait && wait_interval_set)
- xtables_error(PARAMETER_PROBLEM,
- "--wait-interval only makes sense with --wait\n");
-
- if (strcmp(*table, "nat") == 0 &&
- ((policy != NULL && strcmp(policy, "DROP") == 0) ||
- (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
- xtables_error(PARAMETER_PROBLEM,
- "\nThe \"nat\" table is not intended for filtering, "
- "the use of DROP is therefore inhibited.\n\n");
-
- for (matchp = cs.matches; matchp; matchp = matchp->next)
- xtables_option_mfcall(matchp->match);
- if (cs.target != NULL)
- xtables_option_tfcall(cs.target);
-
- /* Fix me: must put inverse options checking here --MN */
-
- if (optind < argc)
- xtables_error(PARAMETER_PROBLEM,
- "unknown arguments found on commandline");
- if (!command)
- xtables_error(PARAMETER_PROBLEM, "no command specified");
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- cs.fw6.ipv6.invflags = invflags;
-
- if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
- if (!(cs.options & OPT_DESTINATION))
- dhostnetworkmask = "::0/0";
- if (!(cs.options & OPT_SOURCE))
- shostnetworkmask = "::0/0";
- }
-
- if (shostnetworkmask)
- xtables_ip6parse_multiple(shostnetworkmask, &saddrs,
- &smasks, &nsaddrs);
-
- if (dhostnetworkmask)
- xtables_ip6parse_multiple(dhostnetworkmask, &daddrs,
- &dmasks, &ndaddrs);
-
- if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
- " source or destination IP addresses");
-
- if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
- xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
- "specify a unique address");
-
- generic_opt_check(command, cs.options);
+ do_parse(argc, argv, &p, &cs, &args);
+
+ command = p.command;
+ chain = p.chain;
+ *table = p.table;
+ rulenum = p.rulenum;
+ policy = p.policy;
+ newname = p.newname;
+ verbose = p.verbose;
+ wait = args.wait;
+ wait_interval = args.wait_interval;
+ nsaddrs = args.s.naddrs;
+ ndaddrs = args.d.naddrs;
+ saddrs = args.s.addr.v6;
+ daddrs = args.d.addr.v6;
+ smasks = args.s.mask.v6;
+ dmasks = args.d.mask.v6;
/* Attempt to acquire the xtables lock */
if (!restore)
@@ -1476,26 +769,6 @@ int do_command6(int argc, char *argv[], char **table,
|| command == CMD_CHECK
|| command == CMD_INSERT
|| command == CMD_REPLACE) {
- if (strcmp(chain, "PREROUTING") == 0
- || strcmp(chain, "INPUT") == 0) {
- /* -o not valid with incoming packets. */
- if (cs.options & OPT_VIANAMEOUT)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEOUT),
- chain);
- }
-
- if (strcmp(chain, "POSTROUTING") == 0
- || strcmp(chain, "OUTPUT") == 0) {
- /* -i not valid with outgoing packets */
- if (cs.options & OPT_VIANAMEIN)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEIN),
- chain);
- }
-
if (cs.target && ip6tc_is_chain(cs.jumpto, *handle)) {
fprintf(stderr,
"Warning: using chain %s, not extension\n",
@@ -1631,9 +904,12 @@ int do_command6(int argc, char *argv[], char **table,
case CMD_SET_POLICY:
ret = ip6tc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw6.counters : NULL, *handle);
break;
+ case CMD_NONE:
+ /* do_parse ignored the line (eg: -4 with ip6tables-restore) */
+ break;
default:
/* We should never reach this... */
- exit_tryhelp(2);
+ exit_tryhelp(2, line);
}
if (verbose > 1)
diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c
index cc2c2b8b..a3efb067 100644
--- a/iptables/iptables-restore.c
+++ b/iptables/iptables-restore.c
@@ -117,7 +117,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
verbose = 1;
break;
case 'V':
- printf("%s v%s (legacy)\n",
+ printf("%s v%s\n",
xt_params->program_name,
xt_params->program_version);
exit(0);
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index 4efd6667..a114e98b 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -173,7 +173,7 @@ do_iptables_save(struct iptables_save_cb *cb, int argc, char *argv[])
do_output(cb, tablename);
exit(0);
case 'V':
- printf("%s v%s (legacy)\n",
+ printf("%s v%s\n",
xt_params->program_name,
xt_params->program_version);
exit(0);
diff --git a/iptables/iptables.c b/iptables/iptables.c
index b925f089..f5fe868c 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -84,134 +84,15 @@ static struct option original_opts[] = {
{NULL},
};
-void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
-
struct xtables_globals iptables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (legacy)",
+ .optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x",
.orig_opts = original_opts,
- .exit_err = iptables_exit_error,
.compat_rev = xtables_compatible_revision,
+ .print_help = xtables_printhelp,
};
-#define opts iptables_globals.opts
-#define prog_name iptables_globals.program_name
-#define prog_vers iptables_globals.program_version
-
-static void __attribute__((noreturn))
-exit_tryhelp(int status)
-{
- if (line != -1)
- fprintf(stderr, "Error occurred at line: %d\n", line);
- fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
- prog_name, prog_name);
- xtables_free_opts(1);
- exit(status);
-}
-
-static void
-exit_printhelp(const struct xtables_rule_match *matches)
-{
- printf("%s v%s\n\n"
-"Usage: %s -[ACD] chain rule-specification [options]\n"
-" %s -I chain [rulenum] rule-specification [options]\n"
-" %s -R chain rulenum rule-specification [options]\n"
-" %s -D chain rulenum [options]\n"
-" %s -[LS] [chain [rulenum]] [options]\n"
-" %s -[FZ] [chain] [options]\n"
-" %s -[NX] chain\n"
-" %s -E old-chain-name new-chain-name\n"
-" %s -P chain target [options]\n"
-" %s -h (print this help information)\n\n",
- prog_name, prog_vers, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name);
-
- printf(
-"Commands:\n"
-"Either long or short options are allowed.\n"
-" --append -A chain Append to chain\n"
-" --check -C chain Check for the existence of a rule\n"
-" --delete -D chain Delete matching rule from chain\n"
-" --delete -D chain rulenum\n"
-" Delete rule rulenum (1 = first) from chain\n"
-" --insert -I chain [rulenum]\n"
-" Insert in chain as rulenum (default 1=first)\n"
-" --replace -R chain rulenum\n"
-" Replace rule rulenum (1 = first) in chain\n"
-" --list -L [chain [rulenum]]\n"
-" List the rules in a chain or all chains\n"
-" --list-rules -S [chain [rulenum]]\n"
-" Print the rules in a chain or all chains\n"
-" --flush -F [chain] Delete all rules in chain or all chains\n"
-" --zero -Z [chain [rulenum]]\n"
-" Zero counters in chain or all chains\n"
-" --new -N chain Create a new user-defined chain\n"
-" --delete-chain\n"
-" -X [chain] Delete a user-defined chain\n"
-" --policy -P chain target\n"
-" Change policy on chain to target\n"
-" --rename-chain\n"
-" -E old-chain new-chain\n"
-" Change chain name, (moving any references)\n"
-
-"Options:\n"
-" --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n"
-" --ipv6 -6 Error (line is ignored by iptables-restore)\n"
-"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n"
-"[!] --source -s address[/mask][...]\n"
-" source specification\n"
-"[!] --destination -d address[/mask][...]\n"
-" destination specification\n"
-"[!] --in-interface -i input name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --jump -j target\n"
-" target for rule (may load target extension)\n"
-#ifdef IPT_F_GOTO
-" --goto -g chain\n"
-" jump to chain with no return\n"
-#endif
-" --match -m match\n"
-" extended match (may load extension)\n"
-" --numeric -n numeric output of addresses and ports\n"
-"[!] --out-interface -o output name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --table -t table table to manipulate (default: `filter')\n"
-" --verbose -v verbose mode\n"
-" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
-" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n"
-" default is 1 second\n"
-" --line-numbers print line numbers when listing\n"
-" --exact -x expand numbers (display exact values)\n"
-"[!] --fragment -f match second or further fragments only\n"
-" --modprobe=<command> try to insert modules using this command\n"
-" --set-counters PKTS BYTES set the counter during insert/append\n"
-"[!] --version -V print package version.\n");
-
- print_extension_helps(xtables_targets, matches);
- exit(0);
-}
-
-void
-iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
-{
- va_list args;
-
- va_start(args, msg);
- fprintf(stderr, "%s v%s (legacy): ", prog_name, prog_vers);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, "\n");
- if (status == PARAMETER_PROBLEM)
- exit_tryhelp(status);
- if (status == VERSION_PROBLEM)
- fprintf(stderr,
- "Perhaps iptables or your kernel needs to be upgraded.\n");
- /* On error paths, make sure that we don't leak memory */
- xtables_free_opts(1);
- exit(status);
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
@@ -223,81 +104,6 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
-static void
-parse_chain(const char *chainname)
-{
- const char *ptr;
-
- if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %u chars)",
- chainname, XT_EXTENSION_MAXNAMELEN);
-
- if (*chainname == '-' || *chainname == '!')
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `%c'\n", *chainname);
-
- if (xtables_find_target(chainname, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
-
- for (ptr = chainname; *ptr; ptr++)
- if (isspace(*ptr))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s'", chainname);
-}
-
-static void
-print_header(unsigned int format, const char *chain, struct xtc_handle *handle)
-{
- struct xt_counters counters;
- const char *pol = iptc_get_policy(chain, &counters, handle);
- printf("Chain %s", chain);
- if (pol) {
- printf(" (policy %s", pol);
- if (!(format & FMT_NOCOUNTS)) {
- fputc(' ', stdout);
- xtables_print_num(counters.pcnt, (format|FMT_NOTABLE));
- fputs("packets, ", stdout);
- xtables_print_num(counters.bcnt, (format|FMT_NOTABLE));
- fputs("bytes", stdout);
- }
- printf(")\n");
- } else {
- unsigned int refs;
- if (!iptc_get_references(&refs, chain, handle))
- printf(" (ERROR obtaining refs)\n");
- else
- printf(" (%u references)\n", refs);
- }
-
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4s ", "%s "), "num");
- if (!(format & FMT_NOCOUNTS)) {
- if (format & FMT_KILOMEGAGIGA) {
- printf(FMT("%5s ","%s "), "pkts");
- printf(FMT("%5s ","%s "), "bytes");
- } else {
- printf(FMT("%8s ","%s "), "pkts");
- printf(FMT("%10s ","%s "), "bytes");
- }
- }
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ","%s "), "target");
- fputs(" prot ", stdout);
- if (format & FMT_OPTIONS)
- fputs("opt", stdout);
- if (format & FMT_VIA) {
- printf(FMT(" %-6s ","%s "), "in");
- printf(FMT("%-6s ","%s "), "out");
- }
- printf(FMT(" %-19s ","%s "), "source");
- printf(FMT(" %-19s "," %s "), "destination");
- printf("\n");
-}
-
static int
print_match(const struct xt_entry_match *m,
@@ -336,7 +142,6 @@ print_firewall(const struct ipt_entry *fw,
{
struct xtables_target *target, *tg;
const struct xt_entry_target *t;
- uint8_t flags;
if (!iptc_is_chain(targname, handle))
target = xtables_find_target(targname, XTF_TRY_LOAD);
@@ -345,35 +150,11 @@ print_firewall(const struct ipt_entry *fw,
XTF_LOAD_MUST_SUCCEED);
t = ipt_get_target((struct ipt_entry *)fw);
- flags = fw->ip.flags;
-
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4u ", "%u "), num);
-
- if (!(format & FMT_NOCOUNTS)) {
- xtables_print_num(fw->counters.pcnt, format);
- xtables_print_num(fw->counters.bcnt, format);
- }
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ", "%s "), targname);
+ print_rule_details(num, &fw->counters, targname, fw->ip.proto,
+ fw->ip.flags, fw->ip.invflags, format);
- fputc(fw->ip.invflags & XT_INV_PROTO ? '!' : ' ', stdout);
- {
- const char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC);
- if (pname)
- printf(FMT("%-5s", "%s "), pname);
- else
- printf(FMT("%-5hu", "%hu "), fw->ip.proto);
- }
-
- if (format & FMT_OPTIONS) {
- if (format & FMT_NOTABLE)
- fputs("opt ", stdout);
- fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
- fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
- fputc(' ', stdout);
- }
+ print_fragment(fw->ip.flags, fw->ip.invflags, format, false);
print_ifaces(fw->ip.iniface, fw->ip.outiface, fw->ip.invflags, format);
@@ -702,8 +483,18 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
if (found) printf("\n");
- if (!rulenum)
- print_header(format, this, handle);
+ if (!rulenum) {
+ struct xt_counters counters;
+ unsigned int urefs;
+ const char *pol;
+ int refs = -1;
+
+ pol = iptc_get_policy(this, &counters, handle);
+ if (!pol && iptc_get_references(&urefs, this, handle))
+ refs = urefs;
+
+ print_header(format, this, pol, &counters, refs, 0);
+ }
i = iptc_first_rule(this, handle);
num = 0;
@@ -724,19 +515,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
return found;
}
-static void print_proto(uint16_t proto, int invert)
-{
- if (proto) {
- const char *pname = proto_to_name(proto, 0);
- const char *invertstr = invert ? " !" : "";
-
- if (pname)
- printf("%s -p %s", invertstr, pname);
- else
- printf("%s -p %u", invertstr, proto);
- }
-}
-
#define IP_PARTS_NATIVE(n) \
(unsigned int)((n)>>24)&0xFF, \
(unsigned int)((n)>>16)&0xFF, \
@@ -745,93 +523,6 @@ static void print_proto(uint16_t proto, int invert)
#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
-/* This assumes that mask is contiguous, and byte-bounded. */
-static void
-print_iface(char letter, const char *iface, const unsigned char *mask,
- int invert)
-{
- unsigned int i;
-
- if (mask[0] == 0)
- return;
-
- printf("%s -%c ", invert ? " !" : "", letter);
-
- for (i = 0; i < IFNAMSIZ; i++) {
- if (mask[i] != 0) {
- if (iface[i] != '\0')
- printf("%c", iface[i]);
- } else {
- /* we can access iface[i-1] here, because
- * a few lines above we make sure that mask[0] != 0 */
- if (iface[i-1] != '\0')
- printf("+");
- break;
- }
- }
-}
-
-static int print_match_save(const struct xt_entry_match *e,
- const struct ipt_ip *ip)
-{
- const char *name = e->u.user.name;
- const int revision = e->u.user.revision;
- struct xtables_match *match, *mt, *mt2;
-
- match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
- if (match) {
- mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD,
- match, revision);
- if (!mt2)
- mt2 = match;
- printf(" -m %s", mt2->alias ? mt2->alias(e) : name);
-
- /* some matches don't provide a save function */
- if (mt && mt->save)
- mt->save(ip, e);
- else if (match->save)
- printf(unsupported_rev);
- } else {
- if (e->u.match_size) {
- fprintf(stderr,
- "Can't find library for match `%s'\n",
- name);
- exit(1);
- }
- }
- return 0;
-}
-
-/* Print a given ip including mask if necessary. */
-static void print_ip(const char *prefix, uint32_t ip,
- uint32_t mask, int invert)
-{
- uint32_t bits, hmask = ntohl(mask);
- int i;
-
- if (!mask && !ip && !invert)
- return;
-
- printf("%s %s %u.%u.%u.%u",
- invert ? " !" : "",
- prefix,
- IP_PARTS(ip));
-
- if (mask == 0xFFFFFFFFU) {
- printf("/32");
- return;
- }
-
- i = 32;
- bits = 0xFFFFFFFEU;
- while (--i >= 0 && hmask != bits)
- bits <<= 1;
- if (i >= 0)
- printf("/%u", i);
- else
- printf("/%u.%u.%u.%u", IP_PARTS(mask));
-}
-
/* We want this to be readable, so only print out necessary fields.
* Because that's the kind of world I want to live in.
*/
@@ -849,23 +540,16 @@ void print_rule4(const struct ipt_entry *e,
printf("-A %s", chain);
/* Print IP part. */
- print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
- e->ip.invflags & IPT_INV_SRCIP);
+ save_ipv4_addr('s', &e->ip.src, &e->ip.smsk,
+ e->ip.invflags & IPT_INV_SRCIP);
- print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
+ save_ipv4_addr('d', &e->ip.dst, &e->ip.dmsk,
e->ip.invflags & IPT_INV_DSTIP);
- print_iface('i', e->ip.iniface, e->ip.iniface_mask,
- e->ip.invflags & IPT_INV_VIA_IN);
-
- print_iface('o', e->ip.outiface, e->ip.outiface_mask,
- e->ip.invflags & IPT_INV_VIA_OUT);
-
- print_proto(e->ip.proto, e->ip.invflags & XT_INV_PROTO);
-
- if (e->ip.flags & IPT_F_FRAG)
- printf("%s -f",
- e->ip.invflags & IPT_INV_FRAG ? " !" : "");
+ save_rule_details(e->ip.iniface, e->ip.iniface_mask,
+ e->ip.outiface, e->ip.outiface_mask,
+ e->ip.proto, e->ip.flags & IPT_F_FRAG,
+ e->ip.invflags);
/* Print matchinfo part */
if (e->target_offset)
@@ -1006,10 +690,24 @@ generate_entry(const struct ipt_entry *fw,
int do_command4(int argc, char *argv[], char **table,
struct xtc_handle **handle, bool restore)
{
+ struct xt_cmd_parse_ops cmd_parse_ops = {
+ .proto_parse = ipv4_proto_parse,
+ .post_parse = ipv4_post_parse,
+ };
+ struct xt_cmd_parse p = {
+ .table = *table,
+ .restore = restore,
+ .line = line,
+ .ops = &cmd_parse_ops,
+ };
struct iptables_command_state cs = {
.jumpto = "",
.argv = argv,
};
+ struct xtables_args args = {
+ .family = AF_INET,
+ .wait_interval.tv_sec = 1,
+ };
struct ipt_entry *e = NULL;
unsigned int nsaddrs = 0, ndaddrs = 0;
struct in_addr *saddrs = NULL, *smasks = NULL;
@@ -1017,433 +715,30 @@ int do_command4(int argc, char *argv[], char **table,
struct timeval wait_interval = {
.tv_sec = 1,
};
- bool wait_interval_set = false;
int verbose = 0;
int wait = 0;
const char *chain = NULL;
- const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
const char *policy = NULL, *newname = NULL;
unsigned int rulenum = 0, command = 0;
- const char *pcnt = NULL, *bcnt = NULL;
int ret = 1;
- struct xtables_match *m;
- struct xtables_rule_match *matchp;
- struct xtables_target *t;
- unsigned long long cnt;
- bool table_set = false;
- uint16_t invflags = 0;
- bool invert = false;
-
- /* re-set optind to 0 in case do_command4 gets called
- * a second time */
- optind = 0;
-
- /* clear mflags in case do_command4 gets called a second time
- * (we clear the global list of all matches for security)*/
- for (m = xtables_matches; m; m = m->next)
- m->mflags = 0;
-
- for (t = xtables_targets; t; t = t->next) {
- t->tflags = 0;
- t->used = 0;
- }
-
- /* Suppress error messages: we may add new options if we
- demand-load a protocol. */
- 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",
- opts, NULL)) != -1) {
- switch (cs.c) {
- /*
- * Command selection
- */
- case 'A':
- add_command(&command, CMD_APPEND, CMD_NONE, invert);
- chain = optarg;
- break;
-
- case 'C':
- add_command(&command, CMD_CHECK, CMD_NONE, invert);
- chain = optarg;
- break;
-
- case 'D':
- add_command(&command, CMD_DELETE, CMD_NONE, invert);
- chain = optarg;
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_DELETE_NUM;
- }
- break;
-
- case 'R':
- add_command(&command, CMD_REPLACE, CMD_NONE, invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a rule number",
- cmd2char(CMD_REPLACE));
- break;
-
- case 'I':
- add_command(&command, CMD_INSERT, CMD_NONE, invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else rulenum = 1;
- break;
-
- case 'L':
- add_command(&command, CMD_LIST,
- CMD_ZERO | CMD_ZERO_NUM, invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'S':
- add_command(&command, CMD_LIST_RULES,
- CMD_ZERO|CMD_ZERO_NUM, invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'F':
- add_command(&command, CMD_FLUSH, CMD_NONE, invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'Z':
- add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_ZERO_NUM;
- }
- break;
-
- case 'N':
- parse_chain(optarg);
- add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert);
- chain = optarg;
- break;
-
- case 'X':
- add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'E':
- add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- newname = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires old-chain-name and "
- "new-chain-name",
- cmd2char(CMD_RENAME_CHAIN));
- break;
-
- case 'P':
- add_command(&command, CMD_SET_POLICY, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- policy = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a chain and a policy",
- cmd2char(CMD_SET_POLICY));
- break;
-
- case 'h':
- if (!optarg)
- optarg = argv[optind];
-
- /* iptables -p icmp -h */
- if (!cs.matches && cs.protocol)
- xtables_find_match(cs.protocol,
- XTF_TRY_LOAD, &cs.matches);
-
- exit_printhelp(cs.matches);
-
- /*
- * Option selection
- */
- case 'p':
- set_option(&cs.options, OPT_PROTOCOL, &invflags,
- invert);
-
- /* Canonicalize into lower case */
- for (cs.protocol = optarg; *cs.protocol; cs.protocol++)
- *cs.protocol = tolower(*cs.protocol);
-
- cs.protocol = optarg;
- cs.fw.ip.proto = xtables_parse_protocol(cs.protocol);
-
- if (cs.fw.ip.proto == 0 && (invflags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM,
- "rule would never match protocol");
- break;
-
- case 's':
- set_option(&cs.options, OPT_SOURCE, &invflags, invert);
- shostnetworkmask = optarg;
- break;
-
- case 'd':
- set_option(&cs.options, OPT_DESTINATION, &invflags,
- invert);
- dhostnetworkmask = optarg;
- break;
-
-#ifdef IPT_F_GOTO
- case 'g':
- set_option(&cs.options, OPT_JUMP, &invflags, invert);
- cs.fw.ip.flags |= IPT_F_GOTO;
- cs.jumpto = xt_parse_target(optarg);
- break;
-#endif
-
- case 'j':
- set_option(&cs.options, OPT_JUMP, &invflags, invert);
- command_jump(&cs, optarg);
- break;
-
-
- case 'i':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs.options, OPT_VIANAMEIN, &invflags,
- invert);
- xtables_parse_interface(optarg,
- cs.fw.ip.iniface,
- cs.fw.ip.iniface_mask);
- break;
-
- case 'o':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs.options, OPT_VIANAMEOUT, &invflags,
- invert);
- xtables_parse_interface(optarg,
- cs.fw.ip.outiface,
- cs.fw.ip.outiface_mask);
- break;
-
- case 'f':
- set_option(&cs.options, OPT_FRAGMENT, &invflags,
- invert);
- cs.fw.ip.flags |= IPT_F_FRAG;
- break;
-
- case 'v':
- if (!verbose)
- set_option(&cs.options, OPT_VERBOSE,
- &invflags, invert);
- verbose++;
- break;
-
- case 'w':
- if (restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-w' from "
- "iptables-restore");
- }
- wait = parse_wait_time(argc, argv);
- break;
- case 'W':
- if (restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-W' from "
- "iptables-restore");
- }
- parse_wait_interval(argc, argv, &wait_interval);
- wait_interval_set = true;
- break;
-
- case 'm':
- command_match(&cs, invert);
- break;
-
- case 'n':
- set_option(&cs.options, OPT_NUMERIC, &invflags,
- invert);
- break;
-
- case 't':
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "unexpected ! flag before --table");
- if (restore && table_set)
- xtables_error(PARAMETER_PROBLEM,
- "The -t option (seen in line %u) cannot be used in %s.\n",
- line, xt_params->program_name);
- *table = optarg;
- table_set = true;
- break;
-
- case 'x':
- set_option(&cs.options, OPT_EXPANDED, &invflags,
- invert);
- break;
-
- case 'V':
- if (invert)
- printf("Not %s ;-)\n", prog_vers);
- else
- printf("%s v%s (legacy)\n",
- prog_name, prog_vers);
- exit(0);
-
- case '0':
- set_option(&cs.options, OPT_LINENUMBERS, &invflags,
- invert);
- break;
-
- case 'M':
- xtables_modprobe_program = optarg;
- break;
-
- case 'c':
-
- set_option(&cs.options, OPT_COUNTERS, &invflags,
- invert);
- pcnt = optarg;
- bcnt = strchr(pcnt + 1, ',');
- if (bcnt)
- bcnt++;
- if (!bcnt && xs_has_arg(argc, argv))
- bcnt = argv[optind++];
- if (!bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires packet and byte counter",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(pcnt, "%llu", &cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c packet counter not numeric",
- opt2char(OPT_COUNTERS));
- cs.fw.counters.pcnt = cnt;
-
- if (sscanf(bcnt, "%llu", &cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c byte counter not numeric",
- opt2char(OPT_COUNTERS));
- cs.fw.counters.bcnt = cnt;
- break;
-
- case '4':
- /* This is indeed the IPv4 iptables */
- break;
-
- case '6':
- /* This is not the IPv6 ip6tables */
- if (line != -1)
- return 1; /* success: line ignored */
- fprintf(stderr, "This is the IPv4 version of iptables.\n");
- exit_tryhelp(2);
-
- case 1: /* non option */
- if (optarg[0] == '!' && optarg[1] == '\0') {
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- invert = true;
- optarg[0] = '\0';
- continue;
- }
- fprintf(stderr, "Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (command_default(&cs, &iptables_globals, invert))
- /* cf. ip6tables.c */
- continue;
- break;
- }
- invert = false;
- }
-
- if (!wait && wait_interval_set)
- xtables_error(PARAMETER_PROBLEM,
- "--wait-interval only makes sense with --wait\n");
-
- if (strcmp(*table, "nat") == 0 &&
- ((policy != NULL && strcmp(policy, "DROP") == 0) ||
- (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
- xtables_error(PARAMETER_PROBLEM,
- "\nThe \"nat\" table is not intended for filtering, "
- "the use of DROP is therefore inhibited.\n\n");
-
- for (matchp = cs.matches; matchp; matchp = matchp->next)
- xtables_option_mfcall(matchp->match);
- if (cs.target != NULL)
- xtables_option_tfcall(cs.target);
-
- /* Fix me: must put inverse options checking here --MN */
-
- if (optind < argc)
- xtables_error(PARAMETER_PROBLEM,
- "unknown arguments found on commandline");
- if (!command)
- xtables_error(PARAMETER_PROBLEM, "no command specified");
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- cs.fw.ip.invflags = invflags;
-
- if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
- if (!(cs.options & OPT_DESTINATION))
- dhostnetworkmask = "0.0.0.0/0";
- if (!(cs.options & OPT_SOURCE))
- shostnetworkmask = "0.0.0.0/0";
- }
-
- if (shostnetworkmask)
- xtables_ipparse_multiple(shostnetworkmask, &saddrs,
- &smasks, &nsaddrs);
-
- if (dhostnetworkmask)
- xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
- &dmasks, &ndaddrs);
-
- if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
- " source or destination IP addresses");
-
- if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
- xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
- "specify a unique address");
-
- generic_opt_check(command, cs.options);
+ do_parse(argc, argv, &p, &cs, &args);
+
+ command = p.command;
+ chain = p.chain;
+ *table = p.table;
+ rulenum = p.rulenum;
+ policy = p.policy;
+ newname = p.newname;
+ verbose = p.verbose;
+ wait = args.wait;
+ wait_interval = args.wait_interval;
+ nsaddrs = args.s.naddrs;
+ ndaddrs = args.d.naddrs;
+ saddrs = args.s.addr.v4;
+ daddrs = args.d.addr.v4;
+ smasks = args.s.mask.v4;
+ dmasks = args.d.mask.v4;
/* Attempt to acquire the xtables lock */
if (!restore)
@@ -1467,26 +762,6 @@ int do_command4(int argc, char *argv[], char **table,
|| command == CMD_CHECK
|| command == CMD_INSERT
|| command == CMD_REPLACE) {
- if (strcmp(chain, "PREROUTING") == 0
- || strcmp(chain, "INPUT") == 0) {
- /* -o not valid with incoming packets. */
- if (cs.options & OPT_VIANAMEOUT)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEOUT),
- chain);
- }
-
- if (strcmp(chain, "POSTROUTING") == 0
- || strcmp(chain, "OUTPUT") == 0) {
- /* -i not valid with outgoing packets */
- if (cs.options & OPT_VIANAMEIN)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEIN),
- chain);
- }
-
if (cs.target && iptc_is_chain(cs.jumpto, *handle)) {
fprintf(stderr,
"Warning: using chain %s, not extension\n",
@@ -1624,9 +899,12 @@ int do_command4(int argc, char *argv[], char **table,
case CMD_SET_POLICY:
ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle);
break;
+ case CMD_NONE:
+ /* do_parse ignored the line (eg: -4 with ip6tables-restore) */
+ break;
default:
/* We should never reach this... */
- exit_tryhelp(2);
+ exit_tryhelp(2, line);
}
if (verbose > 1)
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 2a9387a1..1472b115 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -308,11 +308,10 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
static void nft_arp_print_header(unsigned int format, const char *chain,
const char *pol,
const struct xt_counters *counters,
- bool basechain, uint32_t refs,
- uint32_t entries)
+ int refs, uint32_t entries)
{
printf("Chain %s", chain);
- if (basechain && pol) {
+ if (pol) {
printf(" (policy %s", pol);
if (!(format & FMT_NOCOUNTS)) {
fputc(' ', stdout);
@@ -323,7 +322,7 @@ static void nft_arp_print_header(unsigned int format, const char *chain,
}
printf(")\n");
} else {
- printf(" (%u references)\n", refs);
+ printf(" (%d references)\n", refs);
}
}
@@ -479,6 +478,7 @@ nft_arp_save_rule(const void *data, unsigned int format)
format |= FMT_NUMERIC;
+ printf(" ");
nft_arp_print_rule_details(cs, format);
if (cs->target && cs->target->save)
cs->target->save(&cs->fw, cs->target->t);
@@ -546,6 +546,251 @@ static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
printf(":%s %s\n", chain, policy ?: "-");
}
+static int getlength_and_mask(const char *from, uint8_t *to, uint8_t *mask)
+{
+ char *dup = strdup(from);
+ char *p, *buffer;
+ int i, ret = -1;
+
+ if (!dup)
+ return -1;
+
+ if ( (p = strrchr(dup, '/')) != NULL) {
+ *p = '\0';
+ i = strtol(p+1, &buffer, 10);
+ if (*buffer != '\0' || i < 0 || i > 255)
+ goto out_err;
+ *mask = (uint8_t)i;
+ } else
+ *mask = 255;
+ i = strtol(dup, &buffer, 10);
+ if (*buffer != '\0' || i < 0 || i > 255)
+ goto out_err;
+ *to = (uint8_t)i;
+ ret = 0;
+out_err:
+ free(dup);
+ return ret;
+
+}
+
+static int get16_and_mask(const char *from, uint16_t *to,
+ uint16_t *mask, int base)
+{
+ char *dup = strdup(from);
+ char *p, *buffer;
+ int i, ret = -1;
+
+ if (!dup)
+ return -1;
+
+ if ( (p = strrchr(dup, '/')) != NULL) {
+ *p = '\0';
+ i = strtol(p+1, &buffer, base);
+ if (*buffer != '\0' || i < 0 || i > 65535)
+ goto out_err;
+ *mask = htons((uint16_t)i);
+ } else
+ *mask = 65535;
+ i = strtol(dup, &buffer, base);
+ if (*buffer != '\0' || i < 0 || i > 65535)
+ goto out_err;
+ *to = htons((uint16_t)i);
+ ret = 0;
+out_err:
+ free(dup);
+ return ret;
+}
+
+static void nft_arp_post_parse(int command,
+ struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->arp.arp.invflags = args->invflags;
+
+ memcpy(cs->arp.arp.iniface, args->iniface, IFNAMSIZ);
+ memcpy(cs->arp.arp.iniface_mask, args->iniface_mask, IFNAMSIZ);
+
+ memcpy(cs->arp.arp.outiface, args->outiface, IFNAMSIZ);
+ memcpy(cs->arp.arp.outiface_mask, args->outiface_mask, IFNAMSIZ);
+
+ cs->arp.counters.pcnt = args->pcnt_cnt;
+ cs->arp.counters.bcnt = args->bcnt_cnt;
+
+ if (command & (CMD_REPLACE | CMD_INSERT |
+ CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
+ if (!(cs->options & OPT_DESTINATION))
+ args->dhostnetworkmask = "0.0.0.0/0";
+ if (!(cs->options & OPT_SOURCE))
+ args->shostnetworkmask = "0.0.0.0/0";
+ }
+
+ if (args->shostnetworkmask)
+ xtables_ipparse_multiple(args->shostnetworkmask,
+ &args->s.addr.v4, &args->s.mask.v4,
+ &args->s.naddrs);
+ if (args->dhostnetworkmask)
+ xtables_ipparse_multiple(args->dhostnetworkmask,
+ &args->d.addr.v4, &args->d.mask.v4,
+ &args->d.naddrs);
+
+ if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
+ (cs->arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
+ xtables_error(PARAMETER_PROBLEM,
+ "! not allowed with multiple"
+ " source or destination IP addresses");
+
+ if (args->src_mac &&
+ xtables_parse_mac_and_mask(args->src_mac,
+ cs->arp.arp.src_devaddr.addr,
+ cs->arp.arp.src_devaddr.mask))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified source mac");
+ if (args->dst_mac &&
+ xtables_parse_mac_and_mask(args->dst_mac,
+ cs->arp.arp.tgt_devaddr.addr,
+ cs->arp.arp.tgt_devaddr.mask))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified destination mac");
+ if (args->arp_hlen) {
+ getlength_and_mask(args->arp_hlen, &cs->arp.arp.arhln,
+ &cs->arp.arp.arhln_mask);
+
+ if (cs->arp.arp.arhln != 6)
+ xtables_error(PARAMETER_PROBLEM,
+ "Only harware address length of 6 is supported currently.");
+ }
+ if (args->arp_opcode) {
+ if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop,
+ &cs->arp.arp.arpop_mask, 10)) {
+ int i;
+
+ for (i = 0; i < NUMOPCODES; i++)
+ if (!strcasecmp(arp_opcodes[i],
+ args->arp_opcode))
+ break;
+ if (i == NUMOPCODES)
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified opcode");
+ cs->arp.arp.arpop = htons(i+1);
+ }
+ }
+ if (args->arp_htype) {
+ if (get16_and_mask(args->arp_htype, &cs->arp.arp.arhrd,
+ &cs->arp.arp.arhrd_mask, 16)) {
+ if (strcasecmp(args->arp_htype, "Ethernet"))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified hardware type");
+ cs->arp.arp.arhrd = htons(1);
+ }
+ }
+ if (args->arp_ptype) {
+ if (get16_and_mask(args->arp_ptype, &cs->arp.arp.arpro,
+ &cs->arp.arp.arpro_mask, 0)) {
+ if (strcasecmp(args->arp_ptype, "ipv4"))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified protocol type");
+ cs->arp.arp.arpro = htons(0x800);
+ }
+ }
+}
+
+static void nft_arp_init_cs(struct iptables_command_state *cs)
+{
+ cs->arp.arp.arhln = 6;
+ cs->arp.arp.arhln_mask = 255;
+ cs->arp.arp.arhrd = htons(ARPHRD_ETHER);
+ cs->arp.arp.arhrd_mask = 65535;
+}
+
+static int
+nft_arp_add_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ bool append, int rulenum)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+ cs->arp.arp.tmsk.s_addr = args->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);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_arp_delete_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+ cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_arp_check_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+ cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
+ ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_arp_replace_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ int rulenum)
+{
+ cs->arp.arp.src.s_addr = args->s.addr.v4->s_addr;
+ cs->arp.arp.tgt.s_addr = args->d.addr.v4->s_addr;
+ cs->arp.arp.smsk.s_addr = args->s.mask.v4->s_addr;
+ cs->arp.arp.tmsk.s_addr = args->d.mask.v4->s_addr;
+
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
+}
+
struct nft_family_ops nft_family_ops_arp = {
.add = nft_arp_add,
.is_same = nft_arp_is_same,
@@ -557,8 +802,15 @@ struct nft_family_ops nft_family_ops_arp = {
.print_rule = nft_arp_print_rule,
.save_rule = nft_arp_save_rule,
.save_chain = nft_arp_save_chain,
- .post_parse = NULL,
+ .cmd_parse = {
+ .post_parse = nft_arp_post_parse,
+ },
.rule_to_cs = nft_rule_to_iptables_command_state,
+ .init_cs = nft_arp_init_cs,
.clear_cs = nft_clear_iptables_command_state,
.parse_target = nft_ipv46_parse_target,
+ .add_entry = nft_arp_add_entry,
+ .delete_entry = nft_arp_delete_entry,
+ .check_entry = nft_arp_check_entry,
+ .replace_entry = nft_arp_replace_entry,
};
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index 11f3df35..90d55e44 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -534,7 +534,7 @@ static void nft_bridge_print_table_header(const char *tablename)
static void nft_bridge_print_header(unsigned int format, const char *chain,
const char *pol,
const struct xt_counters *counters,
- bool basechain, uint32_t refs, uint32_t entries)
+ int refs, uint32_t entries)
{
printf("Bridge chain: %s, entries: %u, policy: %s\n",
chain, entries, pol ?: "RETURN");
@@ -601,7 +601,7 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
printf("%s ", ent->e_name);
}
-static void nft_bridge_save_rule(const void *data, unsigned int format)
+static void __nft_bridge_save_rule(const void *data, unsigned int format)
{
const struct iptables_command_state *cs = data;
@@ -652,6 +652,12 @@ static void nft_bridge_save_rule(const void *data, unsigned int format)
fputc('\n', stdout);
}
+static void nft_bridge_save_rule(const void *data, unsigned int format)
+{
+ printf(" ");
+ __nft_bridge_save_rule(data, format);
+}
+
static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format)
{
@@ -661,7 +667,7 @@ static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r,
printf("%d ", num);
nft_rule_to_ebtables_command_state(h, r, &cs);
- nft_bridge_save_rule(&cs, format);
+ __nft_bridge_save_rule(&cs, format);
ebt_cs_clean(&cs);
}
@@ -894,7 +900,6 @@ struct nft_family_ops nft_family_ops_bridge = {
.print_rule = nft_bridge_print_rule,
.save_rule = nft_bridge_save_rule,
.save_chain = nft_bridge_save_chain,
- .post_parse = NULL,
.rule_to_cs = nft_rule_to_ebtables_command_state,
.clear_cs = ebt_cs_clean,
.xlate = nft_bridge_xlate,
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 34f94bd8..f374d468 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -134,32 +134,6 @@ static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv)
ctx->flags &= ~NFT_XT_CTX_BITWISE;
}
-static const char *mask_to_str(uint32_t mask)
-{
- static char mask_str[INET_ADDRSTRLEN];
- uint32_t bits, hmask = ntohl(mask);
- struct in_addr mask_addr = {
- .s_addr = mask,
- };
- int i;
-
- if (mask == 0xFFFFFFFFU) {
- sprintf(mask_str, "32");
- return mask_str;
- }
-
- i = 32;
- bits = 0xFFFFFFFEU;
- while (--i >= 0 && hmask != bits)
- bits <<= 1;
- if (i >= 0)
- sprintf(mask_str, "%u", i);
- else
- inet_ntop(AF_INET, &mask_addr, mask_str, sizeof(mask_str));
-
- return mask_str;
-}
-
static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
void *data)
{
@@ -252,19 +226,6 @@ static void nft_ipv4_parse_immediate(const char *jumpto, bool nft_goto,
cs->fw.ip.flags |= IPT_F_GOTO;
}
-static void print_fragment(unsigned int flags, unsigned int invflags,
- unsigned int format)
-{
- if (!(format & FMT_OPTIONS))
- return;
-
- if (format & FMT_NOTABLE)
- fputs("opt ", stdout);
- fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout);
- fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
- fputc(' ', stdout);
-}
-
static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format)
{
@@ -272,9 +233,9 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
nft_rule_to_iptables_command_state(h, r, &cs);
- print_rule_details(&cs, cs.jumpto, cs.fw.ip.flags,
- cs.fw.ip.invflags, cs.fw.ip.proto, num, format);
- print_fragment(cs.fw.ip.flags, cs.fw.ip.invflags, format);
+ print_rule_details(num, &cs.counters, cs.jumpto, cs.fw.ip.proto,
+ cs.fw.ip.flags, cs.fw.ip.invflags, format);
+ print_fragment(cs.fw.ip.flags, cs.fw.ip.invflags, format, false);
print_ifaces(cs.fw.ip.iniface, cs.fw.ip.outiface, cs.fw.ip.invflags,
format);
print_ipv4_addresses(&cs.fw, format);
@@ -295,97 +256,24 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
nft_clear_iptables_command_state(&cs);
}
-static void save_ipv4_addr(char letter, const struct in_addr *addr,
- uint32_t mask, int invert)
-{
- char addrbuf[INET_ADDRSTRLEN];
-
- if (!mask && !invert && !addr->s_addr)
- return;
-
- printf("%s-%c %s/%s ", invert ? "! " : "", letter,
- inet_ntop(AF_INET, addr, addrbuf, sizeof(addrbuf)),
- mask_to_str(mask));
-}
-
static void nft_ipv4_save_rule(const void *data, unsigned int format)
{
const struct iptables_command_state *cs = data;
- save_ipv4_addr('s', &cs->fw.ip.src, cs->fw.ip.smsk.s_addr,
+ save_ipv4_addr('s', &cs->fw.ip.src, &cs->fw.ip.smsk,
cs->fw.ip.invflags & IPT_INV_SRCIP);
- save_ipv4_addr('d', &cs->fw.ip.dst, cs->fw.ip.dmsk.s_addr,
+ save_ipv4_addr('d', &cs->fw.ip.dst, &cs->fw.ip.dmsk,
cs->fw.ip.invflags & IPT_INV_DSTIP);
- save_rule_details(cs, cs->fw.ip.invflags, cs->fw.ip.proto,
- cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
- cs->fw.ip.outiface, cs->fw.ip.outiface_mask);
-
- if (cs->fw.ip.flags & IPT_F_FRAG) {
- if (cs->fw.ip.invflags & IPT_INV_FRAG)
- printf("! ");
- printf("-f ");
- }
+ save_rule_details(cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
+ cs->fw.ip.outiface, cs->fw.ip.outiface_mask,
+ cs->fw.ip.proto, cs->fw.ip.flags & IPT_F_FRAG,
+ cs->fw.ip.invflags);
save_matches_and_target(cs, cs->fw.ip.flags & IPT_F_GOTO,
&cs->fw, format);
}
-static void nft_ipv4_proto_parse(struct iptables_command_state *cs,
- struct xtables_args *args)
-{
- cs->fw.ip.proto = args->proto;
- cs->fw.ip.invflags = args->invflags;
-}
-
-static void nft_ipv4_post_parse(int command,
- struct iptables_command_state *cs,
- struct xtables_args *args)
-{
- cs->fw.ip.flags = args->flags;
- /* We already set invflags in proto_parse, but we need to refresh it
- * to include new parsed options.
- */
- cs->fw.ip.invflags = args->invflags;
-
- memcpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ);
- memcpy(cs->fw.ip.iniface_mask,
- args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
-
- memcpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ);
- memcpy(cs->fw.ip.outiface_mask,
- args->outiface_mask, IFNAMSIZ*sizeof(unsigned char));
-
- if (args->goto_set)
- cs->fw.ip.flags |= IPT_F_GOTO;
-
- cs->counters.pcnt = args->pcnt_cnt;
- cs->counters.bcnt = args->bcnt_cnt;
-
- if (command & (CMD_REPLACE | CMD_INSERT |
- CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
- if (!(cs->options & OPT_DESTINATION))
- args->dhostnetworkmask = "0.0.0.0/0";
- if (!(cs->options & OPT_SOURCE))
- args->shostnetworkmask = "0.0.0.0/0";
- }
-
- if (args->shostnetworkmask)
- xtables_ipparse_multiple(args->shostnetworkmask,
- &args->s.addr.v4, &args->s.mask.v4,
- &args->s.naddrs);
- if (args->dhostnetworkmask)
- xtables_ipparse_multiple(args->dhostnetworkmask,
- &args->d.addr.v4, &args->d.mask.v4,
- &args->d.naddrs);
-
- if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
- (cs->fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM,
- "! not allowed with multiple"
- " source or destination IP addresses");
-}
-
static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr,
const struct in_addr *mask,
bool inv, struct xt_xlate *xl)
@@ -468,6 +356,95 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
return ret;
}
+static int
+nft_ipv4_add_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ bool append, int rulenum)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ 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;
+
+ 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
+nft_ipv4_delete_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ 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 = nft_cmd_rule_delete(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv4_check_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ 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 = nft_cmd_rule_check(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv4_replace_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ int rulenum)
+{
+ cs->fw.ip.src.s_addr = args->s.addr.v4->s_addr;
+ cs->fw.ip.dst.s_addr = args->d.addr.v4->s_addr;
+ cs->fw.ip.smsk.s_addr = args->s.mask.v4->s_addr;
+ cs->fw.ip.dmsk.s_addr = args->d.mask.v4->s_addr;
+
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
+}
+
struct nft_family_ops nft_family_ops_ipv4 = {
.add = nft_ipv4_add,
.is_same = nft_ipv4_is_same,
@@ -478,10 +455,16 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.print_rule = nft_ipv4_print_rule,
.save_rule = nft_ipv4_save_rule,
.save_chain = nft_ipv46_save_chain,
- .proto_parse = nft_ipv4_proto_parse,
- .post_parse = nft_ipv4_post_parse,
+ .cmd_parse = {
+ .proto_parse = ipv4_proto_parse,
+ .post_parse = ipv4_post_parse,
+ },
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
.xlate = nft_ipv4_xlate,
+ .add_entry = nft_ipv4_add_entry,
+ .delete_entry = nft_ipv4_delete_entry,
+ .check_entry = nft_ipv4_check_entry,
+ .replace_entry = nft_ipv4_replace_entry,
};
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index d9c9400a..9ecc754f 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -198,14 +198,9 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
nft_rule_to_iptables_command_state(h, r, &cs);
- print_rule_details(&cs, cs.jumpto, cs.fw6.ipv6.flags,
- cs.fw6.ipv6.invflags, cs.fw6.ipv6.proto,
- num, format);
- if (format & FMT_OPTIONS) {
- if (format & FMT_NOTABLE)
- fputs("opt ", stdout);
- fputs(" ", stdout);
- }
+ print_rule_details(num, &cs.counters, cs.jumpto, cs.fw6.ipv6.proto,
+ cs.fw6.ipv6.flags, cs.fw6.ipv6.invflags, format);
+ print_fragment(cs.fw6.ipv6.flags, cs.fw6.ipv6.invflags, format, true);
print_ifaces(cs.fw6.ipv6.iniface, cs.fw6.ipv6.outiface,
cs.fw6.ipv6.invflags, format);
print_ipv6_addresses(&cs.fw6, format);
@@ -224,26 +219,6 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
nft_clear_iptables_command_state(&cs);
}
-static void save_ipv6_addr(char letter, const struct in6_addr *addr,
- const struct in6_addr *mask,
- int invert)
-{
- char addr_str[INET6_ADDRSTRLEN];
- int l = xtables_ip6mask_to_cidr(mask);
-
- if (!invert && l == 0)
- return;
-
- printf("%s-%c %s",
- invert ? "! " : "", letter,
- inet_ntop(AF_INET6, addr, addr_str, sizeof(addr_str)));
-
- if (l == -1)
- printf("/%s ", inet_ntop(AF_INET6, mask, addr_str, sizeof(addr_str)));
- else
- printf("/%d ", l);
-}
-
static void nft_ipv6_save_rule(const void *data, unsigned int format)
{
const struct iptables_command_state *cs = data;
@@ -253,86 +228,14 @@ static void nft_ipv6_save_rule(const void *data, unsigned int format)
save_ipv6_addr('d', &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk,
cs->fw6.ipv6.invflags & IP6T_INV_DSTIP);
- save_rule_details(cs, cs->fw6.ipv6.invflags, cs->fw6.ipv6.proto,
- cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask,
- cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask);
+ save_rule_details(cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask,
+ cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask,
+ cs->fw6.ipv6.proto, 0, cs->fw6.ipv6.invflags);
save_matches_and_target(cs, cs->fw6.ipv6.flags & IP6T_F_GOTO,
&cs->fw6, format);
}
-/* These are invalid numbers as upper layer protocol */
-static int is_exthdr(uint16_t proto)
-{
- return (proto == IPPROTO_ROUTING ||
- proto == IPPROTO_FRAGMENT ||
- proto == IPPROTO_AH ||
- proto == IPPROTO_DSTOPTS);
-}
-
-static void nft_ipv6_proto_parse(struct iptables_command_state *cs,
- struct xtables_args *args)
-{
- cs->fw6.ipv6.proto = args->proto;
- cs->fw6.ipv6.invflags = args->invflags;
-
- if (is_exthdr(cs->fw6.ipv6.proto)
- && (cs->fw6.ipv6.invflags & XT_INV_PROTO) == 0)
- fprintf(stderr,
- "Warning: never matched protocol: %s. "
- "use extension match instead.\n",
- cs->protocol);
-}
-
-static void nft_ipv6_post_parse(int command, struct iptables_command_state *cs,
- struct xtables_args *args)
-{
- cs->fw6.ipv6.flags = args->flags;
- /* We already set invflags in proto_parse, but we need to refresh it
- * to include new parsed options.
- */
- cs->fw6.ipv6.invflags = args->invflags;
-
- memcpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ);
- memcpy(cs->fw6.ipv6.iniface_mask,
- args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
-
- memcpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ);
- memcpy(cs->fw6.ipv6.outiface_mask,
- args->outiface_mask, IFNAMSIZ*sizeof(unsigned char));
-
- if (args->goto_set)
- cs->fw6.ipv6.flags |= IP6T_F_GOTO;
-
- cs->fw6.counters.pcnt = args->pcnt_cnt;
- cs->fw6.counters.bcnt = args->bcnt_cnt;
-
- if (command & (CMD_REPLACE | CMD_INSERT |
- CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
- if (!(cs->options & OPT_DESTINATION))
- args->dhostnetworkmask = "::0/0";
- if (!(cs->options & OPT_SOURCE))
- args->shostnetworkmask = "::0/0";
- }
-
- if (args->shostnetworkmask)
- xtables_ip6parse_multiple(args->shostnetworkmask,
- &args->s.addr.v6,
- &args->s.mask.v6,
- &args->s.naddrs);
- if (args->dhostnetworkmask)
- xtables_ip6parse_multiple(args->dhostnetworkmask,
- &args->d.addr.v6,
- &args->d.mask.v6,
- &args->d.naddrs);
-
- if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
- (cs->fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM,
- "! not allowed with multiple"
- " source or destination IP addresses");
-}
-
static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr,
const struct in6_addr *mask,
int invert, struct xt_xlate *xl)
@@ -410,6 +313,106 @@ static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
return ret;
}
+static int
+nft_ipv6_add_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ bool append, int rulenum)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ 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));
+ 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
+nft_ipv6_delete_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ 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 = nft_cmd_rule_delete(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv6_check_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ 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 = nft_cmd_rule_check(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv6_replace_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ int rulenum)
+{
+ memcpy(&cs->fw6.ipv6.src, args->s.addr.v6, sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dst, args->d.addr.v6, sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk, args->s.mask.v6, sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk, args->d.mask.v6, sizeof(struct in6_addr));
+
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
+}
+
struct nft_family_ops nft_family_ops_ipv6 = {
.add = nft_ipv6_add,
.is_same = nft_ipv6_is_same,
@@ -420,10 +423,16 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.print_rule = nft_ipv6_print_rule,
.save_rule = nft_ipv6_save_rule,
.save_chain = nft_ipv46_save_chain,
- .proto_parse = nft_ipv6_proto_parse,
- .post_parse = nft_ipv6_post_parse,
+ .cmd_parse = {
+ .proto_parse = ipv6_proto_parse,
+ .post_parse = ipv6_post_parse,
+ },
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
.xlate = nft_ipv6_xlate,
+ .add_entry = nft_ipv6_add_entry,
+ .delete_entry = nft_ipv6_delete_entry,
+ .check_entry = nft_ipv6_check_entry,
+ .replace_entry = nft_ipv6_replace_entry,
};
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 4253b081..d0d0d558 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -20,8 +20,10 @@
#include <xtables.h>
+#include <linux/netfilter/nf_log.h>
#include <linux/netfilter/xt_comment.h>
#include <linux/netfilter/xt_limit.h>
+#include <linux/netfilter/xt_NFLOG.h>
#include <libmnl/libmnl.h>
#include <libnftnl/rule.h>
@@ -373,21 +375,6 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ctx->h->ops->parse_match(match, ctx->cs);
}
-void print_proto(uint16_t proto, int invert)
-{
- const struct protoent *pent = getprotobynumber(proto);
-
- if (invert)
- printf("! ");
-
- if (pent) {
- printf("-p %s ", pent->p_name);
- return;
- }
-
- printf("-p %u ", proto);
-}
-
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
{
uint32_t len;
@@ -458,7 +445,7 @@ static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD;
}
- ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
+ ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
ctx->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE);
ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET);
ctx->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN);
@@ -595,6 +582,54 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ctx->h->ops->parse_match(match, ctx->cs);
}
+static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ struct xtables_target *target;
+ struct xt_entry_target *t;
+ size_t target_size;
+ /*
+ * In order to handle the longer log-prefix supported by nft, instead of
+ * using struct xt_nflog_info, we use a struct with a compatible layout, but
+ * a larger buffer for the prefix.
+ */
+ struct xt_nflog_info_nft {
+ __u32 len;
+ __u16 group;
+ __u16 threshold;
+ __u16 flags;
+ __u16 pad;
+ char prefix[NF_LOG_PREFIXLEN];
+ } info = {
+ .group = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP),
+ .threshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD),
+ };
+ if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_SNAPLEN)) {
+ info.len = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN);
+ info.flags = XT_NFLOG_F_COPY_LEN;
+ }
+ if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_PREFIX))
+ snprintf(info.prefix, sizeof(info.prefix), "%s",
+ nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX));
+
+ target = xtables_find_target("NFLOG", XTF_TRY_LOAD);
+ if (target == NULL)
+ return;
+
+ target_size = XT_ALIGN(sizeof(struct xt_entry_target)) +
+ XT_ALIGN(sizeof(struct xt_nflog_info_nft));
+
+ t = xtables_calloc(1, target_size);
+ t->u.target_size = target_size;
+ strcpy(t->u.user.name, target->name);
+ t->u.user.revision = target->revision;
+
+ target->t = t;
+
+ memcpy(&target->t->data, &info, sizeof(info));
+
+ ctx->h->ops->parse_target(target, ctx->cs);
+}
+
static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h,
struct nftnl_expr *e)
{
@@ -644,6 +679,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h,
nft_parse_limit(&ctx, expr);
else if (strcmp(name, "lookup") == 0)
nft_parse_lookup(&ctx, h, expr);
+ else if (strcmp(name, "log") == 0)
+ nft_parse_log(&ctx, expr);
expr = nftnl_expr_iter_next(iter);
}
@@ -714,130 +751,6 @@ void nft_clear_iptables_command_state(struct iptables_command_state *cs)
}
}
-void print_header(unsigned int format, const char *chain, const char *pol,
- const struct xt_counters *counters, bool basechain,
- uint32_t refs, uint32_t entries)
-{
- printf("Chain %s", chain);
- if (basechain) {
- printf(" (policy %s", pol);
- if (!(format & FMT_NOCOUNTS)) {
- fputc(' ', stdout);
- xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
- fputs("packets, ", stdout);
- xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
- fputs("bytes", stdout);
- }
- printf(")\n");
- } else {
- printf(" (%u references)\n", refs);
- }
-
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4s ", "%s "), "num");
- if (!(format & FMT_NOCOUNTS)) {
- if (format & FMT_KILOMEGAGIGA) {
- printf(FMT("%5s ","%s "), "pkts");
- printf(FMT("%5s ","%s "), "bytes");
- } else {
- printf(FMT("%8s ","%s "), "pkts");
- printf(FMT("%10s ","%s "), "bytes");
- }
- }
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ","%s "), "target");
- fputs(" prot ", stdout);
- if (format & FMT_OPTIONS)
- fputs("opt", stdout);
- if (format & FMT_VIA) {
- printf(FMT(" %-6s ","%s "), "in");
- printf(FMT("%-6s ","%s "), "out");
- }
- printf(FMT(" %-19s ","%s "), "source");
- printf(FMT(" %-19s "," %s "), "destination");
- printf("\n");
-}
-
-void print_rule_details(const struct iptables_command_state *cs,
- const char *targname, uint8_t flags,
- uint8_t invflags, uint8_t proto,
- unsigned int num, unsigned int format)
-{
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4u ", "%u "), num);
-
- if (!(format & FMT_NOCOUNTS)) {
- xtables_print_num(cs->counters.pcnt, format);
- xtables_print_num(cs->counters.bcnt, format);
- }
-
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ", "%s "), targname ? targname : "");
-
- fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout);
- {
- const char *pname =
- proto_to_name(proto, format&FMT_NUMERIC);
- if (pname)
- printf(FMT("%-5s", "%s "), pname);
- else
- printf(FMT("%-5hu", "%hu "), proto);
- }
-}
-
-static void
-print_iface(char letter, const char *iface, const unsigned char *mask, int inv)
-{
- unsigned int i;
-
- if (mask[0] == 0)
- return;
-
- printf("%s-%c ", inv ? "! " : "", letter);
-
- for (i = 0; i < IFNAMSIZ; i++) {
- if (mask[i] != 0) {
- if (iface[i] != '\0')
- printf("%c", iface[i]);
- } else {
- if (iface[i-1] != '\0')
- printf("+");
- break;
- }
- }
-
- printf(" ");
-}
-
-void save_rule_details(const struct iptables_command_state *cs,
- uint8_t invflags, uint16_t proto,
- const char *iniface,
- unsigned const char *iniface_mask,
- const char *outiface,
- unsigned const char *outiface_mask)
-{
- if (iniface != NULL) {
- print_iface('i', iniface, iniface_mask,
- invflags & IPT_INV_VIA_IN);
- }
- if (outiface != NULL) {
- print_iface('o', outiface, outiface_mask,
- invflags & IPT_INV_VIA_OUT);
- }
-
- if (proto > 0) {
- const char *pname = proto_to_name(proto, 0);
-
- if (invflags & XT_INV_PROTO)
- printf("! ");
-
- if (pname)
- printf("-p %s ", pname);
- else
- printf("-p %u ", proto);
- }
-}
-
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy)
{
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
@@ -856,33 +769,33 @@ void save_matches_and_target(const struct iptables_command_state *cs,
for (matchp = cs->matches; matchp; matchp = matchp->next) {
if (matchp->match->alias) {
- printf("-m %s",
+ printf(" -m %s",
matchp->match->alias(matchp->match->m));
} else
- printf("-m %s", matchp->match->name);
+ printf(" -m %s", matchp->match->name);
if (matchp->match->save != NULL) {
/* cs->fw union makes the trick */
matchp->match->save(fw, matchp->match->m);
}
- printf(" ");
}
if ((format & (FMT_NOCOUNTS | FMT_C_COUNTS)) == FMT_C_COUNTS)
- printf("-c %llu %llu ",
+ printf(" -c %llu %llu",
(unsigned long long)cs->counters.pcnt,
(unsigned long long)cs->counters.bcnt);
if (cs->target != NULL) {
if (cs->target->alias) {
- printf("-j %s", cs->target->alias(cs->target->t));
+ printf(" -j %s", cs->target->alias(cs->target->t));
} else
- printf("-j %s", cs->jumpto);
+ printf(" -j %s", cs->jumpto);
- if (cs->target->save != NULL)
+ if (cs->target->save != NULL) {
cs->target->save(fw, cs->target->t);
+ }
} else if (strlen(cs->jumpto) > 0) {
- printf("-%c %s", goto_flag ? 'g' : 'j', cs->jumpto);
+ printf(" -%c %s", goto_flag ? 'g' : 'j', cs->jumpto);
}
printf("\n");
@@ -992,6 +905,7 @@ void nft_check_xt_legacy(int family, bool is_ipt_save)
{
static const char tables6[] = "/proc/net/ip6_tables_names";
static const char tables4[] = "/proc/net/ip_tables_names";
+ static const char tablesa[] = "/proc/net/arp_tables_names";
const char *prefix = "ip";
FILE *fp = NULL;
char buf[1024];
@@ -1004,6 +918,10 @@ void nft_check_xt_legacy(int family, bool is_ipt_save)
fp = fopen(tables6, "r");
prefix = "ip6";
break;
+ case NFPROTO_ARP:
+ fp = fopen(tablesa, "r");
+ prefix = "arp";
+ break;
default:
break;
}
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index cc8f3a79..c3241f4b 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -94,22 +94,38 @@ struct nft_family_ops {
void (*print_table_header)(const char *tablename);
void (*print_header)(unsigned int format, const char *chain,
const char *pol,
- const struct xt_counters *counters, bool basechain,
- uint32_t refs, uint32_t entries);
+ const struct xt_counters *counters,
+ int refs, uint32_t entries);
void (*print_rule)(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format);
void (*save_rule)(const void *data, unsigned int format);
void (*save_chain)(const struct nftnl_chain *c, const char *policy);
- void (*proto_parse)(struct iptables_command_state *cs,
- struct xtables_args *args);
- void (*post_parse)(int command, struct iptables_command_state *cs,
- struct xtables_args *args);
+ struct xt_cmd_parse_ops cmd_parse;
void (*parse_match)(struct xtables_match *m, void *data);
void (*parse_target)(struct xtables_target *t, void *data);
+ void (*init_cs)(struct iptables_command_state *cs);
void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r,
struct iptables_command_state *cs);
void (*clear_cs)(struct iptables_command_state *cs);
int (*xlate)(const void *data, struct xt_xlate *xl);
+ int (*add_entry)(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ bool append, int rulenum);
+ int (*delete_entry)(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose);
+ int (*check_entry)(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose);
+ int (*replace_entry)(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ int rulenum);
};
void add_meta(struct nftnl_rule *r, uint32_t key);
@@ -139,27 +155,13 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
unsigned char *iniface_mask, char *outiface,
unsigned char *outiface_mask, uint8_t *invflags);
-void print_proto(uint16_t proto, int invert);
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv);
void nft_rule_to_iptables_command_state(struct nft_handle *h,
const struct nftnl_rule *r,
struct iptables_command_state *cs);
void nft_clear_iptables_command_state(struct iptables_command_state *cs);
-void print_header(unsigned int format, const char *chain, const char *pol,
- const struct xt_counters *counters, bool basechain,
- uint32_t refs, uint32_t entries);
-void print_rule_details(const struct iptables_command_state *cs,
- const char *targname, uint8_t flags,
- uint8_t invflags, uint8_t proto,
- unsigned int num, unsigned int format);
void print_matches_and_target(struct iptables_command_state *cs,
unsigned int format);
-void save_rule_details(const struct iptables_command_state *cs,
- uint8_t invflags, uint16_t proto,
- const char *iniface,
- unsigned const char *iniface_mask,
- const char *outiface,
- unsigned const char *outiface_mask);
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy);
void save_matches_and_target(const struct iptables_command_state *cs,
bool goto_flag, const void *fw,
@@ -172,50 +174,6 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data);
bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2);
bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2);
-struct addr_mask {
- union {
- struct in_addr *v4;
- struct in6_addr *v6;
- } addr;
-
- unsigned int naddrs;
-
- union {
- struct in_addr *v4;
- struct in6_addr *v6;
- } mask;
-};
-
-struct xtables_args {
- int family;
- uint16_t proto;
- uint8_t flags;
- uint16_t invflags;
- char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
- unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
- bool goto_set;
- const char *shostnetworkmask, *dhostnetworkmask;
- const char *pcnt, *bcnt;
- struct addr_mask s, d;
- unsigned long long pcnt_cnt, bcnt_cnt;
-};
-
-struct nft_xt_cmd_parse {
- unsigned int command;
- unsigned int rulenum;
- char *table;
- const char *chain;
- const char *newname;
- const char *policy;
- bool restore;
- int verbose;
- bool xlate;
-};
-
-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);
-
struct nftnl_chain_list;
struct nft_xt_restore_cb {
diff --git a/iptables/nft.c b/iptables/nft.c
index dc1f5160..72f7cf13 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -39,6 +39,7 @@
#include <linux/netfilter/nf_tables_compat.h>
#include <linux/netfilter/xt_limit.h>
+#include <linux/netfilter/xt_NFLOG.h>
#include <libmnl/libmnl.h>
#include <libnftnl/gen.h>
@@ -863,7 +864,22 @@ int nft_restart(struct nft_handle *h)
return 0;
}
-int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
+static const struct builtin_table *builtin_tables_lookup(int family)
+{
+ switch (family) {
+ case AF_INET:
+ case AF_INET6:
+ return xtables_ipv4;
+ case NFPROTO_ARP:
+ return xtables_arp;
+ case NFPROTO_BRIDGE:
+ return xtables_bridge;
+ default:
+ return NULL;
+ }
+}
+
+int nft_init(struct nft_handle *h, int family)
{
memset(h, 0, sizeof(*h));
@@ -881,7 +897,7 @@ int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
xtables_error(PARAMETER_PROBLEM, "Unknown family");
h->portid = mnl_socket_get_portid(h->nl);
- h->tables = t;
+ h->tables = builtin_tables_lookup(family);
h->cache = &h->__cache[0];
h->family = family;
@@ -1320,27 +1336,54 @@ int add_verdict(struct nftnl_rule *r, int verdict)
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
bool goto_set)
{
- int ret = 0;
-
- /* If no target at all, add nothing (default to continue) */
- if (cs->target != NULL) {
- /* Standard target? */
- if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
- ret = add_verdict(r, NF_ACCEPT);
- else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
- ret = add_verdict(r, NF_DROP);
- else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
- ret = add_verdict(r, NFT_RETURN);
- else
- ret = add_target(r, cs->target->t);
- } else if (strlen(cs->jumpto) > 0) {
- /* Not standard, then it's a go / jump to chain */
- if (goto_set)
- ret = add_jumpto(r, cs->jumpto, NFT_GOTO);
- else
- ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
- }
- return ret;
+ int ret = 0;
+
+ /* If no target at all, add nothing (default to continue) */
+ if (cs->target != NULL) {
+ /* Standard target? */
+ if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
+ ret = add_verdict(r, NF_ACCEPT);
+ else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
+ ret = add_verdict(r, NF_DROP);
+ else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
+ ret = add_verdict(r, NFT_RETURN);
+ else if (strcmp(cs->jumpto, "NFLOG") == 0)
+ ret = add_log(r, cs);
+ else
+ ret = add_target(r, cs->target->t);
+ } else if (strlen(cs->jumpto) > 0) {
+ /* Not standard, then it's a go / jump to chain */
+ if (goto_set)
+ ret = add_jumpto(r, cs->jumpto, NFT_GOTO);
+ else
+ ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
+ }
+ return ret;
+}
+
+int add_log(struct nftnl_rule *r, struct iptables_command_state *cs)
+{
+ struct nftnl_expr *expr;
+ struct xt_nflog_info *info = (struct xt_nflog_info *)cs->target->t->data;
+
+ expr = nftnl_expr_alloc("log");
+ if (!expr)
+ return -ENOMEM;
+
+ if (info->prefix[0] != '\0')
+ nftnl_expr_set_str(expr, NFTNL_EXPR_LOG_PREFIX,
+ cs->target->udata);
+
+ nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_GROUP, info->group);
+ if (info->flags & XT_NFLOG_F_COPY_LEN)
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_LOG_SNAPLEN,
+ info->len);
+ if (info->threshold)
+ nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_QTHRESHOLD,
+ info->threshold);
+
+ nftnl_rule_add_expr(r, expr);
+ return 0;
}
static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh)
@@ -1498,10 +1541,10 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
/* print chain name */
switch(type) {
case NFT_RULE_APPEND:
- printf("-A %s ", chain);
+ printf("-A %s", chain);
break;
case NFT_RULE_DEL:
- printf("-D %s ", chain);
+ printf("-D %s", chain);
break;
}
@@ -2383,7 +2426,6 @@ static void __nft_print_header(struct nft_handle *h,
{
struct nftnl_chain *c = nc->nftnl;
const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM);
uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
uint32_t entries = nft_rule_count(h, c);
struct xt_counters ctrs = {
@@ -2392,11 +2434,12 @@ static void __nft_print_header(struct nft_handle *h,
};
const char *pname = NULL;
- if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
+ if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) &&
+ nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
h->ops->print_header(format, chain_name, pname,
- &ctrs, basechain, refs - entries, entries);
+ &ctrs, refs - entries, entries);
}
struct nft_rule_list_cb_data {
@@ -3499,6 +3542,10 @@ static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0)
return 0;
+ if (!strcmp(name, "log") &&
+ nftnl_expr_is_set(expr, NFTNL_EXPR_LOG_GROUP))
+ return 0;
+
return -1;
}
diff --git a/iptables/nft.h b/iptables/nft.h
index ef79b018..4c78f761 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -123,7 +123,7 @@ extern const struct builtin_table xtables_bridge[NFT_TABLE_MAX];
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
int (*cb)(const struct nlmsghdr *nlh, void *data),
void *data);
-int nft_init(struct nft_handle *h, int family, const struct builtin_table *t);
+int nft_init(struct nft_handle *h, int family);
void nft_fini(struct nft_handle *h);
int nft_restart(struct nft_handle *h);
@@ -194,6 +194,7 @@ int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match
int add_target(struct nftnl_rule *r, struct xt_entry_target *t);
int add_jumpto(struct nftnl_rule *r, const char *name, int verdict);
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set);
+int add_log(struct nftnl_rule *r, struct iptables_command_state *cs);
char *get_comment(const void *data, uint32_t data_len);
enum nft_rule_print {
diff --git a/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0
index faf37d02..d79f91b1 100755
--- a/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0
+++ b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
case "$XT_MULTI" in
*xtables-nft-multi)
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 2d3ef679..c5a93290 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <arpa/inet.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -47,7 +48,7 @@ void print_extension_helps(const struct xtables_target *t,
}
}
-const char *
+static const char *
proto_to_name(uint16_t proto, int nolookup)
{
unsigned int i;
@@ -106,7 +107,7 @@ static bool should_load_proto(struct iptables_command_state *cs)
return !cs->proto_used;
}
-struct xtables_match *load_proto(struct iptables_command_state *cs)
+static struct xtables_match *load_proto(struct iptables_command_state *cs)
{
if (!should_load_proto(cs))
return NULL;
@@ -546,6 +547,52 @@ void debug_print_argv(struct argv_store *store)
}
#endif
+void print_header(unsigned int format, const char *chain, const char *pol,
+ const struct xt_counters *counters,
+ int refs, uint32_t entries)
+{
+ printf("Chain %s", chain);
+ if (pol) {
+ printf(" (policy %s", pol);
+ if (!(format & FMT_NOCOUNTS)) {
+ fputc(' ', stdout);
+ xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
+ fputs("packets, ", stdout);
+ xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
+ fputs("bytes", stdout);
+ }
+ printf(")\n");
+ } else if (refs < 0) {
+ printf(" (ERROR obtaining refs)\n");
+ } else {
+ printf(" (%d references)\n", refs);
+ }
+
+ if (format & FMT_LINENUMBERS)
+ printf(FMT("%-4s ", "%s "), "num");
+ if (!(format & FMT_NOCOUNTS)) {
+ if (format & FMT_KILOMEGAGIGA) {
+ printf(FMT("%5s ","%s "), "pkts");
+ printf(FMT("%5s ","%s "), "bytes");
+ } else {
+ printf(FMT("%8s ","%s "), "pkts");
+ printf(FMT("%10s ","%s "), "bytes");
+ }
+ }
+ if (!(format & FMT_NOTARGET))
+ printf(FMT("%-9s ","%s "), "target");
+ fputs(" prot ", stdout);
+ if (format & FMT_OPTIONS)
+ fputs("opt", stdout);
+ if (format & FMT_VIA) {
+ printf(FMT(" %-6s ","%s "), "in");
+ printf(FMT("%-6s ","%s "), "out");
+ }
+ printf(FMT(" %-19s ","%s "), "source");
+ printf(FMT(" %-19s "," %s "), "destination");
+ printf("\n");
+}
+
const char *ipv4_addr_to_string(const struct in_addr *addr,
const struct in_addr *mask,
unsigned int format)
@@ -578,6 +625,42 @@ void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format)
ipv4_addr_to_string(&fw->ip.dst, &fw->ip.dmsk, format));
}
+static const char *mask_to_str(const struct in_addr *mask)
+{
+ uint32_t bits, hmask = ntohl(mask->s_addr);
+ static char mask_str[INET_ADDRSTRLEN];
+ int i;
+
+ if (mask->s_addr == 0xFFFFFFFFU) {
+ sprintf(mask_str, "32");
+ return mask_str;
+ }
+
+ i = 32;
+ bits = 0xFFFFFFFEU;
+ while (--i >= 0 && hmask != bits)
+ bits <<= 1;
+ if (i >= 0)
+ sprintf(mask_str, "%u", i);
+ else
+ inet_ntop(AF_INET, mask, mask_str, sizeof(mask_str));
+
+ return mask_str;
+}
+
+void save_ipv4_addr(char letter, const struct in_addr *addr,
+ const struct in_addr *mask, int invert)
+{
+ char addrbuf[INET_ADDRSTRLEN];
+
+ if (!mask->s_addr && !invert && !addr->s_addr)
+ return;
+
+ printf("%s -%c %s/%s", invert ? " !" : "", letter,
+ inet_ntop(AF_INET, addr, addrbuf, sizeof(addrbuf)),
+ mask_to_str(mask));
+}
+
static const char *ipv6_addr_to_string(const struct in6_addr *addr,
const struct in6_addr *mask,
unsigned int format)
@@ -612,6 +695,44 @@ void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format)
&fw6->ipv6.dmsk, format));
}
+void save_ipv6_addr(char letter, const struct in6_addr *addr,
+ const struct in6_addr *mask, int invert)
+{
+ int l = xtables_ip6mask_to_cidr(mask);
+ char addr_str[INET6_ADDRSTRLEN];
+
+ if (!invert && l == 0)
+ return;
+
+ printf("%s -%c %s",
+ invert ? " !" : "", letter,
+ inet_ntop(AF_INET6, addr, addr_str, sizeof(addr_str)));
+
+ if (l == -1)
+ printf("/%s", inet_ntop(AF_INET6, mask,
+ addr_str, sizeof(addr_str)));
+ else
+ printf("/%d", l);
+}
+
+void print_fragment(unsigned int flags, unsigned int invflags,
+ unsigned int format, bool fake)
+{
+ if (!(format & FMT_OPTIONS))
+ return;
+
+ if (format & FMT_NOTABLE)
+ fputs("opt ", stdout);
+
+ if (fake) {
+ fputs(" ", stdout);
+ } else {
+ fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout);
+ fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
+ }
+ fputc(' ', stdout);
+}
+
/* Luckily, IPT_INV_VIA_IN and IPT_INV_VIA_OUT
* have the same values as IP6T_INV_VIA_IN and IP6T_INV_VIA_OUT
* so this function serves for both iptables and ip6tables */
@@ -637,6 +758,31 @@ void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
printf(FMT("%-6s ", "out %s "), iface);
}
+/* This assumes that mask is contiguous, and byte-bounded. */
+void save_iface(char letter, const char *iface,
+ const unsigned char *mask, int invert)
+{
+ unsigned int i;
+
+ if (mask[0] == 0)
+ return;
+
+ printf("%s -%c ", invert ? " !" : "", letter);
+
+ for (i = 0; i < IFNAMSIZ; i++) {
+ if (mask[i] != 0) {
+ if (iface[i] != '\0')
+ printf("%c", iface[i]);
+ } else {
+ /* we can access iface[i-1] here, because
+ * a few lines above we make sure that mask[0] != 0 */
+ if (iface[i-1] != '\0')
+ printf("+");
+ break;
+ }
+ }
+}
+
void command_match(struct iptables_command_state *cs, bool invert)
{
struct option *opts = xt_params->opts;
@@ -892,3 +1038,911 @@ set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
*invflg |= inverse_for_options[i];
}
}
+
+void parse_chain(const char *chainname)
+{
+ const char *ptr;
+
+ if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name `%s' too long (must be under %u chars)",
+ chainname, XT_EXTENSION_MAXNAMELEN);
+
+ if (*chainname == '-' || *chainname == '!')
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name not allowed to start with `%c'\n",
+ *chainname);
+
+ if (xtables_find_target(chainname, XTF_TRY_LOAD))
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name may not clash with target name\n");
+
+ for (ptr = chainname; *ptr; ptr++)
+ if (isspace(*ptr))
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid chain name `%s'", chainname);
+}
+
+void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs,
+ const char *targname, uint8_t proto, uint8_t flags,
+ uint8_t invflags, unsigned int format)
+{
+ const char *pname = proto_to_name(proto, format&FMT_NUMERIC);
+
+ if (format & FMT_LINENUMBERS)
+ printf(FMT("%-4u ", "%u "), linenum);
+
+ if (!(format & FMT_NOCOUNTS)) {
+ xtables_print_num(ctrs->pcnt, format);
+ xtables_print_num(ctrs->bcnt, format);
+ }
+
+ if (!(format & FMT_NOTARGET))
+ printf(FMT("%-9s ", "%s "), targname ? targname : "");
+
+ fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout);
+
+ if (pname)
+ printf(FMT("%-5s", "%s "), pname);
+ else
+ printf(FMT("%-5hu", "%hu "), proto);
+}
+
+void save_rule_details(const char *iniface, unsigned const char *iniface_mask,
+ const char *outiface, unsigned const char *outiface_mask,
+ uint16_t proto, int frag, uint8_t invflags)
+{
+ if (iniface != NULL) {
+ save_iface('i', iniface, iniface_mask,
+ invflags & IPT_INV_VIA_IN);
+ }
+ if (outiface != NULL) {
+ save_iface('o', outiface, outiface_mask,
+ invflags & IPT_INV_VIA_OUT);
+ }
+
+ if (proto > 0) {
+ const char *pname = proto_to_name(proto, 0);
+
+ if (invflags & XT_INV_PROTO)
+ printf(" !");
+
+ if (pname)
+ printf(" -p %s", pname);
+ else
+ printf(" -p %u", proto);
+ }
+
+ if (frag) {
+ if (invflags & IPT_INV_FRAG)
+ printf(" !");
+ printf(" -f");
+ }
+}
+
+int print_match_save(const struct xt_entry_match *e, const void *ip)
+{
+ const char *name = e->u.user.name;
+ const int revision = e->u.user.revision;
+ struct xtables_match *match, *mt, *mt2;
+
+ match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
+ if (match) {
+ mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD,
+ match, revision);
+ if (!mt2)
+ mt2 = match;
+ printf(" -m %s", mt2->alias ? mt2->alias(e) : name);
+
+ /* some matches don't provide a save function */
+ if (mt && mt->save)
+ mt->save(ip, e);
+ else if (match->save)
+ printf(" [unsupported revision]");
+ } else {
+ if (e->u.match_size) {
+ fprintf(stderr,
+ "Can't find library for match `%s'\n",
+ name);
+ exit(1);
+ }
+ }
+ return 0;
+}
+
+void
+xtables_printhelp(const struct xtables_rule_match *matches)
+{
+ const char *prog_name = xt_params->program_name;
+ const char *prog_vers = xt_params->program_version;
+
+ printf("%s v%s\n\n"
+"Usage: %s -[ACD] chain rule-specification [options]\n"
+" %s -I chain [rulenum] rule-specification [options]\n"
+" %s -R chain rulenum rule-specification [options]\n"
+" %s -D chain rulenum [options]\n"
+" %s -[LS] [chain [rulenum]] [options]\n"
+" %s -[FZ] [chain] [options]\n"
+" %s -[NX] chain\n"
+" %s -E old-chain-name new-chain-name\n"
+" %s -P chain target [options]\n"
+" %s -h (print this help information)\n\n",
+ prog_name, prog_vers, prog_name, prog_name,
+ prog_name, prog_name, prog_name, prog_name,
+ prog_name, prog_name, prog_name, prog_name);
+
+ printf(
+"Commands:\n"
+"Either long or short options are allowed.\n"
+" --append -A chain Append to chain\n"
+" --check -C chain Check for the existence of a rule\n"
+" --delete -D chain Delete matching rule from chain\n"
+" --delete -D chain rulenum\n"
+" Delete rule rulenum (1 = first) from chain\n"
+" --insert -I chain [rulenum]\n"
+" Insert in chain as rulenum (default 1=first)\n"
+" --replace -R chain rulenum\n"
+" Replace rule rulenum (1 = first) in chain\n"
+" --list -L [chain [rulenum]]\n"
+" List the rules in a chain or all chains\n"
+" --list-rules -S [chain [rulenum]]\n"
+" Print the rules in a chain or all chains\n"
+" --flush -F [chain] Delete all rules in chain or all chains\n"
+" --zero -Z [chain [rulenum]]\n"
+" Zero counters in chain or all chains\n"
+" --new -N chain Create a new user-defined chain\n"
+" --delete-chain\n"
+" -X [chain] Delete a user-defined chain\n"
+" --policy -P chain target\n"
+" Change policy on chain to target\n"
+" --rename-chain\n"
+" -E old-chain new-chain\n"
+" Change chain name, (moving any references)\n");
+
+ printf(
+"Options:\n"
+" --ipv4 -4 %s (line is ignored by ip6tables-restore)\n"
+" --ipv6 -6 %s (line is ignored by iptables-restore)\n"
+"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n"
+"[!] --source -s address[/mask][...]\n"
+" source specification\n"
+"[!] --destination -d address[/mask][...]\n"
+" destination specification\n"
+"[!] --in-interface -i input name[+]\n"
+" network interface name ([+] for wildcard)\n"
+" --jump -j target\n"
+" target for rule (may load target extension)\n",
+ afinfo->family == NFPROTO_IPV4 ? "Nothing" : "Error",
+ afinfo->family == NFPROTO_IPV4 ? "Error" : "Nothing");
+
+ if (0
+#ifdef IPT_F_GOTO
+ || afinfo->family == NFPROTO_IPV4
+#endif
+#ifdef IP6T_F_GOTO
+ || afinfo->family == NFPROTO_IPV6
+#endif
+ )
+ printf(
+" --goto -g chain\n"
+" jump to chain with no return\n");
+ printf(
+" --match -m match\n"
+" extended match (may load extension)\n"
+" --numeric -n numeric output of addresses and ports\n"
+"[!] --out-interface -o output name[+]\n"
+" network interface name ([+] for wildcard)\n"
+" --table -t table table to manipulate (default: `filter')\n"
+" --verbose -v verbose mode\n"
+" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
+" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n"
+" interval to wait for xtables lock\n"
+" default is 1 second\n"
+" --line-numbers print line numbers when listing\n"
+" --exact -x expand numbers (display exact values)\n");
+
+ if (afinfo->family == NFPROTO_IPV4)
+ printf(
+"[!] --fragment -f match second or further fragments only\n");
+
+ printf(
+" --modprobe=<command> try to insert modules using this command\n"
+" --set-counters PKTS BYTES set the counter during insert/append\n"
+"[!] --version -V print package version.\n");
+
+ print_extension_helps(xtables_targets, matches);
+}
+
+void exit_tryhelp(int status, int line)
+{
+ if (line != -1)
+ fprintf(stderr, "Error occurred at line: %d\n", line);
+ fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
+ xt_params->program_name, xt_params->program_name);
+ xtables_free_opts(1);
+ exit(status);
+}
+
+static void check_empty_interface(struct xtables_args *args, const char *arg)
+{
+ const char *msg = "Empty interface is likely to be undesired";
+
+ if (*arg != '\0')
+ return;
+
+ if (args->family != NFPROTO_ARP)
+ xtables_error(PARAMETER_PROBLEM, msg);
+
+ fprintf(stderr, "%s", msg);
+}
+
+static void check_inverse(struct xtables_args *args, const char option[],
+ bool *invert, int *optidx, int argc)
+{
+ switch (args->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(int argc, char *argv[],
+ struct xt_cmd_parse *p, struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ struct xtables_match *m;
+ struct xtables_rule_match *matchp;
+ bool wait_interval_set = false;
+ struct xtables_target *t;
+ bool table_set = false;
+ bool invert = false;
+
+ /* re-set optind to 0 in case do_command4 gets called
+ * a second time */
+ optind = 0;
+
+ /* clear mflags in case do_command4 gets called a second time
+ * (we clear the global list of all matches for security)*/
+ for (m = xtables_matches; m; m = m->next)
+ m->mflags = 0;
+
+ for (t = xtables_targets; t; t = t->next) {
+ t->tflags = 0;
+ t->used = 0;
+ }
+
+ /* Suppress error messages: we may add new options if we
+ demand-load a protocol. */
+ opterr = 0;
+
+ xt_params->opts = xt_params->orig_opts;
+ while ((cs->c = getopt_long(argc, argv, xt_params->optstring,
+ xt_params->opts, NULL)) != -1) {
+ switch (cs->c) {
+ /*
+ * Command selection
+ */
+ case 'A':
+ add_command(&p->command, CMD_APPEND, CMD_NONE, invert);
+ p->chain = optarg;
+ break;
+
+ case 'C':
+ add_command(&p->command, CMD_CHECK, CMD_NONE, invert);
+ p->chain = optarg;
+ break;
+
+ case 'D':
+ add_command(&p->command, CMD_DELETE, CMD_NONE, invert);
+ p->chain = optarg;
+ if (xs_has_arg(argc, argv)) {
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ p->command = CMD_DELETE_NUM;
+ }
+ break;
+
+ case 'R':
+ add_command(&p->command, CMD_REPLACE, CMD_NONE, invert);
+ p->chain = optarg;
+ if (xs_has_arg(argc, argv))
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ else
+ xtables_error(PARAMETER_PROBLEM,
+ "-%c requires a rule number",
+ cmd2char(CMD_REPLACE));
+ break;
+
+ case 'I':
+ add_command(&p->command, CMD_INSERT, CMD_NONE, invert);
+ p->chain = optarg;
+ if (xs_has_arg(argc, argv))
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ else
+ p->rulenum = 1;
+ break;
+
+ case 'L':
+ add_command(&p->command, CMD_LIST,
+ CMD_ZERO | CMD_ZERO_NUM, invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ if (xs_has_arg(argc, argv))
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ break;
+
+ case 'S':
+ add_command(&p->command, CMD_LIST_RULES,
+ CMD_ZERO|CMD_ZERO_NUM, invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ if (xs_has_arg(argc, argv))
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ break;
+
+ case 'F':
+ add_command(&p->command, CMD_FLUSH, CMD_NONE, invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ break;
+
+ case 'Z':
+ add_command(&p->command, CMD_ZERO,
+ CMD_LIST|CMD_LIST_RULES, invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ if (xs_has_arg(argc, argv)) {
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ p->command = CMD_ZERO_NUM;
+ }
+ break;
+
+ case 'N':
+ parse_chain(optarg);
+ add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
+ invert);
+ p->chain = optarg;
+ break;
+
+ case 'X':
+ add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
+ invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ break;
+
+ case 'E':
+ add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
+ invert);
+ p->chain = optarg;
+ if (xs_has_arg(argc, argv))
+ p->newname = argv[optind++];
+ else
+ xtables_error(PARAMETER_PROBLEM,
+ "-%c requires old-chain-name and "
+ "new-chain-name",
+ cmd2char(CMD_RENAME_CHAIN));
+ break;
+
+ case 'P':
+ add_command(&p->command, CMD_SET_POLICY, CMD_NONE,
+ invert);
+ p->chain = optarg;
+ if (xs_has_arg(argc, argv))
+ p->policy = argv[optind++];
+ else
+ xtables_error(PARAMETER_PROBLEM,
+ "-%c requires a chain and a policy",
+ cmd2char(CMD_SET_POLICY));
+ break;
+
+ case 'h':
+ if (!optarg)
+ optarg = argv[optind];
+
+ /* iptables -p icmp -h */
+ if (!cs->matches && cs->protocol)
+ xtables_find_match(cs->protocol,
+ XTF_TRY_LOAD, &cs->matches);
+
+ xt_params->print_help(cs->matches);
+ p->command = CMD_NONE;
+ return;
+
+ /*
+ * Option selection
+ */
+ case 'p':
+ check_inverse(args, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_PROTOCOL,
+ &args->invflags, invert);
+
+ /* Canonicalize into lower case */
+ for (cs->protocol = argv[optind - 1];
+ *cs->protocol; cs->protocol++)
+ *cs->protocol = tolower(*cs->protocol);
+
+ cs->protocol = argv[optind - 1];
+ args->proto = xtables_parse_protocol(cs->protocol);
+
+ if (args->proto == 0 &&
+ (args->invflags & XT_INV_PROTO))
+ xtables_error(PARAMETER_PROBLEM,
+ "rule would never match protocol");
+
+ /* This needs to happen here to parse extensions */
+ if (p->ops->proto_parse)
+ p->ops->proto_parse(cs, args);
+ break;
+
+ case 's':
+ check_inverse(args, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_SOURCE,
+ &args->invflags, invert);
+ args->shostnetworkmask = argv[optind - 1];
+ break;
+
+ case 'd':
+ check_inverse(args, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_DESTINATION,
+ &args->invflags, invert);
+ args->dhostnetworkmask = argv[optind - 1];
+ break;
+
+#ifdef IPT_F_GOTO
+ case 'g':
+ set_option(&cs->options, OPT_JUMP, &args->invflags,
+ invert);
+ args->goto_set = true;
+ cs->jumpto = xt_parse_target(optarg);
+ break;
+#endif
+
+ case 2:/* src-mac */
+ check_inverse(args, 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(args, 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(args, 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(args, 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(args, 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(args, 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, argv[optind - 1]);
+ break;
+
+ case 'i':
+ check_empty_interface(args, optarg);
+ check_inverse(args, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_VIANAMEIN,
+ &args->invflags, invert);
+ xtables_parse_interface(argv[optind - 1],
+ args->iniface,
+ args->iniface_mask);
+ break;
+
+ case 'o':
+ check_empty_interface(args, optarg);
+ check_inverse(args, optarg, &invert, &optind, argc);
+ set_option(&cs->options, OPT_VIANAMEOUT,
+ &args->invflags, invert);
+ xtables_parse_interface(argv[optind - 1],
+ args->outiface,
+ args->outiface_mask);
+ break;
+
+ case 'f':
+ if (args->family == AF_INET6) {
+ xtables_error(PARAMETER_PROBLEM,
+ "`-f' is not supported in IPv6, "
+ "use -m frag instead");
+ }
+ set_option(&cs->options, OPT_FRAGMENT, &args->invflags,
+ invert);
+ args->flags |= IPT_F_FRAG;
+ break;
+
+ case 'v':
+ if (!p->verbose)
+ set_option(&cs->options, OPT_VERBOSE,
+ &args->invflags, invert);
+ p->verbose++;
+ break;
+
+ case 'm':
+ command_match(cs, invert);
+ break;
+
+ case 'n':
+ set_option(&cs->options, OPT_NUMERIC, &args->invflags,
+ invert);
+ break;
+
+ case 't':
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "unexpected ! flag before --table");
+ if (p->restore && table_set)
+ xtables_error(PARAMETER_PROBLEM,
+ "The -t option cannot be used in %s.\n",
+ xt_params->program_name);
+ p->table = optarg;
+ table_set = true;
+ break;
+
+ case 'x':
+ set_option(&cs->options, OPT_EXPANDED, &args->invflags,
+ invert);
+ break;
+
+ case 'V':
+ if (invert)
+ printf("Not %s ;-)\n",
+ xt_params->program_version);
+ else
+ printf("%s v%s\n",
+ xt_params->program_name,
+ xt_params->program_version);
+ exit(0);
+
+ case 'w':
+ if (p->restore) {
+ xtables_error(PARAMETER_PROBLEM,
+ "You cannot use `-w' from "
+ "iptables-restore");
+ }
+
+ args->wait = parse_wait_time(argc, argv);
+ break;
+
+ case 'W':
+ if (p->restore) {
+ xtables_error(PARAMETER_PROBLEM,
+ "You cannot use `-W' from "
+ "iptables-restore");
+ }
+
+ parse_wait_interval(argc, argv, &args->wait_interval);
+ wait_interval_set = true;
+ break;
+
+ case '0':
+ set_option(&cs->options, OPT_LINENUMBERS,
+ &args->invflags, invert);
+ break;
+
+ case 'M':
+ xtables_modprobe_program = optarg;
+ break;
+
+ case 'c':
+ set_option(&cs->options, OPT_COUNTERS, &args->invflags,
+ invert);
+ args->pcnt = optarg;
+ args->bcnt = strchr(args->pcnt + 1, ',');
+ if (args->bcnt)
+ args->bcnt++;
+ if (!args->bcnt && xs_has_arg(argc, argv))
+ args->bcnt = argv[optind++];
+ if (!args->bcnt)
+ xtables_error(PARAMETER_PROBLEM,
+ "-%c requires packet and byte counter",
+ opt2char(OPT_COUNTERS));
+
+ if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
+ xtables_error(PARAMETER_PROBLEM,
+ "-%c packet counter not numeric",
+ opt2char(OPT_COUNTERS));
+
+ if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
+ xtables_error(PARAMETER_PROBLEM,
+ "-%c byte counter not numeric",
+ opt2char(OPT_COUNTERS));
+ break;
+
+ case '4':
+ if (args->family == AF_INET)
+ break;
+
+ if (p->restore && args->family == AF_INET6)
+ return;
+
+ exit_tryhelp(2, p->line);
+
+ case '6':
+ if (args->family == AF_INET6)
+ break;
+
+ if (p->restore && args->family == AF_INET)
+ return;
+
+ exit_tryhelp(2, p->line);
+
+ case 1: /* non option */
+ if (optarg[0] == '!' && optarg[1] == '\0') {
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "multiple consecutive ! not"
+ " allowed");
+ invert = true;
+ optarg[0] = '\0';
+ continue;
+ }
+ fprintf(stderr, "Bad argument `%s'\n", optarg);
+ exit_tryhelp(2, p->line);
+
+ default:
+ if (command_default(cs, xt_params, invert))
+ /* cf. ip6tables.c */
+ continue;
+ break;
+ }
+ invert = false;
+ }
+
+ if (strcmp(p->table, "nat") == 0 &&
+ ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
+ (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
+ xtables_error(PARAMETER_PROBLEM,
+ "\nThe \"nat\" table is not intended for filtering, "
+ "the use of DROP is therefore inhibited.\n\n");
+
+ if (!args->wait && wait_interval_set)
+ xtables_error(PARAMETER_PROBLEM,
+ "--wait-interval only makes sense with --wait\n");
+
+ for (matchp = cs->matches; matchp; matchp = matchp->next)
+ xtables_option_mfcall(matchp->match);
+ if (cs->target != NULL)
+ xtables_option_tfcall(cs->target);
+
+ /* Fix me: must put inverse options checking here --MN */
+
+ if (optind < argc)
+ xtables_error(PARAMETER_PROBLEM,
+ "unknown arguments found on commandline");
+ if (!p->command)
+ xtables_error(PARAMETER_PROBLEM, "no command specified");
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "nothing appropriate following !");
+
+ if (p->ops->post_parse)
+ p->ops->post_parse(p->command, cs, args);
+
+ if (p->command == CMD_REPLACE &&
+ (args->s.naddrs != 1 || args->d.naddrs != 1))
+ xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
+ "specify a unique address");
+
+ generic_opt_check(p->command, cs->options);
+
+ if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name `%s' too long (must be under %u chars)",
+ p->chain, XT_EXTENSION_MAXNAMELEN);
+
+ if (p->command == CMD_APPEND ||
+ p->command == CMD_DELETE ||
+ p->command == CMD_DELETE_NUM ||
+ p->command == CMD_CHECK ||
+ p->command == CMD_INSERT ||
+ p->command == CMD_REPLACE) {
+ if (strcmp(p->chain, "PREROUTING") == 0
+ || strcmp(p->chain, "INPUT") == 0) {
+ /* -o not valid with incoming packets. */
+ if (cs->options & OPT_VIANAMEOUT)
+ xtables_error(PARAMETER_PROBLEM,
+ "Can't use -%c with %s\n",
+ opt2char(OPT_VIANAMEOUT),
+ p->chain);
+ }
+
+ if (strcmp(p->chain, "POSTROUTING") == 0
+ || strcmp(p->chain, "OUTPUT") == 0) {
+ /* -i not valid with outgoing packets */
+ if (cs->options & OPT_VIANAMEIN)
+ xtables_error(PARAMETER_PROBLEM,
+ "Can't use -%c with %s\n",
+ opt2char(OPT_VIANAMEIN),
+ p->chain);
+ }
+ }
+}
+
+void ipv4_proto_parse(struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->fw.ip.proto = args->proto;
+ cs->fw.ip.invflags = args->invflags;
+}
+
+/* These are invalid numbers as upper layer protocol */
+static int is_exthdr(uint16_t proto)
+{
+ return (proto == IPPROTO_ROUTING ||
+ proto == IPPROTO_FRAGMENT ||
+ proto == IPPROTO_AH ||
+ proto == IPPROTO_DSTOPTS);
+}
+
+void ipv6_proto_parse(struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->fw6.ipv6.proto = args->proto;
+ cs->fw6.ipv6.invflags = args->invflags;
+
+ /* this is needed for ip6tables-legacy only */
+ args->flags |= IP6T_F_PROTO;
+ cs->fw6.ipv6.flags |= IP6T_F_PROTO;
+
+ if (is_exthdr(cs->fw6.ipv6.proto)
+ && (cs->fw6.ipv6.invflags & XT_INV_PROTO) == 0)
+ fprintf(stderr,
+ "Warning: never matched protocol: %s. "
+ "use extension match instead.\n",
+ cs->protocol);
+}
+
+void ipv4_post_parse(int command, struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->fw.ip.flags = args->flags;
+ /* We already set invflags in proto_parse, but we need to refresh it
+ * to include new parsed options.
+ */
+ cs->fw.ip.invflags = args->invflags;
+
+ memcpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ);
+ memcpy(cs->fw.ip.iniface_mask,
+ args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
+
+ memcpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ);
+ memcpy(cs->fw.ip.outiface_mask,
+ args->outiface_mask, IFNAMSIZ*sizeof(unsigned char));
+
+ if (args->goto_set)
+ cs->fw.ip.flags |= IPT_F_GOTO;
+
+ /* nft-variants use cs->counters, legacy uses cs->fw.counters */
+ cs->counters.pcnt = args->pcnt_cnt;
+ cs->counters.bcnt = args->bcnt_cnt;
+ cs->fw.counters.pcnt = args->pcnt_cnt;
+ cs->fw.counters.bcnt = args->bcnt_cnt;
+
+ if (command & (CMD_REPLACE | CMD_INSERT |
+ CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
+ if (!(cs->options & OPT_DESTINATION))
+ args->dhostnetworkmask = "0.0.0.0/0";
+ if (!(cs->options & OPT_SOURCE))
+ args->shostnetworkmask = "0.0.0.0/0";
+ }
+
+ if (args->shostnetworkmask)
+ xtables_ipparse_multiple(args->shostnetworkmask,
+ &args->s.addr.v4, &args->s.mask.v4,
+ &args->s.naddrs);
+ if (args->dhostnetworkmask)
+ xtables_ipparse_multiple(args->dhostnetworkmask,
+ &args->d.addr.v4, &args->d.mask.v4,
+ &args->d.naddrs);
+
+ if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
+ (cs->fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
+ xtables_error(PARAMETER_PROBLEM,
+ "! not allowed with multiple"
+ " source or destination IP addresses");
+}
+
+void ipv6_post_parse(int command, struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->fw6.ipv6.flags = args->flags;
+ /* We already set invflags in proto_parse, but we need to refresh it
+ * to include new parsed options.
+ */
+ cs->fw6.ipv6.invflags = args->invflags;
+
+ memcpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ);
+ memcpy(cs->fw6.ipv6.iniface_mask,
+ args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
+
+ memcpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ);
+ memcpy(cs->fw6.ipv6.outiface_mask,
+ args->outiface_mask, IFNAMSIZ*sizeof(unsigned char));
+
+ if (args->goto_set)
+ cs->fw6.ipv6.flags |= IP6T_F_GOTO;
+
+ cs->fw6.counters.pcnt = args->pcnt_cnt;
+ cs->fw6.counters.bcnt = args->bcnt_cnt;
+
+ if (command & (CMD_REPLACE | CMD_INSERT |
+ CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
+ if (!(cs->options & OPT_DESTINATION))
+ args->dhostnetworkmask = "::0/0";
+ if (!(cs->options & OPT_SOURCE))
+ args->shostnetworkmask = "::0/0";
+ }
+
+ if (args->shostnetworkmask)
+ xtables_ip6parse_multiple(args->shostnetworkmask,
+ &args->s.addr.v6,
+ &args->s.mask.v6,
+ &args->s.naddrs);
+ if (args->dhostnetworkmask)
+ xtables_ip6parse_multiple(args->dhostnetworkmask,
+ &args->d.addr.v6,
+ &args->d.mask.v6,
+ &args->d.naddrs);
+
+ if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
+ (cs->fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))
+ xtables_error(PARAMETER_PROBLEM,
+ "! not allowed with multiple"
+ " source or destination IP addresses");
+}
diff --git a/iptables/xshared.h b/iptables/xshared.h
index 823894f9..d13de95e 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -68,6 +68,8 @@ struct xtables_globals;
struct xtables_rule_match;
struct xtables_target;
+#define OPTSTRING_COMMON "-:A:C:D:E:F::I:L::M:N:P:VX::Z::" "c:d:i:j:o:p:s:t:"
+
/* define invflags which won't collide with IPT ones */
#define IPT_INV_SRCDEVADDR 0x0080
#define IPT_INV_TGTDEVADDR 0x0100
@@ -162,10 +164,8 @@ enum {
extern void print_extension_helps(const struct xtables_target *,
const struct xtables_rule_match *);
-extern const char *proto_to_name(uint16_t, int);
extern int command_default(struct iptables_command_state *,
struct xtables_globals *, bool invert);
-extern struct xtables_match *load_proto(struct iptables_command_state *);
extern int subcmd_main(int, char **, const struct subcommand *);
extern void xs_init_target(struct xtables_target *);
extern void xs_init_match(struct xtables_match *);
@@ -219,11 +219,23 @@ void debug_print_argv(struct argv_store *store);
const char *ipv4_addr_to_string(const struct in_addr *addr,
const struct in_addr *mask,
unsigned int format);
+void print_header(unsigned int format, const char *chain, const char *pol,
+ const struct xt_counters *counters,
+ int refs, uint32_t entries);
void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format);
+void save_ipv4_addr(char letter, const struct in_addr *addr,
+ const struct in_addr *mask, int invert);
void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format);
+void save_ipv6_addr(char letter, const struct in6_addr *addr,
+ const struct in6_addr *mask, int invert);
void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
unsigned int format);
+void save_iface(char letter, const char *iface,
+ const unsigned char *mask, int invert);
+
+void print_fragment(unsigned int flags, unsigned int invflags,
+ unsigned int format, bool fake);
void command_match(struct iptables_command_state *cs, bool invert);
const char *xt_parse_target(const char *targetname);
@@ -233,8 +245,91 @@ char cmd2char(int option);
void add_command(unsigned int *cmd, const int newcmd,
const int othercmds, int invert);
int parse_rulenumber(const char *rule);
+void parse_chain(const char *chainname);
void generic_opt_check(int command, int options);
char opt2char(int option);
+void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs,
+ const char *targname, uint8_t proto, uint8_t flags,
+ uint8_t invflags, unsigned int format);
+void save_rule_details(const char *iniface, unsigned const char *iniface_mask,
+ const char *outiface, unsigned const char *outiface_mask,
+ uint16_t proto, int frag, uint8_t invflags);
+
+int print_match_save(const struct xt_entry_match *e, const void *ip);
+
+void xtables_printhelp(const struct xtables_rule_match *matches);
+void exit_tryhelp(int status, int line) __attribute__((noreturn));
+
+struct addr_mask {
+ union {
+ struct in_addr *v4;
+ struct in6_addr *v6;
+ void *ptr;
+ } addr;
+
+ unsigned int naddrs;
+
+ union {
+ struct in_addr *v4;
+ struct in6_addr *v6;
+ void *ptr;
+ } mask;
+};
+
+struct xtables_args {
+ int family;
+ uint16_t proto;
+ uint8_t flags;
+ uint16_t invflags;
+ char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
+ unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
+ bool goto_set;
+ const char *shostnetworkmask, *dhostnetworkmask;
+ const char *pcnt, *bcnt;
+ struct addr_mask s, d;
+ const char *src_mac, *dst_mac;
+ const char *arp_hlen, *arp_opcode;
+ const char *arp_htype, *arp_ptype;
+ unsigned long long pcnt_cnt, bcnt_cnt;
+ int wait;
+ struct timeval wait_interval;
+};
+
+struct xt_cmd_parse_ops {
+ void (*proto_parse)(struct iptables_command_state *cs,
+ struct xtables_args *args);
+ void (*post_parse)(int command,
+ struct iptables_command_state *cs,
+ struct xtables_args *args);
+};
+
+struct xt_cmd_parse {
+ unsigned int command;
+ unsigned int rulenum;
+ char *table;
+ const char *chain;
+ const char *newname;
+ const char *policy;
+ bool restore;
+ int line;
+ int verbose;
+ bool xlate;
+ struct xt_cmd_parse_ops *ops;
+};
+
+void do_parse(int argc, char *argv[],
+ struct xt_cmd_parse *p, struct iptables_command_state *cs,
+ struct xtables_args *args);
+
+void ipv4_proto_parse(struct iptables_command_state *cs,
+ struct xtables_args *args);
+void ipv6_proto_parse(struct iptables_command_state *cs,
+ struct xtables_args *args);
+void ipv4_post_parse(int command, struct iptables_command_state *cs,
+ struct xtables_args *args);
+void ipv6_post_parse(int command, struct iptables_command_state *cs,
+ struct xtables_args *args);
+
#endif /* IPTABLES_XSHARED_H */
diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c
deleted file mode 100644
index 04cf7dcc..00000000
--- a/iptables/xtables-arp-standalone.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au
- *
- * Based on the ipchains code by Paul Russell and Michael Neuling
- *
- * (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>
- *
- * arptables -- IP firewall administration for kernels with
- * firewall table (aimed for the 2.3 kernels)
- *
- * See the accompanying manual page arptables(8) for information
- * about proper usage of this program.
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <xtables.h>
-#include "nft.h"
-#include <linux/netfilter_arp/arp_tables.h>
-
-#include "xtables-multi.h"
-
-extern struct xtables_globals arptables_globals;
-
-int xtables_arp_main(int argc, char *argv[])
-{
- int ret;
- char *table = "filter";
- struct nft_handle h;
-
- nft_init_arp(&h, "arptables");
-
- ret = do_commandarp(&h, argc, argv, &table, false);
- if (ret)
- ret = nft_commit(&h);
-
- nft_fini(&h);
- xtables_fini();
-
- if (!ret)
- fprintf(stderr, "arptables: %s\n", nft_strerror(errno));
-
- exit(!ret);
-}
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 9a079f06..805fb19a 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -30,35 +30,23 @@
#include "config.h"
#include <getopt.h>
#include <string.h>
-#include <netdb.h>
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <inttypes.h>
-#include <dlfcn.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/wait.h>
-#include <net/if.h>
-#include <netinet/ether.h>
-#include <iptables.h>
#include <xtables.h>
#include "xshared.h"
#include "nft.h"
#include "nft-arp.h"
-#include <linux/netfilter_arp/arp_tables.h>
static struct option original_opts[] = {
{ "append", 1, 0, 'A' },
{ "delete", 1, 0, 'D' },
+ { "check", 1, 0, 'C'},
{ "insert", 1, 0, 'I' },
{ "replace", 1, 0, 'R' },
{ "list", 2, 0, 'L' },
+ { "list-rules", 2, 0, 'S'},
{ "flush", 2, 0, 'F' },
{ "zero", 2, 0, 'Z' },
{ "new-chain", 1, 0, 'N' },
@@ -96,83 +84,29 @@ static struct option original_opts[] = {
#define opts xt_params->opts
-extern 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 arptables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (nf_tables)",
+ .optstring = OPTSTRING_COMMON "C:R:S::" "h::l:nv" /* "m:" */,
.orig_opts = original_opts,
- .exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
+ .print_help = printhelp,
};
-/***********************************************/
-/* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */
-/***********************************************/
-
-static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask)
-{
- char *p, *buffer;
- int i;
-
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- i = strtol(p+1, &buffer, 10);
- if (*buffer != '\0' || i < 0 || i > 255)
- return -1;
- *mask = (uint8_t)i;
- } else
- *mask = 255;
- i = strtol(from, &buffer, 10);
- if (*buffer != '\0' || i < 0 || i > 255)
- return -1;
- *to = (uint8_t)i;
- return 0;
-}
-
-static int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base)
-{
- char *p, *buffer;
- int i;
-
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- i = strtol(p+1, &buffer, base);
- if (*buffer != '\0' || i < 0 || i > 65535)
- return -1;
- *mask = htons((uint16_t)i);
- } else
- *mask = 65535;
- i = strtol(from, &buffer, base);
- if (*buffer != '\0' || i < 0 || i > 65535)
- return -1;
- *to = htons((uint16_t)i);
- return 0;
-}
-
-/*********************************************/
-/* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */
-/*********************************************/
-
-static void
-exit_tryhelp(int status)
-{
- fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
- arptables_globals.program_name,
- arptables_globals.program_version);
- exit(status);
-}
-
static void
-printhelp(void)
+printhelp(const struct xtables_rule_match *m)
{
struct xtables_target *t = NULL;
int i;
printf("%s v%s\n\n"
-"Usage: %s -[AD] chain rule-specification [options]\n"
-" %s -[RI] chain rulenum rule-specification [options]\n"
+"Usage: %s -[ACD] chain rule-specification [options]\n"
+" %s -I chain [rulenum] rule-specification [options]\n"
+" %s -R chain rulenum rule-specification [options]\n"
" %s -D chain rulenum [options]\n"
-" %s -[LFZ] [chain] [options]\n"
+" %s -[LS] [chain [rulenum]] [options]\n"
+" %s -[FZ] [chain] [options]\n"
" %s -[NX] chain\n"
" %s -E old-chain-name new-chain-name\n"
" %s -P chain target [options]\n"
@@ -186,11 +120,14 @@ printhelp(void)
arptables_globals.program_name,
arptables_globals.program_name,
arptables_globals.program_name,
+ arptables_globals.program_name,
+ arptables_globals.program_name,
arptables_globals.program_name);
printf(
"Commands:\n"
"Either long or short options are allowed.\n"
" --append -A chain Append to chain\n"
+" --check -C chain Check for the existence of a rule\n"
" --delete -D chain Delete matching rule from chain\n"
" --delete -D chain rulenum\n"
" Delete rule rulenum (1 = first) from chain\n"
@@ -198,9 +135,13 @@ printhelp(void)
" Insert in chain as rulenum (default 1=first)\n"
" --replace -R chain rulenum\n"
" Replace rule rulenum (1 = first) in chain\n"
-" --list -L [chain] List the rules in a chain or all chains\n"
+" --list -L [chain [rulenum]]\n"
+" List the rules in a chain or all chains\n"
+" --list-rules -S [chain [rulenum]]\n"
+" Print the rules in a chain or all chains\n"
" --flush -F [chain] Delete all rules in chain or all chains\n"
-" --zero -Z [chain] Zero counters in chain or all chains\n"
+" --zero -Z [chain [rulenum]]\n"
+" Zero counters in chain or all chains\n"
" --new -N chain Create a new user-defined chain\n"
" --delete-chain\n"
" -X [chain] Delete a user-defined chain\n"
@@ -255,134 +196,6 @@ printhelp(void)
}
}
-static int
-check_inverse(const char option[], int *invert, int *optidx, int argc)
-{
- if (option && strcmp(option, "!") == 0) {
- 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 `!'");
- }
-
- return true;
- }
- return false;
-}
-
-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
-append_entry(struct nft_handle *h,
- const char *chain,
- const char *table,
- struct iptables_command_state *cs,
- int rulenum,
- unsigned int nsaddrs,
- const struct in_addr saddrs[],
- const struct in_addr smasks[],
- unsigned int ndaddrs,
- const struct in_addr daddrs[],
- const struct in_addr dmasks[],
- bool verbose, bool append)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < nsaddrs; i++) {
- cs->arp.arp.src.s_addr = saddrs[i].s_addr;
- cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
- for (j = 0; j < ndaddrs; j++) {
- cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
- cs->arp.arp.tmsk.s_addr = dmasks[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);
- }
- }
- }
-
- return ret;
-}
-
-static int
-replace_entry(const char *chain,
- const char *table,
- struct iptables_command_state *cs,
- unsigned int rulenum,
- const struct in_addr *saddr,
- const struct in_addr *smask,
- const struct in_addr *daddr,
- const struct in_addr *dmask,
- bool verbose, struct nft_handle *h)
-{
- cs->arp.arp.src.s_addr = saddr->s_addr;
- cs->arp.arp.tgt.s_addr = daddr->s_addr;
- cs->arp.arp.smsk.s_addr = smask->s_addr;
- cs->arp.arp.tmsk.s_addr = dmask->s_addr;
-
- 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,
- unsigned int nsaddrs,
- const struct in_addr saddrs[],
- const struct in_addr smasks[],
- unsigned int ndaddrs,
- const struct in_addr daddrs[],
- const struct in_addr dmasks[],
- bool verbose, struct nft_handle *h)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < nsaddrs; i++) {
- cs->arp.arp.src.s_addr = saddrs[i].s_addr;
- cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
- for (j = 0; j < ndaddrs; j++) {
- cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
- cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
- ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
- }
- }
-
- return ret;
-}
-
int nft_init_arp(struct nft_handle *h, const char *pname)
{
arptables_globals.program_name = pname;
@@ -397,531 +210,9 @@ int nft_init_arp(struct nft_handle *h, const char *pname)
init_extensionsa();
#endif
- if (nft_init(h, NFPROTO_ARP, xtables_arp) < 0)
+ if (nft_init(h, NFPROTO_ARP) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
return 0;
}
-
-int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
- bool restore)
-{
- struct iptables_command_state cs = {
- .jumpto = "",
- .arp.arp = {
- .arhln = 6,
- .arhln_mask = 255,
- .arhrd = htons(ARPHRD_ETHER),
- .arhrd_mask = 65535,
- },
- };
- int invert = 0;
- unsigned int nsaddrs = 0, ndaddrs = 0;
- struct in_addr *saddrs = NULL, *smasks = NULL;
- struct in_addr *daddrs = NULL, *dmasks = NULL;
-
- int c, verbose = 0;
- const char *chain = NULL;
- const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
- const char *policy = NULL, *newname = NULL;
- unsigned int rulenum = 0, options = 0, command = 0;
- const char *pcnt = NULL, *bcnt = NULL;
- int ret = 1;
- struct xtables_target *t;
-
- /* re-set optind to 0 in case do_command gets called
- * a second time */
- optind = 0;
-
- for (t = xtables_targets; t; t = t->next) {
- t->tflags = 0;
- t->used = 0;
- }
-
- /* Suppress error messages: we may add new options if we
- demand-load a protocol. */
- opterr = 0;
-
- opts = xt_params->orig_opts;
- while ((c = getopt_long(argc, argv,
- "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:l:i:vnt:m:c:",
- opts, NULL)) != -1) {
- switch (c) {
- /*
- * Command selection
- */
- case 'A':
- add_command(&command, CMD_APPEND, CMD_NONE,
- invert);
- chain = optarg;
- break;
-
- case 'D':
- add_command(&command, CMD_DELETE, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_DELETE_NUM;
- }
- break;
-
- case 'R':
- add_command(&command, CMD_REPLACE, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a rule number",
- cmd2char(CMD_REPLACE));
- break;
-
- case 'I':
- add_command(&command, CMD_INSERT, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else rulenum = 1;
- break;
-
- case 'L':
- add_command(&command, CMD_LIST, CMD_ZERO,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'F':
- add_command(&command, CMD_FLUSH, CMD_NONE,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'Z':
- add_command(&command, CMD_ZERO, CMD_LIST,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'N':
- if (optarg && *optarg == '-')
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `-'\n");
- if (xtables_find_target(optarg, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
- add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
- invert);
- chain = optarg;
- break;
-
- case 'X':
- add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'E':
- add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- newname = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires old-chain-name and "
- "new-chain-name",
- cmd2char(CMD_RENAME_CHAIN));
- break;
-
- case 'P':
- add_command(&command, CMD_SET_POLICY, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- policy = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a chain and a policy",
- cmd2char(CMD_SET_POLICY));
- break;
-
- case 'h':
- if (!optarg)
- optarg = argv[optind];
-
- printhelp();
- command = CMD_NONE;
- break;
- case 's':
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_SOURCE, &cs.arp.arp.invflags,
- invert);
- shostnetworkmask = argv[optind-1];
- break;
-
- case 'd':
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_DESTINATION, &cs.arp.arp.invflags,
- invert);
- dhostnetworkmask = argv[optind-1];
- break;
-
- case 2:/* src-mac */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_S_MAC, &cs.arp.arp.invflags,
- invert);
- if (xtables_parse_mac_and_mask(argv[optind - 1],
- cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified "
- "source mac");
- break;
-
- case 3:/* dst-mac */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_D_MAC, &cs.arp.arp.invflags,
- invert);
-
- if (xtables_parse_mac_and_mask(argv[optind - 1],
- cs.arp.arp.tgt_devaddr.addr, cs.arp.arp.tgt_devaddr.mask))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified "
- "destination mac");
- break;
-
- case 'l':/* hardware length */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_H_LENGTH, &cs.arp.arp.invflags,
- invert);
- getlength_and_mask(argv[optind - 1], &cs.arp.arp.arhln,
- &cs.arp.arp.arhln_mask);
-
- if (cs.arp.arp.arhln != 6) {
- xtables_error(PARAMETER_PROBLEM,
- "Only harware address length of"
- " 6 is supported currently.");
- }
-
- break;
-
- case 8: /* was never supported, not even in arptables-legacy */
- xtables_error(PARAMETER_PROBLEM, "not supported");
- case 4:/* opcode */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_OPCODE, &cs.arp.arp.invflags,
- invert);
- if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpop,
- &cs.arp.arp.arpop_mask, 10)) {
- int i;
-
- for (i = 0; i < NUMOPCODES; i++)
- if (!strcasecmp(arp_opcodes[i], optarg))
- break;
- if (i == NUMOPCODES)
- xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode");
- cs.arp.arp.arpop = htons(i+1);
- }
- break;
-
- case 5:/* h-type */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_H_TYPE, &cs.arp.arp.invflags,
- invert);
- if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arhrd,
- &cs.arp.arp.arhrd_mask, 16)) {
- if (strcasecmp(argv[optind-1], "Ethernet"))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type");
- cs.arp.arp.arhrd = htons(1);
- }
- break;
-
- case 6:/* proto-type */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_P_TYPE, &cs.arp.arp.invflags,
- invert);
- if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpro,
- &cs.arp.arp.arpro_mask, 0)) {
- if (strcasecmp(argv[optind-1], "ipv4"))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type");
- cs.arp.arp.arpro = htons(0x800);
- }
- break;
-
- case 'j':
- set_option(&options, OPT_JUMP, &cs.arp.arp.invflags,
- invert);
- command_jump(&cs, optarg);
- break;
-
- case 'i':
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_VIANAMEIN, &cs.arp.arp.invflags,
- invert);
- xtables_parse_interface(argv[optind-1],
- cs.arp.arp.iniface,
- cs.arp.arp.iniface_mask);
- break;
-
- case 'o':
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_VIANAMEOUT, &cs.arp.arp.invflags,
- invert);
- xtables_parse_interface(argv[optind-1],
- cs.arp.arp.outiface,
- cs.arp.arp.outiface_mask);
- break;
-
- case 'v':
- if (!verbose)
- set_option(&options, OPT_VERBOSE,
- &cs.arp.arp.invflags, invert);
- verbose++;
- break;
-
- case 'm': /* ignored by arptables-legacy */
- break;
- case 'n':
- set_option(&options, OPT_NUMERIC, &cs.arp.arp.invflags,
- invert);
- break;
-
- case 't':
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "unexpected ! flag before --table");
- /* ignore this option.
- * arptables-legacy parses it, but libarptc doesn't use it.
- * arptables only has a 'filter' table anyway.
- */
- break;
-
- case 'V':
- if (invert)
- printf("Not %s ;-)\n", arptables_globals.program_version);
- else
- printf("%s v%s (nf_tables)\n",
- arptables_globals.program_name,
- arptables_globals.program_version);
- exit(0);
-
- case '0':
- set_option(&options, OPT_LINENUMBERS, &cs.arp.arp.invflags,
- invert);
- break;
-
- case 'M':
- //modprobe = optarg;
- break;
-
- case 'c':
-
- set_option(&options, OPT_COUNTERS, &cs.arp.arp.invflags,
- invert);
- pcnt = optarg;
- if (xs_has_arg(argc, argv))
- bcnt = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires packet and byte counter",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(pcnt, "%llu", &cs.arp.counters.pcnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c packet counter not numeric",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(bcnt, "%llu", &cs.arp.counters.bcnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c byte counter not numeric",
- opt2char(OPT_COUNTERS));
-
- break;
-
-
- case 1: /* non option */
- if (optarg[0] == '!' && optarg[1] == '\0') {
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- invert = true;
- optarg[0] = '\0';
- continue;
- }
- printf("Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (cs.target) {
- xtables_option_tpcall(c, argv,
- invert, cs.target, &cs.arp);
- }
- break;
- }
- invert = false;
- }
-
- if (cs.target)
- xtables_option_tfcall(cs.target);
-
- if (optind < argc)
- xtables_error(PARAMETER_PROBLEM,
- "unknown arguments found on commandline");
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
- if (!(options & OPT_DESTINATION))
- dhostnetworkmask = "0.0.0.0/0";
- if (!(options & OPT_SOURCE))
- shostnetworkmask = "0.0.0.0/0";
- }
-
- if (shostnetworkmask)
- xtables_ipparse_multiple(shostnetworkmask, &saddrs,
- &smasks, &nsaddrs);
-
- if (dhostnetworkmask)
- xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
- &dmasks, &ndaddrs);
-
- if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
- " source or destination IP addresses");
-
- if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
- xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
- "specify a unique address");
-
- if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %i chars)",
- chain, ARPT_FUNCTION_MAXNAMELEN);
-
- if (command == CMD_APPEND
- || command == CMD_DELETE
- || command == CMD_INSERT
- || command == CMD_REPLACE) {
- if (strcmp(chain, "PREROUTING") == 0
- || strcmp(chain, "INPUT") == 0) {
- /* -o not valid with incoming packets. */
- if (options & OPT_VIANAMEOUT)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEOUT),
- chain);
- }
-
- if (strcmp(chain, "POSTROUTING") == 0
- || strcmp(chain, "OUTPUT") == 0) {
- /* -i not valid with outgoing packets */
- if (options & OPT_VIANAMEIN)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEIN),
- chain);
- }
- }
-
- switch (command) {
- case CMD_APPEND:
- ret = append_entry(h, chain, *table, &cs, 0,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- options&OPT_VERBOSE, true);
- break;
- case CMD_DELETE:
- ret = delete_entry(chain, *table, &cs,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- options&OPT_VERBOSE, h);
- break;
- case CMD_DELETE_NUM:
- ret = nft_cmd_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
- break;
- case CMD_REPLACE:
- ret = replace_entry(chain, *table, &cs, rulenum - 1,
- saddrs, smasks, daddrs, dmasks,
- options&OPT_VERBOSE, h);
- break;
- case CMD_INSERT:
- ret = append_entry(h, chain, *table, &cs, rulenum - 1,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- options&OPT_VERBOSE, false);
- break;
- case CMD_LIST:
- ret = list_entries(h, chain, *table,
- rulenum,
- options&OPT_VERBOSE,
- options&OPT_NUMERIC,
- /*options&OPT_EXPANDED*/0,
- options&OPT_LINENUMBERS);
- break;
- case CMD_FLUSH:
- ret = nft_cmd_rule_flush(h, chain, *table, options & OPT_VERBOSE);
- break;
- case CMD_ZERO:
- ret = nft_cmd_chain_zero_counters(h, chain, *table,
- options & OPT_VERBOSE);
- break;
- case CMD_LIST|CMD_ZERO:
- ret = list_entries(h, chain, *table, rulenum,
- options&OPT_VERBOSE,
- options&OPT_NUMERIC,
- /*options&OPT_EXPANDED*/0,
- options&OPT_LINENUMBERS);
- if (ret)
- ret = nft_cmd_chain_zero_counters(h, chain, *table,
- options & OPT_VERBOSE);
- break;
- case CMD_NEW_CHAIN:
- ret = nft_cmd_chain_user_add(h, chain, *table);
- break;
- case CMD_DELETE_CHAIN:
- ret = nft_cmd_chain_del(h, chain, *table,
- options & OPT_VERBOSE);
- break;
- case CMD_RENAME_CHAIN:
- ret = nft_cmd_chain_user_rename(h, chain, *table, newname);
- break;
- case CMD_SET_POLICY:
- ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
- if (ret < 0)
- xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
- policy);
- break;
- case CMD_NONE:
- break;
- default:
- /* We should never reach this... */
- exit_tryhelp(2);
- }
-
- free(saddrs);
- free(smasks);
- free(daddrs);
- free(dmasks);
-
- nft_clear_iptables_command_state(&cs);
- xtables_free_opts(1);
-
-/* if (verbose > 1)
- dump_entries(*handle);*/
-
- return ret;
-}
diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c
index 0539a829..86177024 100644
--- a/iptables/xtables-eb-translate.c
+++ b/iptables/xtables-eb-translate.c
@@ -87,7 +87,6 @@ static int parse_rule_number(const char *rule)
/* Default command line options. Do not mess around with the already
* assigned numbers unless you know what you are doing */
extern struct option ebt_original_options[];
-extern struct xtables_globals ebtables_globals;
#define opts ebtables_globals.opts
#define prog_name ebtables_globals.program_name
#define prog_vers ebtables_globals.program_version
@@ -153,7 +152,7 @@ static void print_ebt_cmd(int argc, char *argv[])
printf("\n");
}
-static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct nft_xt_cmd_parse *p,
+static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct xt_cmd_parse *p,
const struct iptables_command_state *cs, bool append)
{
struct xt_xlate *xl = xt_xlate_alloc(10240);
@@ -192,7 +191,7 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char
int selected_chain = -1;
struct xtables_rule_match *xtrm_i;
struct ebt_match *match;
- struct nft_xt_cmd_parse p = {
+ struct xt_cmd_parse p = {
.table = *table,
};
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 23023ce1..060e06c5 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -216,12 +216,11 @@ struct option ebt_original_options[] =
{ 0 }
};
-extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
struct xtables_globals ebtables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (nf_tables)",
+ .optstring = OPTSTRING_COMMON "h",
.orig_opts = ebt_original_options,
- .exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
};
@@ -672,7 +671,7 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
init_extensionsb();
#endif
- if (nft_init(h, NFPROTO_BRIDGE, xtables_bridge) < 0)
+ if (nft_init(h, NFPROTO_BRIDGE) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
@@ -732,8 +731,8 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
opterr = false;
/* Getopt saves the day */
- while ((c = getopt_long(argc, argv,
- "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, xt_params->optstring,
+ opts, NULL)) != -1) {
cs.c = c;
switch (c) {
@@ -859,7 +858,7 @@ print_zero:
if (OPT_COMMANDS)
xtables_error(PARAMETER_PROBLEM,
"Multiple commands are not allowed");
- printf("%s %s (nf_tables)\n", prog_name, prog_vers);
+ printf("%s %s\n", prog_name, prog_vers);
exit(0);
case 'h': /* Help */
if (OPT_COMMANDS)
@@ -895,8 +894,8 @@ print_zero:
ebt_check_option2(&flags, OPT_TABLE);
if (restore && table_set)
xtables_error(PARAMETER_PROBLEM,
- "The -t option (seen in line %u) cannot be used in %s.\n",
- line, xt_params->program_name);
+ "The -t option cannot be used in %s.\n",
+ xt_params->program_name);
if (!nft_table_builtin_find(h, optarg))
xtables_error(VERSION_PROBLEM,
"table '%s' does not exist",
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 21d4bec0..73dc80c2 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -631,7 +631,7 @@ int xtables_monitor_main(int argc, char *argv[])
init_extensions6();
#endif
- if (nft_init(&h, AF_INET, xtables_ipv4)) {
+ if (nft_init(&h, AF_INET)) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h
index 0fedb430..94c24d5a 100644
--- a/iptables/xtables-multi.h
+++ b/iptables/xtables-multi.h
@@ -22,6 +22,9 @@ extern int xtables_eb_restore_main(int, char **);
extern int xtables_eb_save_main(int, char **);
extern int xtables_config_main(int, char **);
extern int xtables_monitor_main(int, char **);
+
+extern struct xtables_globals arptables_globals;
+extern struct xtables_globals ebtables_globals;
#endif
#endif /* _XTABLES_MULTI_H */
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 72832103..8ca2abff 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -281,7 +281,6 @@ void xtables_restore_parse(struct nft_handle *h,
static int
xtables_restore_main(int family, const char *progname, int argc, char *argv[])
{
- const struct builtin_table *tables;
struct nft_xt_restore_parse p = {
.commit = true,
.cb = &restore_cb,
@@ -313,7 +312,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
verbose = 1;
break;
case 'V':
- printf("%s v%s (nf_tables)\n", prog_name, prog_vers);
+ printf("%s v%s\n", prog_name, prog_vers);
exit(0);
case 't':
p.testing = 1;
@@ -360,7 +359,6 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
switch (family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6: /* fallthough, same table */
- tables = xtables_ipv4;
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
@@ -368,17 +366,14 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
#endif
break;
case NFPROTO_ARP:
- tables = xtables_arp;
- break;
case NFPROTO_BRIDGE:
- tables = xtables_bridge;
break;
default:
fprintf(stderr, "Unknown family %d\n", family);
return 1;
}
- if (nft_init(&h, family, tables) < 0) {
+ if (nft_init(&h, family) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -456,7 +451,7 @@ int xtables_eb_restore_main(int argc, char *argv[])
static const struct nft_xt_restore_cb arp_restore_cb = {
.commit = nft_commit,
.table_flush = nft_cmd_table_flush,
- .do_command = do_commandarp,
+ .do_command = do_commandx,
.chain_set = nft_cmd_chain_set,
.chain_restore = nft_cmd_chain_restore,
};
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index f794e3ff..03d2b980 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -131,7 +131,6 @@ static int
xtables_save_main(int family, int argc, char *argv[],
const char *optstring, const struct option *longopts)
{
- const struct builtin_table *tables;
const char *tablename = NULL;
struct do_output_data d = {
.format = FMT_NOCOUNTS,
@@ -185,7 +184,7 @@ xtables_save_main(int family, int argc, char *argv[],
dump = true;
break;
case 'V':
- printf("%s v%s (nf_tables)\n", prog_name, prog_vers);
+ printf("%s v%s\n", prog_name, prog_vers);
exit(0);
default:
fprintf(stderr,
@@ -208,11 +207,9 @@ xtables_save_main(int family, int argc, char *argv[],
init_extensions4();
init_extensions6();
#endif
- tables = xtables_ipv4;
d.commit = true;
break;
case NFPROTO_ARP:
- tables = xtables_arp;
break;
case NFPROTO_BRIDGE: {
const char *ctr = getenv("EBTABLES_SAVE_COUNTER");
@@ -223,7 +220,6 @@ xtables_save_main(int family, int argc, char *argv[],
d.format &= ~FMT_NOCOUNTS;
d.format |= FMT_C_COUNTS | FMT_EBT_SAVE;
}
- tables = xtables_bridge;
break;
}
default:
@@ -231,7 +227,7 @@ xtables_save_main(int family, int argc, char *argv[],
return 1;
}
- if (nft_init(&h, family, tables) < 0) {
+ if (nft_init(&h, family) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index 1a6b7cf7..5482a856 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -39,32 +39,51 @@
#include "xtables-multi.h"
#include "nft.h"
+static struct xtables_globals *xtables_globals_lookup(int family)
+{
+ switch (family) {
+ case AF_INET:
+ case AF_INET6:
+ return &xtables_globals;
+ case NFPROTO_ARP:
+ return &arptables_globals;
+ case NFPROTO_BRIDGE:
+ return &ebtables_globals;
+ default:
+ xtables_error(OTHER_PROBLEM, "Unknown family value %d", family);
+ }
+}
+
static int
xtables_main(int family, const char *progname, int argc, char *argv[])
{
- int ret;
char *table = "filter";
struct nft_handle h;
+ int ret;
- xtables_globals.program_name = progname;
- ret = xtables_init_all(&xtables_globals, family);
+ ret = xtables_init_all(xtables_globals_lookup(family), family);
if (ret < 0) {
- fprintf(stderr, "%s/%s Failed to initialize xtables\n",
- xtables_globals.program_name,
- xtables_globals.program_version);
- exit(1);
+ fprintf(stderr, "%s: Failed to initialize xtables\n", progname);
+ exit(1);
}
+ xt_params->program_name = progname;
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
- init_extensions4();
- init_extensions6();
+ switch (family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ init_extensions();
+ init_extensions4();
+ init_extensions6();
+ break;
+ case NFPROTO_ARP:
+ init_extensionsa();
+ break;
+ }
#endif
- if (nft_init(&h, family, xtables_ipv4) < 0) {
- fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
- xtables_globals.program_name,
- xtables_globals.program_version,
- strerror(errno));
+ if (nft_init(&h, family) < 0) {
+ fprintf(stderr, "%s: Failed to initialize nft: %s\n",
+ xt_params->program_name, strerror(errno));
exit(EXIT_FAILURE);
}
@@ -96,3 +115,8 @@ int xtables_ip6_main(int argc, char *argv[])
{
return xtables_main(NFPROTO_IPV6, "ip6tables", argc, argv);
}
+
+int xtables_arp_main(int argc, char *argv[])
+{
+ return xtables_main(NFPROTO_ARP, "arptables", argc, argv);
+}
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index 2a00a850..6a1cdac1 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -150,7 +150,7 @@ const char *family2str[] = {
};
static int nft_rule_xlate_add(struct nft_handle *h,
- const struct nft_xt_cmd_parse *p,
+ const struct xt_cmd_parse *p,
const struct iptables_command_state *cs,
bool append)
{
@@ -186,11 +186,11 @@ err_out:
return ret;
}
-static int xlate(struct nft_handle *h, struct nft_xt_cmd_parse *p,
+static int xlate(struct nft_handle *h, struct 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 xt_cmd_parse *p,
const struct iptables_command_state *cs,
bool append))
{
@@ -248,17 +248,26 @@ 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 = {
+ struct xt_cmd_parse p = {
.table = *table,
.restore = restore,
+ .line = line,
.xlate = true,
+ .ops = &h->ops->cmd_parse,
};
- struct iptables_command_state cs;
+ struct iptables_command_state cs = {
+ .jumpto = "",
+ .argv = argv,
+ };
+
struct xtables_args args = {
.family = h->family,
};
- do_parse(h, argc, argv, &p, &cs, &args);
+ if (h->ops->init_cs)
+ h->ops->init_cs(&cs);
+
+ do_parse(argc, argv, &p, &cs, &args);
cs.restore = restore;
@@ -465,7 +474,6 @@ static int xtables_xlate_main_common(struct nft_handle *h,
int family,
const char *progname)
{
- const struct builtin_table *tables;
int ret;
xtables_globals.program_name = progname;
@@ -485,20 +493,16 @@ static int xtables_xlate_main_common(struct nft_handle *h,
init_extensions4();
init_extensions6();
#endif
- tables = xtables_ipv4;
break;
case NFPROTO_ARP:
- tables = xtables_arp;
- break;
case NFPROTO_BRIDGE:
- tables = xtables_bridge;
break;
default:
fprintf(stderr, "Unknown family %d\n", family);
return 1;
}
- if (nft_init(h, family, tables) < 0) {
+ if (nft_init(h, family) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 0a700e08..051d5c7b 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[] = {
@@ -84,133 +86,15 @@ static struct option original_opts[] = {
{NULL},
};
-void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
-
struct xtables_globals xtables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (nf_tables)",
+ .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 = xtables_printhelp,
};
-#define opts xt_params->opts
-#define prog_name xt_params->program_name
-#define prog_vers xt_params->program_version
-
-static void __attribute__((noreturn))
-exit_tryhelp(int status)
-{
- if (line != -1)
- fprintf(stderr, "Error occurred at line: %d\n", line);
- fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
- prog_name, prog_name);
- xtables_free_opts(1);
- exit(status);
-}
-
-static void
-printhelp(const struct xtables_rule_match *matches)
-{
- printf("%s v%s\n\n"
-"Usage: %s -[ACD] chain rule-specification [options]\n"
-" %s -I chain [rulenum] rule-specification [options]\n"
-" %s -R chain rulenum rule-specification [options]\n"
-" %s -D chain rulenum [options]\n"
-" %s -[LS] [chain [rulenum]] [options]\n"
-" %s -[FZ] [chain] [options]\n"
-" %s -[NX] chain\n"
-" %s -E old-chain-name new-chain-name\n"
-" %s -P chain target [options]\n"
-" %s -h (print this help information)\n\n",
- prog_name, prog_vers, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name);
-
- printf(
-"Commands:\n"
-"Either long or short options are allowed.\n"
-" --append -A chain Append to chain\n"
-" --check -C chain Check for the existence of a rule\n"
-" --delete -D chain Delete matching rule from chain\n"
-" --delete -D chain rulenum\n"
-" Delete rule rulenum (1 = first) from chain\n"
-" --insert -I chain [rulenum]\n"
-" Insert in chain as rulenum (default 1=first)\n"
-" --replace -R chain rulenum\n"
-" Replace rule rulenum (1 = first) in chain\n"
-" --list -L [chain [rulenum]]\n"
-" List the rules in a chain or all chains\n"
-" --list-rules -S [chain [rulenum]]\n"
-" Print the rules in a chain or all chains\n"
-" --flush -F [chain] Delete all rules in chain or all chains\n"
-" --zero -Z [chain [rulenum]]\n"
-" Zero counters in chain or all chains\n"
-" --new -N chain Create a new user-defined chain\n"
-" --delete-chain\n"
-" -X [chain] Delete a user-defined chain\n"
-" --policy -P chain target\n"
-" Change policy on chain to target\n"
-" --rename-chain\n"
-" -E old-chain new-chain\n"
-" Change chain name, (moving any references)\n"
-
-"Options:\n"
-" --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n"
-" --ipv6 -6 Error (line is ignored by iptables-restore)\n"
-"[!] --proto -p proto protocol: by number or name, eg. `tcp'\n"
-"[!] --source -s address[/mask][...]\n"
-" source specification\n"
-"[!] --destination -d address[/mask][...]\n"
-" destination specification\n"
-"[!] --in-interface -i input name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --jump -j target\n"
-" target for rule (may load target extension)\n"
-#ifdef IPT_F_GOTO
-" --goto -g chain\n"
-" jump to chain with no return\n"
-#endif
-" --match -m match\n"
-" extended match (may load extension)\n"
-" --numeric -n numeric output of addresses and ports\n"
-"[!] --out-interface -o output name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --table -t table table to manipulate (default: `filter')\n"
-" --verbose -v verbose mode\n"
-" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
-" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n"
-" default is 1 second\n"
-" --line-numbers print line numbers when listing\n"
-" --exact -x expand numbers (display exact values)\n"
-"[!] --fragment -f match second or further fragments only\n"
-" --modprobe=<command> try to insert modules using this command\n"
-" --set-counters PKTS BYTES set the counter during insert/append\n"
-"[!] --version -V print package version.\n");
-
- print_extension_helps(xtables_targets, matches);
-}
-
-void
-xtables_exit_error(enum xtables_exittype status, const char *msg, ...)
-{
- va_list args;
-
- va_start(args, msg);
- fprintf(stderr, "%s v%s (nf_tables): ", prog_name, prog_vers);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, "\n");
- if (status == PARAMETER_PROBLEM)
- exit_tryhelp(status);
- if (status == VERSION_PROBLEM)
- fprintf(stderr,
- "Perhaps iptables or your kernel needs to be upgraded.\n");
- /* On error paths, make sure that we don't leak memory */
- xtables_free_opts(1);
- exit(status);
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
@@ -223,168 +107,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,535 +141,60 @@ list_rules(struct nft_handle *h, const char *chain, const char *table,
return nft_cmd_rule_list_save(h, chain, table, rulenum, counters);
}
-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)
-{
- struct xtables_match *m;
- struct xtables_rule_match *matchp;
- bool wait_interval_set = false;
- struct timeval wait_interval;
- struct xtables_target *t;
- bool table_set = false;
- 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;
-
- /* clear mflags in case do_command4 gets called a second time
- * (we clear the global list of all matches for security)*/
- for (m = xtables_matches; m; m = m->next)
- m->mflags = 0;
-
- for (t = xtables_targets; t; t = t->next) {
- t->tflags = 0;
- t->used = 0;
- }
-
- /* Suppress error messages: we may add new options if we
- demand-load a protocol. */
- 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",
- opts, NULL)) != -1) {
- switch (cs->c) {
- /*
- * Command selection
- */
- case 'A':
- add_command(&p->command, CMD_APPEND, CMD_NONE, invert);
- p->chain = optarg;
- break;
-
- case 'C':
- add_command(&p->command, CMD_CHECK, CMD_NONE, invert);
- p->chain = optarg;
- break;
-
- case 'D':
- add_command(&p->command, CMD_DELETE, CMD_NONE, invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv)) {
- p->rulenum = parse_rulenumber(argv[optind++]);
- p->command = CMD_DELETE_NUM;
- }
- break;
-
- case 'R':
- add_command(&p->command, CMD_REPLACE, CMD_NONE, invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv))
- p->rulenum = parse_rulenumber(argv[optind++]);
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a rule number",
- cmd2char(CMD_REPLACE));
- break;
-
- case 'I':
- add_command(&p->command, CMD_INSERT, CMD_NONE, invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv))
- p->rulenum = parse_rulenumber(argv[optind++]);
- else
- p->rulenum = 1;
- break;
-
- case 'L':
- add_command(&p->command, CMD_LIST,
- CMD_ZERO | CMD_ZERO_NUM, invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- p->rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'S':
- add_command(&p->command, CMD_LIST_RULES,
- CMD_ZERO|CMD_ZERO_NUM, invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- p->rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'F':
- add_command(&p->command, CMD_FLUSH, CMD_NONE, invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- break;
-
- case 'Z':
- add_command(&p->command, CMD_ZERO,
- CMD_LIST|CMD_LIST_RULES, invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- if (xs_has_arg(argc, argv)) {
- p->rulenum = parse_rulenumber(argv[optind++]);
- p->command = CMD_ZERO_NUM;
- }
- break;
-
- case 'N':
- if (optarg && (*optarg == '-' || *optarg == '!'))
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `%c'\n", *optarg);
- if (xtables_find_target(optarg, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
- add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
- invert);
- p->chain = optarg;
- break;
-
- case 'X':
- add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
- invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- break;
-
- case 'E':
- add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
- invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv))
- p->newname = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires old-chain-name and "
- "new-chain-name",
- cmd2char(CMD_RENAME_CHAIN));
- break;
-
- case 'P':
- add_command(&p->command, CMD_SET_POLICY, CMD_NONE,
- invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv))
- p->policy = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a chain and a policy",
- cmd2char(CMD_SET_POLICY));
- break;
-
- case 'h':
- if (!optarg)
- optarg = argv[optind];
-
- /* iptables -p icmp -h */
- if (!cs->matches && cs->protocol)
- xtables_find_match(cs->protocol,
- XTF_TRY_LOAD, &cs->matches);
-
- printhelp(cs->matches);
- p->command = CMD_NONE;
- return;
-
- /*
- * Option selection
- */
- case 'p':
- set_option(&cs->options, OPT_PROTOCOL,
- &args->invflags, invert);
-
- /* Canonicalize into lower case */
- for (cs->protocol = optarg; *cs->protocol; cs->protocol++)
- *cs->protocol = tolower(*cs->protocol);
-
- cs->protocol = optarg;
- args->proto = xtables_parse_protocol(cs->protocol);
-
- if (args->proto == 0 &&
- (args->invflags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM,
- "rule would never match protocol");
-
- /* This needs to happen here to parse extensions */
- h->ops->proto_parse(cs, args);
- break;
-
- case 's':
- set_option(&cs->options, OPT_SOURCE,
- &args->invflags, invert);
- args->shostnetworkmask = optarg;
- break;
-
- case 'd':
- set_option(&cs->options, OPT_DESTINATION,
- &args->invflags, invert);
- args->dhostnetworkmask = optarg;
- break;
-
-#ifdef IPT_F_GOTO
- case 'g':
- set_option(&cs->options, OPT_JUMP, &args->invflags,
- invert);
- args->goto_set = true;
- cs->jumpto = xt_parse_target(optarg);
- break;
-#endif
-
- case 'j':
- set_option(&cs->options, OPT_JUMP, &args->invflags,
- invert);
- command_jump(cs, optarg);
- break;
-
-
- case 'i':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs->options, OPT_VIANAMEIN,
- &args->invflags, invert);
- xtables_parse_interface(optarg,
- args->iniface,
- args->iniface_mask);
- break;
-
- case 'o':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs->options, OPT_VIANAMEOUT,
- &args->invflags, invert);
- xtables_parse_interface(optarg,
- args->outiface,
- args->outiface_mask);
- break;
-
- case 'f':
- if (args->family == AF_INET6) {
- xtables_error(PARAMETER_PROBLEM,
- "`-f' is not supported in IPv6, "
- "use -m frag instead");
- }
- set_option(&cs->options, OPT_FRAGMENT, &args->invflags,
- invert);
- args->flags |= IPT_F_FRAG;
- break;
-
- case 'v':
- if (!p->verbose)
- set_option(&cs->options, OPT_VERBOSE,
- &args->invflags, invert);
- p->verbose++;
- break;
-
- case 'm':
- command_match(cs, invert);
- break;
-
- case 'n':
- set_option(&cs->options, OPT_NUMERIC, &args->invflags,
- invert);
- break;
-
- case 't':
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "unexpected ! flag before --table");
- if (p->restore && table_set)
- xtables_error(PARAMETER_PROBLEM,
- "The -t option (seen in line %u) cannot be used in %s.\n",
- line, xt_params->program_name);
- if (!nft_table_builtin_find(h, optarg))
- xtables_error(VERSION_PROBLEM,
- "table '%s' does not exist",
- optarg);
- p->table = optarg;
- table_set = true;
- break;
-
- case 'x':
- set_option(&cs->options, OPT_EXPANDED, &args->invflags,
- invert);
- break;
-
- case 'V':
- if (invert)
- printf("Not %s ;-)\n", prog_vers);
- else
- printf("%s v%s (nf_tables)\n",
- prog_name, prog_vers);
- exit(0);
-
- case 'w':
- if (p->restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-w' from "
- "iptables-restore");
- }
-
- wait = parse_wait_time(argc, argv);
- break;
-
- case 'W':
- if (p->restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-W' from "
- "iptables-restore");
- }
-
- parse_wait_interval(argc, argv, &wait_interval);
- wait_interval_set = true;
- break;
-
- case '0':
- set_option(&cs->options, OPT_LINENUMBERS,
- &args->invflags, invert);
- break;
-
- case 'M':
- xtables_modprobe_program = optarg;
- break;
-
- case 'c':
- set_option(&cs->options, OPT_COUNTERS, &args->invflags,
- invert);
- args->pcnt = optarg;
- args->bcnt = strchr(args->pcnt + 1, ',');
- if (args->bcnt)
- args->bcnt++;
- if (!args->bcnt && xs_has_arg(argc, argv))
- args->bcnt = argv[optind++];
- if (!args->bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires packet and byte counter",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c packet counter not numeric",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c byte counter not numeric",
- opt2char(OPT_COUNTERS));
- break;
-
- case '4':
- if (args->family == AF_INET)
- break;
-
- if (p->restore && args->family == AF_INET6)
- return;
-
- exit_tryhelp(2);
-
- case '6':
- if (args->family == AF_INET6)
- break;
-
- if (p->restore && args->family == AF_INET)
- return;
-
- exit_tryhelp(2);
-
- case 1: /* non option */
- if (optarg[0] == '!' && optarg[1] == '\0') {
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- invert = true;
- optarg[0] = '\0';
- continue;
- }
- fprintf(stderr, "Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (command_default(cs, &xtables_globals, invert))
- /* cf. ip6tables.c */
- continue;
- break;
- }
- invert = false;
- }
-
- if (strcmp(p->table, "nat") == 0 &&
- ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
- (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
- xtables_error(PARAMETER_PROBLEM,
- "\nThe \"nat\" table is not intended for filtering, "
- "the use of DROP is therefore inhibited.\n\n");
-
- if (!wait && wait_interval_set)
- xtables_error(PARAMETER_PROBLEM,
- "--wait-interval only makes sense with --wait\n");
-
- for (matchp = cs->matches; matchp; matchp = matchp->next)
- xtables_option_mfcall(matchp->match);
- if (cs->target != NULL)
- xtables_option_tfcall(cs->target);
-
- /* Fix me: must put inverse options checking here --MN */
-
- if (optind < argc)
- xtables_error(PARAMETER_PROBLEM,
- "unknown arguments found on commandline");
- if (!p->command)
- xtables_error(PARAMETER_PROBLEM, "no command specified");
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- /* Set only if required, needed by xtables-restore */
- if (h->family == AF_UNSPEC)
- h->family = args->family;
-
- h->ops->post_parse(p->command, cs, args);
-
- if (p->command == CMD_REPLACE &&
- (args->s.naddrs != 1 || args->d.naddrs != 1))
- xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
- "specify a unique address");
-
- generic_opt_check(p->command, cs->options);
-
- if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %u chars)",
- p->chain, XT_EXTENSION_MAXNAMELEN);
-
- if (p->command == CMD_APPEND ||
- p->command == CMD_DELETE ||
- p->command == CMD_DELETE_NUM ||
- p->command == CMD_CHECK ||
- p->command == CMD_INSERT ||
- p->command == CMD_REPLACE) {
- if (strcmp(p->chain, "PREROUTING") == 0
- || strcmp(p->chain, "INPUT") == 0) {
- /* -o not valid with incoming packets. */
- if (cs->options & OPT_VIANAMEOUT)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEOUT),
- p->chain);
- }
-
- if (strcmp(p->chain, "POSTROUTING") == 0
- || strcmp(p->chain, "OUTPUT") == 0) {
- /* -i not valid with outgoing packets */
- if (cs->options & OPT_VIANAMEIN)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEIN),
- p->chain);
- }
- }
-}
-
int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
bool restore)
{
int ret = 1;
- struct nft_xt_cmd_parse p = {
+ 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 iptables_command_state cs;
struct xtables_args args = {
.family = h->family,
};
- do_parse(h, argc, argv, &p, &cs, &args);
+ 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 = 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,
@@ -1012,24 +259,17 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
break;
default:
/* We should never reach this... */
- exit_tryhelp(2);
+ exit_tryhelp(2, line);
}
*table = p.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;
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index d670175d..50fd6a44 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -90,6 +90,18 @@ void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
vfprintf(stderr, msg, args);
va_end(args);
fprintf(stderr, "\n");
+ if (status == PARAMETER_PROBLEM) {
+ if (line != -1)
+ fprintf(stderr, "Error occurred at line: %d\n", line);
+ fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
+ xt_params->program_name, xt_params->program_name);
+ } else if (status == VERSION_PROBLEM) {
+ fprintf(stderr,
+ "Perhaps %s or your kernel needs to be upgraded.\n",
+ xt_params->program_name);
+ }
+ /* On error paths, make sure that we don't leak memory */
+ xtables_free_opts(1);
exit(status);
}
diff --git a/xlate-test.py b/xlate-test.py
index 4a56e798..d78e8648 100755
--- a/xlate-test.py
+++ b/xlate-test.py
@@ -80,15 +80,15 @@ def run_test(name, payload):
def load_test_files():
test_files = total_tests = total_passed = total_error = total_failed = 0
- for test in sorted(os.listdir("extensions")):
- if test.endswith(".txlate"):
- with open("extensions/" + test, "r") as payload:
- tests, passed, failed, errors = run_test(test, payload)
- test_files += 1
- total_tests += tests
- total_passed += passed
- total_failed += failed
- total_error += errors
+ tests = sorted(os.listdir("extensions"))
+ for test in ['extensions/' + f for f in tests if f.endswith(".txlate")]:
+ with open(test, "r") as payload:
+ tests, passed, failed, errors = run_test(test, payload)
+ test_files += 1
+ total_tests += tests
+ total_passed += passed
+ total_failed += failed
+ total_error += errors
return (test_files, total_tests, total_passed, total_failed, total_error)