aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2023-10-23 19:29:30 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-10-23 19:29:30 +0000
commit4463bce0c7d01abf73a92bb6e2bedf358794a2e5 (patch)
treebf90895fed6aa9e1cfbc2958546392e03242a933
parentdda1fee032d9d1d1bae1753249f2e624e85e2b39 (diff)
parent20799e993e23b7650354ad61fdcdf9727e065270 (diff)
downloadiptables-4463bce0c7d01abf73a92bb6e2bedf358794a2e5.tar.gz
Merge changes If212f600,Ibbedf6e7,I7f10813f,I370d68c1,I38949223 into main am: 3dd590f333 am: 20799e993e
Original change: https://android-review.googlesource.com/c/platform/external/iptables/+/2798950 Change-Id: Ib60a0cf211acedce80c944f77f4a76a3c22bd7ef Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--METADATA4
-rw-r--r--config.h6
-rw-r--r--configure.ac9
-rw-r--r--extensions/Android.bp2
-rw-r--r--extensions/GNUmakefile.in4
-rw-r--r--extensions/generic.txlate48
-rw-r--r--extensions/libarpt_mangle.c1
-rw-r--r--extensions/libebt_among.c6
-rw-r--r--extensions/libebt_ip.c3
-rw-r--r--extensions/libebt_ip6.c78
-rw-r--r--extensions/libebt_stp.c3
-rw-r--r--extensions/libip6t_DNAT.c411
-rw-r--r--extensions/libip6t_DNAT.t4
-rw-r--r--extensions/libip6t_DNAT.txlate11
-rw-r--r--extensions/libip6t_MASQUERADE.c2
-rw-r--r--extensions/libip6t_REDIRECT.c170
-rw-r--r--extensions/libip6t_REDIRECT.t6
-rw-r--r--extensions/libip6t_REDIRECT.txlate5
-rw-r--r--extensions/libip6t_SNAT.c13
-rw-r--r--extensions/libip6t_dst.c8
-rw-r--r--extensions/libip6t_hbh.c7
-rw-r--r--extensions/libip6t_ipv6header.c2
-rw-r--r--extensions/libip6t_mh.c2
-rw-r--r--extensions/libip6t_rt.c7
-rw-r--r--extensions/libipt_CLUSTERIP.t4
-rw-r--r--extensions/libipt_DNAT.c555
-rw-r--r--extensions/libipt_DNAT.t4
-rw-r--r--extensions/libipt_DNAT.txlate14
-rw-r--r--extensions/libipt_REDIRECT.c174
-rw-r--r--extensions/libipt_REDIRECT.t6
-rw-r--r--extensions/libipt_REDIRECT.txlate5
-rw-r--r--extensions/libipt_SNAT.c165
-rw-r--r--extensions/libxt_DNAT.c646
-rw-r--r--extensions/libxt_DNAT.man17
-rw-r--r--extensions/libxt_DNAT.txlate35
-rw-r--r--extensions/libxt_LOG.man3
-rw-r--r--extensions/libxt_MARK.c3
-rw-r--r--extensions/libxt_MASQUERADE.man10
-rw-r--r--extensions/libxt_NFLOG.c10
-rw-r--r--extensions/libxt_NFLOG.t12
-rw-r--r--extensions/libxt_REDIRECT.man5
-rw-r--r--extensions/libxt_REDIRECT.t16
-rw-r--r--extensions/libxt_REDIRECT.txlate26
-rw-r--r--extensions/libxt_SECMARK.c90
-rw-r--r--extensions/libxt_SECMARK.t4
-rw-r--r--extensions/libxt_SNAT.man14
-rw-r--r--extensions/libxt_TCPMSS.t2
-rw-r--r--extensions/libxt_TCPMSS.txlate4
-rw-r--r--extensions/libxt_connlimit.c49
-rw-r--r--extensions/libxt_connlimit.txlate15
-rw-r--r--extensions/libxt_conntrack.c30
-rw-r--r--extensions/libxt_conntrack.txlate13
-rw-r--r--extensions/libxt_dccp.c2
-rw-r--r--extensions/libxt_devgroup.man2
-rw-r--r--extensions/libxt_hashlimit.c5
-rw-r--r--extensions/libxt_hashlimit.t6
-rw-r--r--extensions/libxt_iprange.c4
-rw-r--r--extensions/libxt_mac.c4
-rw-r--r--extensions/libxt_multiport.c44
-rw-r--r--extensions/libxt_multiport.txlate3
-rw-r--r--extensions/libxt_sctp.c105
-rw-r--r--extensions/libxt_sctp.man11
-rw-r--r--extensions/libxt_sctp.txlate16
-rw-r--r--extensions/libxt_set.h4
-rw-r--r--extensions/libxt_standard.t12
-rw-r--r--extensions/libxt_string.c2
-rw-r--r--extensions/libxt_tcp.c14
-rw-r--r--extensions/libxt_tcp.txlate6
-rw-r--r--extensions/libxt_tcpmss.c16
-rw-r--r--extensions/libxt_tcpmss.txlate11
-rw-r--r--include/libipulog/libipulog.h39
-rw-r--r--include/linux/netfilter/xt_SECMARK.h6
-rw-r--r--include/xtables.h19
-rwxr-xr-xiptables-test.py177
-rw-r--r--iptables/Makefile.am2
-rw-r--r--iptables/ebtables-nft.870
-rw-r--r--iptables/ip6tables-standalone.c3
-rw-r--r--iptables/ip6tables.c902
-rwxr-xr-xiptables/iptables-apply1
-rw-r--r--iptables/iptables-restore.8.in8
-rw-r--r--iptables/iptables-restore.c26
-rw-r--r--iptables/iptables-save.c6
-rw-r--r--iptables/iptables-standalone.c2
-rw-r--r--iptables/iptables-xml.c4
-rw-r--r--iptables/iptables.8.in26
-rw-r--r--iptables/iptables.c897
-rw-r--r--iptables/nft-arp.c453
-rw-r--r--iptables/nft-arp.h14
-rw-r--r--iptables/nft-bridge.c110
-rw-r--r--iptables/nft-cache.c143
-rw-r--r--iptables/nft-cache.h1
-rw-r--r--iptables/nft-chain.h1
-rw-r--r--iptables/nft-cmd.c38
-rw-r--r--iptables/nft-cmd.h4
-rw-r--r--iptables/nft-ipv4.c318
-rw-r--r--iptables/nft-ipv6.c290
-rw-r--r--iptables/nft-shared.c877
-rw-r--r--iptables/nft-shared.h159
-rw-r--r--iptables/nft.c606
-rw-r--r--iptables/nft.h13
-rwxr-xr-xiptables/tests/shell/run-tests.sh2
-rwxr-xr-xiptables/tests/shell/testcases/chain/0004extra-base_037
-rwxr-xr-xiptables/tests/shell/testcases/chain/0005base-delete_034
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0007-chain-policies_041
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0004-address-masks_024
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0002-parameters_03
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_09
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0002-verbose-output_011
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0004-return-codes_02
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0007-zero-counters_064
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0008-unprivileged_066
-rw-r--r--iptables/xshared.c1253
-rw-r--r--iptables/xshared.h127
-rw-r--r--iptables/xtables-arp-standalone.c65
-rw-r--r--iptables/xtables-arp.c871
-rw-r--r--iptables/xtables-eb-translate.c24
-rw-r--r--iptables/xtables-eb.c121
-rw-r--r--iptables/xtables-monitor.8.in6
-rw-r--r--iptables/xtables-monitor.c8
-rw-r--r--iptables/xtables-multi.h3
-rw-r--r--iptables/xtables-restore.c40
-rw-r--r--iptables/xtables-save.c23
-rw-r--r--iptables/xtables-standalone.c57
-rw-r--r--iptables/xtables-translate.c73
-rw-r--r--iptables/xtables.c880
-rw-r--r--libxtables/xtables.c252
-rw-r--r--libxtables/xtoptions.c15
-rwxr-xr-xxlate-test.py65
128 files changed, 5622 insertions, 6779 deletions
diff --git a/METADATA b/METADATA
index d5267994..857a0617 100644
--- a/METADATA
+++ b/METADATA
@@ -11,7 +11,7 @@ third_party {
type: GIT
value: "git://git.netfilter.org/iptables"
}
- version: "v1.8.7"
- last_upgrade_date { year: 2021 month: 3 day: 23 }
+ version: "v1.8.8"
+ last_upgrade_date { year: 2022 month: 5 day: 13 }
license_type: RESTRICTED
}
diff --git a/config.h b/config.h
index f4a827d6..1711f0d7 100644
--- a/config.h
+++ b/config.h
@@ -62,7 +62,7 @@
#define PACKAGE_NAME "iptables"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "iptables 1.8.7"
+#define PACKAGE_STRING "iptables 1.8.8"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "iptables"
@@ -71,7 +71,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.8.7"
+#define PACKAGE_VERSION "1.8.8"
/* The size of `struct ip6_hdr', as computed by sizeof. */
#define SIZEOF_STRUCT_IP6_HDR 40
@@ -80,7 +80,7 @@
#define STDC_HEADERS 1
/* Version number of package */
-#define VERSION "1.8.7"
+#define VERSION "1.8.8"
/* Location of the iptables lock file */
#define XT_LOCK_NAME "/system/etc/xtables.lock"
diff --git a/configure.ac b/configure.ac
index 6864378a..071afaf1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,9 @@
-AC_INIT([iptables], [1.8.7])
+AC_INIT([iptables], [1.8.8])
# See libtool.info "Libtool's versioning system"
-libxtables_vcurrent=16
-libxtables_vage=4
+libxtables_vcurrent=18
+libxtables_vage=6
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
@@ -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/Android.bp b/extensions/Android.bp
index 8a6b6e99..83561153 100644
--- a/extensions/Android.bp
+++ b/extensions/Android.bp
@@ -20,8 +20,6 @@ cc_defaults {
"-Wno-format",
"-Wno-missing-field-initializers",
- // libxt_recent.c:202:11: error: address of array 'info->name' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion]
- "-Wno-pointer-bool-conversion",
"-Wno-tautological-pointer-compare",
],
}
diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in
index 956ccb38..6dad4e02 100644
--- a/extensions/GNUmakefile.in
+++ b/extensions/GNUmakefile.in
@@ -42,7 +42,7 @@ endif
pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c)))
@ENABLE_NFTABLES_TRUE@ pfb_build_mod := $(patsubst ${srcdir}/libebt_%.c,%,$(sort $(wildcard ${srcdir}/libebt_*.c)))
@ENABLE_NFTABLES_TRUE@ pfa_build_mod := $(patsubst ${srcdir}/libarpt_%.c,%,$(sort $(wildcard ${srcdir}/libarpt_*.c)))
-pfx_symlinks := NOTRACK state
+pfx_symlinks := NOTRACK state REDIRECT
@ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(sort $(wildcard ${srcdir}/libipt_*.c)))
@ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(sort $(wildcard ${srcdir}/libip6t_*.c)))
pfx_build_mod := $(filter-out @blacklist_modules@ @blacklist_x_modules@,${pfx_build_mod})
@@ -130,6 +130,8 @@ libxt_NOTRACK.so: libxt_CT.so
ln -fs $< $@
libxt_state.so: libxt_conntrack.so
ln -fs $< $@
+libxt_REDIRECT.so: libxt_DNAT.so
+ ln -fs $< $@
# Need the LIBADDs in iptables/Makefile.am too for libxtables_la_LIBADD
xt_RATEEST_LIBADD = -lm
diff --git a/extensions/generic.txlate b/extensions/generic.txlate
index 0e256c37..9ae9a5b5 100644
--- a/extensions/generic.txlate
+++ b/extensions/generic.txlate
@@ -10,6 +10,54 @@ nft insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter
iptables-translate -A INPUT -i iif+ ! -d 10.0.0.0/8
nft add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter
+iptables-translate -I INPUT -s 10.11.12.13/255.255.0.0
+nft insert rule ip filter INPUT ip saddr 10.11.0.0/16 counter
+
+iptables-translate -I INPUT -s 10.11.12.13/255.0.255.0
+nft insert rule ip filter INPUT ip saddr & 255.0.255.0 == 10.0.12.0 counter
+
+iptables-translate -I INPUT -s 10.11.12.13/0.255.0.255
+nft insert rule ip filter INPUT ip saddr & 0.255.0.255 == 0.11.0.13 counter
+
+iptables-translate -I INPUT ! -s 10.11.12.13/0.255.0.255
+nft insert rule ip filter INPUT ip saddr & 0.255.0.255 != 0.11.0.13 counter
+
+iptables-translate -I INPUT -s 0.0.0.0/16
+nft insert rule ip filter INPUT ip saddr 0.0.0.0/16 counter
+
+iptables-translate -I INPUT -s 0.0.0.0/0
+nft insert rule ip filter INPUT counter
+
+iptables-translate -I INPUT ! -s 0.0.0.0/0
+nft insert rule ip filter INPUT ip saddr != 0.0.0.0/0 counter
+
+ip6tables-translate -I INPUT -i iifname -s feed::/16
+nft insert rule ip6 filter INPUT iifname "iifname" ip6 saddr feed::/16 counter
+
+ip6tables-translate -A INPUT -i iif+ ! -d feed::/16
+nft add rule ip6 filter INPUT iifname "iif*" ip6 daddr != feed::/16 counter
+
+ip6tables-translate -I INPUT -s feed:babe::1/ffff:ff00::
+nft insert rule ip6 filter INPUT ip6 saddr feed:ba00::/24 counter
+
+ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/ffff:0:ffff:0:ffff:0:ffff:0
+nft insert rule ip6 filter INPUT ip6 saddr & ffff:0:ffff:0:ffff:0:ffff:0 == feed:0:c0ff:0:c0be:0:5678:0 counter
+
+ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff
+nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff == 0:babe:0:ee00:0:1234:0:90ab counter
+
+ip6tables-translate -I INPUT ! -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff
+nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff != 0:babe:0:ee00:0:1234:0:90ab counter
+
+ip6tables-translate -I INPUT -s ::/16
+nft insert rule ip6 filter INPUT ip6 saddr ::/16 counter
+
+ip6tables-translate -I INPUT -s ::/0
+nft insert rule ip6 filter INPUT counter
+
+ip6tables-translate -I INPUT ! -s ::/0
+nft insert rule ip6 filter INPUT ip6 saddr != ::/0 counter
+
ebtables-translate -I INPUT -i iname --logical-in ilogname -s 0:0:0:0:0:0
nft insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter
diff --git a/extensions/libarpt_mangle.c b/extensions/libarpt_mangle.c
index a2378a8b..765edf34 100644
--- a/extensions/libarpt_mangle.c
+++ b/extensions/libarpt_mangle.c
@@ -13,7 +13,6 @@
#include <xtables.h>
#include <linux/netfilter_arp/arpt_mangle.h>
#include "iptables/nft.h"
-#include "iptables/nft-arp.h"
static void arpmangle_print_help(void)
{
diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c
index 2b9a1b65..7eb898f9 100644
--- a/extensions/libebt_among.c
+++ b/extensions/libebt_among.c
@@ -66,7 +66,7 @@ parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip)
if (sep) {
*sep = '\0';
- if (!inet_aton(sep + 1, &pair->in))
+ if (!inet_pton(AF_INET, sep + 1, &pair->in))
xtables_error(PARAMETER_PROBLEM,
"Invalid IP address '%s'\n", sep + 1);
}
@@ -194,6 +194,7 @@ static void __bramong_print(struct nft_among_pair *pairs,
int cnt, bool inv, bool have_ip)
{
const char *isep = inv ? "! " : "";
+ char abuf[INET_ADDRSTRLEN];
int i;
for (i = 0; i < cnt; i++) {
@@ -202,7 +203,8 @@ static void __bramong_print(struct nft_among_pair *pairs,
printf("%s", ether_ntoa(&pairs[i].ether));
if (pairs[i].in.s_addr != INADDR_ANY)
- printf("=%s", inet_ntoa(pairs[i].in));
+ printf("=%s", inet_ntop(AF_INET, &pairs[i].in,
+ abuf, sizeof(abuf)));
}
printf(" ");
}
diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c
index acb9bfcd..51649ffb 100644
--- a/extensions/libebt_ip.c
+++ b/extensions/libebt_ip.c
@@ -175,7 +175,8 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
char *buffer;
char *cp;
- buffer = strdup(portstring);
+ buffer = xtables_strdup(portstring);
+
if ((cp = strchr(buffer, ':')) == NULL)
ports[0] = ports[1] = xtables_parse_port(buffer, NULL);
else {
diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c
index b8a5a5d8..a686a285 100644
--- a/extensions/libebt_ip6.c
+++ b/extensions/libebt_ip6.c
@@ -93,7 +93,7 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
char *buffer;
char *cp;
- buffer = strdup(portstring);
+ buffer = xtables_strdup(portstring);
if ((cp = strchr(buffer, ':')) == NULL)
ports[0] = ports[1] = xtables_parse_port(buffer, NULL);
else {
@@ -247,75 +247,19 @@ static void brip6_init(struct xt_entry_match *match)
memset(ipinfo->dmsk.s6_addr, 0, sizeof(ipinfo->dmsk.s6_addr));
}
-static struct in6_addr *numeric_to_addr(const char *num)
+/* wrap xtables_ip6parse_any(), ignoring any but the first returned address */
+static void ebt_parse_ip6_address(char *address,
+ struct in6_addr *addr, struct in6_addr *msk)
{
- static struct in6_addr ap;
- int err;
-
- if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
- return &ap;
- return (struct in6_addr *)NULL;
-}
-
-static struct in6_addr *parse_ip6_mask(char *mask)
-{
- static struct in6_addr maskaddr;
struct in6_addr *addrp;
- unsigned int bits;
-
- if (mask == NULL) {
- /* no mask at all defaults to 128 bits */
- memset(&maskaddr, 0xff, sizeof maskaddr);
- return &maskaddr;
- }
- if ((addrp = numeric_to_addr(mask)) != NULL)
- return addrp;
- if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
- xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Mask '%s' specified", mask);
- if (bits != 0) {
- char *p = (char *)&maskaddr;
- memset(p, 0xff, bits / 8);
- memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
- p[bits / 8] = 0xff << (8 - (bits & 7));
- return &maskaddr;
- }
+ unsigned int naddrs;
- memset(&maskaddr, 0, sizeof maskaddr);
- return &maskaddr;
-}
-
-/* Set the ipv6 mask and address. Callers should check ebt_errormsg[0].
- * The string pointed to by address can be altered. */
-static void ebt_parse_ip6_address(char *address, struct in6_addr *addr, struct in6_addr *msk)
-{
- struct in6_addr *tmp_addr;
- char buf[256];
- char *p;
- int i;
- int err;
-
- strncpy(buf, address, sizeof(buf) - 1);
- /* first the mask */
- buf[sizeof(buf) - 1] = '\0';
- if ((p = strrchr(buf, '/')) != NULL) {
- *p = '\0';
- tmp_addr = parse_ip6_mask(p + 1);
- } else
- tmp_addr = parse_ip6_mask(NULL);
-
- *msk = *tmp_addr;
-
- /* if a null mask is given, the name is ignored, like in "any/0" */
- if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any)))
- strcpy(buf, "::");
-
- if ((err=inet_pton(AF_INET6, buf, addr)) < 1) {
- xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Address '%s' specified", buf);
- return;
- }
-
- for (i = 0; i < 4; i++)
- addr->s6_addr32[i] &= msk->s6_addr32[i];
+ xtables_ip6parse_any(address, &addrp, msk, &naddrs);
+ if (naddrs != 1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid IPv6 Address '%s' specified", address);
+ memcpy(addr, addrp, sizeof(*addr));
+ free(addrp);
}
#define OPT_SOURCE 0x01
diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c
index 81ba572c..3e9e2447 100644
--- a/extensions/libebt_stp.c
+++ b/extensions/libebt_stp.c
@@ -90,7 +90,8 @@ static int parse_range(const char *portstring, void *lower, void *upper,
uint32_t low_nr, upp_nr;
int ret = 0;
- buffer = strdup(portstring);
+ buffer = xtables_strdup(portstring);
+
if ((cp = strchr(buffer, ':')) == NULL) {
low_nr = strtoul(buffer, &end, 10);
if (*end || low_nr < min || low_nr > max) {
diff --git a/extensions/libip6t_DNAT.c b/extensions/libip6t_DNAT.c
deleted file mode 100644
index 89c5ceb1..00000000
--- a/extensions/libip6t_DNAT.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
- *
- * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT
- * funded by Astaro.
- */
-
-#include <stdio.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <iptables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_DEST = 0,
- O_RANDOM,
- O_PERSISTENT,
- O_X_TO_DEST,
- F_TO_DEST = 1 << O_TO_DEST,
- F_RANDOM = 1 << O_RANDOM,
- F_X_TO_DEST = 1 << O_X_TO_DEST,
-};
-
-static void DNAT_help(void)
-{
- printf(
-"DNAT target options:\n"
-" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
-" Address to map destination to.\n"
-"[--random] [--persistent]\n");
-}
-
-static void DNAT_help_v2(void)
-{
- printf(
-"DNAT target options:\n"
-" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n"
-" Address to map destination to.\n"
-"[--random] [--persistent]\n");
-}
-
-static const struct xt_option_entry DNAT_opts[] = {
- {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_MULTI},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-/* Ranges expected in network order. */
-static void
-parse_to(const char *orig_arg, int portok, struct nf_nat_range2 *range, int rev)
-{
- char *arg, *start, *end = NULL, *colon = NULL, *dash, *error;
- const struct in6_addr *ip;
-
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
-
- start = strchr(arg, '[');
- if (start == NULL) {
- start = arg;
- /* Lets assume one colon is port information. Otherwise its an IPv6 address */
- colon = strchr(arg, ':');
- if (colon && strchr(colon+1, ':'))
- colon = NULL;
- }
- else {
- start++;
- end = strchr(start, ']');
- if (end == NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid address format");
-
- *end = '\0';
- colon = strchr(end + 1, ':');
- }
-
- if (colon) {
- int port;
-
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
-
- range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- port = atoi(colon+1);
- if (port <= 0 || port > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", colon+1);
-
- error = strchr(colon+1, ':');
- if (error)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid port:port syntax - use dash\n");
-
- dash = strchr(colon, '-');
- if (!dash) {
- range->min_proto.tcp.port
- = range->max_proto.tcp.port
- = htons(port);
- } else {
- int maxport;
-
- maxport = atoi(dash + 1);
- if (maxport <= 0 || maxport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", dash+1);
- if (maxport < port)
- /* People are stupid. */
- xtables_error(PARAMETER_PROBLEM,
- "Port range `%s' funky\n", colon+1);
- range->min_proto.tcp.port = htons(port);
- range->max_proto.tcp.port = htons(maxport);
-
- if (rev >= 2) {
- char *slash = strchr(dash, '/');
- if (slash) {
- int baseport;
-
- baseport = atoi(slash + 1);
- if (baseport <= 0 || baseport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", slash+1);
- range->flags |= NF_NAT_RANGE_PROTO_OFFSET;
- range->base_proto.tcp.port = htons(baseport);
- }
- }
- }
- /* Starts with colon or [] colon? No IP info...*/
- if (colon == arg || colon == arg+2) {
- free(arg);
- return;
- }
- *colon = '\0';
- }
-
- range->flags |= NF_NAT_RANGE_MAP_IPS;
- dash = strchr(start, '-');
- if (colon && dash && dash > colon)
- dash = NULL;
-
- if (dash)
- *dash = '\0';
-
- ip = xtables_numeric_to_ip6addr(start);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- start);
- range->min_addr.in6 = *ip;
- if (dash) {
- ip = xtables_numeric_to_ip6addr(dash + 1);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- dash+1);
- range->max_addr.in6 = *ip;
- } else
- range->max_addr = range->min_addr;
-
- free(arg);
- return;
-}
-
-static void _DNAT_parse(struct xt_option_call *cb,
- struct nf_nat_range2 *range, int rev)
-{
- const struct ip6t_entry *entry = cb->xt_entry;
- int portok;
-
- if (entry->ipv6.proto == IPPROTO_TCP ||
- entry->ipv6.proto == IPPROTO_UDP ||
- entry->ipv6.proto == IPPROTO_SCTP ||
- entry->ipv6.proto == IPPROTO_DCCP ||
- entry->ipv6.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- 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(cb->arg, portok, range, rev);
- cb->xflags |= F_X_TO_DEST;
- break;
- case O_PERSISTENT:
- range->flags |= NF_NAT_RANGE_PERSISTENT;
- break;
- }
-}
-
-static void DNAT_parse(struct xt_option_call *cb)
-{
- struct nf_nat_range *range_v1 = (void *)cb->data;
- struct nf_nat_range2 range = {};
-
- memcpy(&range, range_v1, sizeof(*range_v1));
- _DNAT_parse(cb, &range, 1);
- memcpy(range_v1, &range, sizeof(*range_v1));
-}
-
-static void DNAT_parse_v2(struct xt_option_call *cb)
-{
- _DNAT_parse(cb, (struct nf_nat_range2 *)cb->data, 2);
-}
-
-static void _DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags)
-{
- static const unsigned int f = F_TO_DEST | F_RANDOM;
-
- if ((cb->xflags & f) == f)
- *flags |= NF_NAT_RANGE_PROTO_RANDOM;
-}
-
-static void DNAT_fcheck(struct xt_fcheck_call *cb)
-{
- _DNAT_fcheck(cb, &((struct nf_nat_range *)cb->data)->flags);
-}
-
-static void DNAT_fcheck_v2(struct xt_fcheck_call *cb)
-{
- _DNAT_fcheck(cb, &((struct nf_nat_range2 *)cb->data)->flags);
-}
-
-static void print_range(const struct nf_nat_range2 *range, int rev)
-{
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
- printf("[");
- printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6));
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr)))
- printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6));
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
- printf("]");
- }
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(":");
- printf("%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- printf("-%hu", ntohs(range->max_proto.tcp.port));
- if (rev >= 2 && (range->flags & NF_NAT_RANGE_PROTO_OFFSET))
- printf("/%hu", ntohs(range->base_proto.tcp.port));
- }
-}
-
-static void _DNAT_print(const struct nf_nat_range2 *range, int rev)
-{
- printf(" to:");
- print_range(range, rev);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" persistent");
-}
-
-static void DNAT_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_range *range_v1 = (const void *)target->data;
- struct nf_nat_range2 range = {};
-
- memcpy(&range, range_v1, sizeof(*range_v1));
- _DNAT_print(&range, 1);
-}
-
-static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- _DNAT_print((const struct nf_nat_range2 *)target->data, 2);
-}
-
-static void _DNAT_save(const struct nf_nat_range2 *range, int rev)
-{
- printf(" --to-destination ");
- print_range(range, rev);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" --persistent");
-}
-
-static void DNAT_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_range *range_v1 = (const void *)target->data;
- struct nf_nat_range2 range = {};
-
- memcpy(&range, range_v1, sizeof(*range_v1));
- _DNAT_save(&range, 1);
-}
-
-static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target)
-{
- _DNAT_save((const struct nf_nat_range2 *)target->data, 2);
-}
-
-static void print_range_xlate(const struct nf_nat_range2 *range,
- struct xt_xlate *xl, int rev)
-{
- bool proto_specified = range->flags & NF_NAT_RANGE_PROTO_SPECIFIED;
-
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- xt_xlate_add(xl, "%s%s%s",
- proto_specified ? "[" : "",
- xtables_ip6addr_to_numeric(&range->min_addr.in6),
- proto_specified ? "]" : "");
-
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr))) {
- xt_xlate_add(xl, "-%s%s%s",
- proto_specified ? "[" : "",
- xtables_ip6addr_to_numeric(&range->max_addr.in6),
- proto_specified ? "]" : "");
- }
- }
- if (proto_specified) {
- xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port));
-
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- xt_xlate_add(xl, "-%hu",
- ntohs(range->max_proto.tcp.port));
- }
-}
-
-static int _DNAT_xlate(struct xt_xlate *xl,
- const struct nf_nat_range2 *range, int rev)
-{
- bool sep_need = false;
- const char *sep = " ";
-
- xt_xlate_add(xl, "dnat to ");
- print_range_xlate(range, xl, rev);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
- xt_xlate_add(xl, " random");
- sep_need = true;
- }
- if (range->flags & NF_NAT_RANGE_PERSISTENT) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%spersistent", sep);
- }
-
- return 1;
-}
-
-static int DNAT_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_range *range_v1 = (const void *)params->target->data;
- struct nf_nat_range2 range = {};
-
- memcpy(&range, range_v1, sizeof(*range_v1));
- _DNAT_xlate(xl, &range, 1);
-
- return 1;
-}
-
-static int DNAT_xlate_v2(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- _DNAT_xlate(xl, (const struct nf_nat_range2 *)params->target->data, 2);
-
- return 1;
-}
-
-static struct xtables_target dnat_tg_reg[] = {
- {
- .name = "DNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .revision = 1,
- .size = XT_ALIGN(sizeof(struct nf_nat_range)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
- .help = DNAT_help,
- .print = DNAT_print,
- .save = DNAT_save,
- .x6_parse = DNAT_parse,
- .x6_fcheck = DNAT_fcheck,
- .x6_options = DNAT_opts,
- .xlate = DNAT_xlate,
- },
- {
- .name = "DNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .revision = 2,
- .size = XT_ALIGN(sizeof(struct nf_nat_range2)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
- .help = DNAT_help_v2,
- .print = DNAT_print_v2,
- .save = DNAT_save_v2,
- .x6_parse = DNAT_parse_v2,
- .x6_fcheck = DNAT_fcheck_v2,
- .x6_options = DNAT_opts,
- .xlate = DNAT_xlate_v2,
- },
-};
-
-void _init(void)
-{
- xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg));
-}
diff --git a/extensions/libip6t_DNAT.t b/extensions/libip6t_DNAT.t
index ec7d61f4..e53dfa16 100644
--- a/extensions/libip6t_DNAT.t
+++ b/extensions/libip6t_DNAT.t
@@ -13,4 +13,8 @@
-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65535;=;OK
-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/0;;FAIL
-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65536;;FAIL
+-p tcp -j DNAT --to-destination [dead::beef]:ssh;-p tcp -j DNAT --to-destination [dead::beef]:22;OK
+-p tcp -j DNAT --to-destination [dead::beef]:ftp-data;-p tcp -j DNAT --to-destination [dead::beef]:20;OK
+-p tcp -j DNAT --to-destination [dead::beef]:echo-ssh;;FAIL
+-p tcp -j DNAT --to-destination [dead::beef]:10-20/ftp;-p tcp -j DNAT --to-destination [dead::beef]:10-20/21;OK
-j DNAT;;FAIL
diff --git a/extensions/libip6t_DNAT.txlate b/extensions/libip6t_DNAT.txlate
deleted file mode 100644
index 03c4caf7..00000000
--- a/extensions/libip6t_DNAT.txlate
+++ /dev/null
@@ -1,11 +0,0 @@
-ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80
-nft add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80
-
-ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20
-nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20
-
-ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent
-nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent
-
-ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent
-nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent
diff --git a/extensions/libip6t_MASQUERADE.c b/extensions/libip6t_MASQUERADE.c
index f92760fa..f28f071b 100644
--- a/extensions/libip6t_MASQUERADE.c
+++ b/extensions/libip6t_MASQUERADE.c
@@ -163,7 +163,7 @@ static int MASQUERADE_xlate(struct xt_xlate *xl,
xt_xlate_add(xl, " ");
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- xt_xlate_add(xl, "random-fully ");
+ xt_xlate_add(xl, "fully-random ");
return 1;
}
diff --git a/extensions/libip6t_REDIRECT.c b/extensions/libip6t_REDIRECT.c
deleted file mode 100644
index 8e04d2cd..00000000
--- a/extensions/libip6t_REDIRECT.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
- *
- * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 NAT
- * funded by Astaro.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_PORTS = 0,
- O_RANDOM,
- F_TO_PORTS = 1 << O_TO_PORTS,
- F_RANDOM = 1 << O_RANDOM,
-};
-
-static void REDIRECT_help(void)
-{
- printf(
-"REDIRECT target options:\n"
-" --to-ports <port>[-<port>]\n"
-" Port (range) to map to.\n"
-" [--random]\n");
-}
-
-static const struct xt_option_entry REDIRECT_opts[] = {
- {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-/* Parses ports */
-static void
-parse_ports(const char *arg, struct nf_nat_range *range)
-{
- char *end = "";
- unsigned int port, maxport;
-
- range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) &&
- (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1)
- xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
-
- switch (*end) {
- case '\0':
- range->min_proto.tcp.port
- = range->max_proto.tcp.port
- = htons(port);
- return;
- case '-':
- if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) &&
- (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1)
- break;
-
- if (maxport < port)
- break;
-
- range->min_proto.tcp.port = htons(port);
- range->max_proto.tcp.port = htons(maxport);
- return;
- default:
- break;
- }
- xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
-}
-
-static void REDIRECT_parse(struct xt_option_call *cb)
-{
- const struct ip6t_entry *entry = cb->xt_entry;
- struct nf_nat_range *range = (void *)(*cb->target)->data;
- int portok;
-
- if (entry->ipv6.proto == IPPROTO_TCP
- || entry->ipv6.proto == IPPROTO_UDP
- || entry->ipv6.proto == IPPROTO_SCTP
- || entry->ipv6.proto == IPPROTO_DCCP
- || entry->ipv6.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_PORTS:
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
- parse_ports(cb->arg, range);
- if (cb->xflags & F_RANDOM)
- range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- case O_RANDOM:
- if (cb->xflags & F_TO_PORTS)
- range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- }
-}
-
-static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_range *range = (const void *)target->data;
-
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" redir ports ");
- printf("%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- printf("-%hu", ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- }
-}
-
-static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_range *range = (const void *)target->data;
-
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" --to-ports ");
- printf("%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- printf("-%hu", ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- }
-}
-
-static int REDIRECT_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_range *range = (const void *)params->target->data;
-
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, "redirect to :%hu",
- ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- xt_xlate_add(xl, "-%hu ",
- ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- xt_xlate_add(xl, " random ");
- }
-
- return 1;
-}
-
-static struct xtables_target redirect_tg_reg = {
- .name = "REDIRECT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .size = XT_ALIGN(sizeof(struct nf_nat_range)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
- .help = REDIRECT_help,
- .x6_parse = REDIRECT_parse,
- .print = REDIRECT_print,
- .save = REDIRECT_save,
- .x6_options = REDIRECT_opts,
- .xlate = REDIRECT_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&redirect_tg_reg);
-}
diff --git a/extensions/libip6t_REDIRECT.t b/extensions/libip6t_REDIRECT.t
deleted file mode 100644
index a0fb0ed1..00000000
--- a/extensions/libip6t_REDIRECT.t
+++ /dev/null
@@ -1,6 +0,0 @@
-:PREROUTING,OUTPUT
-*nat
--p tcp -j REDIRECT --to-ports 42;=;OK
--p udp -j REDIRECT --to-ports 42-1234;=;OK
--p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK
--j REDIRECT --to-ports 42;;FAIL
diff --git a/extensions/libip6t_REDIRECT.txlate b/extensions/libip6t_REDIRECT.txlate
deleted file mode 100644
index 209f67a4..00000000
--- a/extensions/libip6t_REDIRECT.txlate
+++ /dev/null
@@ -1,5 +0,0 @@
-ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080
-nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080
-
-ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random
-nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random
diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c
index 7d74b3d7..4fe272b2 100644
--- a/extensions/libip6t_SNAT.c
+++ b/extensions/libip6t_SNAT.c
@@ -20,11 +20,9 @@ enum {
O_RANDOM,
O_RANDOM_FULLY,
O_PERSISTENT,
- O_X_TO_SRC,
F_TO_SRC = 1 << O_TO_SRC,
F_RANDOM = 1 << O_RANDOM,
F_RANDOM_FULLY = 1 << O_RANDOM_FULLY,
- F_X_TO_SRC = 1 << O_X_TO_SRC,
};
static void SNAT_help(void)
@@ -38,7 +36,7 @@ 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},
@@ -52,9 +50,7 @@ parse_to(const char *orig_arg, int portok, struct nf_nat_range *range)
char *arg, *start, *end = NULL, *colon = NULL, *dash, *error;
const struct in6_addr *ip;
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
+ arg = xtables_strdup(orig_arg);
start = strchr(arg, '[');
if (start == NULL) {
@@ -165,12 +161,7 @@ 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) {
- xtables_error(PARAMETER_PROBLEM,
- "SNAT: Multiple --to-source not supported");
- }
parse_to(cb->arg, portok, range);
- cb->xflags |= F_X_TO_SRC;
break;
case O_PERSISTENT:
range->flags |= NF_NAT_RANGE_PERSISTENT;
diff --git a/extensions/libip6t_dst.c b/extensions/libip6t_dst.c
index fe7e3403..bf0e3e43 100644
--- a/extensions/libip6t_dst.c
+++ b/extensions/libip6t_dst.c
@@ -57,11 +57,9 @@ parse_options(const char *optsstr, uint16_t *opts)
{
char *buffer, *cp, *next, *range;
unsigned int i;
-
- buffer = strdup(optsstr);
- if (!buffer)
- xtables_error(OTHER_PROBLEM, "strdup failed");
-
+
+ buffer = xtables_strdup(optsstr);
+
for (cp = buffer, i = 0; cp && i < IP6T_OPTS_OPTSNR; cp = next, i++)
{
next = strchr(cp, ',');
diff --git a/extensions/libip6t_hbh.c b/extensions/libip6t_hbh.c
index 4cebecfd..74e87cda 100644
--- a/extensions/libip6t_hbh.c
+++ b/extensions/libip6t_hbh.c
@@ -57,10 +57,9 @@ parse_options(const char *optsstr, uint16_t *opts)
{
char *buffer, *cp, *next, *range;
unsigned int i;
-
- buffer = strdup(optsstr);
- if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
-
+
+ buffer = xtables_strdup(optsstr);
+
for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++)
{
next=strchr(cp, ',');
diff --git a/extensions/libip6t_ipv6header.c b/extensions/libip6t_ipv6header.c
index 6f03087b..9e345629 100644
--- a/extensions/libip6t_ipv6header.c
+++ b/extensions/libip6t_ipv6header.c
@@ -147,7 +147,7 @@ parse_header(const char *flags) {
char *ptr;
char *buffer;
- buffer = strdup(flags);
+ buffer = xtables_strdup(flags);
for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ","))
ret |= add_proto_to_mask(name_to_proto(ptr));
diff --git a/extensions/libip6t_mh.c b/extensions/libip6t_mh.c
index f4c0fd9f..64675405 100644
--- a/extensions/libip6t_mh.c
+++ b/extensions/libip6t_mh.c
@@ -107,7 +107,7 @@ static void parse_mh_types(const char *mhtype, uint8_t *types)
char *buffer;
char *cp;
- buffer = strdup(mhtype);
+ buffer = xtables_strdup(mhtype);
if ((cp = strchr(buffer, ':')) == NULL)
types[0] = types[1] = name_to_type(buffer);
else {
diff --git a/extensions/libip6t_rt.c b/extensions/libip6t_rt.c
index 3cb3b249..9708b5a0 100644
--- a/extensions/libip6t_rt.c
+++ b/extensions/libip6t_rt.c
@@ -73,10 +73,9 @@ parse_addresses(const char *addrstr, struct in6_addr *addrp)
{
char *buffer, *cp, *next;
unsigned int i;
-
- buffer = strdup(addrstr);
- if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
-
+
+ buffer = xtables_strdup(addrstr);
+
for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
{
next=strchr(cp, ',');
diff --git a/extensions/libipt_CLUSTERIP.t b/extensions/libipt_CLUSTERIP.t
index 5af555e0..30b80167 100644
--- a/extensions/libipt_CLUSTERIP.t
+++ b/extensions/libipt_CLUSTERIP.t
@@ -1,4 +1,4 @@
:INPUT
-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 0 --hash-init 1;=;FAIL
--d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 1 --hash-init 1;=;OK
--d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 2 --hash-init 1;=;OK
+-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 1 --hash-init 1;=;OK;LEGACY
+-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 2 --hash-init 1;=;OK;LEGACY
diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c
deleted file mode 100644
index 4907a2e8..00000000
--- a/extensions/libipt_DNAT.c
+++ /dev/null
@@ -1,555 +0,0 @@
-#include <stdio.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <iptables.h> /* get_kernel_version */
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_DEST = 0,
- O_RANDOM,
- O_PERSISTENT,
- O_X_TO_DEST, /* hidden flag */
- F_TO_DEST = 1 << O_TO_DEST,
- F_RANDOM = 1 << O_RANDOM,
- 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(
-"DNAT target options:\n"
-" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
-" Address to map destination to.\n"
-"[--random] [--persistent]\n");
-}
-
-static void DNAT_help_v2(void)
-{
- printf(
-"DNAT target options:\n"
-" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n"
-" Address to map destination to.\n"
-"[--random] [--persistent]\n");
-}
-
-static const struct xt_option_entry DNAT_opts[] = {
- {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_MULTI},
- {.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)
-{
- struct nf_nat_ipv4_range range;
- char *arg, *colon, *dash, *error;
- const struct in_addr *ip;
-
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
- memset(&range, 0, sizeof(range));
- colon = strchr(arg, ':');
-
- if (colon) {
- int port;
-
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
-
- range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- port = atoi(colon+1);
- if (port <= 0 || port > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", colon+1);
-
- error = strchr(colon+1, ':');
- if (error)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid port:port syntax - use dash\n");
-
- dash = strchr(colon, '-');
- if (!dash) {
- range.min.tcp.port
- = range.max.tcp.port
- = htons(port);
- } else {
- int maxport;
-
- maxport = atoi(dash + 1);
- if (maxport <= 0 || maxport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", dash+1);
- if (maxport < port)
- /* 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);
- }
- /* Starts with a colon? No IP info...*/
- if (colon == arg) {
- free(arg);
- return &(append_range(info, &range)->t);
- }
- *colon = '\0';
- }
-
- range.flags |= NF_NAT_RANGE_MAP_IPS;
- dash = strchr(arg, '-');
- if (colon && dash && dash > colon)
- dash = NULL;
-
- if (dash)
- *dash = '\0';
-
- ip = xtables_numeric_to_ipaddr(arg);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- arg);
- 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;
- } else
- range.max_ip = range.min_ip;
-
- free(arg);
- return &(append_range(info, &range)->t);
-}
-
-static void DNAT_parse(struct xt_option_call *cb)
-{
- const struct ipt_entry *entry = cb->xt_entry;
- struct ipt_natinfo *info = (void *)(*cb->target);
- int portok;
-
- if (entry->ip.proto == IPPROTO_TCP
- || entry->ip.proto == IPPROTO_UDP
- || entry->ip.proto == IPPROTO_SCTP
- || entry->ip.proto == IPPROTO_DCCP
- || entry->ip.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- 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);
- cb->xflags |= F_X_TO_DEST;
- break;
- case O_PERSISTENT:
- info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT;
- break;
- }
-}
-
-static void DNAT_fcheck(struct xt_fcheck_call *cb)
-{
- static const unsigned int f = F_TO_DEST | F_RANDOM;
- struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
-
- if ((cb->xflags & f) == f)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
-}
-
-static void print_range(const struct nf_nat_ipv4_range *r)
-{
- if (r->flags & NF_NAT_RANGE_MAP_IPS) {
- struct in_addr a;
-
- a.s_addr = r->min_ip;
- printf("%s", xtables_ipaddr_to_numeric(&a));
- if (r->max_ip != r->min_ip) {
- a.s_addr = r->max_ip;
- printf("-%s", xtables_ipaddr_to_numeric(&a));
- }
- }
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(":");
- printf("%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- printf("-%hu", ntohs(r->max.tcp.port));
- }
-}
-
-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;
-
- 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");
- }
-}
-
-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");
- }
-}
-
-static void print_range_xlate(const struct nf_nat_ipv4_range *r,
- struct xt_xlate *xl)
-{
- if (r->flags & NF_NAT_RANGE_MAP_IPS) {
- struct in_addr a;
-
- a.s_addr = r->min_ip;
- xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&a));
- if (r->max_ip != r->min_ip) {
- a.s_addr = r->max_ip;
- xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&a));
- }
- }
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, ":%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port));
- }
-}
-
-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;
- 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);
- }
- }
-
- return 1;
-}
-
-static void
-parse_to_v2(const char *orig_arg, int portok, struct nf_nat_range2 *range)
-{
- char *arg, *colon, *dash, *error;
- const struct in_addr *ip;
-
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
-
- colon = strchr(arg, ':');
- if (colon) {
- int port;
-
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
-
- range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- port = atoi(colon+1);
- if (port <= 0 || port > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", colon+1);
-
- error = strchr(colon+1, ':');
- if (error)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid port:port syntax - use dash\n");
-
- dash = strchr(colon, '-');
- if (!dash) {
- range->min_proto.tcp.port
- = range->max_proto.tcp.port
- = htons(port);
- } else {
- int maxport;
- char *slash;
-
- maxport = atoi(dash + 1);
- if (maxport <= 0 || maxport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", dash+1);
- if (maxport < port)
- /* People are stupid. */
- xtables_error(PARAMETER_PROBLEM,
- "Port range `%s' funky\n", colon+1);
- range->min_proto.tcp.port = htons(port);
- range->max_proto.tcp.port = htons(maxport);
-
- slash = strchr(dash, '/');
- if (slash) {
- int baseport;
-
- baseport = atoi(slash + 1);
- if (baseport <= 0 || baseport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", slash+1);
- range->flags |= NF_NAT_RANGE_PROTO_OFFSET;
- range->base_proto.tcp.port = htons(baseport);
- }
- }
- /* Starts with a colon? No IP info...*/
- if (colon == arg) {
- free(arg);
- return;
- }
- *colon = '\0';
- }
-
- range->flags |= NF_NAT_RANGE_MAP_IPS;
- dash = strchr(arg, '-');
- if (colon && dash && dash > colon)
- dash = NULL;
-
- if (dash)
- *dash = '\0';
-
- ip = xtables_numeric_to_ipaddr(arg);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- arg);
- range->min_addr.in = *ip;
- if (dash) {
- ip = xtables_numeric_to_ipaddr(dash+1);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- dash+1);
- range->max_addr.in = *ip;
- } else
- range->max_addr = range->min_addr;
-
- free(arg);
- return;
-}
-
-static void DNAT_parse_v2(struct xt_option_call *cb)
-{
- const struct ipt_entry *entry = cb->xt_entry;
- struct nf_nat_range2 *range = cb->data;
- int portok;
-
- if (entry->ip.proto == IPPROTO_TCP
- || entry->ip.proto == IPPROTO_UDP
- || entry->ip.proto == IPPROTO_SCTP
- || entry->ip.proto == IPPROTO_DCCP
- || entry->ip.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- 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;
- case O_PERSISTENT:
- range->flags |= NF_NAT_RANGE_PERSISTENT;
- break;
- }
-}
-
-static void DNAT_fcheck_v2(struct xt_fcheck_call *cb)
-{
- static const unsigned int f = F_TO_DEST | F_RANDOM;
- struct nf_nat_range2 *range = cb->data;
-
- if ((cb->xflags & f) == f)
- range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
-}
-
-static void print_range_v2(const struct nf_nat_range2 *range)
-{
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- printf("%s", xtables_ipaddr_to_numeric(&range->min_addr.in));
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr)))
- printf("-%s", xtables_ipaddr_to_numeric(&range->max_addr.in));
- }
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(":");
- printf("%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- printf("-%hu", ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
- printf("/%hu", ntohs(range->base_proto.tcp.port));
- }
-}
-
-static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_range2 *range = (const void *)target->data;
-
- printf(" to:");
- print_range_v2(range);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" persistent");
-}
-
-static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_range2 *range = (const void *)target->data;
-
- printf(" --to-destination ");
- print_range_v2(range);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" --persistent");
-}
-
-static void print_range_xlate_v2(const struct nf_nat_range2 *range,
- struct xt_xlate *xl)
-{
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&range->min_addr.in));
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr))) {
- xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&range->max_addr.in));
- }
- }
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- xt_xlate_add(xl, "-%hu", ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
- xt_xlate_add(xl, ";%hu", ntohs(range->base_proto.tcp.port));
- }
-}
-
-static int DNAT_xlate_v2(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_range2 *range = (const void *)params->target->data;
- bool sep_need = false;
- const char *sep = " ";
-
- xt_xlate_add(xl, "dnat to ");
- print_range_xlate_v2(range, xl);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
- xt_xlate_add(xl, " random");
- sep_need = true;
- }
- if (range->flags & NF_NAT_RANGE_PERSISTENT) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%spersistent", sep);
- }
-
- return 1;
-}
-
-static struct xtables_target dnat_tg_reg[] = {
- {
- .name = "DNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .revision = 0,
- .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .help = DNAT_help,
- .print = DNAT_print,
- .save = DNAT_save,
- .x6_parse = DNAT_parse,
- .x6_fcheck = DNAT_fcheck,
- .x6_options = DNAT_opts,
- .xlate = DNAT_xlate,
- },
- {
- .name = "DNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .revision = 2,
- .size = XT_ALIGN(sizeof(struct nf_nat_range2)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
- .help = DNAT_help_v2,
- .print = DNAT_print_v2,
- .save = DNAT_save_v2,
- .x6_parse = DNAT_parse_v2,
- .x6_fcheck = DNAT_fcheck_v2,
- .x6_options = DNAT_opts,
- .xlate = DNAT_xlate_v2,
- },
-};
-
-void _init(void)
-{
- xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg));
-}
diff --git a/extensions/libipt_DNAT.t b/extensions/libipt_DNAT.t
index 1c4413b9..9007572a 100644
--- a/extensions/libipt_DNAT.t
+++ b/extensions/libipt_DNAT.t
@@ -13,4 +13,8 @@
-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65535;=;OK
-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/0;;FAIL
-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65536;;FAIL
+-p tcp -j DNAT --to-destination 1.1.1.1:ssh;-p tcp -j DNAT --to-destination 1.1.1.1:22;OK
+-p tcp -j DNAT --to-destination 1.1.1.1:ftp-data;-p tcp -j DNAT --to-destination 1.1.1.1:20;OK
+-p tcp -j DNAT --to-destination 1.1.1.1:echo-ssh;;FAIL
+-p tcp -j DNAT --to-destination 1.1.1.1:10-20/ftp;-p tcp -j DNAT --to-destination 1.1.1.1:10-20/21;OK
-j DNAT;;FAIL
diff --git a/extensions/libipt_DNAT.txlate b/extensions/libipt_DNAT.txlate
deleted file mode 100644
index e88314d9..00000000
--- a/extensions/libipt_DNAT.txlate
+++ /dev/null
@@ -1,14 +0,0 @@
-iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4
-nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4
-
-iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10
-nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10
-
-iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023
-nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023
-
-iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random
-nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random
-
-iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent
-nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent
diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c
deleted file mode 100644
index 7850306f..00000000
--- a/extensions/libipt_REDIRECT.c
+++ /dev/null
@@ -1,174 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_PORTS = 0,
- O_RANDOM,
- F_TO_PORTS = 1 << O_TO_PORTS,
- F_RANDOM = 1 << O_RANDOM,
-};
-
-static void REDIRECT_help(void)
-{
- printf(
-"REDIRECT target options:\n"
-" --to-ports <port>[-<port>]\n"
-" Port (range) to map to.\n"
-" [--random]\n");
-}
-
-static const struct xt_option_entry REDIRECT_opts[] = {
- {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-static void REDIRECT_init(struct xt_entry_target *t)
-{
- struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data;
-
- /* Actually, it's 0, but it's ignored at the moment. */
- mr->rangesize = 1;
-}
-
-/* Parses ports */
-static void
-parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr)
-{
- char *end = "";
- unsigned int port, maxport;
-
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) &&
- (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1)
- xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
-
- switch (*end) {
- case '\0':
- mr->range[0].min.tcp.port
- = mr->range[0].max.tcp.port
- = htons(port);
- return;
- case '-':
- if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) &&
- (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1)
- break;
-
- if (maxport < port)
- break;
-
- mr->range[0].min.tcp.port = htons(port);
- mr->range[0].max.tcp.port = htons(maxport);
- return;
- default:
- break;
- }
- xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
-}
-
-static void REDIRECT_parse(struct xt_option_call *cb)
-{
- const struct ipt_entry *entry = cb->xt_entry;
- struct nf_nat_ipv4_multi_range_compat *mr = (void *)(*cb->target)->data;
- int portok;
-
- if (entry->ip.proto == IPPROTO_TCP
- || entry->ip.proto == IPPROTO_UDP
- || entry->ip.proto == IPPROTO_SCTP
- || entry->ip.proto == IPPROTO_DCCP
- || entry->ip.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_PORTS:
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
- parse_ports(cb->arg, mr);
- if (cb->xflags & F_RANDOM)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- case O_RANDOM:
- if (cb->xflags & F_TO_PORTS)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- }
-}
-
-static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
- const struct nf_nat_ipv4_range *r = &mr->range[0];
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" redir ports ");
- printf("%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- printf("-%hu", ntohs(r->max.tcp.port));
- if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- }
-}
-
-static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
- const struct nf_nat_ipv4_range *r = &mr->range[0];
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" --to-ports ");
- printf("%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- printf("-%hu", ntohs(r->max.tcp.port));
- if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- }
-}
-
-static int REDIRECT_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_ipv4_multi_range_compat *mr =
- (const void *)params->target->data;
- const struct nf_nat_ipv4_range *r = &mr->range[0];
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, "redirect to :%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- xt_xlate_add(xl, "-%hu ", ntohs(r->max.tcp.port));
- if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM)
- xt_xlate_add(xl, " random ");
- }
-
- return 1;
-}
-
-static struct xtables_target redirect_tg_reg = {
- .name = "REDIRECT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .help = REDIRECT_help,
- .init = REDIRECT_init,
- .x6_parse = REDIRECT_parse,
- .print = REDIRECT_print,
- .save = REDIRECT_save,
- .x6_options = REDIRECT_opts,
- .xlate = REDIRECT_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&redirect_tg_reg);
-}
diff --git a/extensions/libipt_REDIRECT.t b/extensions/libipt_REDIRECT.t
deleted file mode 100644
index a0fb0ed1..00000000
--- a/extensions/libipt_REDIRECT.t
+++ /dev/null
@@ -1,6 +0,0 @@
-:PREROUTING,OUTPUT
-*nat
--p tcp -j REDIRECT --to-ports 42;=;OK
--p udp -j REDIRECT --to-ports 42-1234;=;OK
--p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK
--j REDIRECT --to-ports 42;;FAIL
diff --git a/extensions/libipt_REDIRECT.txlate b/extensions/libipt_REDIRECT.txlate
deleted file mode 100644
index 815bb771..00000000
--- a/extensions/libipt_REDIRECT.txlate
+++ /dev/null
@@ -1,5 +0,0 @@
-iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080
-nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080
-
-iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random
-nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random
diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c
index e92d811c..211a20bc 100644
--- a/extensions/libipt_SNAT.c
+++ b/extensions/libipt_SNAT.c
@@ -13,19 +13,9 @@ enum {
O_RANDOM,
O_RANDOM_FULLY,
O_PERSISTENT,
- O_X_TO_SRC,
F_TO_SRC = 1 << O_TO_SRC,
F_RANDOM = 1 << O_RANDOM,
F_RANDOM_FULLY = 1 << O_RANDOM_FULLY,
- 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)
@@ -39,44 +29,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 = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
- memset(&range, 0, sizeof(range));
+ arg = xtables_strdup(orig_arg);
colon = strchr(arg, ':');
if (colon) {
@@ -86,7 +53,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)
@@ -100,8 +67,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;
@@ -114,18 +81,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;
@@ -137,24 +104,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
@@ -169,18 +136,10 @@ 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);
- cb->xflags |= F_X_TO_SRC;
+ parse_to(cb->arg, portok, mr->range);
break;
case O_PERSISTENT:
- info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT;
+ mr->range->flags |= NF_NAT_RANGE_PERSISTENT;
break;
}
}
@@ -192,9 +151,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)
@@ -220,36 +181,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,
@@ -276,29 +233,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.c b/extensions/libxt_DNAT.c
new file mode 100644
index 00000000..5696d31f
--- /dev/null
+++ b/extensions/libxt_DNAT.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
+ *
+ * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT
+ * funded by Astaro.
+ */
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <xtables.h>
+#include <iptables.h> /* get_kernel_version */
+#include <limits.h> /* INT_MAX in ip_tables.h */
+#include <arpa/inet.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/nf_nat.h>
+
+#define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr))
+#define RANGE2_INIT_FROM_IPV4_MRC(ptr) { \
+ .flags = TO_IPV4_MRC(ptr)->range[0].flags, \
+ .min_addr.ip = TO_IPV4_MRC(ptr)->range[0].min_ip, \
+ .max_addr.ip = TO_IPV4_MRC(ptr)->range[0].max_ip, \
+ .min_proto = TO_IPV4_MRC(ptr)->range[0].min, \
+ .max_proto = TO_IPV4_MRC(ptr)->range[0].max, \
+};
+
+enum {
+ O_TO_DEST = 0,
+ O_TO_PORTS,
+ O_RANDOM,
+ O_PERSISTENT,
+ F_TO_DEST = 1 << O_TO_DEST,
+ F_TO_PORTS = 1 << O_TO_PORTS,
+ F_RANDOM = 1 << O_RANDOM,
+};
+
+static void DNAT_help(void)
+{
+ printf(
+"DNAT target options:\n"
+" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
+" Address to map destination to.\n"
+"[--random] [--persistent]\n");
+}
+
+static void DNAT_help_v2(void)
+{
+ printf(
+"DNAT target options:\n"
+" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n"
+" Address to map destination to.\n"
+"[--random] [--persistent]\n");
+}
+
+static void REDIRECT_help(void)
+{
+ printf(
+"REDIRECT target options:\n"
+" --to-ports <port>[-<port>]\n"
+" Port (range) to map to.\n"
+" [--random]\n");
+}
+
+static const struct xt_option_entry DNAT_opts[] = {
+ {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND},
+ {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
+ {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+
+static const struct xt_option_entry REDIRECT_opts[] = {
+ {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
+ {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+
+/* Parses ports */
+static void
+parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range)
+{
+ unsigned int port, maxport, baseport;
+ char *end = NULL;
+
+ if (!portok)
+ xtables_error(PARAMETER_PROBLEM,
+ "Need TCP, UDP, SCTP or DCCP with port specification");
+
+ range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
+
+ if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) {
+ port = xtables_service_to_port(arg, NULL);
+ if (port == (unsigned)-1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid", arg);
+ end = "";
+ }
+
+ switch (*end) {
+ case '\0':
+ range->min_proto.tcp.port
+ = range->max_proto.tcp.port
+ = htons(port);
+ return;
+ case '-':
+ arg = end + 1;
+ break;
+ case ':':
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid port:port syntax - use dash");
+ default:
+ xtables_error(PARAMETER_PROBLEM,
+ "Garbage after port value: `%s'", end);
+ }
+
+ /* it is a range, don't allow service names here */
+ if (!xtables_strtoui(arg, &end, &maxport, 0, UINT16_MAX))
+ xtables_error(PARAMETER_PROBLEM, "Port `%s' not valid", arg);
+
+ if (maxport < port)
+ /* People are stupid. */
+ xtables_error(PARAMETER_PROBLEM,
+ "Port range `%s' funky", arg);
+
+ range->min_proto.tcp.port = htons(port);
+ range->max_proto.tcp.port = htons(maxport);
+
+ switch (*end) {
+ case '\0':
+ return;
+ case '/':
+ arg = end + 1;
+ break;
+ default:
+ xtables_error(PARAMETER_PROBLEM,
+ "Garbage after port range: `%s'", end);
+ }
+
+ if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) {
+ baseport = xtables_service_to_port(arg, NULL);
+ if (baseport == (unsigned)-1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid", arg);
+ }
+
+ range->flags |= NF_NAT_RANGE_PROTO_OFFSET;
+ range->base_proto.tcp.port = htons(baseport);
+}
+
+/* Ranges expected in network order. */
+static void
+parse_to(const char *orig_arg, bool portok,
+ struct nf_nat_range2 *range, int family)
+{
+ char *arg, *start, *end, *colon, *dash;
+
+ arg = xtables_strdup(orig_arg);
+ start = strchr(arg, '[');
+ if (!start) {
+ start = arg;
+ /* Lets assume one colon is port information.
+ * Otherwise its an IPv6 address */
+ colon = strchr(arg, ':');
+ if (colon && strchr(colon + 1, ':'))
+ colon = NULL;
+ } else {
+ start++;
+ end = strchr(start, ']');
+ if (end == NULL || family == AF_INET)
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid address format");
+
+ *end = '\0';
+ colon = strchr(end + 1, ':');
+ }
+
+ if (colon) {
+ parse_ports(colon + 1, portok, range);
+
+ /* Starts with colon or [] colon? No IP info...*/
+ if (colon == arg || colon == arg + 2) {
+ free(arg);
+ return;
+ }
+ *colon = '\0';
+ }
+
+ range->flags |= NF_NAT_RANGE_MAP_IPS;
+ dash = strchr(start, '-');
+ if (colon && dash && dash > colon)
+ dash = NULL;
+
+ if (dash)
+ *dash = '\0';
+
+ if (!inet_pton(family, start, &range->min_addr))
+ xtables_error(PARAMETER_PROBLEM,
+ "Bad IP address \"%s\"", arg);
+ if (dash) {
+ if (!inet_pton(family, dash + 1, &range->max_addr))
+ xtables_error(PARAMETER_PROBLEM,
+ "Bad IP address \"%s\"", dash + 1);
+ } else {
+ range->max_addr = range->min_addr;
+ }
+ free(arg);
+ return;
+}
+
+static void __DNAT_parse(struct xt_option_call *cb, __u16 proto,
+ struct nf_nat_range2 *range, int family)
+{
+ bool portok = proto == IPPROTO_TCP ||
+ proto == IPPROTO_UDP ||
+ proto == IPPROTO_SCTP ||
+ proto == IPPROTO_DCCP ||
+ proto == IPPROTO_ICMP;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_TO_DEST:
+ parse_to(cb->arg, portok, range, family);
+ break;
+ case O_TO_PORTS:
+ parse_ports(cb->arg, portok, range);
+ break;
+ case O_PERSISTENT:
+ range->flags |= NF_NAT_RANGE_PERSISTENT;
+ break;
+ }
+}
+
+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 nf_nat_range2 range = {};
+
+ __DNAT_parse(cb, entry->ip.proto, &range, AF_INET);
+
+ switch (cb->entry->id) {
+ case O_TO_DEST:
+ mr->range->min_ip = range.min_addr.ip;
+ mr->range->max_ip = range.max_addr.ip;
+ /* fall through */
+ case O_TO_PORTS:
+ mr->range->min = range.min_proto;
+ mr->range->max = range.max_proto;
+ /* fall through */
+ case O_PERSISTENT:
+ mr->range->flags |= range.flags;
+ break;
+ }
+}
+
+static void __DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags)
+{
+ static const unsigned int redir_f = F_TO_PORTS | F_RANDOM;
+ static const unsigned int dnat_f = F_TO_DEST | F_RANDOM;
+
+ if ((cb->xflags & redir_f) == redir_f ||
+ (cb->xflags & dnat_f) == dnat_f)
+ *flags |= NF_NAT_RANGE_PROTO_RANDOM;
+}
+
+static void DNAT_fcheck(struct xt_fcheck_call *cb)
+{
+ struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
+
+ mr->rangesize = 1;
+
+ if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET)
+ xtables_error(PARAMETER_PROBLEM,
+ "Shifted portmap ranges not supported with this kernel");
+
+ __DNAT_fcheck(cb, &mr->range[0].flags);
+}
+
+static char *sprint_range(const struct nf_nat_range2 *r, int family)
+{
+ bool brackets = family == AF_INET6 &&
+ r->flags & NF_NAT_RANGE_PROTO_SPECIFIED;
+ static char buf[INET6_ADDRSTRLEN * 2 + 3 + 6 * 3];
+
+ buf[0] = '\0';
+
+ if (r->flags & NF_NAT_RANGE_MAP_IPS) {
+ if (brackets)
+ strcat(buf, "[");
+ inet_ntop(family, &r->min_addr,
+ buf + strlen(buf), INET6_ADDRSTRLEN);
+ if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) {
+ strcat(buf, "-");
+ inet_ntop(family, &r->max_addr,
+ buf + strlen(buf), INET6_ADDRSTRLEN);
+ }
+ if (brackets)
+ strcat(buf, "]");
+ }
+ if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
+ sprintf(buf + strlen(buf), ":%hu",
+ ntohs(r->min_proto.tcp.port));
+ if (r->max_proto.tcp.port != r->min_proto.tcp.port)
+ sprintf(buf + strlen(buf), "-%hu",
+ ntohs(r->max_proto.tcp.port));
+ if (r->flags & NF_NAT_RANGE_PROTO_OFFSET)
+ sprintf(buf + strlen(buf), "/%hu",
+ ntohs(r->base_proto.tcp.port));
+ }
+ return buf;
+}
+
+static void __NAT_print(const struct nf_nat_range2 *r, int family,
+ const char *rangeopt, const char *flag_pfx,
+ bool skip_colon)
+{
+ char *range_str = sprint_range(r, family);
+
+ if (strlen(range_str)) {
+ if (range_str[0] == ':' && skip_colon)
+ range_str++;
+ printf(" %s%s", rangeopt, range_str);
+ }
+ if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ printf(" %srandom", flag_pfx);
+ if (r->flags & NF_NAT_RANGE_PERSISTENT)
+ printf(" %spersistent", flag_pfx);
+}
+#define __DNAT_print(r, family) __NAT_print(r, family, "to:", "", false)
+#define __DNAT_save(r, family) __NAT_print(r, family, "--to-destination ", "--", false)
+#define __REDIRECT_print(r) __NAT_print(r, AF_INET, "redir ports ", "", true)
+#define __REDIRECT_save(r) __NAT_print(r, AF_INET, "--to-ports ", "--", true)
+
+static void DNAT_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data);
+
+ __DNAT_print(&range, AF_INET);
+}
+
+static void DNAT_save(const void *ip, const struct xt_entry_target *target)
+{
+ struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data);
+
+ __DNAT_save(&range, AF_INET);
+}
+
+static int
+__DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, int family)
+{
+ char *range_str = sprint_range(r, family);
+ const char *sep = " ";
+
+ /* shifted portmap ranges are not supported by nftables */
+ if (r->flags & NF_NAT_RANGE_PROTO_OFFSET)
+ return 0;
+
+ xt_xlate_add(xl, "dnat");
+ if (strlen(range_str))
+ xt_xlate_add(xl, " to %s", range_str);
+ if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) {
+ xt_xlate_add(xl, "%srandom", sep);
+ sep = ",";
+ }
+ if (r->flags & NF_NAT_RANGE_PERSISTENT) {
+ xt_xlate_add(xl, "%spersistent", sep);
+ sep = ",";
+ }
+ return 1;
+}
+
+static int DNAT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ struct nf_nat_range2 range =
+ RANGE2_INIT_FROM_IPV4_MRC(params->target->data);
+
+ return __DNAT_xlate(xl, &range, AF_INET);
+}
+
+static void DNAT_parse_v2(struct xt_option_call *cb)
+{
+ const struct ipt_entry *entry = cb->xt_entry;
+
+ __DNAT_parse(cb, entry->ip.proto, cb->data, AF_INET);
+}
+
+static void DNAT_fcheck_v2(struct xt_fcheck_call *cb)
+{
+ __DNAT_fcheck(cb, &((struct nf_nat_range2 *)cb->data)->flags);
+}
+
+static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ __DNAT_print((const void *)target->data, AF_INET);
+}
+
+static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target)
+{
+ __DNAT_save((const void *)target->data, AF_INET);
+}
+
+static int DNAT_xlate_v2(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET);
+}
+
+static void DNAT_parse6(struct xt_option_call *cb)
+{
+ const struct ip6t_entry *entry = cb->xt_entry;
+ struct nf_nat_range *range_v1 = (void *)cb->data;
+ struct nf_nat_range2 range = {};
+
+ memcpy(&range, range_v1, sizeof(*range_v1));
+ __DNAT_parse(cb, entry->ipv6.proto, &range, AF_INET6);
+ memcpy(range_v1, &range, sizeof(*range_v1));
+}
+
+static void DNAT_fcheck6(struct xt_fcheck_call *cb)
+{
+ struct nf_nat_range *range = (void *)cb->data;
+
+ if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
+ xtables_error(PARAMETER_PROBLEM,
+ "Shifted portmap ranges not supported with this kernel");
+
+ __DNAT_fcheck(cb, &range->flags);
+}
+
+static void DNAT_print6(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ struct nf_nat_range2 range = {};
+
+ memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range));
+ __DNAT_print(&range, AF_INET6);
+}
+
+static void DNAT_save6(const void *ip, const struct xt_entry_target *target)
+{
+ struct nf_nat_range2 range = {};
+
+ memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range));
+ __DNAT_save(&range, AF_INET6);
+}
+
+static int DNAT_xlate6(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ struct nf_nat_range2 range = {};
+
+ memcpy(&range, (const void *)params->target->data,
+ sizeof(struct nf_nat_range));
+ return __DNAT_xlate(xl, &range, AF_INET6);
+}
+
+static void DNAT_parse6_v2(struct xt_option_call *cb)
+{
+ const struct ip6t_entry *entry = cb->xt_entry;
+
+ __DNAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6);
+}
+
+static void DNAT_print6_v2(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ __DNAT_print((const void *)target->data, AF_INET6);
+}
+
+static void DNAT_save6_v2(const void *ip, const struct xt_entry_target *target)
+{
+ __DNAT_save((const void *)target->data, AF_INET6);
+}
+
+static int DNAT_xlate6_v2(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET6);
+}
+
+static int __REDIRECT_xlate(struct xt_xlate *xl,
+ const struct nf_nat_range2 *range)
+{
+ char *range_str = sprint_range(range, AF_INET);
+
+ xt_xlate_add(xl, "redirect");
+ if (strlen(range_str))
+ xt_xlate_add(xl, " to %s", range_str);
+ if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ xt_xlate_add(xl, " random");
+
+ return 1;
+}
+
+static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data);
+
+ __REDIRECT_print(&range);
+}
+
+static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
+{
+ struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data);
+
+ __REDIRECT_save(&range);
+}
+
+static int REDIRECT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ struct nf_nat_range2 range =
+ RANGE2_INIT_FROM_IPV4_MRC(params->target->data);
+
+ return __REDIRECT_xlate(xl, &range);
+}
+
+static void REDIRECT_print6(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ struct nf_nat_range2 range = {};
+
+ memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range));
+ __REDIRECT_print(&range);
+}
+
+static void REDIRECT_save6(const void *ip, const struct xt_entry_target *target)
+{
+ struct nf_nat_range2 range = {};
+
+ memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range));
+ __REDIRECT_save(&range);
+}
+
+static int REDIRECT_xlate6(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ struct nf_nat_range2 range = {};
+
+ memcpy(&range, (const void *)params->target->data,
+ sizeof(struct nf_nat_range));
+ return __REDIRECT_xlate(xl, &range);
+}
+
+static struct xtables_target dnat_tg_reg[] = {
+ {
+ .name = "DNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV4,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .help = DNAT_help,
+ .print = DNAT_print,
+ .save = DNAT_save,
+ .x6_parse = DNAT_parse,
+ .x6_fcheck = DNAT_fcheck,
+ .x6_options = DNAT_opts,
+ .xlate = DNAT_xlate,
+ },
+ {
+ .name = "REDIRECT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV4,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .help = REDIRECT_help,
+ .print = REDIRECT_print,
+ .save = REDIRECT_save,
+ .x6_parse = DNAT_parse,
+ .x6_fcheck = DNAT_fcheck,
+ .x6_options = REDIRECT_opts,
+ .xlate = REDIRECT_xlate,
+ },
+ {
+ .name = "DNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV6,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .help = DNAT_help,
+ .print = DNAT_print6,
+ .save = DNAT_save6,
+ .x6_parse = DNAT_parse6,
+ .x6_fcheck = DNAT_fcheck6,
+ .x6_options = DNAT_opts,
+ .xlate = DNAT_xlate6,
+ },
+ {
+ .name = "REDIRECT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV6,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .help = REDIRECT_help,
+ .print = REDIRECT_print6,
+ .save = REDIRECT_save6,
+ .x6_parse = DNAT_parse6,
+ .x6_fcheck = DNAT_fcheck6,
+ .x6_options = REDIRECT_opts,
+ .xlate = REDIRECT_xlate6,
+ },
+ {
+ .name = "DNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV4,
+ .revision = 2,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range2)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
+ .help = DNAT_help_v2,
+ .print = DNAT_print_v2,
+ .save = DNAT_save_v2,
+ .x6_parse = DNAT_parse_v2,
+ .x6_fcheck = DNAT_fcheck_v2,
+ .x6_options = DNAT_opts,
+ .xlate = DNAT_xlate_v2,
+ },
+ {
+ .name = "DNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV6,
+ .revision = 2,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range2)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
+ .help = DNAT_help_v2,
+ .print = DNAT_print6_v2,
+ .save = DNAT_save6_v2,
+ .x6_parse = DNAT_parse6_v2,
+ .x6_fcheck = DNAT_fcheck_v2,
+ .x6_options = DNAT_opts,
+ .xlate = DNAT_xlate6_v2,
+ },
+};
+
+void _init(void)
+{
+ xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg));
+}
diff --git a/extensions/libxt_DNAT.man b/extensions/libxt_DNAT.man
index 225274ff..af9a3f06 100644
--- a/extensions/libxt_DNAT.man
+++ b/extensions/libxt_DNAT.man
@@ -10,7 +10,7 @@ should be modified (and all future packets in this connection will
also be mangled), and rules should cease being examined. It takes the
following options:
.TP
-\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]]
+\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP[\fB/\fIbaseport\fP]]]
which can specify a single new destination IP address, an inclusive
range of IP addresses. Optionally a port range,
if the rule also specifies one of the following protocols:
@@ -18,17 +18,14 @@ 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.
+If \fBbaseport\fP is given, the difference of the original destination port and
+its value is used as offset into the mapping port range. This allows to create
+shifted portmap ranges and is available since kernel version 4.18.
+For a single port or \fIbaseport\fP, a service name as listed in
+\fB/etc/services\fP may be used.
.TP
\fB\-\-random\fP
-If option
-\fB\-\-random\fP
-is used then port mapping will be randomized (kernel >= 2.6.22).
+Randomize source port mapping (kernel >= 2.6.22).
.TP
\fB\-\-persistent\fP
Gives a client the same source-/destination-address for each connection.
diff --git a/extensions/libxt_DNAT.txlate b/extensions/libxt_DNAT.txlate
new file mode 100644
index 00000000..a6597656
--- /dev/null
+++ b/extensions/libxt_DNAT.txlate
@@ -0,0 +1,35 @@
+iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4
+nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4
+
+iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10
+nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10
+
+iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023
+nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023
+
+iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random
+nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random
+
+iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent
+nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234
+nft add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234-fec0::2000
+nft add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234-fec0::2000
+
+ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80
+nft add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80
+
+ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20
+nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20
+
+ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234-fec0::2000]:1-20
+nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234-fec0::2000]:1-20
+
+ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent
+nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent
+
+ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent
+nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent
diff --git a/extensions/libxt_LOG.man b/extensions/libxt_LOG.man
index 354edf4c..1d5071ba 100644
--- a/extensions/libxt_LOG.man
+++ b/extensions/libxt_LOG.man
@@ -30,3 +30,6 @@ Log options from the IP/IPv6 packet header.
.TP
\fB\-\-log\-uid\fP
Log the userid of the process which generated the packet.
+.TP
+\fB\-\-log\-macdecode\fP
+Log MAC addresses and protocol.
diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c
index b765af6c..1536563d 100644
--- a/extensions/libxt_MARK.c
+++ b/extensions/libxt_MARK.c
@@ -77,8 +77,7 @@ static void mark_tg_help(void)
" --set-mark value[/mask] Clear bits in mask and OR value into nfmark\n"
" --and-mark bits Binary AND the nfmark with bits\n"
" --or-mark bits Binary OR the nfmark with bits\n"
-" --xor-mark bits Binary XOR the nfmark with bits\n"
-"\n");
+" --xor-mark bits Binary XOR the nfmark with bits\n");
}
static void MARK_parse_v0(struct xt_option_call *cb)
diff --git a/extensions/libxt_MASQUERADE.man b/extensions/libxt_MASQUERADE.man
index 7746f473..26d91ddb 100644
--- a/extensions/libxt_MASQUERADE.man
+++ b/extensions/libxt_MASQUERADE.man
@@ -20,16 +20,10 @@ if the rule also specifies one of the following protocols:
\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP.
.TP
\fB\-\-random\fP
-Randomize source port mapping
-If option
-\fB\-\-random\fP
-is used then port mapping will be randomized (kernel >= 2.6.21).
+Randomize source port mapping (kernel >= 2.6.21).
Since kernel 5.0, \fB\-\-random\fP is identical to \fB\-\-random-fully\fP.
.TP
\fB\-\-random-fully\fP
-Full randomize source port mapping
-If option
-\fB\-\-random-fully\fP
-is used then port mapping will be fully randomized (kernel >= 3.13).
+Fully randomize source port mapping (kernel >= 3.13).
.TP
IPv6 support available since Linux kernels >= 3.7.
diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c
index 02a1b4aa..7a12e5ac 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;
}
}
@@ -69,7 +74,7 @@ static void NFLOG_check(struct xt_fcheck_call *cb)
if (cb->xflags & F_RANGE)
fprintf(stderr, "warn: --nflog-range has never worked and is no"
- " longer supported, please use --nflog-size insted\n");
+ " longer supported, please use --nflog-size instead\n");
if (cb->xflags & F_SIZE)
info->flags |= XT_NFLOG_F_COPY_LEN;
@@ -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..25f332ae 100644
--- a/extensions/libxt_NFLOG.t
+++ b/extensions/libxt_NFLOG.t
@@ -3,8 +3,10 @@
-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
+# `--nflog-range` is broken and only supported by xtables-legacy.
+# It has been superseded by `--nflog--group`.
+-j NFLOG --nflog-range 1;=;OK;LEGACY;NOMATCH
+-j NFLOG --nflog-range 4294967295;=;OK;LEGACY;NOMATCH
-j NFLOG --nflog-range 4294967296;;FAIL
-j NFLOG --nflog-range -1;;FAIL
-j NFLOG --nflog-size 0;=;OK
@@ -12,10 +14,8 @@
-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_REDIRECT.man b/extensions/libxt_REDIRECT.man
index 28d4d10b..1cbdb9ba 100644
--- a/extensions/libxt_REDIRECT.man
+++ b/extensions/libxt_REDIRECT.man
@@ -16,10 +16,9 @@ This specifies a destination port or range of ports to use: without
this, the destination port is never altered. This is only valid
if the rule also specifies one of the following protocols:
\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP.
+For a single port, a service name as listed in \fB/etc/services\fP may be used.
.TP
\fB\-\-random\fP
-If option
-\fB\-\-random\fP
-is used then port mapping will be randomized (kernel >= 2.6.22).
+Randomize source port mapping (kernel >= 2.6.22).
.TP
IPv6 support available starting Linux kernels >= 3.7.
diff --git a/extensions/libxt_REDIRECT.t b/extensions/libxt_REDIRECT.t
new file mode 100644
index 00000000..f607dd0a
--- /dev/null
+++ b/extensions/libxt_REDIRECT.t
@@ -0,0 +1,16 @@
+:PREROUTING,OUTPUT
+*nat
+-p tcp -j REDIRECT --to-ports 42;=;OK
+-p tcp -j REDIRECT --to-ports 0;=;OK
+-p tcp -j REDIRECT --to-ports 65535;=;OK
+-p tcp -j REDIRECT --to-ports 65536;;FAIL
+-p udp -j REDIRECT --to-ports 0-0;-p udp -j REDIRECT --to-ports 0;OK
+-p udp -j REDIRECT --to-ports 512-512;-p udp -j REDIRECT --to-ports 512;OK
+-p udp -j REDIRECT --to-ports 42-1234;=;OK
+-p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK
+-p tcp -j REDIRECT --to-ports 42-1234/567;;FAIL
+-p tcp -j REDIRECT --to-ports ssh;-p tcp -j REDIRECT --to-ports 22;OK
+-p tcp -j REDIRECT --to-ports ftp-data;-p tcp -j REDIRECT --to-ports 20;OK
+-p tcp -j REDIRECT --to-ports ftp-ssh;;FAIL
+-p tcp -j REDIRECT --to-ports 10-ssh;;FAIL
+-j REDIRECT --to-ports 42;;FAIL
diff --git a/extensions/libxt_REDIRECT.txlate b/extensions/libxt_REDIRECT.txlate
new file mode 100644
index 00000000..2c536495
--- /dev/null
+++ b/extensions/libxt_REDIRECT.txlate
@@ -0,0 +1,26 @@
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT
+nft add rule ip nat prerouting tcp dport 80 counter redirect
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0
+nft add rule ip nat prerouting tcp dport 80 counter redirect to :0
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080
+nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0-65535
+nft add rule ip nat prerouting tcp dport 80 counter redirect to :0-65535
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 10-22
+nft add rule ip nat prerouting tcp dport 80 counter redirect to :10-22
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random
+nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT
+nft add rule ip6 nat prerouting tcp dport 80 counter redirect
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080
+nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random
+nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random
diff --git a/extensions/libxt_SECMARK.c b/extensions/libxt_SECMARK.c
index 6ba86063..24249bd6 100644
--- a/extensions/libxt_SECMARK.c
+++ b/extensions/libxt_SECMARK.c
@@ -29,6 +29,13 @@ static const struct xt_option_entry SECMARK_opts[] = {
XTOPT_TABLEEND,
};
+static const struct xt_option_entry SECMARK_opts_v1[] = {
+ {.name = "selctx", .id = O_SELCTX, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND | XTOPT_PUT,
+ XTOPT_POINTER(struct xt_secmark_target_info_v1, secctx)},
+ XTOPT_TABLEEND,
+};
+
static void SECMARK_parse(struct xt_option_call *cb)
{
struct xt_secmark_target_info *info = cb->data;
@@ -37,15 +44,23 @@ static void SECMARK_parse(struct xt_option_call *cb)
info->mode = SECMARK_MODE_SEL;
}
-static void print_secmark(const struct xt_secmark_target_info *info)
+static void SECMARK_parse_v1(struct xt_option_call *cb)
+{
+ struct xt_secmark_target_info_v1 *info = cb->data;
+
+ xtables_option_parse(cb);
+ info->mode = SECMARK_MODE_SEL;
+}
+
+static void print_secmark(__u8 mode, const char *secctx)
{
- switch (info->mode) {
+ switch (mode) {
case SECMARK_MODE_SEL:
- printf("selctx %s", info->secctx);
+ printf("selctx %s", secctx);
break;
-
+
default:
- xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode);
+ xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", mode);
}
}
@@ -56,7 +71,17 @@ static void SECMARK_print(const void *ip, const struct xt_entry_target *target,
(struct xt_secmark_target_info*)(target)->data;
printf(" SECMARK ");
- print_secmark(info);
+ print_secmark(info->mode, info->secctx);
+}
+
+static void SECMARK_print_v1(const void *ip,
+ const struct xt_entry_target *target, int numeric)
+{
+ const struct xt_secmark_target_info_v1 *info =
+ (struct xt_secmark_target_info_v1 *)(target)->data;
+
+ printf(" SECMARK ");
+ print_secmark(info->mode, info->secctx);
}
static void SECMARK_save(const void *ip, const struct xt_entry_target *target)
@@ -65,24 +90,49 @@ static void SECMARK_save(const void *ip, const struct xt_entry_target *target)
(struct xt_secmark_target_info*)target->data;
printf(" --");
- print_secmark(info);
+ print_secmark(info->mode, info->secctx);
}
-static struct xtables_target secmark_target = {
- .family = NFPROTO_UNSPEC,
- .name = "SECMARK",
- .version = XTABLES_VERSION,
- .revision = 0,
- .size = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
- .help = SECMARK_help,
- .print = SECMARK_print,
- .save = SECMARK_save,
- .x6_parse = SECMARK_parse,
- .x6_options = SECMARK_opts,
+static void SECMARK_save_v1(const void *ip,
+ const struct xt_entry_target *target)
+{
+ const struct xt_secmark_target_info_v1 *info =
+ (struct xt_secmark_target_info_v1 *)target->data;
+
+ printf(" --");
+ print_secmark(info->mode, info->secctx);
+}
+
+static struct xtables_target secmark_tg_reg[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "SECMARK",
+ .version = XTABLES_VERSION,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
+ .help = SECMARK_help,
+ .print = SECMARK_print,
+ .save = SECMARK_save,
+ .x6_parse = SECMARK_parse,
+ .x6_options = SECMARK_opts,
+ },
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "SECMARK",
+ .version = XTABLES_VERSION,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct xt_secmark_target_info_v1)),
+ .userspacesize = XT_ALIGN(offsetof(struct xt_secmark_target_info_v1, secid)),
+ .help = SECMARK_help,
+ .print = SECMARK_print_v1,
+ .save = SECMARK_save_v1,
+ .x6_parse = SECMARK_parse_v1,
+ .x6_options = SECMARK_opts_v1,
+ }
};
void _init(void)
{
- xtables_register_target(&secmark_target);
+ xtables_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
}
diff --git a/extensions/libxt_SECMARK.t b/extensions/libxt_SECMARK.t
new file mode 100644
index 00000000..39d4c093
--- /dev/null
+++ b/extensions/libxt_SECMARK.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+*security
+-j SECMARK --selctx system_u:object_r:firewalld_exec_t:s0;=;OK
+-j SECMARK;;FAIL
diff --git a/extensions/libxt_SNAT.man b/extensions/libxt_SNAT.man
index 8cd0b80e..80a698a6 100644
--- a/extensions/libxt_SNAT.man
+++ b/extensions/libxt_SNAT.man
@@ -19,22 +19,12 @@ 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
-\fB\-\-random\fP
-is used then port mapping will be randomized through a hash-based algorithm (kernel >= 2.6.21).
+Randomize source port mapping through a hash-based algorithm (kernel >= 2.6.21).
.TP
\fB\-\-random-fully\fP
-If option
-\fB\-\-random-fully\fP
-is used then port mapping will be fully randomized through a PRNG (kernel >= 3.14).
+Fully randomize source port mapping through a PRNG (kernel >= 3.14).
.TP
\fB\-\-persistent\fP
Gives a client the same source-/destination-address for each connection.
diff --git a/extensions/libxt_TCPMSS.t b/extensions/libxt_TCPMSS.t
index 553a3452..fbfbfcf8 100644
--- a/extensions/libxt_TCPMSS.t
+++ b/extensions/libxt_TCPMSS.t
@@ -1,6 +1,6 @@
:FORWARD,OUTPUT,POSTROUTING
*mangle
-j TCPMSS;;FAIL
--p tcp -j TCPMSS --set-mss 42;;FAIL
+-p tcp -j TCPMSS --set-mss 42;;FAIL;LEGACY
-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --set-mss 42;=;OK
-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --clamp-mss-to-pmtu;=;OK
diff --git a/extensions/libxt_TCPMSS.txlate b/extensions/libxt_TCPMSS.txlate
index 6a64d2ce..3dbbad66 100644
--- a/extensions/libxt_TCPMSS.txlate
+++ b/extensions/libxt_TCPMSS.txlate
@@ -1,5 +1,5 @@
iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-nft add rule ip filter FORWARD tcp flags & (syn|rst) == syn counter tcp option maxseg size set rt mtu
+nft add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set rt mtu
iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 90
-nft add rule ip filter FORWARD tcp flags & (syn|rst) == syn counter tcp option maxseg size set 90
+nft add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set 90
diff --git a/extensions/libxt_connlimit.c b/extensions/libxt_connlimit.c
index a569f86a..118faea5 100644
--- a/extensions/libxt_connlimit.c
+++ b/extensions/libxt_connlimit.c
@@ -2,6 +2,8 @@
#include <netdb.h>
#include <string.h>
#include <xtables.h>
+#include <arpa/inet.h>
+
#include <linux/netfilter/xt_connlimit.h>
enum {
@@ -183,6 +185,51 @@ static void connlimit_save6(const void *ip, const struct xt_entry_match *match)
}
}
+static int connlimit_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_connlimit_info *info = (const void *)params->match->data;
+ static uint32_t connlimit_id;
+ char netmask[128] = {};
+ char addr[64] = {};
+ uint32_t mask;
+
+ switch (xt_xlate_get_family(xl)) {
+ case AF_INET:
+ mask = count_bits4(info->v4_mask);
+ if (mask != 32) {
+ struct in_addr *in = (struct in_addr *)&info->v4_mask;
+
+ inet_ntop(AF_INET, in, addr, sizeof(addr));
+ snprintf(netmask, sizeof(netmask), "and %s ", addr);
+ }
+ break;
+ case AF_INET6:
+ mask = count_bits6(info->v6_mask);
+ if (mask != 128) {
+ struct in6_addr *in6 = (struct in6_addr *)&info->v6_mask;
+
+ inet_ntop(AF_INET6, in6, addr, sizeof(addr));
+ snprintf(netmask, sizeof(netmask), "and %s ", addr);
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ xt_xlate_set_add(xl, "connlimit%u { type ipv4_addr; flags dynamic; }",
+ connlimit_id);
+ xt_xlate_rule_add(xl, "add @connlimit%u { %s %s %sct count %s%u }",
+ connlimit_id++,
+ xt_xlate_get_family(xl) == AF_INET ? "ip" : "ip6",
+ info->flags & XT_CONNLIMIT_DADDR ? "daddr" : "saddr",
+ netmask,
+ info->flags & XT_CONNLIMIT_INVERT ? "" : "over ",
+ info->limit);
+
+ return 1;
+}
+
static struct xtables_match connlimit_mt_reg[] = {
{
.name = "connlimit",
@@ -228,6 +275,7 @@ static struct xtables_match connlimit_mt_reg[] = {
.print = connlimit_print4,
.save = connlimit_save4,
.x6_options = connlimit_opts,
+ .xlate = connlimit_xlate,
},
{
.name = "connlimit",
@@ -243,6 +291,7 @@ static struct xtables_match connlimit_mt_reg[] = {
.print = connlimit_print6,
.save = connlimit_save6,
.x6_options = connlimit_opts,
+ .xlate = connlimit_xlate,
},
};
diff --git a/extensions/libxt_connlimit.txlate b/extensions/libxt_connlimit.txlate
new file mode 100644
index 00000000..758868c4
--- /dev/null
+++ b/extensions/libxt_connlimit.txlate
@@ -0,0 +1,15 @@
+iptables-translate -A INPUT -m connlimit --connlimit-above 2
+nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }
+nft add rule ip filter INPUT add @connlimit0 { ip saddr ct count over 2 } counter
+
+iptables-translate -A INPUT -m connlimit --connlimit-upto 2
+nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }
+nft add rule ip filter INPUT add @connlimit0 { ip saddr ct count 2 } counter
+
+iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-mask 24
+nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }
+nft add rule ip filter INPUT add @connlimit0 { ip saddr and 255.255.255.0 ct count 2 } counter
+
+iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-daddr
+nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }
+nft add rule ip filter INPUT add @connlimit0 { ip daddr ct count 2 } counter
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 7734509c..64018ce1 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -1148,10 +1148,13 @@ static void state_save(const void *ip, const struct xt_entry_match *match)
state_print_state(sinfo->statemask);
}
-static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask)
+static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask, int inverted)
{
const char *sep = "";
+ if (inverted)
+ xt_xlate_add(xl, "! ");
+
if (statemask & XT_CONNTRACK_STATE_INVALID) {
xt_xlate_add(xl, "%s%s", sep, "invalid");
sep = ",";
@@ -1180,17 +1183,20 @@ static int state_xlate(struct xt_xlate *xl,
const struct xt_conntrack_mtinfo3 *sinfo =
(const void *)params->match->data;
- xt_xlate_add(xl, "ct state %s", sinfo->invert_flags & XT_CONNTRACK_STATE ?
- "!= " : "");
- state_xlate_print(xl, sinfo->state_mask);
+ xt_xlate_add(xl, "ct state ");
+ state_xlate_print(xl, sinfo->state_mask,
+ sinfo->invert_flags & XT_CONNTRACK_STATE);
xt_xlate_add(xl, " ");
return 1;
}
-static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask)
+static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask, int inverted)
{
const char *sep = "";
+ if (inverted)
+ xt_xlate_add(xl, "! ");
+
if (statusmask & IPS_EXPECTED) {
xt_xlate_add(xl, "%s%s", sep, "expected");
sep = ",";
@@ -1256,19 +1262,17 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
sinfo->state_mask & XT_CONNTRACK_STATE_SNAT ? "snat" : "dnat");
space = " ";
} else {
- xt_xlate_add(xl, "%sct state %s", space,
- sinfo->invert_flags & XT_CONNTRACK_STATE ?
- "!= " : "");
- state_xlate_print(xl, sinfo->state_mask);
+ xt_xlate_add(xl, "%sct state ", space);
+ state_xlate_print(xl, sinfo->state_mask,
+ sinfo->invert_flags & XT_CONNTRACK_STATE);
space = " ";
}
}
if (sinfo->match_flags & XT_CONNTRACK_STATUS) {
- xt_xlate_add(xl, "%sct status %s", space,
- sinfo->invert_flags & XT_CONNTRACK_STATUS ?
- "!= " : "");
- status_xlate_print(xl, sinfo->status_mask);
+ xt_xlate_add(xl, "%sct status ", space);
+ status_xlate_print(xl, sinfo->status_mask,
+ sinfo->invert_flags & XT_CONNTRACK_STATUS);
space = " ";
}
diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate
index d374f8a0..45fba984 100644
--- a/extensions/libxt_conntrack.txlate
+++ b/extensions/libxt_conntrack.txlate
@@ -2,7 +2,10 @@ iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW,RELATED -j ACCE
nft add rule ip filter INPUT ct state new,related counter accept
ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW,RELATED -j ACCEPT
-nft add rule ip6 filter INPUT ct state != new,related counter accept
+nft add rule ip6 filter INPUT ct state ! new,related counter accept
+
+ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW -j ACCEPT
+nft add rule ip6 filter INPUT ct state ! new counter accept
iptables-translate -t filter -A INPUT -m conntrack --ctproto UDP -j ACCEPT
nft add rule ip filter INPUT ct original protocol 17 counter accept
@@ -32,7 +35,13 @@ iptables-translate -t filter -A INPUT -m conntrack --ctstatus EXPECTED -j ACCEPT
nft add rule ip filter INPUT ct status expected counter accept
iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED -j ACCEPT
-nft add rule ip filter INPUT ct status != confirmed counter accept
+nft add rule ip filter INPUT ct status ! confirmed counter accept
+
+iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED,ASSURED -j ACCEPT
+nft add rule ip filter INPUT ct status ! assured,confirmed counter accept
+
+iptables-translate -t filter -A INPUT -m conntrack --ctstatus CONFIRMED,ASSURED -j ACCEPT
+nft add rule ip filter INPUT ct status assured,confirmed counter accept
iptables-translate -t filter -A INPUT -m conntrack --ctexpire 3 -j ACCEPT
nft add rule ip filter INPUT ct expiration 3 counter accept
diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c
index aea3e20b..abd420fc 100644
--- a/extensions/libxt_dccp.c
+++ b/extensions/libxt_dccp.c
@@ -85,7 +85,7 @@ parse_dccp_types(const char *typestring)
uint16_t typemask = 0;
char *ptr, *buffer;
- buffer = strdup(typestring);
+ buffer = xtables_strdup(typestring);
for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
unsigned int i;
diff --git a/extensions/libxt_devgroup.man b/extensions/libxt_devgroup.man
index 4a66c9fe..480ee351 100644
--- a/extensions/libxt_devgroup.man
+++ b/extensions/libxt_devgroup.man
@@ -1,4 +1,4 @@
-Match device group of a packets incoming/outgoing interface.
+Match device group of a packet's incoming/outgoing interface.
.TP
[\fB!\fP] \fB\-\-src\-group\fP \fIname\fP
Match device group of incoming device
diff --git a/extensions/libxt_hashlimit.c b/extensions/libxt_hashlimit.c
index 7f1d2a40..3f3c4301 100644
--- a/extensions/libxt_hashlimit.c
+++ b/extensions/libxt_hashlimit.c
@@ -508,10 +508,7 @@ static void hashlimit_mt6_init(struct xt_entry_match *match)
static int parse_mode(uint32_t *mode, const char *option_arg)
{
char *tok;
- char *arg = strdup(option_arg);
-
- if (!arg)
- return -1;
+ char *arg = xtables_strdup(option_arg);
for (tok = strtok(arg, ",|");
tok;
diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t
index ccd0d1e6..206d9293 100644
--- a/extensions/libxt_hashlimit.t
+++ b/extensions/libxt_hashlimit.t
@@ -3,14 +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
-# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
--m hashlimit --hashlimit-above 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-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
-# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
--m hashlimit --hashlimit-upto 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-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_iprange.c b/extensions/libxt_iprange.c
index 8be24814..04ce7b36 100644
--- a/extensions/libxt_iprange.c
+++ b/extensions/libxt_iprange.c
@@ -73,11 +73,9 @@ iprange_parse_spec(const char *from, const char *to, union nf_inet_addr *range,
static void iprange_parse_range(const char *oarg, union nf_inet_addr *range,
uint8_t family, const char *optname)
{
- char *arg = strdup(oarg);
+ char *arg = xtables_strdup(oarg);
char *dash;
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
dash = strchr(arg, '-');
if (dash == NULL) {
iprange_parse_spec(arg, arg, range, family, optname);
diff --git a/extensions/libxt_mac.c b/extensions/libxt_mac.c
index b90eef20..55891b2b 100644
--- a/extensions/libxt_mac.c
+++ b/extensions/libxt_mac.c
@@ -42,10 +42,10 @@ mac_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_mac_info *info = (void *)match->data;
- printf(" MAC");
+ printf(" MAC ");
if (info->invert)
- printf(" !");
+ printf("! ");
xtables_print_mac(info->srcaddr);
}
diff --git a/extensions/libxt_multiport.c b/extensions/libxt_multiport.c
index 07ad4cfd..6b0c8190 100644
--- a/extensions/libxt_multiport.c
+++ b/extensions/libxt_multiport.c
@@ -87,8 +87,7 @@ parse_multi_ports(const char *portstring, uint16_t *ports, const char *proto)
char *buffer, *cp, *next;
unsigned int i;
- buffer = strdup(portstring);
- if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
+ buffer = xtables_strdup(portstring);
for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next,i++)
{
@@ -109,8 +108,7 @@ parse_multi_ports_v1(const char *portstring,
char *buffer, *cp, *next, *range;
unsigned int i;
- buffer = strdup(portstring);
- if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
+ buffer = xtables_strdup(portstring);
for (i=0; i<XT_MULTI_PORTS; i++)
multiinfo->pflags[i] = 0;
@@ -467,7 +465,8 @@ static void multiport_save6_v1(const void *ip_void,
}
static int __multiport_xlate(struct xt_xlate *xl,
- const struct xt_xlate_mt_params *params)
+ const struct xt_xlate_mt_params *params,
+ uint8_t proto)
{
const struct xt_multiport *multiinfo
= (const struct xt_multiport *)params->match->data;
@@ -481,7 +480,17 @@ static int __multiport_xlate(struct xt_xlate *xl,
xt_xlate_add(xl, " dport ");
break;
case XT_MULTIPORT_EITHER:
- return 0;
+ xt_xlate_add(xl, " sport . %s dport { ", proto_to_name(proto));
+ for (i = 0; i < multiinfo->count; i++) {
+ if (i != 0)
+ xt_xlate_add(xl, ", ");
+
+ xt_xlate_add(xl, "0-65535 . %u, %u . 0-65535",
+ multiinfo->ports[i], multiinfo->ports[i]);
+ }
+ xt_xlate_add(xl, " }");
+
+ return 1;
}
if (multiinfo->count > 1)
@@ -502,7 +511,7 @@ static int multiport_xlate(struct xt_xlate *xl,
uint8_t proto = ((const struct ipt_ip *)params->ip)->proto;
xt_xlate_add(xl, "%s", proto_to_name(proto));
- return __multiport_xlate(xl, params);
+ return __multiport_xlate(xl, params, proto);
}
static int multiport_xlate6(struct xt_xlate *xl,
@@ -511,11 +520,12 @@ static int multiport_xlate6(struct xt_xlate *xl,
uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto;
xt_xlate_add(xl, "%s", proto_to_name(proto));
- return __multiport_xlate(xl, params);
+ return __multiport_xlate(xl, params, proto);
}
static int __multiport_xlate_v1(struct xt_xlate *xl,
- const struct xt_xlate_mt_params *params)
+ const struct xt_xlate_mt_params *params,
+ uint8_t proto)
{
const struct xt_multiport_v1 *multiinfo =
(const struct xt_multiport_v1 *)params->match->data;
@@ -529,7 +539,17 @@ static int __multiport_xlate_v1(struct xt_xlate *xl,
xt_xlate_add(xl, " dport ");
break;
case XT_MULTIPORT_EITHER:
- return 0;
+ xt_xlate_add(xl, " sport . %s dport { ", proto_to_name(proto));
+ for (i = 0; i < multiinfo->count; i++) {
+ if (i != 0)
+ xt_xlate_add(xl, ", ");
+
+ xt_xlate_add(xl, "0-65535 . %u, %u . 0-65535",
+ multiinfo->ports[i], multiinfo->ports[i]);
+ }
+ xt_xlate_add(xl, " }");
+
+ return 1;
}
if (multiinfo->invert)
@@ -558,7 +578,7 @@ static int multiport_xlate_v1(struct xt_xlate *xl,
uint8_t proto = ((const struct ipt_ip *)params->ip)->proto;
xt_xlate_add(xl, "%s", proto_to_name(proto));
- return __multiport_xlate_v1(xl, params);
+ return __multiport_xlate_v1(xl, params, proto);
}
static int multiport_xlate6_v1(struct xt_xlate *xl,
@@ -567,7 +587,7 @@ static int multiport_xlate6_v1(struct xt_xlate *xl,
uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto;
xt_xlate_add(xl, "%s", proto_to_name(proto));
- return __multiport_xlate_v1(xl, params);
+ return __multiport_xlate_v1(xl, params, proto);
}
static struct xtables_match multiport_mt_reg[] = {
diff --git a/extensions/libxt_multiport.txlate b/extensions/libxt_multiport.txlate
index 752e7148..bced1b84 100644
--- a/extensions/libxt_multiport.txlate
+++ b/extensions/libxt_multiport.txlate
@@ -9,3 +9,6 @@ nft add rule ip filter INPUT ip protocol tcp tcp dport != 80-88 counter accept
iptables-translate -t filter -A INPUT -p tcp -m multiport --sports 50 -j ACCEPT
nft add rule ip filter INPUT ip protocol tcp tcp sport 50 counter accept
+
+iptables-translate -t filter -I INPUT -p tcp -m multiport --ports 10
+nft insert rule ip filter INPUT ip protocol tcp tcp sport . tcp dport { 0-65535 . 10, 10 . 0-65535 } counter
diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c
index 140de265..a4c5415f 100644
--- a/extensions/libxt_sctp.c
+++ b/extensions/libxt_sctp.c
@@ -69,7 +69,7 @@ parse_sctp_ports(const char *portstring,
char *buffer;
char *cp;
- buffer = strdup(portstring);
+ buffer = xtables_strdup(portstring);
DEBUGP("%s\n", portstring);
if ((cp = strchr(buffer, ':')) == NULL) {
ports[0] = ports[1] = xtables_parse_port(buffer, "sctp");
@@ -92,28 +92,29 @@ struct sctp_chunk_names {
const char *name;
unsigned int chunk_type;
const char *valid_flags;
+ const char *nftname;
};
/*'ALL' and 'NONE' will be treated specially. */
static const struct sctp_chunk_names sctp_chunk_names[]
-= { { .name = "DATA", .chunk_type = 0, .valid_flags = "----IUBE"},
- { .name = "INIT", .chunk_type = 1, .valid_flags = "--------"},
- { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------"},
- { .name = "SACK", .chunk_type = 3, .valid_flags = "--------"},
- { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------"},
- { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------"},
- { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T"},
- { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------"},
- { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------"},
- { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------"},
- { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------"},
- { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------"},
- { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------"},
- { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------"},
- { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T"},
- { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------"},
- { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------"},
- { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------"},
+= { { .name = "DATA", .chunk_type = 0, .valid_flags = "----IUBE", .nftname = "data" },
+ { .name = "INIT", .chunk_type = 1, .valid_flags = "--------", .nftname = "init" },
+ { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------", .nftname = "init-ack" },
+ { .name = "SACK", .chunk_type = 3, .valid_flags = "--------", .nftname = "sack" },
+ { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------", .nftname = "heartbeat" },
+ { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------", .nftname = "heartbeat-ack" },
+ { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T", .nftname = "abort" },
+ { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------", .nftname = "shutdown" },
+ { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------", .nftname = "shutdown-ack" },
+ { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------", .nftname = "error" },
+ { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------", .nftname = "cookie-echo" },
+ { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------", .nftname = "cookie-ack" },
+ { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------", .nftname = "ecne" },
+ { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------", .nftname = "cwr" },
+ { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T", .nftname = "shutdown-complete" },
+ { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------", .nftname = "asconf" },
+ { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------", .nftname = "asconf-ack" },
+ { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------", .nftname = "forward-tsn" },
};
static void
@@ -163,7 +164,7 @@ parse_sctp_chunk(struct xt_sctp_info *einfo,
int found = 0;
char *chunk_flags;
- buffer = strdup(chunks);
+ buffer = xtables_strdup(chunks);
DEBUGP("Buffer: %s\n", buffer);
SCTP_CHUNKMAP_RESET(einfo->chunkmap);
@@ -485,25 +486,63 @@ static void sctp_save(const void *ip, const struct xt_entry_match *match)
}
}
+static const char *sctp_xlate_chunk(struct xt_xlate *xl, const char *space,
+ const struct xt_sctp_info *einfo,
+ const struct sctp_chunk_names *scn)
+{
+ bool inv = einfo->invflags & XT_SCTP_CHUNK_TYPES;
+ const struct xt_sctp_flag_info *flag_info = NULL;
+ int i;
+
+ if (!scn->nftname)
+ return space;
+
+ if (!SCTP_CHUNKMAP_IS_SET(einfo->chunkmap, scn->chunk_type)) {
+ if (einfo->chunk_match_type != SCTP_CHUNK_MATCH_ONLY)
+ return space;
+
+ xt_xlate_add(xl, "%ssctp chunk %s %s", space,
+ scn->nftname, inv ? "exists" : "missing");
+ return " ";
+ }
+
+ for (i = 0; i < einfo->flag_count; i++) {
+ if (einfo->flag_info[i].chunktype == scn->chunk_type) {
+ flag_info = &einfo->flag_info[i];
+ break;
+ }
+ }
+
+ if (!flag_info) {
+ xt_xlate_add(xl, "%ssctp chunk %s %s", space,
+ scn->nftname, inv ? "missing" : "exists");
+ return " ";
+ }
+
+ xt_xlate_add(xl, "%ssctp chunk %s flags & 0x%x %s 0x%x", space,
+ scn->nftname, flag_info->flag_mask,
+ inv ? "!=" : "==", flag_info->flag);
+
+ return " ";
+}
+
static int sctp_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct xt_sctp_info *einfo =
(const struct xt_sctp_info *)params->match->data;
- char *space = "";
+ const char *space = "";
if (!einfo->flags)
return 0;
- xt_xlate_add(xl, "sctp ");
-
if (einfo->flags & XT_SCTP_SRC_PORTS) {
if (einfo->spts[0] != einfo->spts[1])
- xt_xlate_add(xl, "sport%s %u-%u",
+ xt_xlate_add(xl, "sctp sport%s %u-%u",
einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "",
einfo->spts[0], einfo->spts[1]);
else
- xt_xlate_add(xl, "sport%s %u",
+ xt_xlate_add(xl, "sctp sport%s %u",
einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "",
einfo->spts[0]);
space = " ";
@@ -511,13 +550,25 @@ static int sctp_xlate(struct xt_xlate *xl,
if (einfo->flags & XT_SCTP_DEST_PORTS) {
if (einfo->dpts[0] != einfo->dpts[1])
- xt_xlate_add(xl, "%sdport%s %u-%u", space,
+ xt_xlate_add(xl, "%ssctp dport%s %u-%u", space,
einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "",
einfo->dpts[0], einfo->dpts[1]);
else
- xt_xlate_add(xl, "%sdport%s %u", space,
+ xt_xlate_add(xl, "%ssctp dport%s %u", space,
einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "",
einfo->dpts[0]);
+ space = " ";
+ }
+
+ if (einfo->flags & XT_SCTP_CHUNK_TYPES) {
+ int i;
+
+ if (einfo->chunk_match_type == SCTP_CHUNK_MATCH_ANY)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(sctp_chunk_names); i++)
+ space = sctp_xlate_chunk(xl, space, einfo,
+ &sctp_chunk_names[i]);
}
return 1;
diff --git a/extensions/libxt_sctp.man b/extensions/libxt_sctp.man
index 3779d05a..3e5ffa09 100644
--- a/extensions/libxt_sctp.man
+++ b/extensions/libxt_sctp.man
@@ -8,6 +8,17 @@ This module matches Stream Control Transmission Protocol headers.
The flag letter in upper case indicates that the flag is to match if set,
in the lower case indicates to match if unset.
+Match types:
+.TP
+all
+Match if all given chunk types are present and flags match.
+.TP
+any
+Match if any of the given chunk types is present with given flags.
+.TP
+only
+Match if only the given chunk types are present with given flags and none are missing.
+
Chunk types: DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK FORWARD_TSN
chunk type available flags
diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate
index 72f4641a..bb817525 100644
--- a/extensions/libxt_sctp.txlate
+++ b/extensions/libxt_sctp.txlate
@@ -23,16 +23,22 @@ iptables-translate -A INPUT -p sctp ! --dport 50:56 -j ACCEPT
nft add rule ip filter INPUT sctp dport != 50-56 counter accept
iptables-translate -A INPUT -p sctp --dport 80 --sport 50 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50 dport 80 counter accept
+nft add rule ip filter INPUT sctp sport 50 sctp dport 80 counter accept
iptables-translate -A INPUT -p sctp --dport 80:100 --sport 50 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50 dport 80-100 counter accept
+nft add rule ip filter INPUT sctp sport 50 sctp dport 80-100 counter accept
iptables-translate -A INPUT -p sctp --dport 80 --sport 50:55 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50-55 dport 80 counter accept
+nft add rule ip filter INPUT sctp sport 50-55 sctp dport 80 counter accept
iptables-translate -A INPUT -p sctp ! --dport 80:100 --sport 50 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50 dport != 80-100 counter accept
+nft add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept
iptables-translate -A INPUT -p sctp --dport 80 ! --sport 50:55 -j ACCEPT
-nft add rule ip filter INPUT sctp sport != 50-55 dport 80 counter accept
+nft add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept
+
+iptables-translate -A INPUT -p sctp --chunk-types all INIT,DATA:iUbE,SACK,ABORT:T -j ACCEPT
+nft add rule ip filter INPUT sctp chunk data flags & 0xf == 0x5 sctp chunk init exists sctp chunk sack exists sctp chunk abort flags & 0x1 == 0x1 counter accept
+
+iptables-translate -A INPUT -p sctp --chunk-types only SHUTDOWN_COMPLETE -j ACCEPT
+nft add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing counter accept
diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h
index 41dfbd30..ad895a75 100644
--- a/extensions/libxt_set.h
+++ b/extensions/libxt_set.h
@@ -141,7 +141,7 @@ get_set_byname(const char *setname, struct xt_set_info *info)
static void
parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info)
{
- char *saved = strdup(opt_arg);
+ char *saved = xtables_strdup(opt_arg);
char *ptr, *tmp = saved;
int i = 0;
@@ -167,7 +167,7 @@ parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info)
static void
parse_dirs(const char *opt_arg, struct xt_set_info *info)
{
- char *saved = strdup(opt_arg);
+ char *saved = xtables_strdup(opt_arg);
char *ptr, *tmp = saved;
while (info->dim < IPSET_DIM_MAX && tmp != NULL) {
diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t
index 4313f7b7..56d6da2e 100644
--- a/extensions/libxt_standard.t
+++ b/extensions/libxt_standard.t
@@ -9,3 +9,15 @@
-j ACCEPT;=;OK
-j RETURN;=;OK
! -p 0 -j ACCEPT;=;FAIL
+-s 10.11.12.13/8;-s 10.0.0.0/8;OK
+-s 10.11.12.13/9;-s 10.0.0.0/9;OK
+-s 10.11.12.13/10;-s 10.0.0.0/10;OK
+-s 10.11.12.13/11;-s 10.0.0.0/11;OK
+-s 10.11.12.13/12;-s 10.0.0.0/12;OK
+-s 10.11.12.13/30;-s 10.11.12.12/30;OK
+-s 10.11.12.13/31;-s 10.11.12.12/31;OK
+-s 10.11.12.13/32;-s 10.11.12.13/32;OK
+-s 10.11.12.13/255.0.0.0;-s 10.0.0.0/8;OK
+-s 10.11.12.13/255.128.0.0;-s 10.0.0.0/9;OK
+-s 10.11.12.13/255.0.255.0;-s 10.0.12.0/255.0.255.0;OK
+-s 10.11.12.13/255.0.12.0;-s 10.0.12.0/255.0.12.0;OK
diff --git a/extensions/libxt_string.c b/extensions/libxt_string.c
index 7c6366cb..739a8e7f 100644
--- a/extensions/libxt_string.c
+++ b/extensions/libxt_string.c
@@ -81,7 +81,7 @@ parse_string(const char *s, struct xt_string_info *info)
{
/* xt_string does not need \0 at the end of the pattern */
if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) {
- strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
+ memcpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE);
return;
}
diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c
index 58f3c0a0..0b115cdd 100644
--- a/extensions/libxt_tcp.c
+++ b/extensions/libxt_tcp.c
@@ -43,7 +43,7 @@ parse_tcp_ports(const char *portstring, uint16_t *ports)
char *buffer;
char *cp;
- buffer = strdup(portstring);
+ buffer = xtables_strdup(portstring);
if ((cp = strchr(buffer, ':')) == NULL)
ports[0] = ports[1] = xtables_parse_port(buffer, "tcp");
else {
@@ -83,7 +83,7 @@ parse_tcp_flag(const char *flags)
char *ptr;
char *buffer;
- buffer = strdup(flags);
+ buffer = xtables_strdup(flags);
for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
unsigned int i;
@@ -381,7 +381,7 @@ static void print_tcp_xlate(struct xt_xlate *xl, uint8_t flags)
for (i = 0; (flags & tcp_flag_names_xlate[i].flag) == 0; i++);
if (have_flag)
- xt_xlate_add(xl, "|");
+ xt_xlate_add(xl, ",");
xt_xlate_add(xl, "%s", tcp_flag_names_xlate[i].name);
have_flag = 1;
@@ -435,11 +435,11 @@ static int tcp_xlate(struct xt_xlate *xl,
return 0;
if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) {
- xt_xlate_add(xl, "%stcp flags & (", space);
- print_tcp_xlate(xl, tcpinfo->flg_mask);
- xt_xlate_add(xl, ") %s ",
- tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!=": "==");
+ xt_xlate_add(xl, "%stcp flags %s", space,
+ tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!= ": "");
print_tcp_xlate(xl, tcpinfo->flg_cmp);
+ xt_xlate_add(xl, " / ");
+ print_tcp_xlate(xl, tcpinfo->flg_mask);
}
return 1;
diff --git a/extensions/libxt_tcp.txlate b/extensions/libxt_tcp.txlate
index bba63324..921d4af0 100644
--- a/extensions/libxt_tcp.txlate
+++ b/extensions/libxt_tcp.txlate
@@ -11,13 +11,13 @@ iptables-translate -I OUTPUT -p tcp --dport 1020:1023 --sport 53 -j ACCEPT
nft insert rule ip filter OUTPUT tcp sport 53 tcp dport 1020-1023 counter accept
iptables -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP
-nft add rule ip filter INPUT tcp flags & fin|ack == fin counter drop
+nft add rule ip filter INPUT tcp flags fin / fin,ack counter drop
iptables-translate -A INPUT -p tcp --syn -j ACCEPT
-nft add rule ip filter INPUT tcp flags & (fin|syn|rst|ack) == syn counter accept
+nft add rule ip filter INPUT tcp flags syn / fin,syn,rst,ack counter accept
iptables-translate -A INPUT -p tcp --syn --dport 80 -j ACCEPT
-nft add rule ip filter INPUT tcp dport 80 tcp flags & (fin|syn|rst|ack) == syn counter accept
+nft add rule ip filter INPUT tcp dport 80 tcp flags syn / fin,syn,rst,ack counter accept
iptables-translate -A INPUT -f -p tcp
nft add rule ip filter INPUT ip frag-off & 0x1fff != 0 ip protocol tcp counter
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/libipulog/libipulog.h b/include/libipulog/libipulog.h
deleted file mode 100644
index 3f4cc2c7..00000000
--- a/include/libipulog/libipulog.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _LIBIPULOG_H
-#define _LIBIPULOG_H
-
-/* libipulog.h,v 1.3 2001/05/21 19:15:16 laforge Exp */
-
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <asm/types.h>
-#include <linux/netlink.h>
-#include <net/if.h>
-#include <linux/netfilter_ipv4/ipt_ULOG.h>
-
-/* FIXME: glibc sucks */
-#ifndef MSG_TRUNC
-#define MSG_TRUNC 0x20
-#endif
-
-struct ipulog_handle;
-
-u_int32_t ipulog_group2gmask(u_int32_t group);
-
-struct ipulog_handle *ipulog_create_handle(u_int32_t gmask);
-
-void ipulog_destroy_handle(struct ipulog_handle *h);
-
-ssize_t ipulog_read(struct ipulog_handle *h,
- unsigned char *buf, size_t len, int timeout);
-
-ulog_packet_msg_t *ipulog_get_packet(struct ipulog_handle *h,
- const unsigned char *buf,
- size_t len);
-
-void ipulog_perror(const char *s);
-
-#endif /* _LIBULOG_H */
diff --git a/include/linux/netfilter/xt_SECMARK.h b/include/linux/netfilter/xt_SECMARK.h
index 989092bd..31760a28 100644
--- a/include/linux/netfilter/xt_SECMARK.h
+++ b/include/linux/netfilter/xt_SECMARK.h
@@ -19,4 +19,10 @@ struct xt_secmark_target_info {
char secctx[SECMARK_SECCTX_MAX];
};
+struct xt_secmark_target_info_v1 {
+ __u8 mode;
+ char secctx[SECMARK_SECCTX_MAX];
+ __u32 secid;
+};
+
#endif /*_XT_SECMARK_H_target */
diff --git a/include/xtables.h b/include/xtables.h
index df1eaee3..c2694b7b 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -453,6 +453,7 @@ extern void xtables_set_nfproto(uint8_t);
extern void *xtables_calloc(size_t, size_t);
extern void *xtables_malloc(size_t);
extern void *xtables_realloc(void *, size_t);
+char *xtables_strdup(const char *);
extern int xtables_insmod(const char *, const char *, bool);
extern int xtables_load_ko(const char *, bool);
@@ -592,8 +593,17 @@ static inline void xtables_print_mark_mask(unsigned int mark,
extern void init_extensions(void);
extern void init_extensions4(void);
extern void init_extensions6(void);
+ extern void init_extensionsa(void);
+ extern void init_extensionsb(void);
#else
# define _init __attribute__((constructor)) _INIT
+# define EMPTY_FUNC_DEF(x) static inline void x(void) {}
+ EMPTY_FUNC_DEF(init_extensions)
+ EMPTY_FUNC_DEF(init_extensions4)
+ EMPTY_FUNC_DEF(init_extensions6)
+ EMPTY_FUNC_DEF(init_extensionsa)
+ EMPTY_FUNC_DEF(init_extensionsb)
+# undef EMPTY_FUNC_DEF
#endif
extern const struct xtables_pprot xtables_chain_protos[];
@@ -632,9 +642,18 @@ extern const char *xtables_lmap_id2name(const struct xtables_lmap *, int);
struct xt_xlate *xt_xlate_alloc(int size);
void xt_xlate_free(struct xt_xlate *xl);
void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3)));
+#define xt_xlate_rule_add xt_xlate_add
+void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3)));
void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment);
const char *xt_xlate_get_comment(struct xt_xlate *xl);
+void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family);
+uint8_t xt_xlate_get_family(struct xt_xlate *xl);
const char *xt_xlate_get(struct xt_xlate *xl);
+#define xt_xlate_rule_get xt_xlate_get
+const char *xt_xlate_set_get(struct xt_xlate *xl);
+
+/* informed target lookups */
+void xtables_announce_chain(const char *name);
#ifdef XTABLES_INTERNAL
diff --git a/iptables-test.py b/iptables-test.py
index ca5efb1b..6acaa822 100755
--- a/iptables-test.py
+++ b/iptables-test.py
@@ -32,22 +32,26 @@ EXTENSIONS_PATH = "extensions"
LOGFILE="/tmp/iptables-test.log"
log_file = None
+STDOUT_IS_TTY = sys.stdout.isatty()
+STDERR_IS_TTY = sys.stderr.isatty()
-class Colors:
- HEADER = '\033[95m'
- BLUE = '\033[94m'
- GREEN = '\033[92m'
- YELLOW = '\033[93m'
- RED = '\033[91m'
- ENDC = '\033[0m'
+def maybe_colored(color, text, isatty):
+ terminal_sequences = {
+ 'green': '\033[92m',
+ 'red': '\033[91m',
+ }
+
+ return (
+ terminal_sequences[color] + text + '\033[0m' if isatty else text
+ )
def print_error(reason, filename=None, lineno=None):
'''
Prints an error with nice colors, indicating file and line number.
'''
- print(filename + ": " + Colors.RED + "ERROR" +
- Colors.ENDC + ": line %d (%s)" % (lineno, reason))
+ print(filename + ": " + maybe_colored('red', "ERROR", STDERR_IS_TTY) +
+ ": line %d (%s)" % (lineno, reason), file=sys.stderr)
def delete_rule(iptables, rule, filename, lineno):
@@ -69,9 +73,9 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
Executes an unit test. Returns the output of delete_rule().
Parameters:
- :param iptables: string with the iptables command to execute
+ :param iptables: string with the iptables command to execute
:param rule: string with iptables arguments for the rule to test
- :param rule_save: string to find the rule in the output of iptables -save
+ :param rule_save: string to find the rule in the output of iptables-save
:param res: expected result of the rule. Valid values: "OK", "FAIL"
:param filename: name of the file tested (used for print_error purposes)
:param lineno: line number being tested (used for print_error purposes)
@@ -80,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)
@@ -88,7 +92,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
# report failed test
#
if ret:
- if res == "OK":
+ if res != "FAIL":
reason = "cannot load: " + cmd
print_error(reason, filename, lineno)
return -1
@@ -103,28 +107,28 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
return -1
matching = 0
- splitted = iptables.split(" ")
- if len(splitted) == 2:
- if splitted[1] == '-4':
+ tokens = iptables.split(" ")
+ if len(tokens) == 2:
+ if tokens[1] == '-4':
command = IPTABLES_SAVE
- elif splitted[1] == '-6':
+ elif tokens[1] == '-6':
command = IP6TABLES_SAVE
- elif len(splitted) == 1:
- if splitted[0] == IPTABLES:
+ elif len(tokens) == 1:
+ if tokens[0] == IPTABLES:
command = IPTABLES_SAVE
- elif splitted[0] == IP6TABLES:
+ elif tokens[0] == IP6TABLES:
command = IP6TABLES_SAVE
- elif splitted[0] == ARPTABLES:
+ elif tokens[0] == ARPTABLES:
command = ARPTABLES_SAVE
- elif splitted[0] == EBTABLES:
+ elif tokens[0] == EBTABLES:
command = EBTABLES_SAVE
- command = EXECUTEABLE + " " + command
+ command = EXECUTABLE + " " + command
if netns:
command = "ip netns exec ____iptables-container-test " + command
- args = splitted[1:]
+ args = tokens[1:]
proc = subprocess.Popen(command, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -142,10 +146,20 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
# find the rule
matching = out.find(rule_save.encode('utf-8'))
if matching < 0:
- reason = "cannot find: " + iptables + " -I " + rule
- print_error(reason, filename, lineno)
- delete_rule(iptables, rule, filename, lineno)
- return -1
+ if res == "OK":
+ reason = "cannot find: " + iptables + " -I " + rule
+ print_error(reason, filename, lineno)
+ delete_rule(iptables, rule, filename, lineno)
+ return -1
+ else:
+ # do not report this error
+ return 0
+ else:
+ if res != "OK":
+ reason = "should not match: " + cmd
+ print_error(reason, filename, lineno)
+ delete_rule(iptables, rule, filename, lineno)
+ return -1
# Test "ip netns del NETNS" path with rules in place
if netns:
@@ -164,7 +178,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,
@@ -172,12 +186,41 @@ def execute_cmd(cmd, filename, lineno):
log_file.flush()
# generic check for segfaults
- if ret == -11:
+ if ret == -11:
reason = "command segfaults: " + cmd
print_error(reason, filename, lineno)
return ret
+def variant_res(res, variant, alt_res=None):
+ '''
+ Adjust expected result with given variant
+
+ If expected result is scoped to a variant, the other one yields a different
+ result. Therefore map @res to itself if given variant is current, use the
+ alternate result, @alt_res, if specified, invert @res otherwise.
+
+ :param res: expected result from test spec ("OK", "FAIL" or "NOMATCH")
+ :param variant: variant @res is scoped to by test spec ("NFT" or "LEGACY")
+ :param alt_res: optional expected result for the alternate variant.
+ '''
+ variant_executable = {
+ "NFT": "xtables-nft-multi",
+ "LEGACY": "xtables-legacy-multi"
+ }
+ res_inverse = {
+ "OK": "FAIL",
+ "FAIL": "OK",
+ "NOMATCH": "OK"
+ }
+
+ if variant_executable[variant] == EXECUTABLE:
+ return res
+ if alt_res is not None:
+ return alt_res
+ return res_inverse[res]
+
+
def run_test_file(filename, netns):
'''
Runs a test file
@@ -198,12 +241,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:
@@ -215,6 +258,7 @@ def run_test_file(filename, netns):
tests = 0
passed = 0
table = ""
+ chain_array = []
total_test_passed = True
if netns:
@@ -240,7 +284,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
@@ -249,8 +293,10 @@ def run_test_file(filename, netns):
continue
if len(chain_array) == 0:
- print("broken test, missing chain, leaving")
- sys.exit()
+ print_error("broken test, missing chain",
+ filename = filename, lineno = lineno)
+ total_test_passed = False
+ break
test_passed = True
tests += 1
@@ -268,6 +314,14 @@ def run_test_file(filename, netns):
rule_save = chain + " " + item[1]
res = item[2].rstrip()
+ if len(item) > 3:
+ variant = item[3].rstrip()
+ if len(item) > 4:
+ alt_res = item[4].rstrip()
+ else:
+ alt_res = None
+ res = variant_res(res, variant, alt_res)
+
ret = run_test(iptables, rule, rule_save,
res, filename, lineno + 1, netns)
@@ -282,7 +336,7 @@ def run_test_file(filename, netns):
if netns:
execute_cmd("ip netns del ____iptables-container-test", filename, 0)
if total_test_passed:
- print(filename + ": " + Colors.GREEN + "OK" + Colors.ENDC)
+ print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY))
f.close()
return tests, passed
@@ -304,6 +358,31 @@ def show_missing():
print('\n'.join(missing))
+def spawn_netns():
+ # prefer unshare module
+ try:
+ import unshare
+ unshare.unshare(unshare.CLONE_NEWNET)
+ return True
+ except:
+ pass
+
+ # sledgehammer style:
+ # - call ourselves prefixed by 'unshare -n' if found
+ # - pass extra --no-netns parameter to avoid another recursion
+ try:
+ import shutil
+
+ unshare = shutil.which("unshare")
+ if unshare is None:
+ return False
+
+ sys.argv.append("--no-netns")
+ os.execv(unshare, [unshare, "-n", sys.executable] + sys.argv)
+ except:
+ pass
+
+ return False
#
# main
@@ -323,6 +402,8 @@ def main():
help='Test iptables-over-nftables')
parser.add_argument('-N', '--netns', action='store_true',
help='Test netnamespace path')
+ parser.add_argument('--no-netns', action='store_true',
+ help='Do not run testsuite in own network namespace')
args = parser.parse_args()
#
@@ -332,15 +413,19 @@ 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")
+ print("You need to be root to run this, sorry", file=sys.stderr)
return
+ if not args.netns and not args.no_netns and not spawn_netns():
+ print("Cannot run in own namespace, connectivity might break",
+ file=sys.stderr)
+
if not args.host:
os.putenv("XTABLES_LIBDIR", os.path.abspath(EXTENSIONS_PATH))
os.putenv("PATH", "%s/iptables:%s" % (os.path.abspath(os.path.curdir),
@@ -355,7 +440,7 @@ def main():
try:
log_file = open(LOGFILE, 'w')
except IOError:
- print("Couldn't open log file %s" % LOGFILE)
+ print("Couldn't open log file %s" % LOGFILE, file=sys.stderr)
return
if args.filename:
@@ -366,13 +451,6 @@ def main():
if i.endswith('.t')]
file_list.sort()
- if not args.netns:
- try:
- import unshare
- unshare.unshare(unshare.CLONE_NEWNET)
- except:
- print("Cannot run in own namespace, connectivity might break")
-
for filename in file_list:
file_tests, file_passed = run_test_file(filename, args.netns)
if file_tests:
@@ -381,7 +459,8 @@ def main():
test_files += 1
print("%d test files, %d unit tests, %d passed" % (test_files, tests, passed))
+ return passed - tests
if __name__ == '__main__':
- main()
+ sys.exit(main())
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/ebtables-nft.8 b/iptables/ebtables-nft.8
index 1fa5ad93..d75aae24 100644
--- a/iptables/ebtables-nft.8
+++ b/iptables/ebtables-nft.8
@@ -44,12 +44,6 @@ ebtables \- Ethernet bridge frame table administration (nft-based)
.br
.BR "ebtables " [ -t " table ] " --init-table
.br
-.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-commit
-.br
-.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-init
-.br
-.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-save
-.br
.SH DESCRIPTION
.B ebtables
@@ -149,11 +143,9 @@ a table, the commands apply to the default filter table.
Only one command may be used on the command line at a time, except when
the commands
.BR -L " and " -Z
-are combined, the commands
+are combined or the commands
.BR -N " and " -P
-are combined, or when
-.B --atomic-file
-is used.
+are combined.
.TP
.B "-A, --append"
Append a rule to the end of the selected chain.
@@ -313,41 +305,14 @@ of the ebtables kernel table.
.TP
.B "--init-table"
Replace the current table data by the initial table data.
-.TP
-.B "--atomic-init"
-Copy the kernel's initial data of the table to the specified
-file. This can be used as the first action, after which rules are added
-to the file. The file can be specified using the
-.B --atomic-file
-command or through the
-.IR EBTABLES_ATOMIC_FILE " environment variable."
-.TP
-.B "--atomic-save"
-Copy the kernel's current data of the table to the specified
-file. This can be used as the first action, after which rules are added
-to the file. The file can be specified using the
-.B --atomic-file
-command or through the
-.IR EBTABLES_ATOMIC_FILE " environment variable."
-.TP
-.B "--atomic-commit"
-Replace the kernel table data with the data contained in the specified
-file. This is a useful command that allows you to load all your rules of a
-certain table into the kernel at once, saving the kernel a lot of precious
-time and allowing atomic updates of the tables. The file which contains
-the table data is constructed by using either the
-.B "--atomic-init"
-or the
-.B "--atomic-save"
-command to generate a starting file. After that, using the
-.B "--atomic-file"
-command when constructing rules or setting the
-.IR EBTABLES_ATOMIC_FILE " environment variable"
-allows you to extend the file and build the complete table before
-committing it to the kernel. This command can be very useful in boot scripts
-to populate the ebtables tables in a fast way.
.SS MISCELLANOUS COMMANDS
.TP
+.B "-v, --verbose"
+Verbose mode.
+For appending, insertion, deletion and replacement, this causes
+detailed information on the rule or rules to be printed. \fB\-v\fP may be
+specified multiple times to possibly emit more detailed debug statements.
+.TP
.B "-V, --version"
Show the version of the ebtables userspace program.
.TP
@@ -371,16 +336,6 @@ a target extension (see
.BR "TARGET EXTENSIONS" ")"
or a user-defined chain name.
.TP
-.B --atomic-file "\fIfile\fP"
-Let the command operate on the specified
-.IR file .
-The data of the table to
-operate on will be extracted from the file and the result of the operation
-will be saved back into the file. If specified, this option should come
-before the command specification. An alternative that should be preferred,
-is setting the
-.IR EBTABLES_ATOMIC_FILE " environment variable."
-.TP
.B -M, --modprobe "\fIprogram\fP"
When talking to the kernel, use this
.I program
@@ -1100,8 +1055,6 @@ arp message and the hardware address length in the arp header is 6 bytes.
.br
.SH FILES
.I /etc/ethertypes
-.SH ENVIRONMENT VARIABLES
-.I EBTABLES_ATOMIC_FILE
.SH MAILINGLISTS
.BR "" "See " http://netfilter.org/mailinglists.html
.SH BUGS
@@ -1109,7 +1062,12 @@ The version of ebtables this man page ships with does not support the
.B broute
table. Also there is no support for
.B string
-match. And finally, this list is probably not complete.
+match. Further, support for atomic-options
+.RB ( --atomic-file ", " --atomic-init ", " --atomic-save ", " --atomic-commit )
+has not been implemented, although
+.BR ebtables-save " and " ebtables-restore
+might replace them entirely given the inherent atomicity of nftables.
+Finally, this list is probably not complete.
.SH SEE ALSO
.BR xtables-nft "(8), " iptables "(8), " ip (8)
.PP
diff --git a/iptables/ip6tables-standalone.c b/iptables/ip6tables-standalone.c
index 105b83ba..7c8bb0c2 100644
--- a/iptables/ip6tables-standalone.c
+++ b/iptables/ip6tables-standalone.c
@@ -52,11 +52,8 @@ ip6tables_main(int argc, char *argv[])
ip6tables_globals.program_version);
exit(1);
}
-
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions6();
-#endif
ret = do_command6(argc, argv, &table, &handle, false);
if (ret) {
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index c95355b0..75984cc1 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -87,149 +87,13 @@ 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)",
.orig_opts = original_opts,
- .exit_err = ip6tables_exit_error,
.compat_rev = xtables_compatible_revision,
};
-static const unsigned int inverse_for_options[NUMBER_OF_OPT] =
-{
-/* -n */ 0,
-/* -s */ IP6T_INV_SRCIP,
-/* -d */ IP6T_INV_DSTIP,
-/* -p */ XT_INV_PROTO,
-/* -j */ 0,
-/* -v */ 0,
-/* -x */ 0,
-/* -i */ IP6T_INV_VIA_IN,
-/* -o */ IP6T_INV_VIA_OUT,
-/*--line*/ 0,
-/* -c */ 0,
-};
-
-#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.
@@ -239,113 +103,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
-set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
- int invert)
-{
- if (*options & option)
- xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
- opt2char(option));
- *options |= option;
-
- if (invert) {
- unsigned int i;
- for (i = 0; 1 << i != option; i++);
-
- if (!inverse_for_options[i])
- xtables_error(PARAMETER_PROBLEM,
- "cannot have ! before -%c",
- opt2char(option));
- *invflg |= inverse_for_options[i];
- }
-}
-
-
-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,
@@ -392,33 +149,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);
-
- 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);
- }
+ print_rule_details(num, &fw->counters, targname, fw->ipv6.proto,
+ fw->ipv6.flags, fw->ipv6.invflags, format);
- 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);
@@ -748,8 +482,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;
@@ -770,109 +514,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;
- }
- }
-}
-
-/* The ip6tables looks up the /etc/protocols. */
-static void print_proto(uint16_t proto, int invert)
-{
- if (proto) {
- unsigned int i;
- const char *invertstr = invert ? " !" : "";
-
- const struct protoent *pent = getprotobynumber(proto);
- if (pent) {
- printf("%s -p %s",
- invertstr, pent->p_name);
- return;
- }
-
- for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
- if (xtables_chain_protos[i].num == proto) {
- printf("%s -p %s",
- invertstr, xtables_chain_protos[i].name);
- return;
- }
-
- 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.
*/
@@ -890,19 +531,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
@@ -1057,10 +694,23 @@ 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,
+ };
struct ip6t_entry *e = NULL;
unsigned int nsaddrs = 0, ndaddrs = 0;
struct in6_addr *saddrs = NULL, *daddrs = NULL;
@@ -1068,452 +718,31 @@ int do_command6(int argc, char *argv[], char **table,
int verbose = 0;
int wait = 0;
- 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;
-
- /* 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,
- cs.invert);
- chain = optarg;
- break;
-
- case 'C':
- add_command(&command, CMD_CHECK, CMD_NONE,
- cs.invert);
- chain = optarg;
- break;
-
- case 'D':
- add_command(&command, CMD_DELETE, CMD_NONE,
- cs.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,
- cs.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,
- cs.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, cs.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, cs.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,
- cs.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,
- cs.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,
- cs.invert);
- chain = optarg;
- break;
-
- case 'X':
- add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
- cs.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,
- cs.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,
- cs.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, &cs.fw6.ipv6.invflags,
- cs.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
- && (cs.fw6.ipv6.invflags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM,
- "rule would never match protocol");
-
- 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);
- break;
-
- case 's':
- set_option(&cs.options, OPT_SOURCE, &cs.fw6.ipv6.invflags,
- cs.invert);
- shostnetworkmask = optarg;
- break;
-
- case 'd':
- set_option(&cs.options, OPT_DESTINATION, &cs.fw6.ipv6.invflags,
- cs.invert);
- dhostnetworkmask = optarg;
- break;
-
-#ifdef IP6T_F_GOTO
- case 'g':
- set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags,
- cs.invert);
- cs.fw6.ipv6.flags |= IP6T_F_GOTO;
- cs.jumpto = xt_parse_target(optarg);
- break;
-#endif
-
- case 'j':
- set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags,
- cs.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, &cs.fw6.ipv6.invflags,
- cs.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, &cs.fw6.ipv6.invflags,
- cs.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,
- &cs.fw6.ipv6.invflags, cs.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);
- break;
-
- case 'n':
- set_option(&cs.options, OPT_NUMERIC, &cs.fw6.ipv6.invflags,
- cs.invert);
- break;
-
- case 't':
- if (cs.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, &cs.fw6.ipv6.invflags,
- cs.invert);
- break;
-
- case 'V':
- if (cs.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, &cs.fw6.ipv6.invflags,
- cs.invert);
- break;
-
- case 'M':
- xtables_modprobe_program = optarg;
- break;
-
- case 'c':
-
- set_option(&cs.options, OPT_COUNTERS, &cs.fw6.ipv6.invflags,
- cs.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 (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- cs.invert = true;
- optarg[0] = '\0';
- continue;
- }
- fprintf(stderr, "Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (command_default(&cs, &ip6tables_globals) == 1)
- /*
- * If new options were loaded, we must retry
- * getopt immediately and not allow
- * cs.invert=false to be executed.
- */
- continue;
- break;
- }
- cs.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 (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- 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;
+ 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)
- xtables_lock_or_exit(wait, &wait_interval);
+ xtables_lock_or_exit(wait);
/* only allocate handle if we weren't called with a handle */
if (!*handle)
@@ -1533,26 +762,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",
@@ -1688,9 +897,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-apply b/iptables/iptables-apply
index 4683b1b4..3a7df5e3 100755
--- a/iptables/iptables-apply
+++ b/iptables/iptables-apply
@@ -231,7 +231,6 @@ case "$MODE" in
"$RUNCMD" &
CMD_PID=$!
( sleep "$TIMEOUT"; kill "$CMD_PID" 2>/dev/null; exit 0 ) &
- CMDTIMEOUT_PID=$!
if ! wait "$CMD_PID"; then
echo "failed."
echo "Error: unknown error running command: $RUNCMD" >&2
diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in
index b4b62f92..20216842 100644
--- a/iptables/iptables-restore.8.in
+++ b/iptables/iptables-restore.8.in
@@ -54,6 +54,7 @@ Only parse and construct the ruleset, but do not commit it.
.TP
\fB\-v\fP, \fB\-\-verbose\fP
Print additional debug info during ruleset processing.
+Specify multiple times to increase debug level.
.TP
\fB\-V\fP, \fB\-\-version\fP
Print the program version number.
@@ -66,13 +67,6 @@ the program will exit if the lock cannot be obtained. This option will
make the program wait (indefinitely or for optional \fIseconds\fP) until
the exclusive lock can be obtained.
.TP
-\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP
-Interval to wait per each iteration.
-When running latency sensitive applications, waiting for the xtables lock
-for extended durations may not be acceptable. This option will make each
-iteration take the amount of time specified. The default interval is
-1 second. This option only works with \fB\-w\fP.
-.TP
\fB\-M\fP, \fB\-\-modprobe\fP \fImodprobe_program\fP
Specify the path to the modprobe program. By default, iptables-restore will
inspect /proc/sys/kernel/modprobe to determine the executable's path.
diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c
index cc2c2b8b..4410a587 100644
--- a/iptables/iptables-restore.c
+++ b/iptables/iptables-restore.c
@@ -22,10 +22,6 @@
static int counters, verbose, noflush, wait;
-static struct timeval wait_interval = {
- .tv_sec = 1,
-};
-
/* Keeping track of external matches and targets. */
static const struct option options[] = {
{.name = "counters", .has_arg = 0, .val = 'c'},
@@ -51,7 +47,6 @@ static void print_usage(const char *name, const char *version)
" [ --help ]\n"
" [ --noflush ]\n"
" [ --wait=<seconds>\n"
- " [ --wait-interval=<usecs>\n"
" [ --table=<TABLE> ]\n"
" [ --modprobe=<command> ]\n", name);
}
@@ -101,6 +96,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
FILE *in;
int in_table = 0, testing = 0;
const char *tablename = NULL;
+ bool wait_interval_set = false;
line = 0;
lock = XT_LOCK_NOT_ACQUIRED;
@@ -114,10 +110,10 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
counters = 1;
break;
case 'v':
- verbose = 1;
+ verbose++;
break;
case 'V':
- printf("%s v%s (legacy)\n",
+ printf("%s v%s\n",
xt_params->program_name,
xt_params->program_version);
exit(0);
@@ -135,7 +131,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
wait = parse_wait_time(argc, argv);
break;
case 'W':
- parse_wait_interval(argc, argv, &wait_interval);
+ parse_wait_interval(argc, argv);
+ wait_interval_set = true;
break;
case 'M':
xtables_modprobe_program = optarg;
@@ -165,7 +162,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
}
else in = stdin;
- if (!wait_interval.tv_sec && !wait) {
+ if (wait_interval_set && !wait) {
fprintf(stderr, "Option --wait-interval requires option --wait\n");
exit(1);
}
@@ -203,7 +200,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
in_table = 0;
} else if ((buffer[0] == '*') && (!in_table)) {
/* Acquire a lock before we create a new table handle */
- lock = xtables_lock_or_exit(wait, &wait_interval);
+ lock = xtables_lock_or_exit(wait);
/* New table */
char *table;
@@ -311,17 +308,22 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
cb->ops->strerror(errno));
}
+ xtables_announce_chain(chain);
ret = 1;
} else if (in_table) {
char *pcnt = NULL;
char *bcnt = NULL;
char *parsestart = buffer;
+ int i;
add_argv(&av_store, argv[0], 0);
add_argv(&av_store, "-t", 0);
add_argv(&av_store, curtable, 0);
+ for (i = 0; !noflush && i < verbose; i++)
+ add_argv(&av_store, "-v", 0);
+
tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line);
if (counters && pcnt && bcnt) {
add_argv(&av_store, "--set-counters", 0);
@@ -382,10 +384,8 @@ iptables_restore_main(int argc, char *argv[])
iptables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
-#endif
ret = ip46tables_restore_main(&ipt_restore_cb, argc, argv);
@@ -416,10 +416,8 @@ ip6tables_restore_main(int argc, char *argv[])
ip6tables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions6();
-#endif
ret = ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index 4efd6667..a8dded63 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);
@@ -227,10 +227,8 @@ iptables_save_main(int argc, char *argv[])
iptables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
-#endif
ret = do_iptables_save(&ipt_save_cb, argc, argv);
@@ -273,10 +271,8 @@ ip6tables_save_main(int argc, char *argv[])
ip6tables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions6();
-#endif
ret = do_iptables_save(&ip6t_save_cb, argc, argv);
diff --git a/iptables/iptables-standalone.c b/iptables/iptables-standalone.c
index 3c8af60d..4662ba47 100644
--- a/iptables/iptables-standalone.c
+++ b/iptables/iptables-standalone.c
@@ -56,10 +56,8 @@ iptables_main(int argc, char *argv[])
iptables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
-#endif
ret = do_command4(argc, argv, &table, &handle, false);
if (ret) {
diff --git a/iptables/iptables-xml.c b/iptables/iptables-xml.c
index 98d03dda..6cf059fb 100644
--- a/iptables/iptables-xml.c
+++ b/iptables/iptables-xml.c
@@ -213,8 +213,8 @@ saveChain(char *chain, char *policy, struct xt_counters *ctr)
"%s: line %u chain name invalid\n",
prog_name, line);
- chains[nextChain].chain = strdup(chain);
- chains[nextChain].policy = strdup(policy);
+ chains[nextChain].chain = xtables_strdup(chain);
+ chains[nextChain].policy = xtables_strdup(policy);
chains[nextChain].count = *ctr;
chains[nextChain].created = 0;
nextChain++;
diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in
index 999cf339..627ff0e4 100644
--- a/iptables/iptables.8.in
+++ b/iptables/iptables.8.in
@@ -25,10 +25,10 @@
.SH NAME
iptables/ip6tables \(em administration tool for IPv4/IPv6 packet filtering and NAT
.SH SYNOPSIS
-\fBiptables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP}
+\fBiptables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP|\fB-V\fP}
\fIchain\fP \fIrule-specification\fP
.P
-\fBip6tables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP}
+\fBip6tables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP|\fB-V\fP}
\fIchain rule-specification\fP
.PP
\fBiptables\fP [\fB\-t\fP \fItable\fP] \fB\-I\fP \fIchain\fP [\fIrulenum\fP] \fIrule-specification\fP
@@ -220,11 +220,11 @@ Create a new user-defined chain by the given name. There must be no
target of that name already.
.TP
\fB\-X\fP, \fB\-\-delete\-chain\fP [\fIchain\fP]
-Delete the optional user-defined chain specified. There must be no references
+Delete the chain specified. There must be no references
to the chain. If there are, you must delete or replace the referring rules
before the chain can be deleted. The chain must be empty, i.e. not contain
-any rules. If no argument is given, it will attempt to delete every
-non-builtin chain in the table.
+any rules. If no argument is given, it will delete all empty chains in the
+table. Empty builtin chains can only be deleted with \fBiptables-nft\fP.
.TP
\fB\-P\fP, \fB\-\-policy\fP \fIchain target\fP
Set the policy for the built-in (non-user-defined) chain to the given target.
@@ -360,7 +360,14 @@ byte counters are also listed, with the suffix 'K', 'M' or 'G' for
the \fB\-x\fP flag to change this).
For appending, insertion, deletion and replacement, this causes
detailed information on the rule or rules to be printed. \fB\-v\fP may be
-specified multiple times to possibly emit more detailed debug statements.
+specified multiple times to possibly emit more detailed debug statements:
+Specified twice, \fBiptables-legacy\fP will dump table info and entries in
+libiptc, \fBiptables-nft\fP dumps rules in netlink (VM code) presentation.
+Specified three times, \fBiptables-nft\fP will also dump any netlink messages
+sent to kernel.
+.TP
+\fB\-V\fP, \fB\-\-version\fP
+Show program version and the kernel API used.
.TP
\fB\-w\fP, \fB\-\-wait\fP [\fIseconds\fP]
Wait for the xtables lock.
@@ -370,13 +377,6 @@ the program will exit if the lock cannot be obtained. This option will
make the program wait (indefinitely or for optional \fIseconds\fP) until
the exclusive lock can be obtained.
.TP
-\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP
-Interval to wait per each iteration.
-When running latency sensitive applications, waiting for the xtables lock
-for extended durations may not be acceptable. This option will make each
-iteration take the amount of time specified. The default interval is
-1 second. This option only works with \fB\-w\fP.
-.TP
\fB\-n\fP, \fB\-\-numeric\fP
Numeric output.
IP addresses and port numbers will be printed in numeric format.
diff --git a/iptables/iptables.c b/iptables/iptables.c
index 7d618311..e5207ba1 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -84,150 +84,13 @@ 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)",
.orig_opts = original_opts,
- .exit_err = iptables_exit_error,
.compat_rev = xtables_compatible_revision,
};
-static const int inverse_for_options[NUMBER_OF_OPT] =
-{
-/* -n */ 0,
-/* -s */ IPT_INV_SRCIP,
-/* -d */ IPT_INV_DSTIP,
-/* -p */ XT_INV_PROTO,
-/* -j */ 0,
-/* -v */ 0,
-/* -x */ 0,
-/* -i */ IPT_INV_VIA_IN,
-/* -o */ IPT_INV_VIA_OUT,
-/*--line*/ 0,
-/* -c */ 0,
-/* -f */ IPT_INV_FRAG,
-};
-
-#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.
@@ -239,102 +102,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
-set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
- int invert)
-{
- if (*options & option)
- xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
- opt2char(option));
- *options |= option;
-
- if (invert) {
- unsigned int i;
- for (i = 0; 1 << i != option; i++);
-
- if (!inverse_for_options[i])
- xtables_error(PARAMETER_PROBLEM,
- "cannot have ! before -%c",
- opt2char(option));
- *invflg |= inverse_for_options[i];
- }
-}
-
-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,
@@ -373,7 +140,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);
@@ -382,35 +148,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);
@@ -739,8 +481,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;
@@ -761,29 +513,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) {
- unsigned int i;
- const char *invertstr = invert ? " !" : "";
-
- const struct protoent *pent = getprotobynumber(proto);
- if (pent) {
- printf("%s -p %s", invertstr, pent->p_name);
- return;
- }
-
- for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
- if (xtables_chain_protos[i].num == proto) {
- printf("%s -p %s",
- invertstr, xtables_chain_protos[i].name);
- return;
- }
-
- printf("%s -p %u", invertstr, proto);
- }
-}
-
#define IP_PARTS_NATIVE(n) \
(unsigned int)((n)>>24)&0xFF, \
(unsigned int)((n)>>16)&0xFF, \
@@ -792,93 +521,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.
*/
@@ -896,23 +538,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)
@@ -1053,455 +688,54 @@ 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,
+ };
struct ipt_entry *e = NULL;
unsigned int nsaddrs = 0, ndaddrs = 0;
struct in_addr *saddrs = NULL, *smasks = NULL;
struct in_addr *daddrs = NULL, *dmasks = NULL;
- 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;
-
- /* 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,
- cs.invert);
- chain = optarg;
- break;
-
- case 'C':
- add_command(&command, CMD_CHECK, CMD_NONE,
- cs.invert);
- chain = optarg;
- break;
-
- case 'D':
- add_command(&command, CMD_DELETE, CMD_NONE,
- cs.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,
- cs.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,
- cs.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, cs.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, cs.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,
- cs.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,
- cs.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,
- cs.invert);
- chain = optarg;
- break;
-
- case 'X':
- add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
- cs.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,
- cs.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,
- cs.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, &cs.fw.ip.invflags,
- cs.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
- && (cs.fw.ip.invflags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM,
- "rule would never match protocol");
- break;
-
- case 's':
- set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags,
- cs.invert);
- shostnetworkmask = optarg;
- break;
-
- case 'd':
- set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags,
- cs.invert);
- dhostnetworkmask = optarg;
- break;
-
-#ifdef IPT_F_GOTO
- case 'g':
- set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags,
- cs.invert);
- cs.fw.ip.flags |= IPT_F_GOTO;
- cs.jumpto = xt_parse_target(optarg);
- break;
-#endif
-
- case 'j':
- set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags,
- cs.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, &cs.fw.ip.invflags,
- cs.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, &cs.fw.ip.invflags,
- cs.invert);
- xtables_parse_interface(optarg,
- cs.fw.ip.outiface,
- cs.fw.ip.outiface_mask);
- break;
-
- case 'f':
- set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags,
- cs.invert);
- cs.fw.ip.flags |= IPT_F_FRAG;
- break;
-
- case 'v':
- if (!verbose)
- set_option(&cs.options, OPT_VERBOSE,
- &cs.fw.ip.invflags, cs.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);
- break;
-
- case 'n':
- set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags,
- cs.invert);
- break;
-
- case 't':
- if (cs.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, &cs.fw.ip.invflags,
- cs.invert);
- break;
-
- case 'V':
- if (cs.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, &cs.fw.ip.invflags,
- cs.invert);
- break;
-
- case 'M':
- xtables_modprobe_program = optarg;
- break;
-
- case 'c':
-
- set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags,
- cs.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 (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- cs.invert = true;
- optarg[0] = '\0';
- continue;
- }
- fprintf(stderr, "Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (command_default(&cs, &iptables_globals) == 1)
- /* cf. ip6tables.c */
- continue;
- break;
- }
- cs.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 (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- 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;
+ 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)
- xtables_lock_or_exit(wait, &wait_interval);
+ xtables_lock_or_exit(wait);
/* only allocate handle if we weren't called with a handle */
if (!*handle)
@@ -1521,26 +755,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",
@@ -1678,9 +892,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 c82ffdc9..e6e4d2d8 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -25,94 +25,8 @@
#include <linux/netfilter/nf_tables.h>
#include "nft-shared.h"
-#include "nft-arp.h"
#include "nft.h"
-
-/* a few names */
-char *arp_opcodes[] =
-{
- "Request",
- "Reply",
- "Request_Reverse",
- "Reply_Reverse",
- "DRARP_Request",
- "DRARP_Reply",
- "DRARP_Error",
- "InARP_Request",
- "ARP_NAK",
-};
-
-static char *
-addr_to_dotted(const struct in_addr *addrp)
-{
- static char buf[20];
- const unsigned char *bytep;
-
- bytep = (const unsigned char *) &(addrp->s_addr);
- sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
- return buf;
-}
-
-static char *
-addr_to_host(const struct in_addr *addr)
-{
- struct hostent *host;
-
- if ((host = gethostbyaddr((char *) addr,
- sizeof(struct in_addr), AF_INET)) != NULL)
- return (char *) host->h_name;
-
- return (char *) NULL;
-}
-
-static char *
-addr_to_network(const struct in_addr *addr)
-{
- struct netent *net;
-
- if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
- return (char *) net->n_name;
-
- return (char *) NULL;
-}
-
-static char *
-addr_to_anyname(const struct in_addr *addr)
-{
- char *name;
-
- if ((name = addr_to_host(addr)) != NULL ||
- (name = addr_to_network(addr)) != NULL)
- return name;
-
- return addr_to_dotted(addr);
-}
-
-static char *
-mask_to_dotted(const struct in_addr *mask)
-{
- int i;
- static char buf[22];
- u_int32_t maskaddr, bits;
-
- maskaddr = ntohl(mask->s_addr);
-
- if (maskaddr == 0xFFFFFFFFL)
- /* we don't want to see "/32" */
- return "";
-
- i = 32;
- bits = 0xFFFFFFFEL;
- while (--i >= 0 && maskaddr != bits)
- bits <<= 1;
- if (i >= 0)
- sprintf(buf, "/%d", i);
- else
- /* mask was not a decent combination of 1's and 0's */
- snprintf(buf, sizeof(buf), "/%s", addr_to_dotted(mask));
-
- return buf;
-}
+#include "xshared.h"
static bool need_devaddr(struct arpt_devaddr_info *info)
{
@@ -126,59 +40,65 @@ static bool need_devaddr(struct arpt_devaddr_info *info)
return false;
}
-static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
+static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct arpt_entry *fw = &cs->arp;
uint32_t op;
int ret = 0;
if (fw->arp.iniface[0] != '\0') {
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN);
- add_iniface(r, fw->arp.iniface, op);
+ add_iniface(h, r, fw->arp.iniface, op);
}
if (fw->arp.outiface[0] != '\0') {
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT);
- add_outiface(r, fw->arp.outiface, op);
+ add_outiface(h, r, fw->arp.outiface, op);
}
if (fw->arp.arhrd != 0 ||
fw->arp.invflags & IPT_INV_ARPHRD) {
+ uint8_t reg;
+
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD);
- add_payload(r, offsetof(struct arphdr, ar_hrd), 2,
- NFT_PAYLOAD_NETWORK_HEADER);
- add_cmp_u16(r, fw->arp.arhrd, op);
+ add_payload(h, r, offsetof(struct arphdr, ar_hrd), 2,
+ NFT_PAYLOAD_NETWORK_HEADER, &reg);
+ add_cmp_u16(r, fw->arp.arhrd, op, reg);
}
if (fw->arp.arpro != 0 ||
fw->arp.invflags & IPT_INV_PROTO) {
+ uint8_t reg;
+
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO);
- add_payload(r, offsetof(struct arphdr, ar_pro), 2,
- NFT_PAYLOAD_NETWORK_HEADER);
- add_cmp_u16(r, fw->arp.arpro, op);
+ add_payload(h, r, offsetof(struct arphdr, ar_pro), 2,
+ NFT_PAYLOAD_NETWORK_HEADER, &reg);
+ add_cmp_u16(r, fw->arp.arpro, op, reg);
}
if (fw->arp.arhln != 0 ||
fw->arp.invflags & IPT_INV_ARPHLN) {
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN);
- add_proto(r, offsetof(struct arphdr, ar_hln), 1,
+ add_proto(h, r, offsetof(struct arphdr, ar_hln), 1,
fw->arp.arhln, op);
}
- add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
+ add_proto(h, r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
if (fw->arp.arpop != 0 ||
fw->arp.invflags & IPT_INV_ARPOP) {
+ uint8_t reg;
+
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP);
- add_payload(r, offsetof(struct arphdr, ar_op), 2,
- NFT_PAYLOAD_NETWORK_HEADER);
- add_cmp_u16(r, fw->arp.arpop, op);
+ add_payload(h, r, offsetof(struct arphdr, ar_op), 2,
+ NFT_PAYLOAD_NETWORK_HEADER, &reg);
+ add_cmp_u16(r, fw->arp.arpop, op, reg);
}
if (need_devaddr(&fw->arp.src_devaddr)) {
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
sizeof(struct arphdr),
&fw->arp.src_devaddr.addr,
&fw->arp.src_devaddr.mask,
@@ -190,7 +110,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
fw->arp.smsk.s_addr != 0 ||
fw->arp.invflags & IPT_INV_SRCIP) {
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
sizeof(struct arphdr) + fw->arp.arhln,
&fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
sizeof(struct in_addr), op);
@@ -199,7 +119,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (need_devaddr(&fw->arp.tgt_devaddr)) {
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
&fw->arp.tgt_devaddr.addr,
&fw->arp.tgt_devaddr.mask,
@@ -210,7 +130,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
fw->arp.tmsk.s_addr != 0 ||
fw->arp.invflags & IPT_INV_DSTIP) {
op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
&fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
sizeof(struct in_addr), op);
@@ -241,27 +161,18 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
}
static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data)
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct arpt_entry *fw = &cs->arp;
uint8_t flags = 0;
- parse_meta(e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask,
+ parse_meta(ctx, e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask,
fw->arp.outiface, fw->arp.outiface_mask,
&flags);
fw->arp.invflags |= flags;
}
-static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
-{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-}
-
static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
{
mask->s_addr = ctx->bitwise.mask[0];
@@ -293,9 +204,9 @@ static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx,
}
static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct arpt_entry *fw = &cs->arp;
struct in_addr addr;
uint16_t ar_hrd, ar_pro, ar_op;
@@ -380,11 +291,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);
@@ -395,7 +305,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);
}
}
@@ -403,7 +313,6 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
unsigned int format)
{
const struct arpt_entry *fw = &cs->arp;
- char buf[BUFSIZ];
char iface[IFNAMSIZ+2];
const char *sep = "";
int print_iface = 0;
@@ -450,15 +359,10 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
}
if (fw->arp.smsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCIP
- ? "! " : "");
- if (format & FMT_NUMERIC)
- sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src)));
- else
- sprintf(buf, "%s", addr_to_anyname(&(fw->arp.src)));
- strncat(buf, mask_to_dotted(&(fw->arp.smsk)),
- sizeof(buf) - strlen(buf) - 1);
- printf("-s %s", buf);
+ printf("%s%s-s %s", sep,
+ fw->arp.invflags & IPT_INV_SRCIP ? "! " : "",
+ ipv4_addr_to_string(&fw->arp.src,
+ &fw->arp.smsk, format));
sep = " ";
}
@@ -476,15 +380,10 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
after_devsrc:
if (fw->arp.tmsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & IPT_INV_DSTIP
- ? "! " : "");
- if (format & FMT_NUMERIC)
- sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt)));
- else
- sprintf(buf, "%s", addr_to_anyname(&(fw->arp.tgt)));
- strncat(buf, mask_to_dotted(&(fw->arp.tmsk)),
- sizeof(buf) - strlen(buf) - 1);
- printf("-d %s", buf);
+ printf("%s%s-d %s", sep,
+ fw->arp.invflags & IPT_INV_DSTIP ? "! " : "",
+ ipv4_addr_to_string(&fw->arp.tgt,
+ &fw->arp.tmsk, format));
sep = " ";
}
@@ -516,7 +415,7 @@ after_devdst:
printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP
? "! " : "");
- if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC))
+ if (tmp <= ARP_NUMOPCODES && !(format & FMT_NUMERIC))
printf("--opcode %s", arp_opcodes[tmp-1]);
else
printf("--opcode %d", tmp);
@@ -556,12 +455,11 @@ after_devdst:
}
static void
-nft_arp_save_rule(const void *data, unsigned int format)
+nft_arp_save_rule(const struct iptables_command_state *cs, unsigned int format)
{
- const struct iptables_command_state *cs = data;
-
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);
@@ -595,11 +493,11 @@ nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r,
nft_clear_iptables_command_state(&cs);
}
-static bool nft_arp_is_same(const void *data_a,
- const void *data_b)
+static bool nft_arp_is_same(const struct iptables_command_state *cs_a,
+ const struct iptables_command_state *cs_b)
{
- const struct arpt_entry *a = data_a;
- const struct arpt_entry *b = data_b;
+ const struct arpt_entry *a = &cs_a->arp;
+ const struct arpt_entry *b = &cs_b->arp;
if (a->arp.src.s_addr != b->arp.src.s_addr
|| a->arp.tgt.s_addr != b->arp.tgt.s_addr
@@ -629,19 +527,270 @@ 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 < ARP_NUMOPCODES; i++)
+ if (!strcasecmp(arp_opcodes[i],
+ args->arp_opcode))
+ break;
+ if (i == ARP_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,
.print_payload = NULL,
.parse_meta = nft_arp_parse_meta,
.parse_payload = nft_arp_parse_payload,
- .parse_immediate = nft_arp_parse_immediate,
.print_header = nft_arp_print_header,
.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-arp.h b/iptables/nft-arp.h
deleted file mode 100644
index 0d93a31f..00000000
--- a/iptables/nft-arp.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _NFT_ARP_H_
-#define _NFT_ARP_H_
-
-extern char *arp_opcodes[];
-#define NUMOPCODES 9
-
-/* define invflags which won't collide with IPT ones */
-#define IPT_INV_SRCDEVADDR 0x0080
-#define IPT_INV_TGTDEVADDR 0x0100
-#define IPT_INV_ARPHLN 0x0200
-#define IPT_INV_ARPOP 0x0400
-#define IPT_INV_ARPHRD 0x0800
-
-#endif
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index d98fd527..106bcc72 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -65,30 +65,34 @@ static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char
xtables_print_mac_and_mask(mac, mask);
}
-static void add_logical_iniface(struct nftnl_rule *r, char *iface, uint32_t op)
+static void add_logical_iniface(struct nft_handle *h, struct nftnl_rule *r,
+ char *iface, uint32_t op)
{
int iface_len;
+ uint8_t reg;
iface_len = strlen(iface);
- add_meta(r, NFT_META_BRI_IIFNAME);
+ add_meta(h, r, NFT_META_BRI_IIFNAME, &reg);
if (iface[iface_len - 1] == '+')
- add_cmp_ptr(r, op, iface, iface_len - 1);
+ add_cmp_ptr(r, op, iface, iface_len - 1, reg);
else
- add_cmp_ptr(r, op, iface, iface_len + 1);
+ add_cmp_ptr(r, op, iface, iface_len + 1, reg);
}
-static void add_logical_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
+static void add_logical_outiface(struct nft_handle *h, struct nftnl_rule *r,
+ char *iface, uint32_t op)
{
int iface_len;
+ uint8_t reg;
iface_len = strlen(iface);
- add_meta(r, NFT_META_BRI_OIFNAME);
+ add_meta(h, r, NFT_META_BRI_OIFNAME, &reg);
if (iface[iface_len - 1] == '+')
- add_cmp_ptr(r, op, iface, iface_len - 1);
+ add_cmp_ptr(r, op, iface, iface_len - 1, reg);
else
- add_cmp_ptr(r, op, iface, iface_len + 1);
+ add_cmp_ptr(r, op, iface, iface_len + 1, reg);
}
static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
@@ -97,52 +101,54 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
}
static int nft_bridge_add(struct nft_handle *h,
- struct nftnl_rule *r, void *data)
+ struct nftnl_rule *r,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct ebt_match *iter;
struct ebt_entry *fw = &cs->eb;
uint32_t op;
if (fw->in[0] != '\0') {
op = nft_invflags2cmp(fw->invflags, EBT_IIN);
- add_iniface(r, fw->in, op);
+ add_iniface(h, r, fw->in, op);
}
if (fw->out[0] != '\0') {
op = nft_invflags2cmp(fw->invflags, EBT_IOUT);
- add_outiface(r, fw->out, op);
+ add_outiface(h, r, fw->out, op);
}
if (fw->logical_in[0] != '\0') {
op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN);
- add_logical_iniface(r, fw->logical_in, op);
+ add_logical_iniface(h, r, fw->logical_in, op);
}
if (fw->logical_out[0] != '\0') {
op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT);
- add_logical_outiface(r, fw->logical_out, op);
+ add_logical_outiface(h, r, fw->logical_out, op);
}
if (fw->bitmask & EBT_ISOURCE) {
op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE);
- add_addr(r, NFT_PAYLOAD_LL_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_LL_HEADER,
offsetof(struct ethhdr, h_source),
fw->sourcemac, fw->sourcemsk, ETH_ALEN, op);
}
if (fw->bitmask & EBT_IDEST) {
op = nft_invflags2cmp(fw->invflags, EBT_IDEST);
- add_addr(r, NFT_PAYLOAD_LL_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_LL_HEADER,
offsetof(struct ethhdr, h_dest),
fw->destmac, fw->destmsk, ETH_ALEN, op);
}
if ((fw->bitmask & EBT_NOPROTO) == 0) {
+ uint8_t reg;
+
op = nft_invflags2cmp(fw->invflags, EBT_IPROTO);
- add_payload(r, offsetof(struct ethhdr, h_proto), 2,
- NFT_PAYLOAD_LL_HEADER);
- add_cmp_u16(r, fw->ethproto, op);
+ add_payload(h, r, offsetof(struct ethhdr, h_proto), 2,
+ NFT_PAYLOAD_LL_HEADER, &reg);
+ add_cmp_u16(r, fw->ethproto, op, reg);
}
add_compat(r, fw->ethproto, fw->invflags & EBT_IPROTO);
@@ -164,14 +170,14 @@ static int nft_bridge_add(struct nft_handle *h,
}
static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct ebt_entry *fw = &cs->eb;
uint8_t invflags = 0;
char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {};
- parse_meta(e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags);
+ parse_meta(ctx, e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags);
switch (ctx->meta.key) {
case NFT_META_BRI_IIFNAME:
@@ -200,9 +206,9 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx,
}
static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct ebt_entry *fw = &cs->eb;
unsigned char addr[ETH_ALEN];
unsigned short int ethproto;
@@ -251,14 +257,6 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
}
}
-static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
-{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-}
-
/* return 0 if saddr, 1 if daddr, -1 on error */
static int
lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len)
@@ -405,7 +403,7 @@ static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx,
}
static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
+ struct nftnl_expr *e)
{
struct xtables_match *match = NULL;
struct nft_among_data *among_data;
@@ -477,11 +475,7 @@ static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx,
static void parse_watcher(void *object, struct ebt_match **match_list,
bool ismatch)
{
- struct ebt_match *m;
-
- m = calloc(1, sizeof(struct ebt_match));
- if (m == NULL)
- xtables_error(OTHER_PROBLEM, "Can't allocate memory");
+ struct ebt_match *m = xtables_calloc(1, sizeof(struct ebt_match));
if (ismatch)
m->u.match = object;
@@ -495,17 +489,15 @@ static void parse_watcher(void *object, struct ebt_match **match_list,
(*match_list)->next = m;
}
-static void nft_bridge_parse_match(struct xtables_match *m, void *data)
+static void nft_bridge_parse_match(struct xtables_match *m,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
parse_watcher(m, &cs->match_list, true);
}
-static void nft_bridge_parse_target(struct xtables_target *t, void *data)
+static void nft_bridge_parse_target(struct xtables_target *t,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
/* harcoded names :-( */
if (strcmp(t->name, "log") == 0 ||
strcmp(t->name, "nflog") == 0) {
@@ -514,6 +506,7 @@ static void nft_bridge_parse_target(struct xtables_target *t, void *data)
}
cs->target = t;
+ cs->jumpto = t->name;
}
static void nft_rule_to_ebtables_command_state(struct nft_handle *h,
@@ -538,7 +531,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");
@@ -605,10 +598,9 @@ 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 struct iptables_command_state *cs,
+ unsigned int format)
{
- const struct iptables_command_state *cs = data;
-
if (cs->eb.ethproto)
print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO,
cs->eb.bitmask);
@@ -656,6 +648,13 @@ static void nft_bridge_save_rule(const void *data, unsigned int format)
fputc('\n', stdout);
}
+static void nft_bridge_save_rule(const struct iptables_command_state *cs,
+ unsigned int format)
+{
+ printf(" ");
+ __nft_bridge_save_rule(cs, format);
+}
+
static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format)
{
@@ -665,7 +664,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);
}
@@ -677,10 +676,11 @@ static void nft_bridge_save_chain(const struct nftnl_chain *c,
printf(":%s %s\n", chain, policy ?: "ACCEPT");
}
-static bool nft_bridge_is_same(const void *data_a, const void *data_b)
+static bool nft_bridge_is_same(const struct iptables_command_state *cs_a,
+ const struct iptables_command_state *cs_b)
{
- const struct ebt_entry *a = data_a;
- const struct ebt_entry *b = data_b;
+ const struct ebt_entry *a = &cs_a->eb;
+ const struct ebt_entry *b = &cs_b->eb;
int i;
if (a->ethproto != b->ethproto ||
@@ -826,9 +826,9 @@ static void nft_bridge_xlate_mac(struct xt_xlate *xl, const char *type, bool inv
xt_xlate_add(xl, " ");
}
-static int nft_bridge_xlate(const void *data, struct xt_xlate *xl)
+static int nft_bridge_xlate(const struct iptables_command_state *cs,
+ struct xt_xlate *xl)
{
- const struct iptables_command_state *cs = data;
int ret;
xlate_ifname(xl, "iifname", cs->eb.in,
@@ -889,7 +889,6 @@ struct nft_family_ops nft_family_ops_bridge = {
.print_payload = NULL,
.parse_meta = nft_bridge_parse_meta,
.parse_payload = nft_bridge_parse_payload,
- .parse_immediate = nft_bridge_parse_immediate,
.parse_lookup = nft_bridge_parse_lookup,
.parse_match = nft_bridge_parse_match,
.parse_target = nft_bridge_parse_target,
@@ -898,7 +897,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-cache.c b/iptables/nft-cache.c
index 6b6e6da4..608e42a7 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -40,7 +40,7 @@ static void cache_chain_list_insert(struct list_head *list, const char *name)
}
new = xtables_malloc(sizeof(*new));
- new->name = strdup(name);
+ new->name = xtables_strdup(name);
list_add_tail(&new->head, pos ? &pos->head : list);
}
@@ -56,7 +56,7 @@ void nft_cache_level_set(struct nft_handle *h, int level,
return;
if (!req->table)
- req->table = strdup(cmd->table);
+ req->table = xtables_strdup(cmd->table);
else
assert(!strcmp(req->table, cmd->table));
@@ -202,42 +202,111 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
return NULL;
}
+static int
+nft_cache_add_base_chain(struct nft_handle *h, const struct builtin_table *t,
+ struct nft_chain *nc)
+{
+ uint32_t hooknum = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_HOOKNUM);
+ const char *name = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_NAME);
+ const char *type = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_TYPE);
+ uint32_t prio = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_PRIO);
+ const struct builtin_chain *bc = NULL;
+ int i;
+
+ for (i = 0; i < NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) {
+ if (hooknum == t->chains[i].hook) {
+ bc = &t->chains[i];
+ break;
+ }
+ }
+
+ if (!bc ||
+ prio != bc->prio ||
+ strcmp(name, bc->name) ||
+ strcmp(type, bc->type))
+ return -EINVAL;
+
+ nc->base_slot = &h->cache->table[t->type].base_chains[hooknum];
+ if (*nc->base_slot)
+ return -EEXIST;
+
+ *nc->base_slot = nc;
+ return 0;
+}
+
int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
struct nftnl_chain *c)
{
const char *cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
struct nft_chain *nc = nft_chain_alloc(c);
+ int ret;
if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
- uint32_t hooknum = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
-
- if (hooknum >= NF_INET_NUMHOOKS) {
+ ret = nft_cache_add_base_chain(h, t, nc);
+ if (ret) {
+ h->cache->table[t->type].tainted = true;
nft_chain_free(nc);
- return -EINVAL;
+ return ret;
}
+ } else {
+ list_add_tail(&nc->head,
+ &h->cache->table[t->type].chains->list);
+ }
+ hlist_add_head(&nc->hnode, chain_name_hlist(h, t, cname));
+ return 0;
+}
- if (h->cache->table[t->type].base_chains[hooknum]) {
- nft_chain_free(nc);
- return -EEXIST;
- }
+static void __nft_chain_list_sort(struct list_head *list,
+ int (*cmp)(struct nft_chain *a,
+ struct nft_chain *b))
+{
+ struct nft_chain *pivot, *cur, *sav;
+ LIST_HEAD(sublist);
- h->cache->table[t->type].base_chains[hooknum] = nc;
- } else {
- struct nft_chain_list *clist = h->cache->table[t->type].chains;
- struct list_head *pos = &clist->list;
- struct nft_chain *cur;
- const char *n;
-
- list_for_each_entry(cur, &clist->list, head) {
- n = nftnl_chain_get_str(cur->nftnl, NFTNL_CHAIN_NAME);
- if (strcmp(cname, n) <= 0) {
- pos = &cur->head;
- break;
- }
+ if (list_empty(list))
+ return;
+
+ /* grab first item as pivot (dividing) value */
+ pivot = list_entry(list->next, struct nft_chain, head);
+ list_del(&pivot->head);
+
+ /* move any smaller value into sublist */
+ list_for_each_entry_safe(cur, sav, list, head) {
+ if (cmp(pivot, cur) > 0) {
+ list_del(&cur->head);
+ list_add_tail(&cur->head, &sublist);
}
- list_add_tail(&nc->head, pos);
}
- hlist_add_head(&nc->hnode, chain_name_hlist(h, t, cname));
+ /* conquer divided */
+ __nft_chain_list_sort(&sublist, cmp);
+ __nft_chain_list_sort(list, cmp);
+
+ /* merge divided and pivot again */
+ list_add_tail(&pivot->head, &sublist);
+ list_splice(&sublist, list);
+}
+
+static int nft_chain_cmp_byname(struct nft_chain *a, struct nft_chain *b)
+{
+ const char *aname = nftnl_chain_get_str(a->nftnl, NFTNL_CHAIN_NAME);
+ const char *bname = nftnl_chain_get_str(b->nftnl, NFTNL_CHAIN_NAME);
+
+ return strcmp(aname, bname);
+}
+
+int nft_cache_sort_chains(struct nft_handle *h, const char *table)
+{
+ const struct builtin_table *t = nft_table_builtin_find(h, table);
+
+ if (!t)
+ return -1;
+
+ if (h->cache->table[t->type].sorted)
+ return 0;
+
+ __nft_chain_list_sort(&h->cache->table[t->type].chains->list,
+ nft_chain_cmp_byname);
+ h->cache->table[t->type].sorted = true;
return 0;
}
@@ -271,9 +340,7 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
goto out;
}
- if (nft_cache_add_chain(h, t, c))
- goto out;
-
+ nft_cache_add_chain(h, t, c);
return MNL_CB_OK;
out:
nftnl_chain_free(c);
@@ -471,9 +538,15 @@ static int fetch_chain_cache(struct nft_handle *h,
return ret;
}
+struct rule_list_cb_data {
+ struct nftnl_chain *chain;
+ int verbose;
+};
+
static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
{
- struct nftnl_chain *c = data;
+ struct rule_list_cb_data *rld = data;
+ struct nftnl_chain *c = rld->chain;
struct nftnl_rule *r;
r = nftnl_rule_alloc();
@@ -485,6 +558,10 @@ static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
+ if (rld->verbose > 1) {
+ nftnl_rule_fprintf(stdout, r, 0, 0);
+ fprintf(stdout, "\n");
+ }
nftnl_chain_rule_add_tail(r, c);
return MNL_CB_OK;
}
@@ -493,6 +570,10 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data)
{
struct nftnl_chain *c = nc->nftnl;
struct nft_handle *h = data;
+ struct rule_list_cb_data rld = {
+ .chain = c,
+ .verbose = h->verbose,
+ };
char buf[16536];
struct nlmsghdr *nlh;
struct nftnl_rule *rule;
@@ -514,7 +595,7 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data)
NLM_F_DUMP, h->seq);
nftnl_rule_nlmsg_build_payload(nlh, rule);
- ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
+ ret = mnl_talk(h, nlh, nftnl_rule_list_cb, &rld);
if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
@@ -663,6 +744,7 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
flush_base_chain_cache(c->table[table->type].base_chains);
nft_chain_foreach(h, tablename, __flush_chain_cache, NULL);
+ c->table[table->type].sorted = false;
if (c->table[table->type].sets)
nftnl_set_list_foreach(c->table[table->type].sets,
@@ -678,6 +760,7 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
if (c->table[i].chains) {
nft_chain_list_free(c->table[i].chains);
c->table[i].chains = NULL;
+ c->table[i].sorted = false;
}
if (c->table[i].sets) {
diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h
index 20d96bee..58a01526 100644
--- a/iptables/nft-cache.h
+++ b/iptables/nft-cache.h
@@ -16,6 +16,7 @@ int flush_rule_cache(struct nft_handle *h, const char *table,
void nft_cache_build(struct nft_handle *h);
int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
struct nftnl_chain *c);
+int nft_cache_sort_chains(struct nft_handle *h, const char *table);
struct nft_chain *
nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
diff --git a/iptables/nft-chain.h b/iptables/nft-chain.h
index 137f4b7f..9adf1738 100644
--- a/iptables/nft-chain.h
+++ b/iptables/nft-chain.h
@@ -9,6 +9,7 @@ struct nft_handle;
struct nft_chain {
struct list_head head;
struct hlist_node hnode;
+ struct nft_chain **base_slot;
struct nftnl_chain *nftnl;
};
diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c
index 5d33f1f0..fcd01bd0 100644
--- a/iptables/nft-cmd.c
+++ b/iptables/nft-cmd.c
@@ -11,6 +11,7 @@
#include <stdlib.h>
#include <string.h>
+#include <xtables.h>
#include "nft.h"
#include "nft-cmd.h"
@@ -22,26 +23,25 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
struct nftnl_rule *rule;
struct nft_cmd *cmd;
- cmd = calloc(1, sizeof(struct nft_cmd));
- if (!cmd)
- return NULL;
-
+ cmd = xtables_calloc(1, sizeof(struct nft_cmd));
cmd->command = command;
- cmd->table = strdup(table);
+ cmd->table = xtables_strdup(table);
if (chain)
- cmd->chain = strdup(chain);
+ cmd->chain = xtables_strdup(chain);
cmd->rulenum = rulenum;
cmd->verbose = verbose;
if (state) {
rule = nft_rule_new(h, chain, table, state);
- if (!rule)
+ if (!rule) {
+ nft_cmd_free(cmd);
return NULL;
+ }
cmd->obj.rule = rule;
if (!state->target && strlen(state->jumpto) > 0)
- cmd->jumpto = strdup(state->jumpto);
+ cmd->jumpto = xtables_strdup(state->jumpto);
}
list_add_tail(&cmd->head, &h->cmd_list);
@@ -167,7 +167,9 @@ int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- if (chain || verbose)
+ if (h->family == NFPROTO_BRIDGE)
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else if (chain || verbose)
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
else
nft_cache_level_set(h, NFT_CL_TABLES, cmd);
@@ -185,7 +187,7 @@ int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
@@ -205,12 +207,12 @@ int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
return 1;
}
-int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
- const char *table, bool verbose)
+int nft_cmd_chain_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
{
struct nft_cmd *cmd;
- cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_DEL, table, chain, NULL, -1,
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_DEL, table, chain, NULL, -1,
verbose);
if (!cmd)
return 0;
@@ -218,7 +220,7 @@ int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
/* This triggers nft_bridge_chain_postprocess() when fetching the
* rule cache.
*/
- if (h->family == NFPROTO_BRIDGE)
+ if (h->family == NFPROTO_BRIDGE || !chain)
nft_cache_level_set(h, NFT_CL_RULES, cmd);
else
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
@@ -236,7 +238,7 @@ int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
if (!cmd)
return 0;
- cmd->rename = strdup(newname);
+ cmd->rename = xtables_strdup(newname);
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
@@ -302,7 +304,7 @@ int nft_cmd_chain_set(struct nft_handle *h, const char *table,
if (!cmd)
return 0;
- cmd->policy = strdup(policy);
+ cmd->policy = xtables_strdup(policy);
if (counters)
cmd->counters = *counters;
@@ -317,7 +319,7 @@ int nft_cmd_table_flush(struct nft_handle *h, const char *table, bool verbose)
if (verbose) {
return nft_cmd_rule_flush(h, NULL, table, verbose) &&
- nft_cmd_chain_user_del(h, NULL, table, verbose);
+ nft_cmd_chain_del(h, NULL, table, verbose);
}
cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1,
@@ -387,7 +389,7 @@ int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
if (!cmd)
return 0;
- cmd->policy = strdup(policy);
+ cmd->policy = xtables_strdup(policy);
nft_cache_level_set(h, NFT_CL_RULES, cmd);
diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h
index ecf7655a..b5a99ef7 100644
--- a/iptables/nft-cmd.h
+++ b/iptables/nft-cmd.h
@@ -49,8 +49,8 @@ int nft_cmd_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose);
int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
const char *table);
-int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
- const char *table, bool verbose);
+int nft_cmd_chain_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose);
int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index fdc15c6f..59c4a41f 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -26,54 +26,56 @@
#include "nft.h"
#include "nft-shared.h"
-static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
+static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct xtables_rule_match *matchp;
uint32_t op;
int ret;
if (cs->fw.ip.iniface[0] != '\0') {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_IN);
- add_iniface(r, cs->fw.ip.iniface, op);
+ add_iniface(h, r, cs->fw.ip.iniface, op);
}
if (cs->fw.ip.outiface[0] != '\0') {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_OUT);
- add_outiface(r, cs->fw.ip.outiface, op);
+ add_outiface(h, r, cs->fw.ip.outiface, op);
}
if (cs->fw.ip.proto != 0) {
op = nft_invflags2cmp(cs->fw.ip.invflags, XT_INV_PROTO);
- add_l4proto(r, cs->fw.ip.proto, op);
+ add_l4proto(h, r, cs->fw.ip.proto, op);
}
if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct iphdr, saddr),
&cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr,
sizeof(struct in_addr), op);
}
if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct iphdr, daddr),
&cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr,
sizeof(struct in_addr), op);
}
if (cs->fw.ip.flags & IPT_F_FRAG) {
- add_payload(r, offsetof(struct iphdr, frag_off), 2,
- NFT_PAYLOAD_NETWORK_HEADER);
+ uint8_t reg;
+
+ add_payload(h, r, offsetof(struct iphdr, frag_off), 2,
+ NFT_PAYLOAD_NETWORK_HEADER, &reg);
/* get the 13 bits that contain the fragment offset */
- add_bitwise_u16(r, htons(0x1fff), 0);
+ add_bitwise_u16(h, r, htons(0x1fff), 0, reg, &reg);
/* if offset is non-zero, this is a fragment */
op = NFT_CMP_NEQ;
if (cs->fw.ip.invflags & IPT_INV_FRAG)
op = NFT_CMP_EQ;
- add_cmp_u16(r, 0, op);
+ add_cmp_u16(r, 0, op, reg);
}
add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO);
@@ -93,12 +95,9 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
return add_action(r, cs, !!(cs->fw.ip.flags & IPT_F_GOTO));
}
-static bool nft_ipv4_is_same(const void *data_a,
- const void *data_b)
+static bool nft_ipv4_is_same(const struct iptables_command_state *a,
+ const struct iptables_command_state *b)
{
- const struct iptables_command_state *a = data_a;
- const struct iptables_command_state *b = data_b;
-
if (a->fw.ip.src.s_addr != b->fw.ip.src.s_addr
|| a->fw.ip.dst.s_addr != b->fw.ip.dst.s_addr
|| a->fw.ip.smsk.s_addr != b->fw.ip.smsk.s_addr
@@ -134,37 +133,9 @@ 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[sizeof("255.255.255.255")];
- 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
- sprintf(mask_str, "%s", inet_ntoa(mask_addr));
-
- return mask_str;
-}
-
static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data)
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
switch (ctx->meta.key) {
case NFT_META_L4PROTO:
cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
@@ -175,7 +146,7 @@ static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
break;
}
- parse_meta(e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
+ parse_meta(ctx, e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
cs->fw.ip.outiface, cs->fw.ip.outiface_mask,
&cs->fw.ip.invflags);
}
@@ -186,9 +157,9 @@ static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
}
static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct in_addr addr;
uint8_t proto;
bool inv;
@@ -241,28 +212,9 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
}
}
-static void nft_ipv4_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
+static void nft_ipv4_set_goto_flag(struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-
- if (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);
+ cs->fw.ip.flags |= IPT_F_GOTO;
}
static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
@@ -272,9 +224,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 +247,54 @@ 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)
-{
- if (!mask && !invert && !addr->s_addr)
- return;
-
- printf("%s-%c %s/%s ", invert ? "! " : "", letter, inet_ntoa(*addr),
- mask_to_str(mask));
-}
-
-static void nft_ipv4_save_rule(const void *data, unsigned int format)
+static void nft_ipv4_save_rule(const struct iptables_command_state *cs,
+ 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)
+static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr,
+ const struct in_addr *mask,
+ bool inv, struct xt_xlate *xl)
{
- 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;
-
- strncpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ);
- memcpy(cs->fw.ip.iniface_mask,
- args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
+ char mbuf[INET_ADDRSTRLEN], abuf[INET_ADDRSTRLEN];
+ const char *op = inv ? "!= " : "";
+ int cidr;
- strncpy(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;
+ if (!inv && !addr->s_addr && !mask->s_addr)
+ return;
- cs->counters.pcnt = args->pcnt_cnt;
- cs->counters.bcnt = args->bcnt_cnt;
+ inet_ntop(AF_INET, addr, abuf, sizeof(abuf));
- 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";
+ cidr = xtables_ipmask_to_cidr(mask);
+ switch (cidr) {
+ case -1:
+ xt_xlate_add(xl, "%s & %s %s %s ", selector,
+ inet_ntop(AF_INET, mask, mbuf, sizeof(mbuf)),
+ inv ? "!=" : "==", abuf);
+ break;
+ case 32:
+ xt_xlate_add(xl, "%s %s%s ", selector, op, abuf);
+ break;
+ default:
+ xt_xlate_add(xl, "%s %s%s/%d ", selector, op, abuf, cidr);
}
-
- 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 int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
+static int nft_ipv4_xlate(const struct iptables_command_state *cs,
+ struct xt_xlate *xl)
{
- const struct iptables_command_state *cs = data;
const char *comment;
int ret;
@@ -417,18 +326,10 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
}
}
- if (cs->fw.ip.src.s_addr != 0) {
- xt_xlate_add(xl, "ip saddr %s%s%s ",
- cs->fw.ip.invflags & IPT_INV_SRCIP ? "!= " : "",
- inet_ntoa(cs->fw.ip.src),
- xtables_ipmask_to_numeric(&cs->fw.ip.smsk));
- }
- if (cs->fw.ip.dst.s_addr != 0) {
- xt_xlate_add(xl, "ip daddr %s%s%s ",
- cs->fw.ip.invflags & IPT_INV_DSTIP ? "!= " : "",
- inet_ntoa(cs->fw.ip.dst),
- xtables_ipmask_to_numeric(&cs->fw.ip.dmsk));
- }
+ xlate_ipv4_addr("ip saddr", &cs->fw.ip.src, &cs->fw.ip.smsk,
+ cs->fw.ip.invflags & IPT_INV_SRCIP, xl);
+ xlate_ipv4_addr("ip daddr", &cs->fw.ip.dst, &cs->fw.ip.dmsk,
+ cs->fw.ip.invflags & IPT_INV_DSTIP, xl);
ret = xlate_matches(cs, xl);
if (!ret)
@@ -445,20 +346,115 @@ 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,
.parse_meta = nft_ipv4_parse_meta,
.parse_payload = nft_ipv4_parse_payload,
- .parse_immediate = nft_ipv4_parse_immediate,
+ .set_goto_flag = nft_ipv4_set_goto_flag,
.print_header = print_header,
.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 130ad3e6..9a29d18b 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -25,33 +25,33 @@
#include "nft.h"
#include "nft-shared.h"
-static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
+static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct xtables_rule_match *matchp;
uint32_t op;
int ret;
if (cs->fw6.ipv6.iniface[0] != '\0') {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN);
- add_iniface(r, cs->fw6.ipv6.iniface, op);
+ add_iniface(h, r, cs->fw6.ipv6.iniface, op);
}
if (cs->fw6.ipv6.outiface[0] != '\0') {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT);
- add_outiface(r, cs->fw6.ipv6.outiface, op);
+ add_outiface(h, r, cs->fw6.ipv6.outiface, op);
}
if (cs->fw6.ipv6.proto != 0) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO);
- add_l4proto(r, cs->fw6.ipv6.proto, op);
+ add_l4proto(h, r, cs->fw6.ipv6.proto, op);
}
if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src) ||
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_SRCIP);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct ip6_hdr, ip6_src),
&cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
sizeof(struct in6_addr), op);
@@ -60,7 +60,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_DSTIP);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct ip6_hdr, ip6_dst),
&cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk,
sizeof(struct in6_addr), op);
@@ -82,12 +82,9 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
return add_action(r, cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO));
}
-static bool nft_ipv6_is_same(const void *data_a,
- const void *data_b)
+static bool nft_ipv6_is_same(const struct iptables_command_state *a,
+ const struct iptables_command_state *b)
{
- const struct iptables_command_state *a = data_a;
- const struct iptables_command_state *b = data_b;
-
if (memcmp(a->fw6.ipv6.src.s6_addr, b->fw6.ipv6.src.s6_addr,
sizeof(struct in6_addr)) != 0
|| memcmp(a->fw6.ipv6.dst.s6_addr, b->fw6.ipv6.dst.s6_addr,
@@ -108,10 +105,8 @@ static bool nft_ipv6_is_same(const void *data_a,
}
static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data)
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
switch (ctx->meta.key) {
case NFT_META_L4PROTO:
cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
@@ -122,7 +117,7 @@ static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
break;
}
- parse_meta(e, ctx->meta.key, cs->fw6.ipv6.iniface,
+ parse_meta(ctx, e, ctx->meta.key, cs->fw6.ipv6.iniface,
cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface,
cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags);
}
@@ -133,9 +128,9 @@ static void parse_mask_ipv6(struct nft_xt_ctx *ctx, struct in6_addr *mask)
}
static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct in6_addr addr;
uint8_t proto;
bool inv;
@@ -180,15 +175,9 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
}
}
-static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
+static void nft_ipv6_set_goto_flag(struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-
- if (nft_goto)
- cs->fw6.ipv6.flags |= IP6T_F_GOTO;
+ cs->fw6.ipv6.flags |= IP6T_F_GOTO;
}
static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
@@ -198,14 +187,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,132 +208,52 @@ 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)
+static void nft_ipv6_save_rule(const struct iptables_command_state *cs,
+ unsigned int format)
{
- 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;
-
save_ipv6_addr('s', &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
cs->fw6.ipv6.invflags & IP6T_INV_SRCIP);
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;
-
- strncpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ);
- memcpy(cs->fw6.ipv6.iniface_mask,
- args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
-
- strncpy(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)
{
+ const char *op = invert ? "!= " : "";
char addr_str[INET6_ADDRSTRLEN];
+ int cidr;
- if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr))
+ if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr) && IN6_IS_ADDR_UNSPECIFIED(mask))
return;
inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
- xt_xlate_add(xl, "%s %s%s%s ", selector, invert ? "!= " : "", addr_str,
- xtables_ip6mask_to_numeric(mask));
+ cidr = xtables_ip6mask_to_cidr(mask);
+ switch (cidr) {
+ case -1:
+ xt_xlate_add(xl, "%s & %s %s %s ", selector,
+ xtables_ip6addr_to_numeric(mask),
+ invert ? "!=" : "==", addr_str);
+ break;
+ case 128:
+ xt_xlate_add(xl, "%s %s%s ", selector, op, addr_str);
+ break;
+ default:
+ xt_xlate_add(xl, "%s %s%s/%d ", selector, op, addr_str, cidr);
+ }
}
-static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
+static int nft_ipv6_xlate(const struct iptables_command_state *cs,
+ struct xt_xlate *xl)
{
- const struct iptables_command_state *cs = data;
const char *comment;
int ret;
@@ -397,20 +301,126 @@ 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,
.parse_meta = nft_ipv6_parse_meta,
.parse_payload = nft_ipv6_parse_payload,
- .parse_immediate = nft_ipv6_parse_immediate,
+ .set_goto_flag = nft_ipv6_set_goto_flag,
.print_header = print_header,
.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 10553ab2..27e95c1a 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -20,8 +20,11 @@
#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 <linux/netfilter/xt_mark.h>
#include <libmnl/libmnl.h>
#include <libnftnl/rule.h>
@@ -37,73 +40,89 @@ extern struct nft_family_ops nft_family_ops_ipv6;
extern struct nft_family_ops nft_family_ops_arp;
extern struct nft_family_ops nft_family_ops_bridge;
-void add_meta(struct nftnl_rule *r, uint32_t key)
+void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key,
+ uint8_t *dreg)
{
struct nftnl_expr *expr;
+ uint8_t reg;
expr = nftnl_expr_alloc("meta");
if (expr == NULL)
return;
+ reg = NFT_REG_1;
nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, key);
- nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
-
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, reg);
nftnl_rule_add_expr(r, expr);
+
+ *dreg = reg;
}
-void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base)
+void add_payload(struct nft_handle *h, struct nftnl_rule *r,
+ int offset, int len, uint32_t base, uint8_t *dreg)
{
struct nftnl_expr *expr;
+ uint8_t reg;
expr = nftnl_expr_alloc("payload");
if (expr == NULL)
return;
+ reg = NFT_REG_1;
nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base);
- nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, NFT_REG_1);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, reg);
nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len);
-
nftnl_rule_add_expr(r, expr);
+
+ *dreg = reg;
}
/* bitwise operation is = sreg & mask ^ xor */
-void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor)
+void add_bitwise_u16(struct nft_handle *h, struct nftnl_rule *r,
+ uint16_t mask, uint16_t xor, uint8_t sreg, uint8_t *dreg)
{
struct nftnl_expr *expr;
+ uint8_t reg;
expr = nftnl_expr_alloc("bitwise");
if (expr == NULL)
return;
- nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1);
- nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1);
+ reg = NFT_REG_1;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg);
nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, sizeof(uint16_t));
nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, &mask, sizeof(uint16_t));
nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, sizeof(uint16_t));
-
nftnl_rule_add_expr(r, expr);
+
+ *dreg = reg;
}
-void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len)
+void add_bitwise(struct nft_handle *h, struct nftnl_rule *r,
+ uint8_t *mask, size_t len, uint8_t sreg, uint8_t *dreg)
{
struct nftnl_expr *expr;
uint32_t xor[4] = { 0 };
+ uint8_t reg = *dreg;
expr = nftnl_expr_alloc("bitwise");
if (expr == NULL)
return;
- nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1);
- nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg);
nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len);
nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len);
nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, len);
-
nftnl_rule_add_expr(r, expr);
+
+ *dreg = reg;
}
-void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len)
+void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len,
+ uint8_t sreg)
{
struct nftnl_expr *expr;
@@ -111,62 +130,69 @@ void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len)
if (expr == NULL)
return;
- nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, NFT_REG_1);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, sreg);
nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op);
nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, len);
-
nftnl_rule_add_expr(r, expr);
}
-void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op)
+void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op, uint8_t sreg)
{
- add_cmp_ptr(r, op, &val, sizeof(val));
+ add_cmp_ptr(r, op, &val, sizeof(val), sreg);
}
-void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op)
+void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op, uint8_t sreg)
{
- add_cmp_ptr(r, op, &val, sizeof(val));
+ add_cmp_ptr(r, op, &val, sizeof(val), sreg);
}
-void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op)
+void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg)
{
- add_cmp_ptr(r, op, &val, sizeof(val));
+ add_cmp_ptr(r, op, &val, sizeof(val), sreg);
}
-void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op)
+void add_iniface(struct nft_handle *h, struct nftnl_rule *r,
+ char *iface, uint32_t op)
{
int iface_len;
+ uint8_t reg;
iface_len = strlen(iface);
- add_meta(r, NFT_META_IIFNAME);
+ add_meta(h, r, NFT_META_IIFNAME, &reg);
if (iface[iface_len - 1] == '+') {
if (iface_len > 1)
- add_cmp_ptr(r, op, iface, iface_len - 1);
- } else
- add_cmp_ptr(r, op, iface, iface_len + 1);
+ add_cmp_ptr(r, op, iface, iface_len - 1, reg);
+ } else {
+ add_cmp_ptr(r, op, iface, iface_len + 1, reg);
+ }
}
-void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
+void add_outiface(struct nft_handle *h, struct nftnl_rule *r,
+ char *iface, uint32_t op)
{
int iface_len;
+ uint8_t reg;
iface_len = strlen(iface);
- add_meta(r, NFT_META_OIFNAME);
+ add_meta(h, r, NFT_META_OIFNAME, &reg);
if (iface[iface_len - 1] == '+') {
if (iface_len > 1)
- add_cmp_ptr(r, op, iface, iface_len - 1);
- } else
- add_cmp_ptr(r, op, iface, iface_len + 1);
+ add_cmp_ptr(r, op, iface, iface_len - 1, reg);
+ } else {
+ add_cmp_ptr(r, op, iface, iface_len + 1, reg);
+ }
}
-void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
+void add_addr(struct nft_handle *h, struct nftnl_rule *r,
+ enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op)
{
const unsigned char *m = mask;
bool bitwise = false;
- int i;
+ uint8_t reg;
+ int i, j;
for (i = 0; i < len; i++) {
if (m[i] != 0xff) {
@@ -174,29 +200,36 @@ void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
break;
}
}
+ for (j = i + 1; !bitwise && j < len; j++)
+ bitwise = !!m[j];
if (!bitwise)
len = i;
- add_payload(r, offset, len, base);
+ add_payload(h, r, offset, len, base, &reg);
if (bitwise)
- add_bitwise(r, mask, len);
+ add_bitwise(h, r, mask, len, reg, &reg);
- add_cmp_ptr(r, op, data, len);
+ add_cmp_ptr(r, op, data, len, reg);
}
-void add_proto(struct nftnl_rule *r, int offset, size_t len,
- uint8_t proto, uint32_t op)
+void add_proto(struct nft_handle *h, struct nftnl_rule *r,
+ int offset, size_t len, uint8_t proto, uint32_t op)
{
- add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
- add_cmp_u8(r, proto, op);
+ uint8_t reg;
+
+ add_payload(h, r, offset, len, NFT_PAYLOAD_NETWORK_HEADER, &reg);
+ add_cmp_u8(r, proto, op, reg);
}
-void add_l4proto(struct nftnl_rule *r, uint8_t proto, uint32_t op)
+void add_l4proto(struct nft_handle *h, struct nftnl_rule *r,
+ uint8_t proto, uint32_t op)
{
- add_meta(r, NFT_META_L4PROTO);
- add_cmp_u8(r, proto, op);
+ uint8_t reg;
+
+ add_meta(h, r, NFT_META_L4PROTO, &reg);
+ add_cmp_u8(r, proto, op, reg);
}
bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
@@ -257,9 +290,41 @@ static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned
memset(mask, 0xff, len - 2);
}
-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)
+static struct xtables_match *
+nft_create_match(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ const char *name);
+
+static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ struct xt_mark_mtinfo1 *mark;
+ struct xtables_match *match;
+ uint32_t value;
+
+ match = nft_create_match(ctx, ctx->cs, "mark");
+ if (!match)
+ return -1;
+
+ mark = (void*)match->m->data;
+
+ if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+ mark->invert = 1;
+
+ value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
+ mark->mark = value;
+ if (ctx->flags & NFT_XT_CTX_BITWISE) {
+ memcpy(&mark->mask, &ctx->bitwise.mask, sizeof(mark->mask));
+ ctx->flags &= ~NFT_XT_CTX_BITWISE;
+ } else {
+ mark->mask = 0xffffffff;
+ }
+
+ return 0;
+}
+
+int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key,
+ char *iniface, unsigned char *iniface_mask,
+ char *outiface, unsigned char *outiface_mask, uint8_t *invflags)
{
uint32_t value;
const void *ifname;
@@ -300,6 +365,9 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
parse_ifname(ifname, len, outiface, outiface_mask);
break;
+ case NFT_META_MARK:
+ parse_meta_mark(ctx, e);
+ break;
default:
return -1;
}
@@ -315,7 +383,6 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
struct xtables_target *target;
struct xt_entry_target *t;
size_t size;
- void *data = ctx->cs;
target = xtables_find_target(targname, XTF_TRY_LOAD);
if (target == NULL)
@@ -331,7 +398,7 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
target->t = t;
- ctx->h->ops->parse_target(target, data);
+ ctx->h->ops->parse_target(target, ctx->cs);
}
static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
@@ -371,21 +438,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;
@@ -456,7 +508,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);
@@ -472,6 +524,8 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
if (ctx->reg && reg != ctx->reg)
return;
+ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG);
+ ctx->reg = reg;
data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len);
memcpy(ctx->bitwise.xor, data, len);
data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len);
@@ -479,9 +533,407 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ctx->flags |= NFT_XT_CTX_BITWISE;
}
+static struct xtables_match *
+nft_create_match(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ const char *name)
+{
+ struct xtables_match *match;
+ struct xt_entry_match *m;
+ unsigned int size;
+
+ match = xtables_find_match(name, XTF_TRY_LOAD,
+ &cs->matches);
+ if (!match)
+ return NULL;
+
+ size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size;
+ m = xtables_calloc(1, size);
+ m->u.match_size = size;
+ m->u.user.revision = match->revision;
+
+ strcpy(m->u.user.name, match->name);
+ match->m = m;
+
+ xs_init_match(match);
+
+ return match;
+}
+
+static struct xt_udp *nft_udp_match(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs)
+{
+ struct xt_udp *udp = ctx->tcpudp.udp;
+ struct xtables_match *match;
+
+ if (!udp) {
+ match = nft_create_match(ctx, cs, "udp");
+ if (!match)
+ return NULL;
+
+ udp = (void*)match->m->data;
+ ctx->tcpudp.udp = udp;
+ }
+
+ return udp;
+}
+
+static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs)
+{
+ struct xt_tcp *tcp = ctx->tcpudp.tcp;
+ struct xtables_match *match;
+
+ if (!tcp) {
+ match = nft_create_match(ctx, cs, "tcp");
+ if (!match)
+ return NULL;
+
+ tcp = (void*)match->m->data;
+ ctx->tcpudp.tcp = tcp;
+ }
+
+ return tcp;
+}
+
+static void nft_parse_udp_range(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to,
+ uint8_t op)
+{
+ struct xt_udp *udp = nft_udp_match(ctx, cs);
+
+ if (!udp)
+ return;
+
+ if (sport_from >= 0) {
+ switch (op) {
+ case NFT_RANGE_NEQ:
+ udp->invflags |= XT_UDP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_RANGE_EQ:
+ udp->spts[0] = sport_from;
+ udp->spts[1] = sport_to;
+ break;
+ }
+ }
+
+ if (dport_to >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ udp->invflags |= XT_UDP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ udp->dpts[0] = dport_from;
+ udp->dpts[1] = dport_to;
+ break;
+ }
+ }
+}
+
+static void nft_parse_tcp_range(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to,
+ uint8_t op)
+{
+ struct xt_tcp *tcp = nft_tcp_match(ctx, cs);
+
+ if (!tcp)
+ return;
+
+ if (sport_from >= 0) {
+ switch (op) {
+ case NFT_RANGE_NEQ:
+ tcp->invflags |= XT_TCP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_RANGE_EQ:
+ tcp->spts[0] = sport_from;
+ tcp->spts[1] = sport_to;
+ break;
+ }
+ }
+
+ if (dport_to >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ tcp->invflags |= XT_TCP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ tcp->dpts[0] = dport_from;
+ tcp->dpts[1] = dport_to;
+ break;
+ }
+ }
+}
+
+static void nft_parse_udp(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport, int dport,
+ uint8_t op)
+{
+ struct xt_udp *udp = nft_udp_match(ctx, cs);
+
+ if (!udp)
+ return;
+
+ if (sport >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ udp->invflags |= XT_UDP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ udp->spts[0] = sport;
+ udp->spts[1] = sport;
+ break;
+ case NFT_CMP_LT:
+ udp->spts[1] = sport > 1 ? sport - 1 : 1;
+ break;
+ case NFT_CMP_LTE:
+ udp->spts[1] = sport;
+ break;
+ case NFT_CMP_GT:
+ udp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff;
+ break;
+ case NFT_CMP_GTE:
+ udp->spts[0] = sport;
+ break;
+ }
+ }
+ if (dport >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ udp->invflags |= XT_UDP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ udp->dpts[0] = dport;
+ udp->dpts[1] = dport;
+ break;
+ case NFT_CMP_LT:
+ udp->dpts[1] = dport > 1 ? dport - 1 : 1;
+ break;
+ case NFT_CMP_LTE:
+ udp->dpts[1] = dport;
+ break;
+ case NFT_CMP_GT:
+ udp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff;
+ break;
+ case NFT_CMP_GTE:
+ udp->dpts[0] = dport;
+ break;
+ }
+ }
+}
+
+static void nft_parse_tcp(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport, int dport,
+ uint8_t op)
+{
+ struct xt_tcp *tcp = nft_tcp_match(ctx, cs);
+
+ if (!tcp)
+ return;
+
+ if (sport >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ tcp->invflags |= XT_TCP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ tcp->spts[0] = sport;
+ tcp->spts[1] = sport;
+ break;
+ case NFT_CMP_LT:
+ tcp->spts[1] = sport > 1 ? sport - 1 : 1;
+ break;
+ case NFT_CMP_LTE:
+ tcp->spts[1] = sport;
+ break;
+ case NFT_CMP_GT:
+ tcp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff;
+ break;
+ case NFT_CMP_GTE:
+ tcp->spts[0] = sport;
+ break;
+ }
+ }
+
+ if (dport >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ tcp->invflags |= XT_TCP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ tcp->dpts[0] = dport;
+ tcp->dpts[1] = dport;
+ break;
+ case NFT_CMP_LT:
+ tcp->dpts[1] = dport > 1 ? dport - 1 : 1;
+ break;
+ case NFT_CMP_LTE:
+ tcp->dpts[1] = dport;
+ break;
+ case NFT_CMP_GT:
+ tcp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff;
+ break;
+ case NFT_CMP_GTE:
+ tcp->dpts[0] = dport;
+ break;
+ }
+ }
+}
+
+static void nft_parse_th_port(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ uint8_t proto,
+ int sport, int dport, uint8_t op)
+{
+ switch (proto) {
+ case IPPROTO_UDP:
+ nft_parse_udp(ctx, cs, sport, dport, op);
+ break;
+ case IPPROTO_TCP:
+ nft_parse_tcp(ctx, cs, sport, dport, op);
+ break;
+ }
+}
+
+static void nft_parse_th_port_range(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ uint8_t proto,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to, uint8_t op)
+{
+ switch (proto) {
+ case IPPROTO_UDP:
+ nft_parse_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op);
+ break;
+ case IPPROTO_TCP:
+ nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op);
+ break;
+ }
+}
+
+static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ uint8_t op, uint8_t flags, uint8_t mask)
+{
+ struct xt_tcp *tcp = nft_tcp_match(ctx, cs);
+
+ if (!tcp)
+ return;
+
+ if (op == NFT_CMP_NEQ)
+ tcp->invflags |= XT_TCP_INV_FLAGS;
+ tcp->flg_cmp = flags;
+ tcp->flg_mask = mask;
+}
+
+static void nft_parse_transport(struct nft_xt_ctx *ctx,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ uint32_t sdport;
+ uint16_t port;
+ uint8_t proto, op;
+ unsigned int len;
+
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ proto = ctx->cs->fw.ip.proto;
+ break;
+ case NFPROTO_IPV6:
+ proto = ctx->cs->fw6.ipv6.proto;
+ break;
+ default:
+ proto = 0;
+ break;
+ }
+
+ nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
+ op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
+
+ switch(ctx->payload.offset) {
+ case 0: /* th->sport */
+ switch (len) {
+ case 2: /* load sport only */
+ port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA));
+ nft_parse_th_port(ctx, cs, proto, port, -1, op);
+ return;
+ case 4: /* load both src and dst port */
+ sdport = ntohl(nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA));
+ nft_parse_th_port(ctx, cs, proto, sdport >> 16, sdport & 0xffff, op);
+ return;
+ }
+ break;
+ case 2: /* th->dport */
+ switch (len) {
+ case 2:
+ port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA));
+ nft_parse_th_port(ctx, cs, proto, -1, port, op);
+ return;
+ }
+ break;
+ case 13: /* th->flags */
+ if (len == 1 && proto == IPPROTO_TCP) {
+ uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
+ uint8_t mask = ~0;
+
+ if (ctx->flags & NFT_XT_CTX_BITWISE) {
+ memcpy(&mask, &ctx->bitwise.mask, sizeof(mask));
+ ctx->flags &= ~NFT_XT_CTX_BITWISE;
+ }
+ nft_parse_tcp_flags(ctx, cs, op, flags, mask);
+ }
+ return;
+ }
+}
+
+static void nft_parse_transport_range(struct nft_xt_ctx *ctx,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ unsigned int len_from, len_to;
+ uint8_t proto, op;
+ uint16_t from, to;
+
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ proto = ctx->cs->fw.ip.proto;
+ break;
+ case NFPROTO_IPV6:
+ proto = ctx->cs->fw6.ipv6.proto;
+ break;
+ default:
+ proto = 0;
+ break;
+ }
+
+ nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_from);
+ nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_to);
+ if (len_to != len_from || len_to != 2)
+ return;
+
+ op = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_OP);
+
+ from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA));
+ to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA));
+
+ switch(ctx->payload.offset) {
+ case 0:
+ nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op);
+ return;
+ case 2:
+ to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA));
+ nft_parse_th_port_range(ctx, cs, proto, -1, -1, from, to, op);
+ return;
+ }
+}
+
static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
- void *data = ctx->cs;
uint32_t reg;
reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
@@ -489,13 +941,23 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
return;
if (ctx->flags & NFT_XT_CTX_META) {
- ctx->h->ops->parse_meta(ctx, e, data);
+ ctx->h->ops->parse_meta(ctx, e, ctx->cs);
ctx->flags &= ~NFT_XT_CTX_META;
}
/* bitwise context is interpreted from payload */
if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
- ctx->h->ops->parse_payload(ctx, e, data);
- ctx->flags &= ~NFT_XT_CTX_PAYLOAD;
+ switch (ctx->payload.base) {
+ case NFT_PAYLOAD_LL_HEADER:
+ if (ctx->h->family == NFPROTO_BRIDGE)
+ ctx->h->ops->parse_payload(ctx, e, ctx->cs);
+ break;
+ case NFT_PAYLOAD_NETWORK_HEADER:
+ ctx->h->ops->parse_payload(ctx, e, ctx->cs);
+ break;
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ nft_parse_transport(ctx, e, ctx->cs);
+ break;
+ }
}
}
@@ -508,9 +970,9 @@ static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters
static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
- const char *jumpto = NULL;
- bool nft_goto = false;
- void *data = ctx->cs;
+ struct iptables_command_state *cs = ctx->cs;
+ struct xt_entry_target *t;
+ uint32_t size;
int verdict;
if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) {
@@ -533,23 +995,35 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
/* Standard target? */
switch(verdict) {
case NF_ACCEPT:
- jumpto = "ACCEPT";
+ cs->jumpto = "ACCEPT";
break;
case NF_DROP:
- jumpto = "DROP";
+ cs->jumpto = "DROP";
break;
case NFT_RETURN:
- jumpto = "RETURN";
+ cs->jumpto = "RETURN";
break;;
case NFT_GOTO:
- nft_goto = true;
+ if (ctx->h->ops->set_goto_flag)
+ ctx->h->ops->set_goto_flag(cs);
/* fall through */
case NFT_JUMP:
- jumpto = chain;
- break;
+ cs->jumpto = chain;
+ /* fall through */
+ default:
+ return;
}
- ctx->h->ops->parse_immediate(jumpto, nft_goto, data);
+ cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
+ if (!cs->target)
+ return;
+
+ size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
+ t = xtables_calloc(1, size);
+ t->u.target_size = size;
+ t->u.user.revision = cs->target->revision;
+ strcpy(t->u.user.name, cs->jumpto);
+ cs->target->t = t;
}
static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
@@ -593,11 +1067,78 @@ 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)
{
if (ctx->h->ops->parse_lookup)
- ctx->h->ops->parse_lookup(ctx, e, NULL);
+ ctx->h->ops->parse_lookup(ctx, e);
+}
+
+static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ uint32_t reg;
+
+ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG);
+ if (reg != ctx->reg)
+ return;
+
+ if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
+ switch (ctx->payload.base) {
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ nft_parse_transport_range(ctx, e, ctx->cs);
+ break;
+ default:
+ break;
+ }
+ }
}
void nft_rule_to_iptables_command_state(struct nft_handle *h,
@@ -642,6 +1183,10 @@ 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);
+ else if (strcmp(name, "range") == 0)
+ nft_parse_range(&ctx, expr);
expr = nftnl_expr_iter_next(iter);
}
@@ -677,25 +1222,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h,
}
}
- if (cs->target != NULL) {
- cs->jumpto = cs->target->name;
- } else if (cs->jumpto != NULL) {
- struct xt_entry_target *t;
- uint32_t size;
-
- cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
- if (!cs->target)
- return;
-
- size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
- t = xtables_calloc(1, size);
- t->u.target_size = size;
- t->u.user.revision = cs->target->revision;
- strcpy(t->u.user.name, cs->jumpto);
- cs->target->t = t;
- } else {
+ if (!cs->jumpto)
cs->jumpto = "";
- }
}
void nft_clear_iptables_command_state(struct iptables_command_state *cs)
@@ -712,130 +1240,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 struct protoent *pent = getprotobynumber(proto);
-
- if (invflags & XT_INV_PROTO)
- printf("! ");
-
- if (pent)
- printf("-p %s ", pent->p_name);
- 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);
@@ -854,33 +1258,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");
@@ -979,17 +1383,18 @@ bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2)
return true;
}
-void nft_ipv46_parse_target(struct xtables_target *t, void *data)
+void nft_ipv46_parse_target(struct xtables_target *t,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
cs->target = t;
+ cs->jumpto = t->name;
}
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];
@@ -1002,6 +1407,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 da4ba9d2..b0404904 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -13,7 +13,6 @@
#include "xshared.h"
#ifdef DEBUG
-#define NLDEBUG
#define DEBUG_DEL
#endif
@@ -45,6 +44,7 @@ enum {
NFT_XT_CTX_BITWISE = (1 << 2),
NFT_XT_CTX_IMMEDIATE = (1 << 3),
NFT_XT_CTX_PREV_PAYLOAD = (1 << 4),
+ NFT_XT_CTX_RANGE = (1 << 5),
};
struct nft_xt_ctx {
@@ -53,6 +53,10 @@ struct nft_xt_ctx {
struct nft_handle *h;
uint32_t flags;
const char *table;
+ union {
+ struct xt_tcp *tcp;
+ struct xt_udp *udp;
+ } tcpudp;
uint32_t reg;
struct {
@@ -74,59 +78,75 @@ struct nft_xt_ctx {
};
struct nft_family_ops {
- int (*add)(struct nft_handle *h, struct nftnl_rule *r, void *data);
- bool (*is_same)(const void *data_a,
- const void *data_b);
+ int (*add)(struct nft_handle *h, struct nftnl_rule *r,
+ struct iptables_command_state *cs);
+ bool (*is_same)(const struct iptables_command_state *cs_a,
+ const struct iptables_command_state *cs_b);
void (*print_payload)(struct nftnl_expr *e,
struct nftnl_expr_iter *iter);
void (*parse_meta)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
+ struct iptables_command_state *cs);
void (*parse_payload)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
- void (*parse_bitwise)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
- void (*parse_cmp)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
- void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
- void (*parse_immediate)(const char *jumpto, bool nft_goto, void *data);
+ struct iptables_command_state *cs);
+ void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
+ void (*set_goto_flag)(struct iptables_command_state *cs);
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_rule)(const struct iptables_command_state *cs,
+ 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);
- void (*parse_match)(struct xtables_match *m, void *data);
- void (*parse_target)(struct xtables_target *t, void *data);
+ struct xt_cmd_parse_ops cmd_parse;
+ void (*parse_match)(struct xtables_match *m,
+ struct iptables_command_state *cs);
+ void (*parse_target)(struct xtables_target *t,
+ struct iptables_command_state *cs);
+ 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 (*xlate)(const struct iptables_command_state *cs,
+ 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);
-void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base);
-void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len);
-void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor);
-void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len);
-void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op);
-void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op);
-void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op);
-void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op);
-void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op);
-void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
+void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key, uint8_t *dreg);
+void add_payload(struct nft_handle *h, struct nftnl_rule *r, int offset, int len, uint32_t base, uint8_t *dreg);
+void add_bitwise(struct nft_handle *h, struct nftnl_rule *r, uint8_t *mask, size_t len, uint8_t sreg, uint8_t *dreg);
+void add_bitwise_u16(struct nft_handle *h, struct nftnl_rule *r, uint16_t mask, uint16_t xor, uint8_t sreg, uint8_t *dreg);
+void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len, uint8_t sreg);
+void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op, uint8_t sreg);
+void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op, uint8_t sreg);
+void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg);
+void add_iniface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op);
+void add_outiface(struct nft_handle *h, struct nftnl_rule *r, char *iface, uint32_t op);
+void add_addr(struct nft_handle *h, struct nftnl_rule *r, enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op);
-void add_proto(struct nftnl_rule *r, int offset, size_t len,
+void add_proto(struct nft_handle *h, struct nftnl_rule *r, int offset, size_t len,
uint8_t proto, uint32_t op);
-void add_l4proto(struct nftnl_rule *r, uint8_t proto, uint32_t op);
+void add_l4proto(struct nft_handle *h, struct nftnl_rule *r, uint8_t proto, uint32_t op);
void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv);
bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
@@ -136,30 +156,16 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
unsigned const char *b_iniface_mask,
unsigned const char *b_outiface_mask);
-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);
+int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key,
+ char *iniface, unsigned char *iniface_mask, char *outiface,
+ unsigned char *outiface_mask, uint8_t *invflags);
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,
@@ -167,55 +173,12 @@ void save_matches_and_target(const struct iptables_command_state *cs,
struct nft_family_ops *nft_family_ops_lookup(int family);
-void nft_ipv46_parse_target(struct xtables_target *t, void *data);
+void nft_ipv46_parse_target(struct xtables_target *t,
+ struct iptables_command_state *cs);
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;
- uint8_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 bde4ca72..ec79f2bc 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -39,6 +39,8 @@
#include <linux/netfilter/nf_tables_compat.h>
#include <linux/netfilter/xt_limit.h>
+#include <linux/netfilter/xt_NFLOG.h>
+#include <linux/netfilter/xt_mark.h>
#include <libmnl/libmnl.h>
#include <libnftnl/gen.h>
@@ -88,11 +90,11 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
#define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize())
-/* selected batch page is 256 Kbytes long to load ruleset of
- * half a million rules without hitting -EMSGSIZE due to large
- * iovec.
+/* Selected batch page is 2 Mbytes long to support loading a ruleset of 3.5M
+ * rules matching on source and destination address as well as input and output
+ * interfaces. This is what legacy iptables supports.
*/
-#define BATCH_PAGE_SIZE getpagesize() * 32
+#define BATCH_PAGE_SIZE 2 * 1024 * 1024
static struct nftnl_batch *mnl_batch_init(void)
{
@@ -143,7 +145,7 @@ struct mnl_err {
static void mnl_err_list_node_add(struct list_head *err_list, int error,
int seqnum)
{
- struct mnl_err *err = malloc(sizeof(struct mnl_err));
+ struct mnl_err *err = xtables_malloc(sizeof(struct mnl_err));
err->seqnum = seqnum;
err->err = error;
@@ -220,8 +222,10 @@ static int mnl_batch_talk(struct nft_handle *h, int numcmds)
int err = 0;
ret = mnl_nft_socket_sendmsg(h, numcmds);
- if (ret == -1)
+ if (ret == -1) {
+ fprintf(stderr, "sendmsg() failed: %s\n", strerror(errno));
return -1;
+ }
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
@@ -288,7 +292,7 @@ static int mnl_append_error(const struct nft_handle *h,
[NFT_COMPAT_TABLE_FLUSH] = "TABLE_FLUSH",
[NFT_COMPAT_CHAIN_ADD] = "CHAIN_ADD",
[NFT_COMPAT_CHAIN_USER_ADD] = "CHAIN_USER_ADD",
- [NFT_COMPAT_CHAIN_USER_DEL] = "CHAIN_USER_DEL",
+ [NFT_COMPAT_CHAIN_DEL] = "CHAIN_DEL",
[NFT_COMPAT_CHAIN_USER_FLUSH] = "CHAIN_USER_FLUSH",
[NFT_COMPAT_CHAIN_UPDATE] = "CHAIN_UPDATE",
[NFT_COMPAT_CHAIN_RENAME] = "CHAIN_RENAME",
@@ -319,7 +323,7 @@ static int mnl_append_error(const struct nft_handle *h,
case NFT_COMPAT_CHAIN_ADD:
case NFT_COMPAT_CHAIN_ZERO:
case NFT_COMPAT_CHAIN_USER_ADD:
- case NFT_COMPAT_CHAIN_USER_DEL:
+ case NFT_COMPAT_CHAIN_DEL:
case NFT_COMPAT_CHAIN_USER_FLUSH:
case NFT_COMPAT_CHAIN_UPDATE:
case NFT_COMPAT_CHAIN_RENAME:
@@ -360,10 +364,7 @@ static struct obj_update *batch_add(struct nft_handle *h, enum obj_update_type t
{
struct obj_update *obj;
- obj = calloc(1, sizeof(struct obj_update));
- if (obj == NULL)
- return NULL;
-
+ obj = xtables_calloc(1, sizeof(struct obj_update));
obj->ptr = ptr;
obj->error.lineno = h->error.lineno;
obj->type = type;
@@ -657,6 +658,7 @@ static int nft_table_builtin_add(struct nft_handle *h,
if (t == NULL)
return -1;
+ nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, h->family);
nftnl_table_set_str(t, NFTNL_TABLE_NAME, _t->name);
ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1;
@@ -665,7 +667,7 @@ static int nft_table_builtin_add(struct nft_handle *h,
}
static struct nftnl_chain *
-nft_chain_builtin_alloc(const struct builtin_table *table,
+nft_chain_builtin_alloc(int family, const char *tname,
const struct builtin_chain *chain, int policy)
{
struct nftnl_chain *c;
@@ -674,7 +676,8 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
if (c == NULL)
return NULL;
- nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table->name);
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, family);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, tname);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain->name);
nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
@@ -693,7 +696,7 @@ static void nft_chain_builtin_add(struct nft_handle *h,
{
struct nftnl_chain *c;
- c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT);
+ c = nft_chain_builtin_alloc(h->family, table->name, chain, NF_ACCEPT);
if (c == NULL)
return;
@@ -864,7 +867,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));
@@ -882,7 +900,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;
@@ -911,15 +929,16 @@ void nft_fini(struct nft_handle *h)
mnl_socket_close(h->nl);
}
-static void nft_chain_print_debug(struct nftnl_chain *c, struct nlmsghdr *nlh)
+static void nft_chain_print_debug(struct nft_handle *h,
+ struct nftnl_chain *c, struct nlmsghdr *nlh)
{
-#ifdef NLDEBUG
- char tmp[1024];
-
- nftnl_chain_snprintf(tmp, sizeof(tmp), c, 0, 0);
- printf("DEBUG: chain: %s\n", tmp);
- mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
-#endif
+ if (h->verbose > 1) {
+ nftnl_chain_fprintf(stdout, c, 0, 0);
+ fprintf(stdout, "\n");
+ }
+ if (h->verbose > 2)
+ mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
+ sizeof(struct nfgenmsg));
}
static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
@@ -943,7 +962,7 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
_c = nft_chain_builtin_find(_t, chain);
if (_c != NULL) {
/* This is a built-in chain */
- c = nft_chain_builtin_alloc(_t, _c, policy);
+ c = nft_chain_builtin_alloc(h->family, _t->name, _c, policy);
if (c == NULL)
return NULL;
} else {
@@ -995,10 +1014,7 @@ static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
nftnl_expr_set(e, NFTNL_EXPR_MT_NAME, m->u.user.name, strlen(m->u.user.name));
nftnl_expr_set_u32(e, NFTNL_EXPR_MT_REV, m->u.user.revision);
- info = calloc(1, m->u.match_size);
- if (info == NULL)
- return -ENOMEM;
-
+ info = xtables_calloc(1, m->u.match_size);
memcpy(info, m->data, m->u.match_size - sizeof(*m));
nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m));
@@ -1074,16 +1090,32 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
}
static struct nftnl_expr *
-gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint32_t dreg)
+__gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint8_t reg)
{
struct nftnl_expr *e = nftnl_expr_alloc("payload");
if (!e)
return NULL;
+
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base);
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len);
- nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, reg);
+
+ return e;
+}
+
+static struct nftnl_expr *
+gen_payload(struct nft_handle *h, uint32_t base, uint32_t offset, uint32_t len,
+ uint8_t *dreg)
+{
+ struct nftnl_expr *e;
+ uint8_t reg;
+
+ reg = NFT_REG_1;
+ e = __gen_payload(base, offset, len, reg);
+ *dreg = reg;
+
return e;
}
@@ -1128,6 +1160,7 @@ static int __add_nft_among(struct nft_handle *h, const char *table,
struct nftnl_expr *e;
struct nftnl_set *s;
uint32_t flags = 0;
+ uint8_t reg;
int idx = 0;
if (ip) {
@@ -1168,21 +1201,22 @@ static int __add_nft_among(struct nft_handle *h, const char *table,
nftnl_set_elem_add(s, elem);
}
- e = gen_payload(NFT_PAYLOAD_LL_HEADER,
- eth_addr_off[dst], ETH_ALEN, NFT_REG_1);
+ e = gen_payload(h, NFT_PAYLOAD_LL_HEADER,
+ eth_addr_off[dst], ETH_ALEN, &reg);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
if (ip) {
- e = gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst],
- sizeof(struct in_addr), NFT_REG32_02);
+ e = gen_payload(h, NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst],
+ sizeof(struct in_addr), &reg);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
}
- e = gen_lookup(NFT_REG_1, "__set%d", set_id, inv);
+ reg = NFT_REG_1;
+ e = gen_lookup(reg, "__set%d", set_id, inv);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
@@ -1199,9 +1233,10 @@ static int add_nft_among(struct nft_handle *h,
if ((data->src.cnt && data->src.ip) ||
(data->dst.cnt && data->dst.ip)) {
uint16_t eth_p_ip = htons(ETH_P_IP);
+ uint8_t reg;
- add_meta(r, NFT_META_PROTOCOL);
- add_cmp_ptr(r, NFT_CMP_EQ, &eth_p_ip, 2);
+ add_meta(h, r, NFT_META_PROTOCOL, &reg);
+ add_cmp_ptr(r, NFT_CMP_EQ, &eth_p_ip, 2, reg);
}
if (data->src.cnt)
@@ -1214,6 +1249,202 @@ static int add_nft_among(struct nft_handle *h,
return 0;
}
+static int expr_gen_range_cmp16(struct nftnl_rule *r,
+ uint16_t lo,
+ uint16_t hi,
+ bool invert, uint8_t reg)
+{
+ struct nftnl_expr *e;
+
+ if (lo == hi) {
+ add_cmp_u16(r, htons(lo), invert ? NFT_CMP_NEQ : NFT_CMP_EQ, reg);
+ return 0;
+ }
+
+ if (lo == 0 && hi < 0xffff) {
+ add_cmp_u16(r, htons(hi) , invert ? NFT_CMP_GT : NFT_CMP_LTE, reg);
+ return 0;
+ }
+
+ e = nftnl_expr_alloc("range");
+ if (!e)
+ return -ENOMEM;
+
+ nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_SREG, reg);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_OP, invert ? NFT_RANGE_NEQ : NFT_RANGE_EQ);
+
+ lo = htons(lo);
+ nftnl_expr_set(e, NFTNL_EXPR_RANGE_FROM_DATA, &lo, sizeof(lo));
+ hi = htons(hi);
+ nftnl_expr_set(e, NFTNL_EXPR_RANGE_TO_DATA, &hi, sizeof(hi));
+
+ nftnl_rule_add_expr(r, e);
+ return 0;
+}
+
+static int add_nft_tcpudp(struct nft_handle *h,struct nftnl_rule *r,
+ uint16_t src[2], bool invert_src,
+ uint16_t dst[2], bool invert_dst)
+{
+ struct nftnl_expr *expr;
+ uint8_t op = NFT_CMP_EQ;
+ uint8_t reg;
+ int ret;
+
+ if (src[0] && src[0] == src[1] &&
+ dst[0] && dst[0] == dst[1] &&
+ invert_src == invert_dst) {
+ uint32_t combined = dst[0] | (src[0] << 16);
+
+ if (invert_src)
+ op = NFT_CMP_NEQ;
+
+ expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 0, 4, &reg);
+ if (!expr)
+ return -ENOMEM;
+
+ nftnl_rule_add_expr(r, expr);
+ add_cmp_u32(r, htonl(combined), op, reg);
+ return 0;
+ }
+
+ if (src[0] || src[1] < 0xffff) {
+ expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 0, 2, &reg);
+ if (!expr)
+ return -ENOMEM;
+
+ nftnl_rule_add_expr(r, expr);
+ ret = expr_gen_range_cmp16(r, src[0], src[1], invert_src, reg);
+ if (ret)
+ return ret;
+ }
+
+ if (dst[0] || dst[1] < 0xffff) {
+ expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 2, 2, &reg);
+ if (!expr)
+ return -ENOMEM;
+
+ nftnl_rule_add_expr(r, expr);
+ ret = expr_gen_range_cmp16(r, dst[0], dst[1], invert_dst, reg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* without this, "iptables -A INPUT -m udp" is
+ * turned into "iptables -A INPUT", which isn't
+ * compatible with iptables-legacy behaviour.
+ */
+static bool udp_all_zero(const struct xt_udp *u)
+{
+ static const struct xt_udp zero = {
+ .spts[1] = 0xffff,
+ .dpts[1] = 0xffff,
+ };
+
+ return memcmp(u, &zero, sizeof(*u)) == 0;
+}
+
+static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r,
+ struct xt_entry_match *m)
+{
+ struct xt_udp *udp = (void *)m->data;
+
+ if (udp->invflags > XT_UDP_INV_MASK ||
+ udp_all_zero(udp)) {
+ struct nftnl_expr *expr = nftnl_expr_alloc("match");
+ int ret;
+
+ ret = __add_match(expr, m);
+ nftnl_rule_add_expr(r, expr);
+ return ret;
+ }
+
+ return add_nft_tcpudp(h, r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT,
+ udp->dpts, udp->invflags & XT_UDP_INV_DSTPT);
+}
+
+static int add_nft_tcpflags(struct nft_handle *h, struct nftnl_rule *r,
+ uint8_t cmp, uint8_t mask,
+ bool invert)
+{
+ struct nftnl_expr *e;
+ uint8_t reg;
+
+ e = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 13, 1, &reg);
+
+ if (!e)
+ return -ENOMEM;
+
+ nftnl_rule_add_expr(r, e);
+
+ add_bitwise(h, r, &mask, 1, reg, &reg);
+ add_cmp_u8(r, cmp, invert ? NFT_CMP_NEQ : NFT_CMP_EQ, reg);
+
+ return 0;
+}
+
+static bool tcp_all_zero(const struct xt_tcp *t)
+{
+ static const struct xt_tcp zero = {
+ .spts[1] = 0xffff,
+ .dpts[1] = 0xffff,
+ };
+
+ return memcmp(t, &zero, sizeof(*t)) == 0;
+}
+
+static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r,
+ struct xt_entry_match *m)
+{
+ static const uint8_t supported = XT_TCP_INV_SRCPT | XT_TCP_INV_DSTPT | XT_TCP_INV_FLAGS;
+ struct xt_tcp *tcp = (void *)m->data;
+
+ if (tcp->invflags & ~supported || tcp->option ||
+ tcp_all_zero(tcp)) {
+ struct nftnl_expr *expr = nftnl_expr_alloc("match");
+ int ret;
+
+ ret = __add_match(expr, m);
+ nftnl_rule_add_expr(r, expr);
+ return ret;
+ }
+
+ if (tcp->flg_mask) {
+ int ret = add_nft_tcpflags(h, r, tcp->flg_cmp, tcp->flg_mask,
+ tcp->invflags & XT_TCP_INV_FLAGS);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return add_nft_tcpudp(h, r, tcp->spts, tcp->invflags & XT_TCP_INV_SRCPT,
+ tcp->dpts, tcp->invflags & XT_TCP_INV_DSTPT);
+}
+
+static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r,
+ struct xt_entry_match *m)
+{
+ struct xt_mark_mtinfo1 *mark = (void *)m->data;
+ uint8_t reg;
+ int op;
+
+ add_meta(h, r, NFT_META_MARK, &reg);
+ if (mark->mask != 0xffffffff)
+ add_bitwise(h, r, (uint8_t *)&mark->mask, sizeof(uint32_t), reg, &reg);
+
+ if (mark->invert)
+ op = NFT_CMP_NEQ;
+ else
+ op = NFT_CMP_EQ;
+
+ add_cmp_u32(r, mark->mark, op, reg);
+
+ return 0;
+}
+
int add_match(struct nft_handle *h,
struct nftnl_rule *r, struct xt_entry_match *m)
{
@@ -1224,6 +1455,12 @@ int add_match(struct nft_handle *h,
return add_nft_limit(r, m);
else if (!strcmp(m->u.user.name, "among"))
return add_nft_among(h, r, m);
+ else if (!strcmp(m->u.user.name, "udp"))
+ return add_nft_udp(h, r, m);
+ else if (!strcmp(m->u.user.name, "tcp"))
+ return add_nft_tcp(h, r, m);
+ else if (!strcmp(m->u.user.name, "mark"))
+ return add_nft_mark(h, r, m);
expr = nftnl_expr_alloc("match");
if (expr == NULL)
@@ -1243,10 +1480,7 @@ static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
strlen(t->u.user.name));
nftnl_expr_set_u32(e, NFTNL_EXPR_TG_REV, t->u.user.revision);
- info = calloc(1, t->u.target_size);
- if (info == NULL)
- return -ENOMEM;
-
+ info = xtables_calloc(1, t->u.target_size);
memcpy(info, t->data, t->u.target_size - sizeof(*t));
nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t));
@@ -1327,38 +1561,66 @@ 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;
-}
-
-static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh)
-{
-#ifdef NLDEBUG
- char tmp[1024];
-
- nftnl_rule_snprintf(tmp, sizeof(tmp), r, 0, 0);
- printf("DEBUG: rule: %s\n", tmp);
- mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
-#endif
+ 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 nft_handle *h,
+ struct nftnl_rule *r, struct nlmsghdr *nlh)
+{
+ if (h->verbose > 1) {
+ nftnl_rule_fprintf(stdout, r, 0, 0);
+ fprintf(stdout, "\n");
+ }
+ if (h->verbose > 2)
+ mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
+ sizeof(struct nfgenmsg));
}
int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes)
@@ -1427,7 +1689,7 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
struct nftnl_rule *
nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
- void *data)
+ struct iptables_command_state *cs)
{
struct nftnl_rule *r;
@@ -1439,7 +1701,7 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
- if (h->ops->add(h, r, data) < 0)
+ if (h->ops->add(h, r, cs) < 0)
goto err;
return r;
@@ -1505,10 +1767,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;
}
@@ -1754,6 +2016,8 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
return 1;
}
+ nft_cache_sort_chains(h, table);
+
ret = nft_chain_foreach(h, table, nft_rule_flush_cb, &d);
/* the core expects 1 for success and 0 for error */
@@ -1778,6 +2042,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (c == NULL)
return 0;
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
if (h->family == NFPROTO_BRIDGE)
@@ -1808,6 +2073,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
if (!c)
return 0;
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
created = true;
@@ -1841,51 +2107,71 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
#define NLM_F_NONREC 0x100 /* Do not delete recursively */
#endif
-struct chain_user_del_data {
+struct chain_del_data {
struct nft_handle *handle;
+ const char *chain;
bool verbose;
- int builtin_err;
};
-static int __nft_chain_user_del(struct nft_chain *nc, void *data)
+static bool nft_may_delete_chain(struct nftnl_chain *c)
{
- struct chain_user_del_data *d = data;
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY) &&
+ nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY) != NF_ACCEPT)
+ return false;
+
+ return nftnl_rule_lookup_byindex(c, 0) == NULL;
+}
+
+static int __nft_chain_del(struct nft_chain *nc, void *data)
+{
+ struct chain_del_data *d = data;
struct nftnl_chain *c = nc->nftnl;
struct nft_handle *h = d->handle;
+ bool builtin = nft_chain_builtin(c);
+ struct obj_update *obj;
+ int ret = 0;
- /* don't delete built-in chain */
- if (nft_chain_builtin(c))
- return d->builtin_err;
-
- if (d->verbose)
+ if (d->verbose && !builtin)
fprintf(stdout, "Deleting chain `%s'\n",
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
/* XXX This triggers a fast lookup from the kernel. */
nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
- if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c))
+ obj = batch_chain_add(h, NFT_COMPAT_CHAIN_DEL, c);
+ if (!obj)
return -1;
+ if (builtin) {
+ obj->skip = !nft_may_delete_chain(c);
+ if (obj->skip && d->chain) {
+ /* complain if explicitly requested */
+ errno = EBUSY;
+ ret = -1;
+ }
+ *nc->base_slot = NULL;
+ }
+
/* nftnl_chain is freed when deleting the batch object */
nc->nftnl = NULL;
nft_chain_list_del(nc);
nft_chain_free(nc);
- return 0;
+ return ret;
}
-int nft_chain_user_del(struct nft_handle *h, const char *chain,
- const char *table, bool verbose)
+int nft_chain_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
{
- struct chain_user_del_data d = {
+ struct chain_del_data d = {
.handle = h,
+ .chain = chain,
.verbose = verbose,
};
struct nft_chain *c;
int ret = 0;
- nft_fn = nft_chain_user_del;
+ nft_fn = nft_chain_del;
if (chain) {
c = nft_chain_find(h, table, chain);
@@ -1893,14 +2179,15 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
errno = ENOENT;
return 0;
}
- d.builtin_err = -2;
- ret = __nft_chain_user_del(c, &d);
- if (ret == -2)
- errno = EINVAL;
+
+ ret = __nft_chain_del(c, &d);
goto out;
}
- ret = nft_chain_foreach(h, table, __nft_chain_user_del, &d);
+ if (verbose)
+ nft_cache_sort_chains(h, table);
+
+ ret = nft_chain_foreach(h, table, __nft_chain_del, &d);
out:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1948,6 +2235,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
if (c == NULL)
return 0;
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
@@ -1996,6 +2284,7 @@ static int __nft_table_flush(struct nft_handle *h, const char *table, bool exist
if (t == NULL)
return -1;
+ nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, h->family);
nftnl_table_set_str(t, NFTNL_TABLE_NAME, table);
obj = batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t);
@@ -2367,7 +2656,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 = {
@@ -2376,11 +2664,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 {
@@ -2437,6 +2726,8 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
return 1;
}
+ nft_cache_sort_chains(h, table);
+
if (ops->print_table_header)
ops->print_table_header(table);
@@ -2540,6 +2831,8 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
return nft_rule_list_cb(c, &d);
}
+ nft_cache_sort_chains(h, table);
+
/* Dump policies and custom chains first */
nft_chain_foreach(h, table, nft_rule_list_chain_save, &counters);
@@ -2582,6 +2875,18 @@ error:
return ret;
}
+static void nft_table_print_debug(struct nft_handle *h,
+ struct nftnl_table *t, struct nlmsghdr *nlh)
+{
+ if (h->verbose > 1) {
+ nftnl_table_fprintf(stdout, t, 0, 0);
+ fprintf(stdout, "\n");
+ }
+ if (h->verbose > 2)
+ mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
+ sizeof(struct nfgenmsg));
+}
+
static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
uint16_t flags, uint32_t seq,
struct nftnl_table *table)
@@ -2591,6 +2896,7 @@ static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
nlh = nftnl_table_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
type, h->family, flags, seq);
nftnl_table_nlmsg_build_payload(nlh, table);
+ nft_table_print_debug(h, table, nlh);
}
static void nft_compat_set_batch_add(struct nft_handle *h, uint16_t type,
@@ -2635,7 +2941,7 @@ static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
nlh = nftnl_chain_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
type, h->family, flags, seq);
nftnl_chain_nlmsg_build_payload(nlh, chain);
- nft_chain_print_debug(chain, nlh);
+ nft_chain_print_debug(h, chain, nlh);
}
static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
@@ -2647,7 +2953,7 @@ static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
nlh = nftnl_rule_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
type, h->family, flags, seq);
nftnl_rule_nlmsg_build_payload(nlh, rule);
- nft_rule_print_debug(rule, nlh);
+ nft_rule_print_debug(h, rule, nlh);
}
static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
@@ -2661,7 +2967,7 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
case NFT_COMPAT_CHAIN_USER_ADD:
case NFT_COMPAT_CHAIN_ADD:
break;
- case NFT_COMPAT_CHAIN_USER_DEL:
+ case NFT_COMPAT_CHAIN_DEL:
case NFT_COMPAT_CHAIN_USER_FLUSH:
case NFT_COMPAT_CHAIN_UPDATE:
case NFT_COMPAT_CHAIN_RENAME:
@@ -2743,10 +3049,14 @@ static void nft_refresh_transaction(struct nft_handle *h)
n->skip = !nft_chain_find(h, tablename, chainname);
break;
+ case NFT_COMPAT_CHAIN_DEL:
+ if (!nftnl_chain_get(n->chain, NFTNL_CHAIN_HOOKNUM))
+ break;
+ n->skip = !nft_may_delete_chain(n->chain);
+ break;
case NFT_COMPAT_TABLE_ADD:
case NFT_COMPAT_CHAIN_ADD:
case NFT_COMPAT_CHAIN_ZERO:
- case NFT_COMPAT_CHAIN_USER_DEL:
case NFT_COMPAT_CHAIN_USER_FLUSH:
case NFT_COMPAT_CHAIN_UPDATE:
case NFT_COMPAT_CHAIN_RENAME:
@@ -2812,7 +3122,7 @@ retry:
NLM_F_EXCL, n->seq,
n->chain);
break;
- case NFT_COMPAT_CHAIN_USER_DEL:
+ case NFT_COMPAT_CHAIN_DEL:
nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
NLM_F_NONREC, n->seq,
n->chain);
@@ -3057,9 +3367,9 @@ static int nft_prepare(struct nft_handle *h)
case NFT_COMPAT_CHAIN_USER_ADD:
ret = nft_chain_user_add(h, cmd->chain, cmd->table);
break;
- case NFT_COMPAT_CHAIN_USER_DEL:
- ret = nft_chain_user_del(h, cmd->chain, cmd->table,
- cmd->verbose);
+ case NFT_COMPAT_CHAIN_DEL:
+ ret = nft_chain_del(h, cmd->chain, cmd->table,
+ cmd->verbose);
break;
case NFT_COMPAT_CHAIN_RESTORE:
ret = nft_chain_restore(h, cmd->chain, cmd->table);
@@ -3115,7 +3425,7 @@ static int nft_prepare(struct nft_handle *h)
case NFT_COMPAT_RULE_CHECK:
assert_chain_exists(h, cmd->table, cmd->jumpto);
ret = nft_rule_check(h, cmd->chain, cmd->table,
- cmd->obj.rule, cmd->rulenum);
+ cmd->obj.rule, cmd->verbose);
break;
case NFT_COMPAT_RULE_ZERO:
ret = nft_rule_zero_counters(h, cmd->chain, cmd->table,
@@ -3245,6 +3555,20 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt)
err:
mnl_socket_close(nl);
+ /* ignore EPERM and errors for revision 0 -
+ * this is required for printing extension help texts as user, also
+ * helps error messaging on unavailable kernel extension */
+ if (ret < 0) {
+ if (errno == EPERM)
+ return 1;
+ if (rev == 0) {
+ fprintf(stderr,
+ "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
+ name);
+ return 1;
+ }
+ }
+
return ret < 0 ? 0 : 1;
}
@@ -3258,10 +3582,9 @@ const char *nft_strerror(int err)
const char *message;
} table[] =
{
- { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" },
- { nft_chain_user_del, EINVAL, "Can't delete built-in chain" },
- { nft_chain_user_del, EBUSY, "Directory not empty" },
- { nft_chain_user_del, EMLINK,
+ { nft_chain_del, ENOTEMPTY, "Chain is not empty" },
+ { nft_chain_del, EBUSY, "Directory not empty" },
+ { nft_chain_del, EMLINK,
"Can't delete chain with references left" },
{ nft_chain_user_add, EEXIST, "Chain already exists" },
{ nft_chain_user_rename, EEXIST, "File exists" },
@@ -3431,6 +3754,9 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
goto err;
}
+ if (verbose)
+ nft_cache_sort_chains(h, table);
+
ret = nft_chain_foreach(h, table, __nft_chain_zero_counters, &d);
err:
/* the core expects 1 for success and 0 for error */
@@ -3455,6 +3781,7 @@ static const char *supported_exprs[] = {
"counter",
"immediate",
"lookup",
+ "range",
};
@@ -3473,6 +3800,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;
}
@@ -3484,38 +3815,8 @@ static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data)
static int nft_is_chain_compatible(struct nft_chain *nc, void *data)
{
struct nftnl_chain *c = nc->nftnl;
- const struct builtin_table *table;
- const struct builtin_chain *chain;
- const char *tname, *cname, *type;
- struct nft_handle *h = data;
- enum nf_inet_hooks hook;
- int prio;
-
- if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL))
- return -1;
-
- if (!nft_chain_builtin(c))
- return 0;
-
- tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- table = nft_table_builtin_find(h, tname);
- if (!table)
- return -1;
-
- cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- chain = nft_chain_builtin_find(table, cname);
- if (!chain)
- return -1;
- type = nftnl_chain_get_str(c, NFTNL_CHAIN_TYPE);
- prio = nftnl_chain_get_u32(c, NFTNL_CHAIN_PRIO);
- hook = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
- if (strcmp(type, chain->type) ||
- prio != chain->prio ||
- hook != chain->hook)
- return -1;
-
- return 0;
+ return nftnl_rule_foreach(c, nft_is_rule_compatible, NULL);
}
bool nft_is_table_compatible(struct nft_handle *h,
@@ -3530,13 +3831,24 @@ bool nft_is_table_compatible(struct nft_handle *h,
return !nft_chain_foreach(h, table, nft_is_chain_compatible, h);
}
+bool nft_is_table_tainted(struct nft_handle *h, const char *table)
+{
+ const struct builtin_table *t = nft_table_builtin_find(h, table);
+
+ return t ? h->cache->table[t->type].tainted : false;
+}
+
void nft_assert_table_compatible(struct nft_handle *h,
const char *table, const char *chain)
{
const char *pfx = "", *sfx = "";
- if (nft_is_table_compatible(h, table, chain))
+ if (nft_is_table_compatible(h, table, chain)) {
+ if (nft_is_table_tainted(h, table))
+ printf("# Table `%s' contains incompatible base-chains, use 'nft' tool to list them.\n",
+ table);
return;
+ }
if (chain) {
pfx = "chain `";
diff --git a/iptables/nft.h b/iptables/nft.h
index 0910f82a..68b0910c 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -44,6 +44,8 @@ struct nft_cache {
struct nft_chain_list *chains;
struct nftnl_set_list *sets;
bool exists;
+ bool sorted;
+ bool tainted;
} table[NFT_TABLE_MAX];
};
@@ -52,7 +54,7 @@ enum obj_update_type {
NFT_COMPAT_TABLE_FLUSH,
NFT_COMPAT_CHAIN_ADD,
NFT_COMPAT_CHAIN_USER_ADD,
- NFT_COMPAT_CHAIN_USER_DEL,
+ NFT_COMPAT_CHAIN_DEL,
NFT_COMPAT_CHAIN_USER_FLUSH,
NFT_COMPAT_CHAIN_UPDATE,
NFT_COMPAT_CHAIN_RENAME,
@@ -107,6 +109,7 @@ struct nft_handle {
int8_t config_done;
struct list_head cmd_list;
bool cache_init;
+ int verbose;
/* meta data, for error reporting */
struct {
@@ -121,7 +124,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);
@@ -146,7 +149,7 @@ struct nftnl_chain;
int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters);
int nft_chain_save(struct nft_chain *c, void *data);
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table);
-int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose);
+int nft_chain_del(struct nft_handle *h, const char *chain, const char *table, bool verbose);
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table);
int nft_chain_user_rename(struct nft_handle *h, const char *chain, const char *table, const char *newname);
int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose);
@@ -170,7 +173,7 @@ struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
*/
struct nftnl_rule;
-struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data);
+struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cs);
int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose);
int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
@@ -192,6 +195,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 {
@@ -261,6 +265,7 @@ void nft_rule_to_arpt_entry(struct nftnl_rule *r, struct arpt_entry *fw);
bool nft_is_table_compatible(struct nft_handle *h,
const char *table, const char *chain);
+bool nft_is_table_tainted(struct nft_handle *h, const char *table);
void nft_assert_table_compatible(struct nft_handle *h,
const char *table, const char *chain);
diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh
index 65c37adb..7878760f 100755
--- a/iptables/tests/shell/run-tests.sh
+++ b/iptables/tests/shell/run-tests.sh
@@ -195,4 +195,4 @@ failed=$((legacy_fail+failed))
msg_info "combined results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
-exit 0
+exit -$failed
diff --git a/iptables/tests/shell/testcases/chain/0004extra-base_0 b/iptables/tests/shell/testcases/chain/0004extra-base_0
new file mode 100755
index 00000000..cc07e4be
--- /dev/null
+++ b/iptables/tests/shell/testcases/chain/0004extra-base_0
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+case $XT_MULTI in
+*xtables-nft-multi)
+ ;;
+*)
+ echo skip $XT_MULTI
+ exit 0
+ ;;
+esac
+
+set -e
+
+nft -f - <<EOF
+table ip filter {
+ chain a {
+ type filter hook input priority filter
+ }
+
+ chain INPUT {
+ type filter hook input priority filter
+ counter packets 218 bytes 91375 accept
+ }
+
+ chain x {
+ type filter hook input priority filter
+ }
+}
+EOF
+
+EXPECT="# Table \`filter' contains incompatible base-chains, use 'nft' tool to list them.
+-P INPUT ACCEPT
+-P FORWARD ACCEPT
+-P OUTPUT ACCEPT
+-A INPUT -j ACCEPT"
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -S)
diff --git a/iptables/tests/shell/testcases/chain/0005base-delete_0 b/iptables/tests/shell/testcases/chain/0005base-delete_0
new file mode 100755
index 00000000..033a2819
--- /dev/null
+++ b/iptables/tests/shell/testcases/chain/0005base-delete_0
@@ -0,0 +1,34 @@
+#!/bin/bash -x
+
+$XT_MULTI iptables -N foo || exit 1
+$XT_MULTI iptables -P FORWARD DROP || exit 1
+$XT_MULTI iptables -X || exit 1
+$XT_MULTI iptables -X foo && exit 1
+
+# indefinite -X fails if a non-empty user-defined chain exists
+$XT_MULTI iptables -N foo
+$XT_MULTI iptables -N bar
+$XT_MULTI iptables -A bar -j ACCEPT
+$XT_MULTI iptables -X && exit 1
+$XT_MULTI iptables -D bar -j ACCEPT
+$XT_MULTI iptables -X || exit 1
+
+# make sure OUTPUT chain is created by iptables-nft
+$XT_MULTI iptables -A OUTPUT -j ACCEPT || exit 1
+$XT_MULTI iptables -D OUTPUT -j ACCEPT || exit 1
+
+case $XT_MULTI in
+*xtables-nft-multi)
+ # must not delete chain FORWARD, its policy is not ACCEPT
+ $XT_MULTI iptables -X FORWARD && exit 1
+ nft list chain ip filter FORWARD || exit 1
+ # this should evict chain OUTPUT
+ $XT_MULTI iptables -X OUTPUT || exit 1
+ nft list chain ip filter OUTPUT && exit 1
+ ;;
+*)
+ $XT_MULTI iptables -X FORWARD && exit 1
+ $XT_MULTI iptables -X OUTPUT && exit 1
+ ;;
+esac
+exit 0
diff --git a/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0
new file mode 100755
index 00000000..d79f91b1
--- /dev/null
+++ b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+case "$XT_MULTI" in
+*xtables-nft-multi)
+ ;;
+*)
+ echo "skip $XT_MULTI"
+ exit 0
+ ;;
+esac
+
+set -e
+
+# ebtables supports policies in user-defined chains %)
+# and the default policy is ACCEPT ...
+$XT_MULTI ebtables -N FOO -P DROP
+$XT_MULTI ebtables -N BAR
+$XT_MULTI ebtables -P BAR RETURN
+$XT_MULTI ebtables -N BAZ
+
+EXPECT_BASE="*filter
+:INPUT ACCEPT
+:FORWARD ACCEPT
+:OUTPUT ACCEPT"
+
+EXPECT="$EXPECT_BASE
+:BAR RETURN
+:BAZ ACCEPT
+:FOO DROP"
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
+
+# rule commands must not break the policies
+$XT_MULTI ebtables -A FOO -j ACCEPT
+$XT_MULTI ebtables -D FOO -j ACCEPT
+$XT_MULTI ebtables -F
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
+
+# dropping the chains must implicitly remove the policy rule as well
+$XT_MULTI ebtables -X
+diff -u -Z <(echo -e "$EXPECT_BASE") <($XT_MULTI ebtables-save | grep -v '^#')
diff --git a/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0 b/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0
new file mode 100755
index 00000000..7eb42f08
--- /dev/null
+++ b/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -e
+
+$XT_MULTI ip6tables-restore <<EOF
+*filter
+-A FORWARD -s feed:babe::/ffff::0
+-A FORWARD -s feed:babe::/ffff:ff00::0
+-A FORWARD -s feed:babe::/ffff:fff0::0
+-A FORWARD -s feed:babe::/ffff:ffff::0
+-A FORWARD -s feed:babe::/0:ffff::0
+-A FORWARD -s feed:c0ff::babe:f00/ffff::ffff:0
+COMMIT
+EOF
+
+EXPECT='-P FORWARD ACCEPT
+-A FORWARD -s feed::/16
+-A FORWARD -s feed:ba00::/24
+-A FORWARD -s feed:bab0::/28
+-A FORWARD -s feed:babe::/32
+-A FORWARD -s 0:babe::/0:ffff::
+-A FORWARD -s feed::babe:0/ffff::ffff:0'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ip6tables -S FORWARD)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0 b/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0
index 5c8748ec..d632cbc0 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0
@@ -2,7 +2,7 @@
set -e
-# make sure wait and wait-interval options are accepted
+# make sure wait options are accepted
clean_tempfile()
{
@@ -18,4 +18,3 @@ tmpfile=$(mktemp) || exit 1
$XT_MULTI iptables-save -f $tmpfile
$XT_MULTI iptables-restore $tmpfile
$XT_MULTI iptables-restore -w 5 $tmpfile
-$XT_MULTI iptables-restore -w 5 -W 1 $tmpfile
diff --git a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
index fc8559c5..5daf7a78 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
@@ -33,6 +33,7 @@ Flushing chain \`bar'
Flushing chain \`foo'
Deleting chain \`bar'
Deleting chain \`foo'
+ACCEPT all opt -- in * out * 0.0.0.0/0 -> 0.0.0.0/0
Flushing chain \`PREROUTING'
Flushing chain \`INPUT'
Flushing chain \`OUTPUT'
@@ -41,6 +42,7 @@ Flushing chain \`natbar'
Flushing chain \`natfoo'
Deleting chain \`natbar'
Deleting chain \`natfoo'
+ACCEPT all opt -- in * out * 0.0.0.0/0 -> 0.0.0.0/0
Flushing chain \`PREROUTING'
Flushing chain \`OUTPUT'
Flushing chain \`rawfoo'
@@ -58,9 +60,10 @@ Flushing chain \`OUTPUT'
Flushing chain \`secfoo'
Deleting chain \`secfoo'"
-for ipt in iptables-restore ip6tables-restore; do
- diff -u -Z <(echo "$EXPECT") <($XT_MULTI $ipt -v <<< "$DUMP")
-done
+EXPECT6=$(sed -e 's/0\.0\.0\.0/::/g' -e 's/opt --/opt /' <<< "$EXPECT")
+
+diff -u -Z <(echo "$EXPECT") <($XT_MULTI iptables-restore -v <<< "$DUMP")
+diff -u -Z <(echo "$EXPECT6") <($XT_MULTI ip6tables-restore -v <<< "$DUMP")
DUMP="*filter
:baz - [0:0]
diff --git a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0
index b1ef91f6..5d2af4c8 100755
--- a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0
+++ b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0
@@ -54,3 +54,14 @@ diff -u <(echo "Flushing chain \`foobar'") <($XT_MULTI iptables -v -F foobar)
diff -u <(echo "Zeroing chain \`foobar'") <($XT_MULTI iptables -v -Z foobar)
diff -u <(echo "Deleting chain \`foobar'") <($XT_MULTI iptables -v -X foobar)
+
+# make sure non-verbose mode is silent
+diff -u <(echo -n "") <(
+ $XT_MULTI iptables -N foobar
+ $XT_MULTI iptables -A foobar $RULE1
+ $XT_MULTI iptables -A foobar $RULE2
+ $XT_MULTI iptables -C foobar $RULE1
+ $XT_MULTI iptables -D foobar $RULE2
+ $XT_MULTI iptables -F foobar
+ $XT_MULTI iptables -X foobar
+)
diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
index dcd9dfd3..33c5f1f3 100755
--- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
@@ -39,7 +39,7 @@ E2BIG_D=": Index of deletion too big."
E2BIG_R=": Index of replacement too big."
EBADRULE=": Bad rule (does a matching rule exist in that chain?)."
#ENOTGT=" v[0-9\.]* [^ ]*: Couldn't load target \`foobar':No such file or directory"
-ENOMTH=" v[0-9\.]* [^ ]*: Couldn't load match \`foobar':No such file or directory"
+ENOMTH=" v[0-9\.]* [^ ]*: Couldn't \(load\|find\) match \`foobar'\(:No such file or directory\|\)"
ENOTBL=": can't initialize iptables table \`foobar': Table does not exist"
# test chain creation
diff --git a/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0
new file mode 100755
index 00000000..36da1907
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+RC=0
+COUNTR=$RANDOM$RANDOM
+
+$XT_MULTI iptables-restore -c <<EOF
+*filter
+:INPUT ACCEPT [1:23]
+:FOO - [0:0]
+[12:345] -A INPUT -i lo -p icmp -m comment --comment "$COUNTR"
+[22:123] -A FOO -m comment --comment one
+[44:123] -A FOO -m comment --comment two
+COMMIT
+EOF
+EXPECT="*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+:FOO - [0:0]
+[0:0] -A INPUT -i lo -p icmp -m comment --comment "$COUNTR"
+[0:0] -A FOO -m comment --comment one
+[0:0] -A FOO -m comment --comment two
+COMMIT"
+
+COUNTER=$($XT_MULTI iptables-save -c |grep "comment $COUNTR"| cut -f 1 -d " ")
+if [ $COUNTER != "[12:345]" ]; then
+ echo "Counter $COUNTER is wrong, expected 12:345"
+ RC=1
+fi
+
+$XT_MULTI iptables -Z FOO
+COUNTER=$($XT_MULTI iptables-save -c |grep "comment $COUNTR"| cut -f 1 -d " ")
+if [ $COUNTER = "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, should not have been zeroed"
+ RC=1
+fi
+
+for c in one two; do
+ COUNTER=$($XT_MULTI iptables-save -c |grep "comment $c"| cut -f 1 -d " ")
+ if [ $COUNTER != "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, should have been zeroed at rule $c"
+ RC=1
+ fi
+done
+
+$XT_MULTI iptables -Z
+COUNTER=$($XT_MULTI iptables-save -c |grep "comment $COUNTR"| cut -f 1 -d " ")
+
+if [ $COUNTER != "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, expected 0:0 after -Z"
+ RC=1
+fi
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save -c | grep -v '^#')
+if [ $? -ne 0 ]; then
+ echo "Diff error: counters were not zeroed"
+ RC=1
+fi
+
+$XT_MULTI iptables -D INPUT -i lo -p icmp -m comment --comment "$COUNTR"
+$XT_MULTI iptables -D FOO -m comment --comment one
+$XT_MULTI iptables -D FOO -m comment --comment two
+$XT_MULTI iptables -X FOO
+exit $RC
diff --git a/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0
new file mode 100755
index 00000000..983531fe
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# iptables may print match/target specific help texts
+# help output should work for unprivileged users
+
+run() {
+ echo "running: $*" >&2
+ runuser -u nobody -- "$@"
+}
+
+grep_or_rc() {
+ declare -g rc
+ grep -q "$*" && return 0
+ echo "missing in output: $*" >&2
+ return 1
+}
+
+out=$(run $XT_MULTI iptables --help)
+let "rc+=$?"
+grep_or_rc "iptables -h (print this help information)" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -m limit --help)
+let "rc+=$?"
+grep_or_rc "limit match options:" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -p tcp --help)
+let "rc+=$?"
+grep_or_rc "tcp match options:" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -j DNAT --help)
+let "rc+=$?"
+grep_or_rc "DNAT target options:" <<< "$out"
+let "rc+=$?"
+
+# TEE has no revision 0
+out=$(run $XT_MULTI iptables -j TEE --help)
+let "rc+=$?"
+grep_or_rc "TEE target options:" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -p tcp -j DNAT --help)
+let "rc+=$?"
+grep_or_rc "tcp match options:" <<< "$out"
+let "rc+=$?"
+out=$(run $XT_MULTI iptables -p tcp -j DNAT --help)
+let "rc+=$?"
+grep_or_rc "DNAT target options:" <<< "$out"
+let "rc+=$?"
+
+
+run $XT_MULTI iptables -L 2>&1 | \
+ grep_or_rc "Permission denied"
+let "rc+=$?"
+
+run $XT_MULTI iptables -A FORWARD -p tcp --dport 123 2>&1 | \
+ grep_or_rc "Permission denied"
+let "rc+=$?"
+
+run $XT_MULTI iptables -A FORWARD -j DNAT --to-destination 1.2.3.4 2>&1 | \
+ grep_or_rc "Permission denied"
+let "rc+=$?"
+
+exit $rc
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 71f68990..a8512d38 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -9,16 +9,31 @@
#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>
-#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <xtables.h>
#include <math.h>
+#include <signal.h>
#include "xshared.h"
+/* a few arp opcode names */
+char *arp_opcodes[] =
+{
+ "Request",
+ "Reply",
+ "Request_Reverse",
+ "Reply_Reverse",
+ "DRARP_Request",
+ "DRARP_Reply",
+ "DRARP_Error",
+ "InARP_Request",
+ "ARP_NAK",
+};
+
/*
* Print out any special helps. A user might like to be able to add a --help
* to the commandline, and see expected results. So we call help for all
@@ -47,21 +62,21 @@ void print_extension_helps(const struct xtables_target *t,
}
}
-const char *
-proto_to_name(uint8_t proto, int nolookup)
+static const char *
+proto_to_name(uint16_t proto, int nolookup)
{
unsigned int i;
+ for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
+ if (xtables_chain_protos[i].num == proto)
+ return xtables_chain_protos[i].name;
+
if (proto && !nolookup) {
struct protoent *pent = getprotobynumber(proto);
if (pent)
return pent->p_name;
}
- for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
- if (xtables_chain_protos[i].num == proto)
- return xtables_chain_protos[i].name;
-
return NULL;
}
@@ -106,7 +121,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;
@@ -115,7 +130,7 @@ struct xtables_match *load_proto(struct iptables_command_state *cs)
}
int command_default(struct iptables_command_state *cs,
- struct xtables_globals *gl)
+ struct xtables_globals *gl, bool invert)
{
struct xtables_rule_match *matchp;
struct xtables_match *m;
@@ -124,7 +139,7 @@ int command_default(struct iptables_command_state *cs,
(cs->target->parse != NULL || cs->target->x6_parse != NULL) &&
cs->c >= cs->target->option_offset &&
cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) {
- xtables_option_tpcall(cs->c, cs->argv, cs->invert,
+ xtables_option_tpcall(cs->c, cs->argv, invert,
cs->target, &cs->fw);
return 0;
}
@@ -138,7 +153,7 @@ int command_default(struct iptables_command_state *cs,
if (cs->c < matchp->match->option_offset ||
cs->c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE)
continue;
- xtables_option_mpcall(cs->c, cs->argv, cs->invert, m, &cs->fw);
+ xtables_option_mpcall(cs->c, cs->argv, invert, m, &cs->fw);
return 0;
}
@@ -220,9 +235,7 @@ void xs_init_target(struct xtables_target *target)
{
if (target->udata_size != 0) {
free(target->udata);
- target->udata = calloc(1, target->udata_size);
- if (target->udata == NULL)
- xtables_error(RESOURCE_PROBLEM, "malloc");
+ target->udata = xtables_calloc(1, target->udata_size);
}
if (target->init != NULL)
target->init(target->t);
@@ -238,22 +251,20 @@ void xs_init_match(struct xtables_match *match)
* Same goes for target.
*/
free(match->udata);
- match->udata = calloc(1, match->udata_size);
- if (match->udata == NULL)
- xtables_error(RESOURCE_PROBLEM, "malloc");
+ match->udata = xtables_calloc(1, match->udata_size);
}
if (match->init != NULL)
match->init(match->m);
}
-static int xtables_lock(int wait, struct timeval *wait_interval)
+static void alarm_ignore(int i) {
+}
+
+static int xtables_lock(int wait)
{
- struct timeval time_left, wait_time;
+ struct sigaction sigact_alarm;
const char *lock_file;
- int fd, i = 0;
-
- time_left.tv_sec = wait;
- time_left.tv_usec = 0;
+ int fd;
lock_file = getenv("XTABLES_LOCKFILE");
if (lock_file == NULL || lock_file[0] == '\0')
@@ -266,31 +277,24 @@ static int xtables_lock(int wait, struct timeval *wait_interval)
return XT_LOCK_FAILED;
}
- if (wait == -1) {
- if (flock(fd, LOCK_EX) == 0)
- return fd;
-
- fprintf(stderr, "Can't lock %s: %s\n", lock_file,
- strerror(errno));
- return XT_LOCK_BUSY;
+ if (wait != -1) {
+ sigact_alarm.sa_handler = alarm_ignore;
+ sigact_alarm.sa_flags = SA_RESETHAND;
+ sigemptyset(&sigact_alarm.sa_mask);
+ sigaction(SIGALRM, &sigact_alarm, NULL);
+ alarm(wait);
}
- while (1) {
- if (flock(fd, LOCK_EX | LOCK_NB) == 0)
- return fd;
- else if (timercmp(&time_left, wait_interval, <))
- return XT_LOCK_BUSY;
+ if (flock(fd, LOCK_EX) == 0)
+ return fd;
- if (++i % 10 == 0) {
- fprintf(stderr, "Another app is currently holding the xtables lock; "
- "still %lds %ldus time ahead to have a chance to grab the lock...\n",
- time_left.tv_sec, time_left.tv_usec);
- }
-
- wait_time = *wait_interval;
- select(0, NULL, NULL, NULL, &wait_time);
- timersub(&time_left, wait_interval, &time_left);
+ if (errno == EINTR) {
+ errno = EWOULDBLOCK;
}
+
+ fprintf(stderr, "Can't lock %s: %s\n", lock_file,
+ strerror(errno));
+ return XT_LOCK_BUSY;
}
void xtables_unlock(int lock)
@@ -299,9 +303,9 @@ void xtables_unlock(int lock)
close(lock);
}
-int xtables_lock_or_exit(int wait, struct timeval *wait_interval)
+int xtables_lock_or_exit(int wait)
{
- int lock = xtables_lock(wait, wait_interval);
+ int lock = xtables_lock(wait);
if (lock == XT_LOCK_FAILED) {
xtables_free_opts(1);
@@ -337,7 +341,7 @@ int parse_wait_time(int argc, char *argv[])
return wait;
}
-void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval)
+void parse_wait_interval(int argc, char *argv[])
{
const char *arg;
unsigned int usec;
@@ -357,8 +361,7 @@ void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval)
"too long usec wait %u > 999999 usec",
usec);
- wait_interval->tv_sec = 0;
- wait_interval->tv_usec = usec;
+ fprintf(stderr, "Ignoring deprecated --wait-interval option.\n");
return;
}
xtables_error(PARAMETER_PROBLEM, "wait interval not numeric");
@@ -435,7 +438,7 @@ void add_argv(struct argv_store *store, const char *what, int quoted)
xtables_error(PARAMETER_PROBLEM,
"Trying to store NULL argument\n");
- store->argv[store->argc] = strdup(what);
+ store->argv[store->argc] = xtables_strdup(what);
store->argvattr[store->argc] = quoted;
store->argv[++store->argc] = NULL;
}
@@ -550,9 +553,55 @@ void debug_print_argv(struct argv_store *store)
}
#endif
-static 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)
+{
+ 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)
{
static char buf[BUFSIZ];
@@ -582,6 +631,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)
@@ -616,6 +701,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 */
@@ -641,13 +764,38 @@ void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
printf(FMT("%-6s ", "out %s "), iface);
}
-void command_match(struct iptables_command_state *cs)
+/* 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;
struct xtables_match *m;
size_t size;
- if (cs->invert)
+ if (invert)
xtables_error(PARAMETER_PROBLEM,
"unexpected ! flag before --match");
@@ -853,3 +1001,998 @@ char opt2char(int option)
return *ptr;
}
+
+static const int inverse_for_options[NUMBER_OF_OPT] =
+{
+/* -n */ 0,
+/* -s */ IPT_INV_SRCIP,
+/* -d */ IPT_INV_DSTIP,
+/* -p */ XT_INV_PROTO,
+/* -j */ 0,
+/* -v */ 0,
+/* -x */ 0,
+/* -i */ IPT_INV_VIA_IN,
+/* -o */ IPT_INV_VIA_OUT,
+/*--line*/ 0,
+/* -c */ 0,
+/* -f */ IPT_INV_FRAG,
+/* 2 */ IPT_INV_SRCDEVADDR,
+/* 3 */ IPT_INV_TGTDEVADDR,
+/* -l */ IPT_INV_ARPHLN,
+/* 4 */ IPT_INV_ARPOP,
+/* 5 */ IPT_INV_ARPHRD,
+/* 6 */ IPT_INV_PROTO,
+};
+
+void
+set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
+ bool invert)
+{
+ if (*options & option)
+ xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
+ opt2char(option));
+ *options |= option;
+
+ if (invert) {
+ unsigned int i;
+ for (i = 0; 1 << i != option; i++);
+
+ if (!inverse_for_options[i])
+ xtables_error(PARAMETER_PROBLEM,
+ "cannot have ! before -%c",
+ opt2char(option));
+ *invflg |= inverse_for_options[i];
+ }
+}
+
+void assert_valid_chain_name(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;
+}
+
+static 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"
+"\n"
+"Options:\n");
+
+ if (afinfo->family == NFPROTO_ARP) {
+ printf(
+"[!] --source-ip -s address[/mask]\n"
+" source specification\n"
+"[!] --destination-ip -d address[/mask]\n"
+" destination specification\n"
+"[!] --source-mac address[/mask]\n"
+"[!] --destination-mac address[/mask]\n"
+" --h-length -l length[/mask] hardware length (nr of bytes)\n"
+" --opcode code[/mask] operation code (2 bytes)\n"
+" --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n"
+" --proto-type type[/mask] protocol type (2 bytes)\n");
+ } else {
+ printf(
+" --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",
+ afinfo->family == NFPROTO_IPV4 ? "Nothing" : "Error",
+ afinfo->family == NFPROTO_IPV4 ? "Error" : "Nothing");
+ }
+
+ printf(
+"[!] --in-interface -i input name[+]\n"
+" network interface name ([+] for wildcard)\n"
+" --jump -j target\n"
+" target for rule (may load target extension)\n");
+
+ 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"
+" --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 -c PKTS BYTES set the counter during insert/append\n"
+"[!] --version -V print package version.\n");
+
+ if (afinfo->family == NFPROTO_ARP) {
+ int i;
+
+ printf(" opcode strings: \n");
+ for (i = 0; i < ARP_NUMOPCODES; i++)
+ printf(" %d = %s\n", i + 1, arp_opcodes[i]);
+ printf(
+ " hardware type string: 1 = Ethernet\n"
+ " protocol type string: 0x800 = IPv4\n");
+
+ xtables_find_target("standard", XTF_TRY_LOAD);
+ xtables_find_target("mangle", XTF_TRY_LOAD);
+ xtables_find_target("CLASSIFY", XTF_TRY_LOAD);
+ xtables_find_target("MARK", XTF_TRY_LOAD);
+ }
+
+ 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, "%s", 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 `!'");
+ }
+}
+
+static const char *optstring_lookup(int family)
+{
+ switch (family) {
+ case AF_INET:
+ case AF_INET6:
+ return IPT_OPTSTRING;
+ case NFPROTO_ARP:
+ return ARPT_OPTSTRING;
+ case NFPROTO_BRIDGE:
+ return EBT_OPTSTRING;
+ }
+ return "";
+}
+
+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,
+ optstring_lookup(afinfo->family),
+ 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':
+ assert_valid_chain_name(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);
+
+ xtables_printhelp(cs->matches);
+ exit(0);
+
+ /*
+ * 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);
+ 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 9159b2b1..14568bb0 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -6,7 +6,6 @@
#include <stdint.h>
#include <netinet/in.h>
#include <net/if.h>
-#include <sys/time.h>
#include <linux/netfilter_arp/arp_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
@@ -68,6 +67,22 @@ 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 IPT_OPTSTRING OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x"
+#define ARPT_OPTSTRING OPTSTRING_COMMON "R:S::" "h::l:nv" /* "m:" */
+#define EBT_OPTSTRING OPTSTRING_COMMON "hv"
+
+/* define invflags which won't collide with IPT ones */
+#define IPT_INV_SRCDEVADDR 0x0080
+#define IPT_INV_TGTDEVADDR 0x0100
+#define IPT_INV_ARPHLN 0x0200
+#define IPT_INV_ARPOP 0x0400
+#define IPT_INV_ARPHRD 0x0800
+
+void
+set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
+ bool invert);
+
/**
* xtables_afinfo - protocol family dependent information
* @kmod: kernel module basename (e.g. "ip_tables")
@@ -125,7 +140,6 @@ struct iptables_command_state {
struct ip6t_entry fw6;
struct arpt_entry arp;
};
- int invert;
int c;
unsigned int options;
struct xtables_rule_match *matches;
@@ -152,10 +166,8 @@ enum {
extern void print_extension_helps(const struct xtables_target *,
const struct xtables_rule_match *);
-extern const char *proto_to_name(uint8_t, int);
extern int command_default(struct iptables_command_state *,
- struct xtables_globals *);
-extern struct xtables_match *load_proto(struct iptables_command_state *);
+ struct xtables_globals *, bool invert);
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 *);
@@ -179,10 +191,10 @@ enum {
XT_LOCK_NOT_ACQUIRED = -3,
};
extern void xtables_unlock(int lock);
-extern int xtables_lock_or_exit(int wait, struct timeval *tv);
+extern int xtables_lock_or_exit(int wait);
int parse_wait_time(int argc, char *argv[]);
-void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval);
+void parse_wait_interval(int argc, char *argv[]);
int parse_counters(const char *string, struct xt_counters *ctr);
bool tokenize_rule_counters(char **bufferp, char **pcnt, char **bcnt, int line);
bool xs_has_arg(int argc, char *argv[]);
@@ -206,13 +218,28 @@ void debug_print_argv(struct argv_store *store);
# define debug_print_argv(...) /* nothing */
#endif
+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 command_match(struct iptables_command_state *cs);
+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);
void command_jump(struct iptables_command_state *cs, const char *jumpto);
@@ -220,8 +247,92 @@ 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 assert_valid_chain_name(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 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 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);
+
+extern char *arp_opcodes[];
+#define ARP_NUMOPCODES 9
+
#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 4a89ae95..71518a9c 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -30,35 +30,22 @@
#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,337 +83,13 @@ 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)));
struct xtables_globals arptables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (nf_tables)",
.orig_opts = original_opts,
- .exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
};
-/* index relates to bit of each OPT_* value */
-static int inverse_for_options[] =
-{
-/* -n */ 0,
-/* -s */ IPT_INV_SRCIP,
-/* -d */ IPT_INV_DSTIP,
-/* -p */ 0,
-/* -j */ 0,
-/* -v */ 0,
-/* -x */ 0,
-/* -i */ IPT_INV_VIA_IN,
-/* -o */ IPT_INV_VIA_OUT,
-/*--line*/ 0,
-/* -c */ 0,
-/* -f */ 0,
-/* 2 */ IPT_INV_SRCDEVADDR,
-/* 3 */ IPT_INV_TGTDEVADDR,
-/* -l */ IPT_INV_ARPHLN,
-/* 4 */ IPT_INV_ARPOP,
-/* 5 */ IPT_INV_ARPHRD,
-/* 6 */ IPT_INV_PROTO,
-};
-
-/***********************************************/
-/* 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)
-{
- 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"
-" %s -D chain rulenum [options]\n"
-" %s -[LFZ] [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",
- arptables_globals.program_name,
- arptables_globals.program_version,
- arptables_globals.program_name,
- arptables_globals.program_name,
- 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"
-" --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] List 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"
-" --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"
-" --source-ip -s [!] address[/mask]\n"
-" source specification\n"
-" --destination-ip -d [!] address[/mask]\n"
-" destination specification\n"
-" --source-mac [!] address[/mask]\n"
-" --destination-mac [!] address[/mask]\n"
-" --h-length -l length[/mask] hardware length (nr of bytes)\n"
-" --opcode code[/mask] operation code (2 bytes)\n"
-" --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n"
-" --proto-type type[/mask] protocol type (2 bytes)\n"
-" --in-interface -i [!] input name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --out-interface -o [!] output name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --jump -j target\n"
-" target for rule (may load target extension)\n"
-" --match -m match\n"
-" extended match (may load extension)\n"
-" --numeric -n numeric output of addresses and ports\n"
-" --table -t table table to manipulate (default: `filter')\n"
-" --verbose -v verbose mode\n"
-" --line-numbers print line numbers when listing\n"
-" --exact -x expand numbers (display exact values)\n"
-" --modprobe=<command> try to insert modules using this command\n"
-" --set-counters -c PKTS BYTES set the counter during insert/append\n"
-"[!] --version -V print package version.\n");
- printf(" opcode strings: \n");
- for (i = 0; i < NUMOPCODES; i++)
- printf(" %d = %s\n", i + 1, arp_opcodes[i]);
- printf(
-" hardware type string: 1 = Ethernet\n"
-" protocol type string: 0x800 = IPv4\n");
-
- /* Print out any special helps. A user might like to be able
- to add a --help to the commandline, and see expected
- results. So we call help for all matches & targets */
- for (t = xtables_targets; t; t = t->next) {
- if (strcmp(t->name, "CLASSIFY") && strcmp(t->name, "mangle"))
- continue;
- printf("\n");
- t->help();
- }
-}
-
-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 void
-set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
- int invert)
-{
- if (*options & option)
- xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
- opt2char(option));
- *options |= option;
-
- if (invert) {
- unsigned int i;
- for (i = 0; 1 << i != option; i++);
-
- if (!inverse_for_options[i])
- xtables_error(PARAMETER_PROBLEM,
- "cannot have ! before -%c",
- opt2char(option));
- *invflg |= inverse_for_options[i];
- }
-}
-
-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;
@@ -436,536 +99,12 @@ int nft_init_arp(struct nft_handle *h, const char *pname)
arptables_globals.program_version);
exit(1);
}
-
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
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_user_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 83ae77cb..86177024 100644
--- a/iptables/xtables-eb-translate.c
+++ b/iptables/xtables-eb-translate.c
@@ -64,22 +64,6 @@ static int parse_rule_number(const char *rule)
return rule_nr;
}
-static int get_current_chain(const char *chain)
-{
- if (strcmp(chain, "PREROUTING") == 0)
- return NF_BR_PRE_ROUTING;
- else if (strcmp(chain, "INPUT") == 0)
- return NF_BR_LOCAL_IN;
- else if (strcmp(chain, "FORWARD") == 0)
- return NF_BR_FORWARD;
- else if (strcmp(chain, "OUTPUT") == 0)
- return NF_BR_LOCAL_OUT;
- else if (strcmp(chain, "POSTROUTING") == 0)
- return NF_BR_POST_ROUTING;
-
- return -1;
-}
-
/*
* The original ebtables parser
*/
@@ -103,7 +87,6 @@ static int get_current_chain(const char *chain)
/* 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
@@ -169,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);
@@ -208,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,
};
@@ -220,7 +203,6 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char
while ((c = getopt_long(argc, argv,
"-A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) {
cs.c = c;
- cs.invert = ebt_invert;
switch (c) {
case 'A': /* Add a rule */
case 'D': /* Delete a rule */
@@ -241,7 +223,7 @@ static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char
"Multiple commands are not allowed");
command = c;
chain = optarg;
- selected_chain = get_current_chain(chain);
+ selected_chain = ebt_get_current_chain(chain);
p.chain = chain;
flags |= OPT_COMMAND;
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index cfa9317c..3d15063e 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -195,6 +195,7 @@ struct option ebt_original_options[] =
{ "out-interface" , required_argument, 0, 'o' },
{ "out-if" , required_argument, 0, 'o' },
{ "version" , no_argument , 0, 'V' },
+ { "verbose" , no_argument , 0, 'v' },
{ "help" , no_argument , 0, 'h' },
{ "jump" , required_argument, 0, 'j' },
{ "set-counters" , required_argument, 0, 'c' },
@@ -211,21 +212,15 @@ struct option ebt_original_options[] =
{ "new-chain" , required_argument, 0, 'N' },
{ "rename-chain" , required_argument, 0, 'E' },
{ "delete-chain" , optional_argument, 0, 'X' },
- { "atomic-init" , no_argument , 0, 7 },
- { "atomic-commit" , no_argument , 0, 8 },
- { "atomic-file" , required_argument, 0, 9 },
- { "atomic-save" , no_argument , 0, 10 },
{ "init-table" , no_argument , 0, 11 },
{ "concurrent" , no_argument , 0, 13 },
{ 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)",
.orig_opts = ebt_original_options,
- .exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
};
@@ -278,9 +273,7 @@ static struct option *merge_options(struct option *oldopts,
ebtables_globals.option_offset += OPTION_OFFSET;
*options_offset = ebtables_globals.option_offset;
- merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
- if (!merge)
- return NULL;
+ merge = xtables_malloc(sizeof(struct option) * (num_new + num_old + 1));
memcpy(merge, oldopts, num_old * sizeof(struct option));
for (i = 0; i < num_new; i++) {
merge[num_old + i] = newopts[i];
@@ -320,10 +313,6 @@ static void print_help(const struct xtables_target *t,
"--new-chain -N chain : create a user defined chain\n"
"--rename-chain -E old new : rename a chain\n"
"--delete-chain -X [chain] : delete a user defined chain\n"
-"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
-"--atomic-init : put the initial kernel table into <FILE>\n"
-"--atomic-save : put the current kernel table into <FILE>\n"
-"--atomic-file file : set <FILE> to file\n\n"
"Options:\n"
"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
"--src -s [!] address[/mask]: source mac address\n"
@@ -336,6 +325,7 @@ static void print_help(const struct xtables_target *t,
" pcnt bcnt : set the counters of the to be added rule\n"
"--modprobe -M program : try to insert modules using this program\n"
"--concurrent : use a file lock to support concurrent scripts\n"
+"--verbose -v : verbose mode\n"
"--version -V : print package version\n\n"
"Environment variable:\n"
/*ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"*/
@@ -579,10 +569,7 @@ void ebt_add_match(struct xtables_match *m,
m->mflags = 0;
/* glue code for watchers */
- newnode = calloc(1, sizeof(struct ebt_match));
- if (newnode == NULL)
- xtables_error(OTHER_PROBLEM, "Unable to alloc memory");
-
+ newnode = xtables_calloc(1, sizeof(struct ebt_match));
newnode->ismatch = true;
newnode->u.match = newm;
@@ -611,10 +598,7 @@ void ebt_add_watcher(struct xtables_target *watcher,
watcher->tflags = 0;
- newnode = calloc(1, sizeof(struct ebt_match));
- if (newnode == NULL)
- xtables_error(OTHER_PROBLEM, "Unable to alloc memory");
-
+ newnode = xtables_calloc(1, sizeof(struct ebt_match));
newnode->u.watcher = clone;
for (matchp = &cs->match_list; *matchp; matchp = &(*matchp)->next)
@@ -683,12 +667,10 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
ebtables_globals.program_version);
exit(1);
}
-
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
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.");
@@ -743,15 +725,17 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
struct ebt_match *match;
bool table_set = false;
+ /* avoid cumulating verbosity with ebtables-restore */
+ h->verbose = 0;
+
/* prevent getopt to spoil our error reporting */
optind = 0;
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, EBT_OPTSTRING,
+ opts, NULL)) != -1) {
cs.c = c;
- cs.invert = ebt_invert;
switch (c) {
case 'A': /* Add a rule */
@@ -788,7 +772,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
chain = argv[optind];
optind++;
}
- ret = nft_cmd_chain_user_del(h, chain, *table, 0);
+ ret = nft_cmd_chain_del(h, chain, *table, 0);
break;
}
@@ -872,11 +856,15 @@ print_zero:
optind++;
}
break;
+ case 'v': /* verbose */
+ flags |= OPT_VERBOSE;
+ h->verbose++;
+ break;
case 'V': /* Version */
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)
@@ -912,12 +900,12 @@ 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);
- if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
- xtables_error(PARAMETER_PROBLEM,
- "Table name length cannot exceed %d characters",
- EBT_TABLE_MAXNAMELEN - 1);
+ "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",
+ optarg);
*table = optarg;
table_set = true;
break;
@@ -1088,54 +1076,9 @@ print_zero:
"Use --Lmac2 with -L");
flags |= LIST_MAC2;
break;
- case 8 : /* atomic-commit */
-/*
- replace->command = c;
- if (OPT_COMMANDS)
- ebt_print_error2("Multiple commands are not allowed");
- replace->flags |= OPT_COMMAND;
- if (!replace->filename)
- ebt_print_error2("No atomic file specified");*/
- /* Get the information from the file */
- /*ebt_get_table(replace, 0);*/
- /* We don't want the kernel giving us its counters,
- * they would overwrite the counters extracted from
- * the file */
- /*replace->num_counters = 0;*/
- /* Make sure the table will be written to the kernel */
- /*free(replace->filename);
- replace->filename = NULL;
- break;*/
- /*case 7 :*/ /* atomic-init */
- /*case 10:*/ /* atomic-save */
case 11: /* init-table */
nft_cmd_table_flush(h, *table, false);
return 1;
- /*
- replace->command = c;
- if (OPT_COMMANDS)
- ebt_print_error2("Multiple commands are not allowed");
- if (c != 11 && !replace->filename)
- ebt_print_error2("No atomic file specified");
- replace->flags |= OPT_COMMAND;
- {
- char *tmp = replace->filename;*/
-
- /* Get the kernel table */
- /*replace->filename = NULL;
- ebt_get_kernel_table(replace, c == 10 ? 0 : 1);
- replace->filename = tmp;
- }
- break;
- case 9 :*/ /* atomic */
- /*
- if (OPT_COMMANDS)
- ebt_print_error2("--atomic has to come before the command");*/
- /* A possible memory leak here, but this is not
- * executed in daemon mode */
- /*replace->filename = (char *)malloc(strlen(optarg) + 1);
- strcpy(replace->filename, optarg);
- break; */
case 13 :
break;
case 1 :
@@ -1209,24 +1152,26 @@ print_zero:
}
} else if (command == 'L') {
ret = list_rules(h, chain, *table, rule_nr,
- 0,
+ flags & OPT_VERBOSE,
0,
/*flags&OPT_EXPANDED*/0,
flags&LIST_N,
flags&LIST_C);
}
if (flags & OPT_ZERO) {
- ret = nft_cmd_chain_zero_counters(h, chain, *table, 0);
+ ret = nft_cmd_chain_zero_counters(h, chain, *table,
+ flags & OPT_VERBOSE);
} else if (command == 'F') {
- ret = nft_cmd_rule_flush(h, chain, *table, 0);
+ ret = nft_cmd_rule_flush(h, chain, *table, flags & OPT_VERBOSE);
} else if (command == 'A') {
- ret = append_entry(h, chain, *table, &cs, 0, 0, true);
+ ret = append_entry(h, chain, *table, &cs, 0,
+ flags & OPT_VERBOSE, true);
} else if (command == 'I') {
ret = append_entry(h, chain, *table, &cs, rule_nr - 1,
- 0, false);
+ flags & OPT_VERBOSE, false);
} else if (command == 'D') {
ret = delete_entry(h, chain, *table, &cs, rule_nr - 1,
- rule_nr_end, 0);
+ rule_nr_end, flags & OPT_VERBOSE);
} /*else if (replace->command == 'C') {
ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter);
if (ebt_errormsg[0] != '\0')
diff --git a/iptables/xtables-monitor.8.in b/iptables/xtables-monitor.8.in
index b647a79e..a7f22c0d 100644
--- a/iptables/xtables-monitor.8.in
+++ b/iptables/xtables-monitor.8.in
@@ -51,9 +51,9 @@ The second line dumps information about the packet. Incoming interface
and packet headers such as source and destination addresses are shown.
The third line shows that the packet completed traversal of the raw table
-PREROUTING chain, and is returning, followed by use the chain policy to make accept/drop
+PREROUTING chain, and is returning, followed by use of the chain policy to make accept/drop
decision (the example shows accept being applied).
-The fifth line shows that the packet leaves the filter INPUT chain, i.e., no rules in the filter tables
+The fifth line shows that the packet leaves the filter INPUT chain, i.e., no rules in the filter table's
INPUT chain matched the packet.
It then got DROPPED by the policy of the INPUT table, as shown by line six.
The last line shows another packet arriving \-\- the packet id is different.
@@ -81,7 +81,7 @@ by three base hooks INPUT, FORWARD and OUTPUT. The iptables-nftables tools all
chains automatically when needed, so this is expected when a table was not yet initialized or when it is
re-created from scratch by iptables-nftables-restore. Line five shows a new user-defined chain (TCP)
being added, followed by addition a few rules. the last line shows that a new ruleset generation has
-become active, i.e., the rule set changes are now active. This also lists the process id and the programs name.
+become active, i.e., the rule set changes are now active. This also lists the process id and the program name.
.SH LIMITATIONS
.B xtables-monitor
only works with rules added using iptables-nftables, rules added using
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 4b980980..905bb7fe 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -37,7 +37,6 @@
#include "iptables.h" /* for xtables_globals */
#include "xtables-multi.h"
#include "nft.h"
-#include "nft-arp.h"
struct cb_arg {
uint32_t nfproto;
@@ -625,12 +624,13 @@ int xtables_monitor_main(int argc, char *argv[])
xtables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
-#endif
+ init_extensions6();
+ init_extensionsa();
+ init_extensionsb();
- 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 d2739497..1363f96a 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -155,10 +155,8 @@ static void xtables_restore_parse_line(struct nft_handle *h,
"%s: line %u chain name invalid\n",
xt_params->program_name, line);
- if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s' (%u chars max)",
- chain, XT_EXTENSION_MAXNAMELEN - 1);
+ xtables_announce_chain(chain);
+ assert_valid_chain_name(chain);
policy = strtok(NULL, " \t\n");
DEBUGP("line %u, policy '%s'\n", line, policy);
@@ -206,11 +204,15 @@ static void xtables_restore_parse_line(struct nft_handle *h,
char *pcnt = NULL;
char *bcnt = NULL;
char *parsestart = buffer;
+ int i;
add_argv(&state->av_store, xt_params->program_name, 0);
add_argv(&state->av_store, "-t", 0);
add_argv(&state->av_store, state->curtable->name, 0);
+ for (i = 0; !h->noflush && i < verbose; i++)
+ add_argv(&state->av_store, "-v", 0);
+
tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line);
if (counters && pcnt && bcnt) {
add_argv(&state->av_store, "--set-counters", 0);
@@ -281,7 +283,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,
@@ -310,10 +311,10 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
counters = 1;
break;
case 'v':
- verbose = 1;
+ verbose++;
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;
@@ -357,27 +358,26 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
p.in = stdin;
}
+ init_extensions();
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();
-#endif
+ break;
+ case NFPROTO_IPV6:
+ init_extensions6();
break;
case NFPROTO_ARP:
- tables = xtables_arp;
+ init_extensionsa();
break;
case NFPROTO_BRIDGE:
- tables = xtables_bridge;
+ init_extensionsb();
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,
@@ -417,6 +417,7 @@ static const struct nft_xt_restore_cb ebt_restore_cb = {
static const struct option ebt_restore_options[] = {
{.name = "noflush", .has_arg = 0, .val = 'n'},
+ {.name = "verbose", .has_arg = 0, .val = 'v'},
{ 0 }
};
@@ -430,15 +431,18 @@ int xtables_eb_restore_main(int argc, char *argv[])
struct nft_handle h;
int c;
- while ((c = getopt_long(argc, argv, "n",
+ while ((c = getopt_long(argc, argv, "nv",
ebt_restore_options, NULL)) != -1) {
switch(c) {
case 'n':
noflush = 1;
break;
+ case 'v':
+ verbose++;
+ break;
default:
fprintf(stderr,
- "Usage: ebtables-restore [ --noflush ]\n");
+ "Usage: ebtables-restore [ --verbose ] [ --noflush ]\n");
exit(1);
break;
}
@@ -455,7 +459,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 d7901c65..5a82cac5 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -78,6 +78,9 @@ __do_output(struct nft_handle *h, const char *tablename, void *data)
printf("# Table `%s' is incompatible, use 'nft' tool.\n",
tablename);
return 0;
+ } else if (nft_is_table_tainted(h, tablename)) {
+ printf("# Table `%s' contains incompatible base-chains, use 'nft' tool to list them.\n",
+ tablename);
}
now = time(NULL);
@@ -87,6 +90,7 @@ __do_output(struct nft_handle *h, const char *tablename, void *data)
printf("*%s\n", tablename);
/* Dump out chain names first,
* thereby preventing dependency conflicts */
+ nft_cache_sort_chains(h, tablename);
nft_chain_foreach(h, tablename, nft_chain_save, h);
nft_rule_save(h, tablename, d->format);
if (d->commit)
@@ -127,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,
@@ -181,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,
@@ -196,18 +199,18 @@ xtables_save_main(int family, int argc, char *argv[],
exit(1);
}
+ init_extensions();
switch (family) {
case NFPROTO_IPV4:
- case NFPROTO_IPV6: /* fallthough, same table */
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
init_extensions4();
-#endif
- tables = xtables_ipv4;
+ d.commit = true;
+ break;
+ case NFPROTO_IPV6:
+ init_extensions6();
d.commit = true;
break;
case NFPROTO_ARP:
- tables = xtables_arp;
+ init_extensionsa();
break;
case NFPROTO_BRIDGE: {
const char *ctr = getenv("EBTABLES_SAVE_COUNTER");
@@ -218,7 +221,7 @@ xtables_save_main(int family, int argc, char *argv[],
d.format &= ~FMT_NOCOUNTS;
d.format |= FMT_C_COUNTS | FMT_EBT_SAVE;
}
- tables = xtables_bridge;
+ init_extensionsb();
break;
}
default:
@@ -226,7 +229,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 7b71db62..117b0c69 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -39,31 +39,53 @@
#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);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ xt_params->program_name = progname;
init_extensions();
- init_extensions4();
-#endif
+ switch (family) {
+ case NFPROTO_IPV4:
+ init_extensions4();
+ break;
+ case NFPROTO_IPV6:
+ init_extensions6();
+ break;
+ case NFPROTO_ARP:
+ init_extensionsa();
+ break;
+ case NFPROTO_BRIDGE:
+ init_extensionsb();
+ break;
+ }
- 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);
}
@@ -95,3 +117,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 575fb320..d1e87f16 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -150,34 +150,47 @@ 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)
{
struct xt_xlate *xl = xt_xlate_alloc(10240);
+ const char *set;
int ret;
+ xl_xlate_set_family(xl, h->family);
+ ret = h->ops->xlate(cs, xl);
+ if (!ret)
+ goto err_out;
+
+ set = xt_xlate_set_get(xl);
+ if (set[0]) {
+ printf("add set %s %s %s\n", family2str[h->family], p->table,
+ xt_xlate_set_get(xl));
+
+ if (!cs->restore && p->command != CMD_NONE)
+ printf("nft ");
+ }
+
if (append) {
- xt_xlate_add(xl, "add rule %s %s %s ",
- family2str[h->family], p->table, p->chain);
+ printf("add rule %s %s %s ",
+ family2str[h->family], p->table, p->chain);
} else {
- xt_xlate_add(xl, "insert rule %s %s %s ",
- family2str[h->family], p->table, p->chain);
+ printf("insert rule %s %s %s ",
+ family2str[h->family], p->table, p->chain);
}
+ printf("%s\n", xt_xlate_rule_get(xl));
- ret = h->ops->xlate(cs, xl);
- if (ret)
- printf("%s\n", xt_xlate_get(xl));
-
+err_out:
xt_xlate_free(xl);
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))
{
@@ -235,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 = {
+ .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);
cs.restore = restore;
@@ -341,9 +363,10 @@ static void print_usage(const char *name, const char *version)
{
fprintf(stderr, "%s %s "
"(c) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>\n"
- "Usage: %s [-h] [-f]\n"
+ "Usage: %s [-h] [-f <FILE>] [-V]\n"
" [ --help ]\n"
- " [ --file=<FILE> ]\n", name, version, name);
+ " [ --file=<FILE> ]\n"
+ " [ --version ]\n", name, version, name);
exit(1);
}
@@ -451,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;
@@ -463,27 +485,26 @@ static int xtables_xlate_main_common(struct nft_handle *h,
xtables_globals.program_version);
return 1;
}
+ init_extensions();
switch (family) {
case NFPROTO_IPV4:
- case NFPROTO_IPV6: /* fallthrough: same table */
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
- init_extensions4();
-#endif
- tables = xtables_ipv4;
+ init_extensions4();
+ break;
+ case NFPROTO_IPV6:
+ init_extensions6();
break;
case NFPROTO_ARP:
- tables = xtables_arp;
+ init_extensionsa();
break;
case NFPROTO_BRIDGE:
- tables = xtables_bridge;
+ init_extensionsb();
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 9779bd83..70924176 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -36,6 +36,7 @@
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
+#include <netinet/ether.h>
#include <iptables.h>
#include <xtables.h>
#include <fcntl.h>
@@ -84,149 +85,13 @@ 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)",
.orig_opts = original_opts,
- .exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
};
-static const int inverse_for_options[NUMBER_OF_OPT] =
-{
-/* -n */ 0,
-/* -s */ IPT_INV_SRCIP,
-/* -d */ IPT_INV_DSTIP,
-/* -p */ XT_INV_PROTO,
-/* -j */ 0,
-/* -v */ 0,
-/* -x */ 0,
-/* -i */ IPT_INV_VIA_IN,
-/* -o */ IPT_INV_VIA_OUT,
-/*--line*/ 0,
-/* -c */ 0,
-/* -f */ IPT_INV_FRAG,
-};
-
-#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.
@@ -238,189 +103,6 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...)
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
-static void
-set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
- int invert)
-{
- if (*options & option)
- xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
- opt2char(option));
- *options |= option;
-
- if (invert) {
- unsigned int i;
- for (i = 0; 1 << i != option; i++);
-
- if (!inverse_for_options[i])
- xtables_error(PARAMETER_PROBLEM,
- "cannot have ! before -%c",
- opt2char(option));
- *invflg |= inverse_for_options[i];
- }
-}
-
-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,
@@ -456,540 +138,61 @@ 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;
- 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,
- cs->invert);
- p->chain = optarg;
- break;
-
- case 'C':
- add_command(&p->command, CMD_CHECK, CMD_NONE,
- cs->invert);
- p->chain = optarg;
- break;
-
- case 'D':
- add_command(&p->command, CMD_DELETE, CMD_NONE,
- cs->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,
- cs->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,
- cs->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, cs->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, cs->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,
- cs->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, cs->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,
- cs->invert);
- p->chain = optarg;
- break;
-
- case 'X':
- add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
- cs->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,
- cs->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,
- cs->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, cs->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, cs->invert);
- args->shostnetworkmask = optarg;
- break;
-
- case 'd':
- set_option(&cs->options, OPT_DESTINATION,
- &args->invflags, cs->invert);
- args->dhostnetworkmask = optarg;
- break;
-
-#ifdef IPT_F_GOTO
- case 'g':
- set_option(&cs->options, OPT_JUMP, &args->invflags,
- cs->invert);
- args->goto_set = true;
- cs->jumpto = xt_parse_target(optarg);
- break;
-#endif
-
- case 'j':
- set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags,
- cs->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, cs->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, cs->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,
- cs->invert);
- args->flags |= IPT_F_FRAG;
- break;
-
- case 'v':
- if (!p->verbose)
- set_option(&cs->options, OPT_VERBOSE,
- &args->invflags, cs->invert);
- p->verbose++;
- break;
-
- case 'm':
- command_match(cs);
- break;
-
- case 'n':
- set_option(&cs->options, OPT_NUMERIC, &args->invflags,
- cs->invert);
- break;
-
- case 't':
- if (cs->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,
- cs->invert);
- break;
-
- case 'V':
- if (cs->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, cs->invert);
- break;
-
- case 'M':
- xtables_modprobe_program = optarg;
- break;
-
- case 'c':
- set_option(&cs->options, OPT_COUNTERS, &args->invflags,
- cs->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 (cs->invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- cs->invert = true;
- optarg[0] = '\0';
- continue;
- }
- fprintf(stderr, "Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (command_default(cs, &xtables_globals) == 1)
- /* cf. ip6tables.c */
- continue;
- break;
- }
- cs->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 (cs->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);
+ h->verbose = p.verbose;
+ if (!nft_table_builtin_find(h, p.table))
+ xtables_error(VERSION_PROBLEM,
+ "table '%s' does not exist",
+ p.table);
switch (p.command) {
case CMD_APPEND:
- ret = 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,
@@ -1040,8 +243,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
ret = nft_cmd_chain_user_add(h, p.chain, p.table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_cmd_chain_user_del(h, p.chain, p.table,
- cs.options & OPT_VERBOSE);
+ ret = nft_cmd_chain_del(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
break;
case CMD_RENAME_CHAIN:
ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
@@ -1054,24 +257,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 35fa6258..fb4eeca3 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -45,12 +45,11 @@
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
-#ifdef __BIONIC__
#include <linux/if_ether.h> /* ETH_ALEN */
-#endif
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <libiptc/libxtc.h>
+#include <libiptc/linux_list.h>
#ifndef NO_SHARED_LIBS
#include <dlfcn.h>
@@ -92,6 +91,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);
}
@@ -245,8 +256,83 @@ static void dlreg_free(void)
}
#endif
+struct notarget {
+ struct hlist_node node;
+ char name[];
+};
+
+#define NOTARGET_HSIZE 512
+static struct hlist_head notargets[NOTARGET_HSIZE];
+
+static void notargets_hlist_init(void)
+{
+ int i;
+
+ for (i = 0; i < NOTARGET_HSIZE; i++)
+ INIT_HLIST_HEAD(&notargets[i]);
+}
+
+static void notargets_hlist_free(void)
+{
+ struct hlist_node *pos, *n;
+ struct notarget *cur;
+ int i;
+
+ for (i = 0; i < NOTARGET_HSIZE; i++) {
+ hlist_for_each_entry_safe(cur, pos, n, &notargets[i], node) {
+ hlist_del(&cur->node);
+ free(cur);
+ }
+ }
+}
+
+static uint32_t djb_hash(const char *key)
+{
+ uint32_t i, hash = 5381;
+
+ for (i = 0; i < strlen(key); i++)
+ hash = ((hash << 5) + hash) + key[i];
+
+ return hash;
+}
+
+static struct notarget *notargets_hlist_lookup(const char *name)
+{
+ uint32_t key = djb_hash(name) % NOTARGET_HSIZE;
+ struct hlist_node *node;
+ struct notarget *cur;
+
+ hlist_for_each_entry(cur, node, &notargets[key], node) {
+ if (!strcmp(name, cur->name))
+ return cur;
+ }
+ return NULL;
+}
+
+static void notargets_hlist_insert(const char *name)
+{
+ struct notarget *cur;
+
+ if (!name)
+ return;
+
+ cur = xtables_malloc(sizeof(*cur) + strlen(name) + 1);
+ strcpy(cur->name, name);
+ hlist_add_head(&cur->node, &notargets[djb_hash(name) % NOTARGET_HSIZE]);
+}
+
+void xtables_announce_chain(const char *name)
+{
+ if (!notargets_hlist_lookup(name))
+ notargets_hlist_insert(name);
+}
+
void xtables_init(void)
{
+ /* xtables cannot be used with setuid in a safe way. */
+ if (getuid() != geteuid())
+ _exit(111);
+
xtables_libdir = getenv("XTABLES_LIBDIR");
if (xtables_libdir != NULL)
return;
@@ -270,6 +356,8 @@ void xtables_init(void)
return;
}
xtables_libdir = XTABLES_LIBDIR;
+
+ notargets_hlist_init();
}
void xtables_fini(void)
@@ -277,6 +365,7 @@ void xtables_fini(void)
#ifndef NO_SHARED_LIBS
dlreg_free();
#endif
+ notargets_hlist_free();
}
void xtables_set_nfproto(uint8_t nfproto)
@@ -371,6 +460,18 @@ void *xtables_realloc(void *ptr, size_t size)
return p;
}
+char *xtables_strdup(const char *s)
+{
+ char *dup = strdup(s);
+
+ if (!dup) {
+ perror("ip[6]tables: strdup failed");
+ exit(1);
+ }
+
+ return dup;
+}
+
static char *get_modprobe(void)
{
int procfile;
@@ -671,6 +772,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_match **dptr;
struct xtables_match *ptr;
const char *icmp6 = "icmp6";
+ bool found = false;
if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
@@ -689,7 +791,9 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_match(ptr, prev)) {
+ if (!found &&
+ xtables_fully_register_pending_match(ptr, prev)) {
+ found = true;
prev = ptr;
continue;
} else if (prev) {
@@ -791,6 +895,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
struct xtables_target *prev = NULL;
struct xtables_target **dptr;
struct xtables_target *ptr;
+ bool found = false;
/* Standard target? */
if (strcmp(name, "") == 0
@@ -799,13 +904,19 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
|| strcmp(name, XTC_LABEL_QUEUE) == 0
|| strcmp(name, XTC_LABEL_RETURN) == 0)
name = "standard";
+ /* known non-target? */
+ else if (notargets_hlist_lookup(name) &&
+ tryload != XTF_LOAD_MUST_SUCCEED)
+ return NULL;
/* Trigger delayed initialization */
for (dptr = &xtables_pending_targets; *dptr; ) {
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_target(ptr, prev)) {
+ if (!found &&
+ xtables_fully_register_pending_target(ptr, prev)) {
+ found = true;
prev = ptr;
continue;
} else if (prev) {
@@ -864,6 +975,8 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
if (ptr)
ptr->used = 1;
+ else
+ notargets_hlist_insert(name);
return ptr;
}
@@ -928,7 +1041,12 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
/* Definitely don't support this? */
if (errno == ENOENT || errno == EPROTONOSUPPORT) {
close(sockfd);
- return 0;
+ /* Pretend revision 0 support for better error messaging */
+ if (revision == 0)
+ fprintf(stderr,
+ "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
+ name);
+ return (revision == 0);
} else if (errno == ENOPROTOOPT) {
close(sockfd);
/* Assume only revision 0 support (old kernel) */
@@ -1383,7 +1501,7 @@ void xtables_param_act(unsigned int status, const char *p1, ...)
const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
{
- static char buf[20];
+ static char buf[16];
const unsigned char *bytep = (const void *)&addrp->s_addr;
sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
@@ -1435,16 +1553,11 @@ int xtables_ipmask_to_cidr(const struct in_addr *mask)
int i;
maskaddr = ntohl(mask->s_addr);
- /* shortcut for /32 networks */
- if (maskaddr == 0xFFFFFFFFL)
- return 32;
- i = 32;
- bits = 0xFFFFFFFEL;
- while (--i >= 0 && maskaddr != bits)
- bits <<= 1;
- if (i >= 0)
- return i;
+ for (i = 32, bits = (uint32_t)-1; i >= 0; i--, bits <<= 1) {
+ if (bits == maskaddr)
+ return i;
+ }
/* this mask cannot be converted to CIDR notation */
return -1;
@@ -1817,9 +1930,8 @@ const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
{
static struct in6_addr ap;
- int err;
- if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
+ if (inet_pton(AF_INET6, num, &ap) == 1)
return &ap;
return NULL;
@@ -2072,10 +2184,11 @@ const struct xtables_pprot xtables_chain_protos[] = {
{"udp", IPPROTO_UDP},
{"udplite", IPPROTO_UDPLITE},
{"icmp", IPPROTO_ICMP},
- {"icmpv6", IPPROTO_ICMPV6},
{"ipv6-icmp", IPPROTO_ICMPV6},
+ {"icmpv6", IPPROTO_ICMPV6},
{"esp", IPPROTO_ESP},
{"ah", IPPROTO_AH},
+ {"mobility-header", IPPROTO_MH},
{"ipv6-mh", IPPROTO_MH},
{"mh", IPPROTO_MH},
{"all", 0},
@@ -2091,23 +2204,15 @@ xtables_parse_protocol(const char *s)
if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
return proto;
- /* first deal with the special case of 'all' to prevent
- * people from being able to redefine 'all' in nsswitch
- * and/or provoke expensive [not working] ldap/nis/...
- * lookups */
- if (strcmp(s, "all") == 0)
- return 0;
+ for (i = 0; xtables_chain_protos[i].name != NULL; ++i) {
+ if (strcmp(s, xtables_chain_protos[i].name) == 0)
+ return xtables_chain_protos[i].num;
+ }
pent = getprotobyname(s);
if (pent != NULL)
return pent->p_proto;
- for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
- if (xtables_chain_protos[i].name == NULL)
- continue;
- if (strcmp(s, xtables_chain_protos[i].name) == 0)
- return xtables_chain_protos[i].num;
- }
xt_params->exit_err(PARAMETER_PROBLEM,
"unknown protocol \"%s\" specified", s);
return -1;
@@ -2328,32 +2433,35 @@ void get_kernel_version(void)
#include <linux/netfilter/nf_tables.h>
+enum xt_xlate_type {
+ XT_XLATE_RULE = 0,
+ XT_XLATE_SET,
+ __XT_XLATE_MAX
+};
+
struct xt_xlate {
- struct {
+ struct xt_xlate_buf {
char *data;
int size;
int rem;
int off;
- } buf;
+ } buf[__XT_XLATE_MAX];
char comment[NFT_USERDATA_MAXLEN];
+ int family;
};
struct xt_xlate *xt_xlate_alloc(int size)
{
- struct xt_xlate *xl;
-
- xl = malloc(sizeof(struct xt_xlate));
- if (xl == NULL)
- xtables_error(RESOURCE_PROBLEM, "OOM");
-
- xl->buf.data = malloc(size);
- if (xl->buf.data == NULL)
- xtables_error(RESOURCE_PROBLEM, "OOM");
+ struct xt_xlate *xl = xtables_malloc(sizeof(struct xt_xlate));
+ int i;
- xl->buf.data[0] = '\0';
- xl->buf.size = size;
- xl->buf.rem = size;
- xl->buf.off = 0;
+ for (i = 0; i < __XT_XLATE_MAX; i++) {
+ xl->buf[i].data = xtables_malloc(size);
+ xl->buf[i].data[0] = '\0';
+ xl->buf[i].size = size;
+ xl->buf[i].rem = size;
+ xl->buf[i].off = 0;
+ }
xl->comment[0] = '\0';
return xl;
@@ -2361,23 +2469,44 @@ struct xt_xlate *xt_xlate_alloc(int size)
void xt_xlate_free(struct xt_xlate *xl)
{
- free(xl->buf.data);
+ int i;
+
+ for (i = 0; i < __XT_XLATE_MAX; i++)
+ free(xl->buf[i].data);
+
free(xl);
}
-void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...)
+static void __xt_xlate_add(struct xt_xlate *xl, enum xt_xlate_type type,
+ const char *fmt, va_list ap)
{
- va_list ap;
+ struct xt_xlate_buf *buf = &xl->buf[type];
int len;
- va_start(ap, fmt);
- len = vsnprintf(xl->buf.data + xl->buf.off, xl->buf.rem, fmt, ap);
- if (len < 0 || len >= xl->buf.rem)
+ len = vsnprintf(buf->data + buf->off, buf->rem, fmt, ap);
+ if (len < 0 || len >= buf->rem)
xtables_error(RESOURCE_PROBLEM, "OOM");
+ buf->rem -= len;
+ buf->off += len;
+}
+
+void xt_xlate_rule_add(struct xt_xlate *xl, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __xt_xlate_add(xl, XT_XLATE_RULE, fmt, ap);
+ va_end(ap);
+}
+
+void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __xt_xlate_add(xl, XT_XLATE_SET, fmt, ap);
va_end(ap);
- xl->buf.rem -= len;
- xl->buf.off += len;
}
void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment)
@@ -2391,7 +2520,22 @@ const char *xt_xlate_get_comment(struct xt_xlate *xl)
return xl->comment[0] ? xl->comment : NULL;
}
+void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family)
+{
+ xl->family = family;
+}
+
+uint8_t xt_xlate_get_family(struct xt_xlate *xl)
+{
+ return xl->family;
+}
+
const char *xt_xlate_get(struct xt_xlate *xl)
{
- return xl->buf.data;
+ return xl->buf[XT_XLATE_RULE].data;
+}
+
+const char *xt_xlate_set_get(struct xt_xlate *xl)
+{
+ return xl->buf[XT_XLATE_SET].data;
}
diff --git a/libxtables/xtoptions.c b/libxtables/xtoptions.c
index d329f2ff..9d3ac5c8 100644
--- a/libxtables/xtoptions.c
+++ b/libxtables/xtoptions.c
@@ -604,9 +604,7 @@ static void xtopt_parse_mport(struct xt_option_call *cb)
unsigned int maxiter;
int value;
- wp_arg = lo_arg = strdup(cb->arg);
- if (lo_arg == NULL)
- xt_params->exit_err(RESOURCE_PROBLEM, "strdup");
+ wp_arg = lo_arg = xtables_strdup(cb->arg);
maxiter = entry->size / esize;
if (maxiter == 0)
@@ -747,9 +745,7 @@ static void xtopt_parse_hostmask(struct xt_option_call *cb)
xtopt_parse_host(cb);
return;
}
- work = strdup(orig_arg);
- if (work == NULL)
- xt_params->exit_err(PARAMETER_PROBLEM, "strdup");
+ work = xtables_strdup(orig_arg);
p = strchr(work, '/'); /* by def this can't be NULL now */
*p++ = '\0';
/*
@@ -763,6 +759,7 @@ static void xtopt_parse_hostmask(struct xt_option_call *cb)
cb->arg = p;
xtopt_parse_plenmask(cb);
cb->arg = orig_arg;
+ free(work);
}
static void xtopt_parse_ethermac(struct xt_option_call *cb)
@@ -1138,11 +1135,7 @@ struct xtables_lmap *xtables_lmap_init(const char *file)
goto out;
}
lmap_this->id = id;
- lmap_this->name = strdup(cur);
- if (lmap_this->name == NULL) {
- free(lmap_this);
- goto out;
- }
+ lmap_this->name = xtables_strdup(cur);
lmap_this->next = NULL;
if (lmap_prev != NULL)
diff --git a/xlate-test.py b/xlate-test.py
index 4c014f9b..03bef7e2 100755
--- a/xlate-test.py
+++ b/xlate-test.py
@@ -39,22 +39,29 @@ def run_test(name, payload):
tests = passed = failed = errors = 0
result = []
- for line in payload:
+ line = payload.readline()
+ while line:
if line.startswith(keywords):
+ sourceline = line
tests += 1
process = Popen([ xtables_nft_multi ] + shlex.split(line), stdout=PIPE, stderr=PIPE)
(output, error) = process.communicate()
if process.returncode == 0:
translation = output.decode("utf-8").rstrip(" \n")
- expected = next(payload).rstrip(" \n")
+ expected = payload.readline().rstrip(" \n")
+ next_expected = payload.readline()
+ if next_expected.startswith("nft"):
+ expected += "\n" + next_expected.rstrip(" \n")
+ line = payload.readline()
+ else:
+ line = next_expected
if translation != expected:
test_passed = False
failed += 1
result.append(name + ": " + red("Fail"))
- result.append(magenta("src: ") + line.rstrip(" \n"))
+ result.append(magenta("src: ") + sourceline.rstrip(" \n"))
result.append(magenta("exp: ") + expected)
result.append(magenta("res: ") + translation + "\n")
- test_passed = False
else:
passed += 1
else:
@@ -62,31 +69,30 @@ def run_test(name, payload):
errors += 1
result.append(name + ": " + red("Error: ") + "iptables-translate failure")
result.append(error.decode("utf-8"))
+ line = payload.readline()
+ else:
+ line = payload.readline()
if (passed == tests) and not args.test:
print(name + ": " + green("OK"))
if not test_passed:
- print("\n".join(result))
- if args.test:
- print("1 test file, %d tests, %d tests passed, %d tests failed, %d errors" % (tests, passed, failed, errors))
- else:
- return tests, passed, failed, errors
+ print("\n".join(result), file=sys.stderr)
+ return tests, passed, failed, errors
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)
- print("%d test files, %d tests, %d tests passed, %d tests failed, %d errors" % (test_files, total_tests, total_passed, total_failed, total_error))
-
def main():
global xtables_nft_multi
if not args.host:
@@ -94,16 +100,27 @@ def main():
xtables_nft_multi = os.path.abspath(os.path.curdir) \
+ '/iptables/' + xtables_nft_multi
+ files = tests = passed = failed = errors = 0
if args.test:
if not args.test.endswith(".txlate"):
args.test += ".txlate"
try:
with open(args.test, "r") as payload:
- run_test(args.test, payload)
+ files = 1
+ tests, passed, failed, errors = run_test(args.test, payload)
except IOError:
- print(red("Error: ") + "test file does not exist")
+ print(red("Error: ") + "test file does not exist", file=sys.stderr)
+ return -1
+ else:
+ files, tests, passed, failed, errors = load_test_files()
+
+ if files > 1:
+ file_word = "files"
else:
- load_test_files()
+ file_word = "file"
+ print("%d test %s, %d tests, %d tests passed, %d tests failed, %d errors"
+ % (files, file_word, tests, passed, failed, errors))
+ return passed - tests
parser = argparse.ArgumentParser()
@@ -111,4 +128,4 @@ parser.add_argument('-H', '--host', action='store_true',
help='Run tests against installed binaries')
parser.add_argument("test", nargs="?", help="run only the specified test file")
args = parser.parse_args()
-main()
+sys.exit(main())