aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaciej Żenczykowski <maze@google.com>2020-04-08 07:31:12 -0700
committerMaciej Żenczykowski <maze@google.com>2020-04-08 07:31:53 -0700
commit7a98e699b6e22cf505d3efffd3561f4965c00d0d (patch)
treea52da76fd1c8cee9377c02702fb7d06be96c6c0b
parentb68f7ec3cad0a37be41b5d25002714b73a7ec800 (diff)
parent2b506c6681c7b01803f06b258a39e9da9012e5c5 (diff)
downloadplatform_external_iptables-7a98e699b6e22cf505d3efffd3561f4965c00d0d.tar.gz
platform_external_iptables-7a98e699b6e22cf505d3efffd3561f4965c00d0d.tar.bz2
platform_external_iptables-7a98e699b6e22cf505d3efffd3561f4965c00d0d.zip
Merge tag 'v1.8.4' of git://git.netfilter.org/iptables into work
iptables 1.8.4 release Generated via: git fetch git://git.netfilter.org/iptables v1.8.4 git merge FETCH_HEAD with minimal conflict resolution in: .gitignore include/iptables/internal.h Signed-off-by: Maciej Żenczykowski <maze@google.com> Change-Id: If19ae73e4514ac08b59b775e978f79e7be22f840
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac25
-rw-r--r--extensions/libebt_among.c243
-rw-r--r--extensions/libebt_among.t16
-rw-r--r--extensions/libebt_standard.t17
-rw-r--r--extensions/libxt_MASQUERADE.man1
-rw-r--r--extensions/libxt_REDIRECT.man3
-rw-r--r--extensions/libxt_SYNPROXY.c23
-rw-r--r--extensions/libxt_SYNPROXY.txlate2
-rw-r--r--extensions/libxt_conntrack.c2
-rw-r--r--extensions/libxt_conntrack.txlate3
-rw-r--r--extensions/libxt_hashlimit.c2
-rw-r--r--extensions/libxt_nfacct.c40
-rw-r--r--extensions/libxt_owner.c24
-rw-r--r--extensions/libxt_owner.man4
-rw-r--r--extensions/libxt_owner.t4
-rw-r--r--include/iptables/internal.h2
-rw-r--r--include/iptables/internal.h.in13
-rw-r--r--include/linux/netfilter/xt_nfacct.h5
-rw-r--r--include/linux/netfilter/xt_owner.h7
-rwxr-xr-xiptables-test.py38
-rw-r--r--iptables/.gitignore5
-rw-r--r--iptables/Makefile.am25
-rw-r--r--iptables/ebtables-nft.866
-rw-r--r--iptables/ip6tables.c83
-rw-r--r--iptables/iptables-restore.c92
-rw-r--r--iptables/iptables-save.c3
-rw-r--r--iptables/iptables-xml.c157
-rw-r--r--iptables/iptables.c74
-rw-r--r--iptables/nft-arp.c44
-rw-r--r--iptables/nft-bridge.c271
-rw-r--r--iptables/nft-bridge.h56
-rw-r--r--iptables/nft-cache.c688
-rw-r--r--iptables/nft-cache.h20
-rw-r--r--iptables/nft-ipv4.c10
-rw-r--r--iptables/nft-ipv6.c10
-rw-r--r--iptables/nft-shared.c74
-rw-r--r--iptables/nft-shared.h66
-rw-r--r--iptables/nft.c1034
-rw-r--r--iptables/nft.h50
-rwxr-xr-xiptables/tests/shell/run-tests.sh28
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0001-arptables-save-restore_07
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_06
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_05
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0001-ebtables-basic_028
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_04
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_06
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0004-save-counters_064
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0005-ifnamechecks_021
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_018
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0004-restore-race_04
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0005-ipt-6_026
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0006-ip6t-4_026
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_042
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0008-restore-counters_022
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0009-table-name-comment_030
-rwxr-xr-xiptables/tests/shell/testcases/ipt-save/0006iptables-xml_013
-rw-r--r--iptables/tests/shell/testcases/ipt-save/dumps/fedora27-iptables.xml925
-rw-r--r--iptables/xshared.c173
-rw-r--r--iptables/xshared.h61
-rw-r--r--iptables/xtables-arp.c502
-rw-r--r--iptables/xtables-config-parser.y248
-rw-r--r--iptables/xtables-config-syntax.l54
-rw-r--r--iptables/xtables-eb-standalone.c2
-rw-r--r--iptables/xtables-eb.c20
-rw-r--r--iptables/xtables-monitor.c22
-rw-r--r--iptables/xtables-restore.c508
-rw-r--r--iptables/xtables-save.c251
-rw-r--r--iptables/xtables-translate.c18
-rw-r--r--iptables/xtables.c67
-rw-r--r--libiptc/Makefile.am7
-rw-r--r--libiptc/libip4tc.c174
-rw-r--r--libiptc/libip6tc.c178
-rw-r--r--libiptc/libiptc.c18
-rw-r--r--m4/ax_check_linker_flags.m478
-rw-r--r--utils/nfnl_osf.c15
76 files changed, 3926 insertions, 3049 deletions
diff --git a/Makefile.am b/Makefile.am
index b1ba015f..799bf8b8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,4 +30,4 @@ tarball:
rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION};
config.status: extensions/GNUmakefile.in \
- include/xtables-version.h.in include/iptables/internal.h.in
+ include/xtables-version.h.in
diff --git a/configure.ac b/configure.ac
index b94512d7..cab77a48 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
-AC_INIT([iptables], [1.8.3])
+AC_INIT([iptables], [1.8.4])
# See libtool.info "Libtool's versioning system"
libxtables_vcurrent=14
@@ -73,11 +73,6 @@ AC_ARG_WITH([xt-lock-name], AS_HELP_STRING([--with-xt-lock-name=PATH],
[xt_lock_name="$withval"],
[xt_lock_name="/run/xtables.lock"])
-libiptc_LDFLAGS2="";
-AX_CHECK_LINKER_FLAGS([-Wl,--no-as-needed],
- [libiptc_LDFLAGS2="-Wl,--no-as-needed"])
-AC_SUBST([libiptc_LDFLAGS2])
-
AC_MSG_CHECKING([whether $LD knows -Wl,--no-undefined])
saved_LDFLAGS="$LDFLAGS";
LDFLAGS="-Wl,--no-undefined";
@@ -146,22 +141,6 @@ if test "x$enable_nftables" = "xyes"; then
echo " iptables-compat over nftables support."
exit 1
fi
-
- AM_PROG_LEX
- AC_PROG_YACC
-
- if test -z "$ac_cv_prog_YACC"
- then
- echo "*** Error: No suitable bison/yacc found. ***"
- echo " Please install the 'bison' package."
- exit 1
- fi
- if test -z "$ac_cv_prog_LEX"
- then
- echo "*** Error: No suitable flex/lex found. ***"
- echo " Please install the 'flex' package."
- exit 1
- fi
fi
AM_CONDITIONAL([HAVE_LIBMNL], [test "$mnl" = 1])
@@ -250,7 +229,7 @@ AC_CONFIG_FILES([Makefile extensions/GNUmakefile include/Makefile
libiptc/Makefile libiptc/libiptc.pc
libiptc/libip4tc.pc libiptc/libip6tc.pc
libxtables/Makefile utils/Makefile
- include/xtables-version.h include/iptables/internal.h
+ include/xtables-version.h
iptables/xtables-monitor.8
utils/nfnl_osf.8
utils/nfbpf_compile.8])
diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c
new file mode 100644
index 00000000..2e87db3b
--- /dev/null
+++ b/extensions/libebt_among.c
@@ -0,0 +1,243 @@
+/* ebt_among
+ *
+ * Authors:
+ * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
+ *
+ * August, 2003
+ */
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <xtables.h>
+#include <arpa/inet.h>
+#include <netinet/ether.h>
+#include <netinet/in.h>
+#include <linux/if_ether.h>
+#include <linux/netfilter_bridge/ebt_among.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include "iptables/nft.h"
+#include "iptables/nft-bridge.h"
+
+#define AMONG_DST '1'
+#define AMONG_SRC '2'
+#define AMONG_DST_F '3'
+#define AMONG_SRC_F '4'
+
+static const struct option bramong_opts[] = {
+ {"among-dst", required_argument, 0, AMONG_DST},
+ {"among-src", required_argument, 0, AMONG_SRC},
+ {"among-dst-file", required_argument, 0, AMONG_DST_F},
+ {"among-src-file", required_argument, 0, AMONG_SRC_F},
+ {0}
+};
+
+static void bramong_print_help(void)
+{
+ printf(
+"`among' options:\n"
+"--among-dst [!] list : matches if ether dst is in list\n"
+"--among-src [!] list : matches if ether src is in list\n"
+"--among-dst-file [!] file : obtain dst list from file\n"
+"--among-src-file [!] file : obtain src list from file\n"
+"list has form:\n"
+" xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip],yy:yy:yy:yy:yy:yy[=ip.ip.ip.ip]"
+",...,zz:zz:zz:zz:zz:zz[=ip.ip.ip.ip][,]\n"
+"Things in brackets are optional.\n"
+"If you want to allow two (or more) IP addresses to one MAC address, you\n"
+"can specify two (or more) pairs with the same MAC, e.g.\n"
+" 00:00:00:fa:eb:fe=153.19.120.250,00:00:00:fa:eb:fe=192.168.0.1\n"
+ );
+}
+
+static void
+parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip)
+{
+ char *sep = index(buf, '=');
+ struct ether_addr *ether;
+
+ if (have_ip ^ !!sep)
+ xtables_error(PARAMETER_PROBLEM,
+ "among: Mixed MAC and MAC=IP not allowed.");
+
+ if (sep) {
+ *sep = '\0';
+
+ if (!inet_aton(sep + 1, &pair->in))
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid IP address '%s'\n", sep + 1);
+ }
+ ether = ether_aton(buf);
+ if (!ether)
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid MAC address '%s'\n", buf);
+ memcpy(&pair->ether, ether, sizeof(*ether));
+}
+
+static void
+parse_nft_among_pairs(struct nft_among_pair *pairs, char *buf,
+ size_t cnt, bool have_ip)
+{
+ size_t tmpcnt = 0;
+
+ buf = strtok(buf, ",");
+ while (buf) {
+ struct nft_among_pair pair = {};
+
+ parse_nft_among_pair(buf, &pair, have_ip);
+ nft_among_insert_pair(pairs, &tmpcnt, &pair);
+ buf = strtok(NULL, ",");
+ }
+}
+
+static size_t count_nft_among_pairs(char *buf)
+{
+ size_t cnt = 0;
+ char *p = buf;
+
+ if (!*buf)
+ return 0;
+
+ do {
+ cnt++;
+ p = index(++p, ',');
+ } while (p);
+
+ return cnt;
+}
+
+static bool nft_among_pairs_have_ip(char *buf)
+{
+ return !!index(buf, '=');
+}
+
+static int bramong_parse(int c, char **argv, int invert,
+ unsigned int *flags, const void *entry,
+ struct xt_entry_match **match)
+{
+ struct nft_among_data *data = (struct nft_among_data *)(*match)->data;
+ struct xt_entry_match *new_match;
+ bool have_ip, dst = false;
+ size_t new_size, cnt;
+ struct stat stats;
+ int fd = -1, poff;
+ long flen = 0;
+
+ switch (c) {
+ case AMONG_DST_F:
+ dst = true;
+ /* fall through */
+ case AMONG_SRC_F:
+ if ((fd = open(optarg, O_RDONLY)) == -1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Couldn't open file '%s'", optarg);
+ fstat(fd, &stats);
+ flen = stats.st_size;
+ /* use mmap because the file will probably be big */
+ optarg = mmap(0, flen, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+ if (optarg == MAP_FAILED)
+ xtables_error(PARAMETER_PROBLEM,
+ "Couldn't map file to memory");
+ if (optarg[flen-1] != '\n')
+ xtables_error(PARAMETER_PROBLEM,
+ "File should end with a newline");
+ if (strchr(optarg, '\n') != optarg+flen-1)
+ xtables_error(PARAMETER_PROBLEM,
+ "File should only contain one line");
+ optarg[flen-1] = '\0';
+ /* fall through */
+ case AMONG_DST:
+ if (c == AMONG_DST)
+ dst = true;
+ /* fall through */
+ case AMONG_SRC:
+ break;
+ default:
+ return 0;
+ }
+
+ cnt = count_nft_among_pairs(optarg);
+ if (cnt == 0)
+ return 0;
+
+ new_size = data->src.cnt + data->dst.cnt + cnt;
+ new_size *= sizeof(struct nft_among_pair);
+ new_size += XT_ALIGN(sizeof(struct xt_entry_match)) +
+ sizeof(struct nft_among_data);
+ new_match = xtables_calloc(1, new_size);
+ memcpy(new_match, *match, (*match)->u.match_size);
+ new_match->u.match_size = new_size;
+
+ data = (struct nft_among_data *)new_match->data;
+ have_ip = nft_among_pairs_have_ip(optarg);
+ poff = nft_among_prepare_data(data, dst, cnt, invert, have_ip);
+ parse_nft_among_pairs(data->pairs + poff, optarg, cnt, have_ip);
+
+ free(*match);
+ *match = new_match;
+
+ if (c == AMONG_DST_F || c == AMONG_SRC_F) {
+ munmap(argv, flen);
+ close(fd);
+ }
+ return 1;
+}
+
+static void __bramong_print(struct nft_among_pair *pairs,
+ int cnt, bool inv, bool have_ip)
+{
+ const char *isep = inv ? "! " : "";
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ printf("%s", isep);
+ isep = ",";
+
+ printf("%s", ether_ntoa(&pairs[i].ether));
+ if (have_ip)
+ printf("=%s", inet_ntoa(pairs[i].in));
+ }
+ printf(" ");
+}
+
+static void bramong_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ struct nft_among_data *data = (struct nft_among_data *)match->data;
+
+ if (data->src.cnt) {
+ printf("--among-src ");
+ __bramong_print(data->pairs,
+ data->src.cnt, data->src.inv, data->src.ip);
+ }
+ if (data->dst.cnt) {
+ printf("--among-dst ");
+ __bramong_print(data->pairs + data->src.cnt,
+ data->dst.cnt, data->dst.inv, data->dst.ip);
+ }
+}
+
+static struct xtables_match bramong_match = {
+ .name = "among",
+ .revision = 0,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_BRIDGE,
+ .size = XT_ALIGN(sizeof(struct nft_among_data)),
+ .userspacesize = XT_ALIGN(sizeof(struct nft_among_data)),
+ .help = bramong_print_help,
+ .parse = bramong_parse,
+ .print = bramong_print,
+ .extra_opts = bramong_opts,
+};
+
+void _init(void)
+{
+ xtables_register_match(&bramong_match);
+}
diff --git a/extensions/libebt_among.t b/extensions/libebt_among.t
new file mode 100644
index 00000000..56b29916
--- /dev/null
+++ b/extensions/libebt_among.t
@@ -0,0 +1,16 @@
+:INPUT,FORWARD,OUTPUT
+--among-dst de:ad:0:be:ee:ff,c0:ff:ee:0:ba:be;--among-dst c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;OK
+--among-dst ! c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;=;OK
+--among-src be:ef:0:c0:ff:ee,c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;=;OK
+--among-src de:ad:0:be:ee:ff=10.0.0.1,c0:ff:ee:0:ba:be=192.168.1.1;--among-src c0:ff:ee:0:ba:be=192.168.1.1,de:ad:0:be:ee:ff=10.0.0.1;OK
+--among-src ! c0:ff:ee:0:ba:be=192.168.1.1,de:ad:0:be:ee:ff=10.0.0.1;=;OK
+--among-src de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be;=;OK
+--among-src de:ad:0:be:ee:ff=10.0.0.1 --among-dst c0:ff:ee:0:ba:be=192.168.1.1;=;OK
+--among-src ! de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be;=;OK
+--among-src de:ad:0:be:ee:ff=10.0.0.1 --among-dst ! c0:ff:ee:0:ba:be=192.168.1.1;=;OK
+--among-src ! de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be=192.168.1.1;=;OK
+--among-src de:ad:0:be:ee:ff=10.0.0.1 --among-dst ! c0:ff:ee:0:ba:be=192.168.1.1;=;OK
+--among-src;=;FAIL
+--among-src 00:11=10.0.0.1;=;FAIL
+--among-src de:ad:0:be:ee:ff=10.256.0.1;=;FAIL
+--among-src de:ad:0:be:ee:ff,c0:ff:ee:0:ba:be=192.168.1.1;=;FAIL
diff --git a/extensions/libebt_standard.t b/extensions/libebt_standard.t
index 0d678fb2..c6c31727 100644
--- a/extensions/libebt_standard.t
+++ b/extensions/libebt_standard.t
@@ -9,3 +9,20 @@
-p ! ARP -j ACCEPT;=;OK
-p 0 -j ACCEPT;=;FAIL
-p ! 0 -j ACCEPT;=;FAIL
+:INPUT
+-i foobar;=;OK
+-o foobar;=;FAIL
+:FORWARD
+-i foobar;=;OK
+-o foobar;=;OK
+:OUTPUT
+-i foobar;=;FAIL
+-o foobar;=;OK
+:PREROUTING
+*nat
+-i foobar;=;OK
+-o foobar;=;FAIL
+:POSTROUTING
+*nat
+-i foobar;=;FAIL
+-o foobar;=;OK
diff --git a/extensions/libxt_MASQUERADE.man b/extensions/libxt_MASQUERADE.man
index cc1e7690..7746f473 100644
--- a/extensions/libxt_MASQUERADE.man
+++ b/extensions/libxt_MASQUERADE.man
@@ -24,6 +24,7 @@ Randomize source port mapping
If option
\fB\-\-random\fP
is used then port mapping will be randomized (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
diff --git a/extensions/libxt_REDIRECT.man b/extensions/libxt_REDIRECT.man
index 3400a6df..28d4d10b 100644
--- a/extensions/libxt_REDIRECT.man
+++ b/extensions/libxt_REDIRECT.man
@@ -8,7 +8,8 @@ chains, and user-defined chains which are only called from those
chains. It redirects the packet to the machine itself by changing the
destination IP to the primary address of the incoming interface
(locally-generated packets are mapped to the localhost address,
-127.0.0.1 for IPv4 and ::1 for IPv6).
+127.0.0.1 for IPv4 and ::1 for IPv6, and packets arriving on
+interfaces that don't have an IP address configured are dropped).
.TP
\fB\-\-to\-ports\fP \fIport\fP[\fB\-\fP\fIport\fP]
This specifies a destination port or range of ports to use: without
diff --git a/extensions/libxt_SYNPROXY.c b/extensions/libxt_SYNPROXY.c
index 475590ea..6a0b913e 100644
--- a/extensions/libxt_SYNPROXY.c
+++ b/extensions/libxt_SYNPROXY.c
@@ -106,6 +106,28 @@ static void SYNPROXY_save(const void *ip, const struct xt_entry_target *target)
printf(" --ecn");
}
+static int SYNPROXY_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_synproxy_info *info =
+ (const struct xt_synproxy_info *)params->target->data;
+
+ xt_xlate_add(xl, "synproxy ");
+
+ if (info->options & XT_SYNPROXY_OPT_SACK_PERM)
+ xt_xlate_add(xl, "sack-perm ");
+ if (info->options & XT_SYNPROXY_OPT_TIMESTAMP)
+ xt_xlate_add(xl, "timestamp ");
+ if (info->options & XT_SYNPROXY_OPT_WSCALE)
+ xt_xlate_add(xl, "wscale %u ", info->wscale);
+ if (info->options & XT_SYNPROXY_OPT_MSS)
+ xt_xlate_add(xl, "mss %u ", info->mss);
+ if (info->options & XT_SYNPROXY_OPT_ECN)
+ xt_xlate_add(xl, "ecn ");
+
+ return 1;
+}
+
static struct xtables_target synproxy_tg_reg = {
.family = NFPROTO_UNSPEC,
.name = "SYNPROXY",
@@ -119,6 +141,7 @@ static struct xtables_target synproxy_tg_reg = {
.x6_parse = SYNPROXY_parse,
.x6_fcheck = SYNPROXY_check,
.x6_options = SYNPROXY_opts,
+ .xlate = SYNPROXY_xlate,
};
void _init(void)
diff --git a/extensions/libxt_SYNPROXY.txlate b/extensions/libxt_SYNPROXY.txlate
new file mode 100644
index 00000000..b3de2b2a
--- /dev/null
+++ b/extensions/libxt_SYNPROXY.txlate
@@ -0,0 +1,2 @@
+iptables-translate -t mangle -A INPUT -i iifname -p tcp -m tcp --dport 80 -m state --state INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
+nft add rule ip mangle INPUT iifname "iifname" tcp dport 80 ct state invalid,untracked counter synproxy sack-perm timestamp wscale 7 mss 1460
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 1817d335..6f350393 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -1257,8 +1257,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_STATUS) {
- if (sinfo->status_mask == 1)
- return 0;
xt_xlate_add(xl, "%sct status %s", space,
sinfo->invert_flags & XT_CONNTRACK_STATUS ?
"!= " : "");
diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate
index e35d5ce8..8a3d0181 100644
--- a/extensions/libxt_conntrack.txlate
+++ b/extensions/libxt_conntrack.txlate
@@ -28,6 +28,9 @@ nft add rule ip filter INPUT ct reply daddr 10.100.2.131 counter accept
iptables-translate -t filter -A INPUT -m conntrack --ctproto tcp --ctorigsrcport 443:444 -j ACCEPT
nft add rule ip filter INPUT ct original protocol 6 ct original proto-src 443-444 counter accept
+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
diff --git a/extensions/libxt_hashlimit.c b/extensions/libxt_hashlimit.c
index f3b6e043..7f1d2a40 100644
--- a/extensions/libxt_hashlimit.c
+++ b/extensions/libxt_hashlimit.c
@@ -772,7 +772,7 @@ static void hashlimit_mt_check(struct xt_fcheck_call *cb)
if (cb->xflags & F_BURST) {
if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
xtables_error(PARAMETER_PROBLEM,
- "burst cannot be smaller than %lub", cost_to_bytes(info->cfg.avg));
+ "burst cannot be smaller than %"PRIu64"b", cost_to_bytes(info->cfg.avg));
burst = info->cfg.burst;
burst /= cost_to_bytes(info->cfg.avg);
diff --git a/extensions/libxt_nfacct.c b/extensions/libxt_nfacct.c
index 2ad59d52..d9c0309a 100644
--- a/extensions/libxt_nfacct.c
+++ b/extensions/libxt_nfacct.c
@@ -70,20 +70,36 @@ static void nfacct_save(const void *ip, const struct xt_entry_match *match)
nfacct_print_name(info, "--");
}
-static struct xtables_match nfacct_match = {
- .family = NFPROTO_UNSPEC,
- .name = "nfacct",
- .version = XTABLES_VERSION,
- .size = XT_ALIGN(sizeof(struct xt_nfacct_match_info)),
- .userspacesize = offsetof(struct xt_nfacct_match_info, nfacct),
- .help = nfacct_help,
- .x6_parse = nfacct_parse,
- .print = nfacct_print,
- .save = nfacct_save,
- .x6_options = nfacct_opts,
+static struct xtables_match nfacct_matches[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .revision = 0,
+ .name = "nfacct",
+ .version = XTABLES_VERSION,
+ .size = XT_ALIGN(sizeof(struct xt_nfacct_match_info)),
+ .userspacesize = offsetof(struct xt_nfacct_match_info, nfacct),
+ .help = nfacct_help,
+ .x6_parse = nfacct_parse,
+ .print = nfacct_print,
+ .save = nfacct_save,
+ .x6_options = nfacct_opts,
+ },
+ {
+ .family = NFPROTO_UNSPEC,
+ .revision = 1,
+ .name = "nfacct",
+ .version = XTABLES_VERSION,
+ .size = XT_ALIGN(sizeof(struct xt_nfacct_match_info_v1)),
+ .userspacesize = offsetof(struct xt_nfacct_match_info_v1, nfacct),
+ .help = nfacct_help,
+ .x6_parse = nfacct_parse,
+ .print = nfacct_print,
+ .save = nfacct_save,
+ .x6_options = nfacct_opts,
+ },
};
void _init(void)
{
- xtables_register_match(&nfacct_match);
+ xtables_register_matches(nfacct_matches, ARRAY_SIZE(nfacct_matches));
}
diff --git a/extensions/libxt_owner.c b/extensions/libxt_owner.c
index 87e4df31..1702b478 100644
--- a/extensions/libxt_owner.c
+++ b/extensions/libxt_owner.c
@@ -56,6 +56,7 @@ enum {
O_PROCESS,
O_SESSION,
O_COMM,
+ O_SUPPL_GROUPS,
};
static void owner_mt_help_v0(void)
@@ -87,7 +88,8 @@ static void owner_mt_help(void)
"owner match options:\n"
"[!] --uid-owner userid[-userid] Match local UID\n"
"[!] --gid-owner groupid[-groupid] Match local GID\n"
-"[!] --socket-exists Match if socket exists\n");
+"[!] --socket-exists Match if socket exists\n"
+" --suppl-groups Also match supplementary groups set with --gid-owner\n");
}
#define s struct ipt_owner_info
@@ -131,6 +133,7 @@ static const struct xt_option_entry owner_mt_opts[] = {
.flags = XTOPT_INVERT},
{.name = "socket-exists", .id = O_SOCK_EXISTS, .type = XTTYPE_NONE,
.flags = XTOPT_INVERT},
+ {.name = "suppl-groups", .id = O_SUPPL_GROUPS, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
@@ -275,6 +278,11 @@ static void owner_mt_parse(struct xt_option_call *cb)
info->invert |= XT_OWNER_SOCKET;
info->match |= XT_OWNER_SOCKET;
break;
+ case O_SUPPL_GROUPS:
+ if (!(info->match & XT_OWNER_GID))
+ xtables_param_act(XTF_BAD_VALUE, "owner", "--suppl-groups", "you need to use --gid-owner first");
+ info->match |= XT_OWNER_SUPPL_GROUPS;
+ break;
}
}
@@ -455,9 +463,10 @@ static void owner_mt_print(const void *ip, const struct xt_entry_match *match,
{
const struct xt_owner_match_info *info = (void *)match->data;
- owner_mt_print_item(info, "owner socket exists", XT_OWNER_SOCKET, numeric);
- owner_mt_print_item(info, "owner UID match", XT_OWNER_UID, numeric);
- owner_mt_print_item(info, "owner GID match", XT_OWNER_GID, numeric);
+ owner_mt_print_item(info, "owner socket exists", XT_OWNER_SOCKET, numeric);
+ owner_mt_print_item(info, "owner UID match", XT_OWNER_UID, numeric);
+ owner_mt_print_item(info, "owner GID match", XT_OWNER_GID, numeric);
+ owner_mt_print_item(info, "incl. suppl. groups", XT_OWNER_SUPPL_GROUPS, numeric);
}
static void
@@ -487,9 +496,10 @@ static void owner_mt_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_owner_match_info *info = (void *)match->data;
- owner_mt_print_item(info, "--socket-exists", XT_OWNER_SOCKET, true);
- owner_mt_print_item(info, "--uid-owner", XT_OWNER_UID, true);
- owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, true);
+ owner_mt_print_item(info, "--socket-exists", XT_OWNER_SOCKET, true);
+ owner_mt_print_item(info, "--uid-owner", XT_OWNER_UID, true);
+ owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, true);
+ owner_mt_print_item(info, "--suppl-groups", XT_OWNER_SUPPL_GROUPS, true);
}
static int
diff --git a/extensions/libxt_owner.man b/extensions/libxt_owner.man
index 49b58cee..e2479865 100644
--- a/extensions/libxt_owner.man
+++ b/extensions/libxt_owner.man
@@ -15,5 +15,9 @@ given user. You may also specify a numerical UID, or an UID range.
Matches if the packet socket's file structure is owned by the given group.
You may also specify a numerical GID, or a GID range.
.TP
+\fB\-\-suppl\-groups\fP
+Causes group(s) specified with \fB\-\-gid-owner\fP to be also checked in the
+supplementary groups of a process.
+.TP
[\fB!\fP] \fB\-\-socket\-exists\fP
Matches if the packet is associated with a socket.
diff --git a/extensions/libxt_owner.t b/extensions/libxt_owner.t
index aec30b65..2779e5c1 100644
--- a/extensions/libxt_owner.t
+++ b/extensions/libxt_owner.t
@@ -8,5 +8,9 @@
-m owner --uid-owner 0-10 --gid-owner 0-10;=;OK
-m owner ! --uid-owner root;-m owner ! --uid-owner 0;OK
-m owner --socket-exists;=;OK
+-m owner --gid-owner 0-10 --suppl-groups;=;OK
+-m owner --suppl-groups --gid-owner 0-10;;FAIL
+-m owner --gid-owner 0-10 ! --suppl-groups;;FAIL
+-m owner --suppl-groups;;FAIL
:INPUT
-m owner --uid-owner root;;FAIL
diff --git a/include/iptables/internal.h b/include/iptables/internal.h
index bf5aa64c..86ba074a 100644
--- a/include/iptables/internal.h
+++ b/include/iptables/internal.h
@@ -1,8 +1,6 @@
#ifndef IPTABLES_INTERNAL_H
#define IPTABLES_INTERNAL_H 1
-#define IPTABLES_VERSION "1.6.2"
-
/**
* Program's own name and version.
*/
diff --git a/include/iptables/internal.h.in b/include/iptables/internal.h.in
deleted file mode 100644
index 8568e581..00000000
--- a/include/iptables/internal.h.in
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef IPTABLES_INTERNAL_H
-#define IPTABLES_INTERNAL_H 1
-
-#define IPTABLES_VERSION "@PACKAGE_VERSION@"
-
-/**
- * Program's own name and version.
- */
-extern const char *program_name, *program_version;
-
-extern int line;
-
-#endif /* IPTABLES_INTERNAL_H */
diff --git a/include/linux/netfilter/xt_nfacct.h b/include/linux/netfilter/xt_nfacct.h
index 59ab00dd..04ec2b04 100644
--- a/include/linux/netfilter/xt_nfacct.h
+++ b/include/linux/netfilter/xt_nfacct.h
@@ -14,4 +14,9 @@ struct xt_nfacct_match_info {
struct nf_acct *nfacct;
};
+struct xt_nfacct_match_info_v1 {
+ char name[NFACCT_NAME_MAX];
+ struct nf_acct *nfacct __attribute__((aligned(8)));
+};
+
#endif /* _XT_NFACCT_MATCH_H */
diff --git a/include/linux/netfilter/xt_owner.h b/include/linux/netfilter/xt_owner.h
index 20817617..e7731dcc 100644
--- a/include/linux/netfilter/xt_owner.h
+++ b/include/linux/netfilter/xt_owner.h
@@ -4,9 +4,10 @@
#include <linux/types.h>
enum {
- XT_OWNER_UID = 1 << 0,
- XT_OWNER_GID = 1 << 1,
- XT_OWNER_SOCKET = 1 << 2,
+ XT_OWNER_UID = 1 << 0,
+ XT_OWNER_GID = 1 << 1,
+ XT_OWNER_SOCKET = 1 << 2,
+ XT_OWNER_SUPPL_GROUPS = 1 << 3,
};
struct xt_owner_match_info {
diff --git a/iptables-test.py b/iptables-test.py
index 532dee7c..fdb4e6a3 100755
--- a/iptables-test.py
+++ b/iptables-test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
# (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
#
@@ -10,6 +10,7 @@
# This software has been sponsored by Sophos Astaro <http://www.sophos.com>
#
+from __future__ import print_function
import sys
import os
import subprocess
@@ -45,7 +46,7 @@ def print_error(reason, filename=None, lineno=None):
'''
Prints an error with nice colors, indicating file and line number.
'''
- print (filename + ": " + Colors.RED + "ERROR" +
+ print(filename + ": " + Colors.RED + "ERROR" +
Colors.ENDC + ": line %d (%s)" % (lineno, reason))
@@ -140,7 +141,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
return -1
# find the rule
- matching = out.find(rule_save)
+ matching = out.find(rule_save.encode('utf-8'))
if matching < 0:
reason = "cannot find: " + iptables + " -I " + rule
print_error(reason, filename, lineno)
@@ -166,7 +167,7 @@ def execute_cmd(cmd, filename, lineno):
if cmd.startswith('iptables ') or cmd.startswith('ip6tables ') or cmd.startswith('ebtables ') or cmd.startswith('arptables '):
cmd = os.path.abspath(os.path.curdir) + "/iptables/" + EXECUTEABLE + " " + cmd
- print >> log_file, "command: %s" % cmd
+ print("command: {}".format(cmd), file=log_file)
ret = subprocess.call(cmd, shell=True, universal_newlines=True,
stderr=subprocess.STDOUT, stdout=log_file)
log_file.flush()
@@ -249,7 +250,7 @@ def run_test_file(filename, netns):
continue
if len(chain_array) == 0:
- print "broken test, missing chain, leaving"
+ print("broken test, missing chain, leaving")
sys.exit()
test_passed = True
@@ -282,7 +283,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 + ": " + Colors.GREEN + "OK" + Colors.ENDC)
f.close()
return tests, passed
@@ -302,7 +303,7 @@ def show_missing():
missing = [test_name(i) for i in libfiles
if not test_name(i) in testfiles]
- print '\n'.join(missing)
+ print('\n'.join(missing))
#
@@ -313,6 +314,8 @@ def main():
parser.add_argument('filename', nargs='?',
metavar='path/to/file.t',
help='Run only this test')
+ parser.add_argument('-H', '--host', action='store_true',
+ help='Run tests against installed binaries')
parser.add_argument('-l', '--legacy', action='store_true',
help='Test iptables-legacy')
parser.add_argument('-m', '--missing', action='store_true',
@@ -336,11 +339,13 @@ def main():
EXECUTEABLE = "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")
return
- os.putenv("XTABLES_LIBDIR", os.path.abspath(EXTENSIONS_PATH))
- os.putenv("PATH", "%s/iptables:%s" % (os.path.abspath(os.path.curdir), os.getenv("PATH")))
+ 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),
+ os.getenv("PATH")))
test_files = 0
tests = 0
@@ -351,13 +356,17 @@ 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)
return
- file_list = [os.path.join(EXTENSIONS_PATH, i)
- for i in os.listdir(EXTENSIONS_PATH)]
if args.filename:
file_list = [args.filename]
+ else:
+ file_list = [os.path.join(EXTENSIONS_PATH, i)
+ for i in os.listdir(EXTENSIONS_PATH)
+ if i.endswith('.t')]
+ file_list.sort()
+
for filename in file_list:
file_tests, file_passed = run_test_file(filename, args.netns)
if file_tests:
@@ -365,8 +374,7 @@ def main():
passed += file_passed
test_files += 1
- print ("%d test files, %d unit tests, %d passed" %
- (test_files, tests, passed))
+ print("%d test files, %d unit tests, %d passed" % (test_files, tests, passed))
if __name__ == '__main__':
diff --git a/iptables/.gitignore b/iptables/.gitignore
index c638139b..cd7d87b1 100644
--- a/iptables/.gitignore
+++ b/iptables/.gitignore
@@ -3,6 +3,7 @@
/ip6tables-restore
/ip6tables-static
/ip6tables-translate.8
+/ip6tables-restore-translate.8
/iptables
/iptables.8
/iptables-extensions.8
@@ -13,14 +14,12 @@
/iptables-restore.8
/iptables-static
/iptables-translate.8
+/iptables-restore-translate.8
/iptables-xml
/iptables-xml.1
/xtables-multi
/xtables-legacy-multi
/xtables-nft-multi
-/xtables-config-parser.c
-/xtables-config-parser.h
-/xtables-config-syntax.c
/xtables-monitor.8
/xtables.pc
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index 3ff85893..fc834e0f 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -2,7 +2,6 @@
AM_CFLAGS = ${regular_CFLAGS}
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir} ${kinclude_CPPFLAGS} ${libmnl_CFLAGS} ${libnftnl_CFLAGS} ${libnetfilter_conntrack_CFLAGS}
-AM_YFLAGS = -d
BUILT_SOURCES =
@@ -27,7 +26,6 @@ xtables_legacy_multi_LDADD += ../libxtables/libxtables.la -lm
# iptables using nf_tables api
if ENABLE_NFTABLES
-BUILT_SOURCES += xtables-config-parser.h
xtables_nft_multi_SOURCES = xtables-nft-multi.c iptables-xml.c
xtables_nft_multi_CFLAGS = ${AM_CFLAGS}
xtables_nft_multi_LDADD = ../extensions/libext.a ../extensions/libext_ebt.a
@@ -35,19 +33,16 @@ if ENABLE_STATIC
xtables_nft_multi_CFLAGS += -DALL_INCLUSIVE
endif
xtables_nft_multi_CFLAGS += -DENABLE_NFTABLES -DENABLE_IPV4 -DENABLE_IPV6
-xtables_nft_multi_SOURCES += xtables-config-parser.y xtables-config-syntax.l
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 \
+ xtables-monitor.c nft-cache.c \
xtables-arp-standalone.c xtables-arp.c \
nft-bridge.c \
xtables-eb-standalone.c xtables-eb.c \
xtables-eb-translate.c \
xtables-translate.c
xtables_nft_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS} ${libnetfilter_conntrack_LIBS} ../extensions/libext4.a ../extensions/libext6.a ../extensions/libext_ebt.a ../extensions/libext_arpt.a
-# yacc and lex generate dirty code
-xtables_nft_multi-xtables-config-parser.o xtables_nft_multi-xtables-config-syntax.o: AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls
xtables_nft_multi_SOURCES += xshared.c
xtables_nft_multi_LDADD += ../libxtables/libxtables.la -lm
endif
@@ -58,17 +53,17 @@ sbin_PROGRAMS += xtables-nft-multi
endif
man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \
iptables-xml.1 ip6tables.8 ip6tables-restore.8 \
- ip6tables-save.8 iptables-extensions.8 \
- xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
- iptables-translate.8 ip6tables-translate.8 \
- xtables-monitor.8
+ ip6tables-save.8 iptables-extensions.8
if ENABLE_NFTABLES
-man_MANS += arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \
- ebtables-nft.8
+man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
+ iptables-translate.8 ip6tables-translate.8 \
+ iptables-restore-translate.8 ip6tables-restore-translate.8 \
+ xtables-monitor.8 \
+ arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \
+ ebtables-nft.8
endif
CLEANFILES = iptables.8 xtables-monitor.8 \
- iptables-translate.8 ip6tables-translate.8 \
- xtables-config-parser.c xtables-config-syntax.c
+ iptables-translate.8 ip6tables-translate.8
vx_bin_links = iptables-xml
if ENABLE_IPV4
@@ -98,7 +93,7 @@ iptables-extensions.8: iptables-extensions.8.tmpl ../extensions/matches.man ../e
-e '/@MATCH@/ r ../extensions/matches.man' \
-e '/@TARGET@/ r ../extensions/targets.man' $< >$@;
-iptables-translate.8 ip6tables-translate.8:
+iptables-translate.8 ip6tables-translate.8 iptables-restore-translate.8 ip6tables-restore-translate.8:
${AM_VERBOSE_GEN} echo '.so man8/xtables-translate.8' >$@
pkgconfig_DATA = xtables.pc
diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8
index db8b2ab2..a91f0c1a 100644
--- a/iptables/ebtables-nft.8
+++ b/iptables/ebtables-nft.8
@@ -522,35 +522,39 @@ If the 802.3 DSAP and SSAP values are 0xaa then the SNAP type field must
be consulted to determine the payload protocol. This is a two byte
(hexadecimal) argument. Only 802.3 frames with DSAP/SSAP 0xaa are
checked for type.
-.\" .SS among
-.\" Match a MAC address or MAC/IP address pair versus a list of MAC addresses
-.\" and MAC/IP address pairs.
-.\" A list entry has the following format:
-.\" .IR xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip][,] ". Multiple"
-.\" list entries are separated by a comma, specifying an IP address corresponding to
-.\" the MAC address is optional. Multiple MAC/IP address pairs with the same MAC address
-.\" but different IP address (and vice versa) can be specified. If the MAC address doesn't
-.\" match any entry from the list, the frame doesn't match the rule (unless "!" was used).
-.\" .TP
-.\" .BR "--among-dst " "[!] \fIlist\fP"
-.\" Compare the MAC destination to the given list. If the Ethernet frame has type
-.\" .IR IPv4 " or " ARP ,
-.\" then comparison with MAC/IP destination address pairs from the
-.\" list is possible.
-.\" .TP
-.\" .BR "--among-src " "[!] \fIlist\fP"
-.\" Compare the MAC source to the given list. If the Ethernet frame has type
-.\" .IR IPv4 " or " ARP ,
-.\" then comparison with MAC/IP source address pairs from the list
-.\" is possible.
-.\" .TP
-.\" .BR "--among-dst-file " "[!] \fIfile\fP"
-.\" Same as
-.\" .BR --among-dst " but the list is read in from the specified file."
-.\" .TP
-.\" .BR "--among-src-file " "[!] \fIfile\fP"
-.\" Same as
-.\" .BR --among-src " but the list is read in from the specified file."
+.SS among
+Match a MAC address or MAC/IP address pair versus a list of MAC addresses
+and MAC/IP address pairs.
+A list entry has the following format:
+.IR xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip][,] ". Multiple"
+list entries are separated by a comma, specifying an IP address corresponding to
+the MAC address is optional. Multiple MAC/IP address pairs with the same MAC address
+but different IP address (and vice versa) can be specified. If the MAC address doesn't
+match any entry from the list, the frame doesn't match the rule (unless "!" was used).
+.TP
+.BR "--among-dst " "[!] \fIlist\fP"
+Compare the MAC destination to the given list. If the Ethernet frame has type
+.IR IPv4 " or " ARP ,
+then comparison with MAC/IP destination address pairs from the
+list is possible.
+.TP
+.BR "--among-src " "[!] \fIlist\fP"
+Compare the MAC source to the given list. If the Ethernet frame has type
+.IR IPv4 " or " ARP ,
+then comparison with MAC/IP source address pairs from the list
+is possible.
+.TP
+.BR "--among-dst-file " "[!] \fIfile\fP"
+Same as
+.BR --among-dst " but the list is read in from the specified file."
+.TP
+.BR "--among-src-file " "[!] \fIfile\fP"
+Same as
+.BR --among-src " but the list is read in from the specified file."
+.PP
+Note that in this implementation of ebtables, among lists uses must be
+internally homogeneous regarding whether IP addresses are present or not. Mixed
+use of MAC addresses and MAC/IP address pairs is not supported yet.
.SS arp
Specify (R)ARP fields. The protocol must be specified as
.IR ARP " or " RARP .
@@ -1108,8 +1112,8 @@ arp message and the hardware address length in the arp header is 6 bytes.
The version of ebtables this man page ships with does not support the
.B broute
table. Also there is no support for
-.BR among " and " string
-matches. And finally, this list is probably not complete.
+.B string
+match. And finally, this list is probably not complete.
.SH SEE ALSO
.BR xtables-nft "(8), " iptables "(8), " ip (8)
.PP
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index 050afa9a..576c2cf8 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -24,7 +24,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
+#include "config.h"
#include <getopt.h>
#include <string.h>
#include <netdb.h>
@@ -45,33 +45,6 @@
#include "ip6tables-multi.h"
#include "xshared.h"
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#define CMD_NONE 0x0000U
-#define CMD_INSERT 0x0001U
-#define CMD_DELETE 0x0002U
-#define CMD_DELETE_NUM 0x0004U
-#define CMD_REPLACE 0x0008U
-#define CMD_APPEND 0x0010U
-#define CMD_LIST 0x0020U
-#define CMD_FLUSH 0x0040U
-#define CMD_ZERO 0x0080U
-#define CMD_NEW_CHAIN 0x0100U
-#define CMD_DELETE_CHAIN 0x0200U
-#define CMD_SET_POLICY 0x0400U
-#define CMD_RENAME_CHAIN 0x0800U
-#define CMD_LIST_RULES 0x1000U
-#define CMD_ZERO_NUM 0x2000U
-#define CMD_CHECK 0x4000U
-#define NUMBER_OF_CMD 16
-static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
- 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
-
#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
static const char optflags[]
= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c'};
@@ -121,7 +94,7 @@ static struct option original_opts[] = {
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 = IPTABLES_VERSION,
+ .program_version = PACKAGE_VERSION,
.orig_opts = original_opts,
.exit_err = ip6tables_exit_error,
.compat_rev = xtables_compatible_revision,
@@ -175,12 +148,6 @@ static const unsigned int inverse_for_options[NUMBER_OF_OPT] =
#define opts ip6tables_globals.opts
#define prog_name ip6tables_globals.program_name
#define prog_vers ip6tables_globals.program_version
-/* A few hardcoded protocols for 'all' and in case the user has no
- /etc/protocols */
-struct pprot {
- const char *name;
- uint8_t num;
-};
static void __attribute__((noreturn))
exit_tryhelp(int status)
@@ -342,27 +309,6 @@ opt2char(int option)
return *ptr;
}
-static char
-cmd2char(int option)
-{
- const char *ptr;
- for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
-static void
-add_command(unsigned int *cmd, const int newcmd, const int othercmds,
- int invert)
-{
- if (invert)
- xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag");
- if (*cmd & (~othercmds))
- xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
- cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
- *cmd |= newcmd;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
@@ -381,19 +327,6 @@ static int is_exthdr(uint16_t proto)
proto == IPPROTO_DSTOPTS);
}
-/* Can't be zero. */
-static int
-parse_rulenumber(const char *rule)
-{
- unsigned int rulenum;
-
- if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid rule number `%s'", rule);
-
- return rulenum;
-}
-
static void
parse_chain(const char *chainname)
{
@@ -1228,6 +1161,7 @@ int do_command6(int argc, char *argv[], char **table,
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 */
@@ -1508,7 +1442,12 @@ int do_command6(int argc, char *argv[], char **table,
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':
@@ -1578,7 +1517,7 @@ int do_command6(int argc, char *argv[], char **table,
xtables_error(PARAMETER_PROBLEM,
"multiple consecutive ! not"
" allowed");
- cs.invert = TRUE;
+ cs.invert = true;
optarg[0] = '\0';
continue;
}
@@ -1590,12 +1529,12 @@ int do_command6(int argc, char *argv[], char **table,
/*
* If new options were loaded, we must retry
* getopt immediately and not allow
- * cs.invert=FALSE to be executed.
+ * cs.invert=false to be executed.
*/
continue;
break;
}
- cs.invert = FALSE;
+ cs.invert = false;
}
if (!wait && wait_interval_set)
diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c
index 575e619c..b0a51d49 100644
--- a/iptables/iptables-restore.c
+++ b/iptables/iptables-restore.c
@@ -4,7 +4,7 @@
*
* This code is distributed under the terms of GNU GPL v2
*/
-
+#include "config.h"
#include <getopt.h>
#include <errno.h>
#include <stdbool.h>
@@ -43,7 +43,7 @@ static const struct option options[] = {
static void print_usage(const char *name, const char *version)
{
- fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]\n"
+ fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command] [file]\n"
" [ --counters ]\n"
" [ --verbose ]\n"
" [ --version]\n"
@@ -70,7 +70,7 @@ struct iptables_restore_cb {
};
static struct xtc_handle *
-create_handle(struct iptables_restore_cb *cb, const char *tablename)
+create_handle(const struct iptables_restore_cb *cb, const char *tablename)
{
struct xtc_handle *handle;
@@ -82,18 +82,19 @@ create_handle(struct iptables_restore_cb *cb, const char *tablename)
handle = cb->ops->init(tablename);
}
- if (!handle) {
+ if (!handle)
xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
"table '%s'\n", xt_params->program_name, tablename);
- exit(1);
- }
+
return handle;
}
static int
-ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
+ip46tables_restore_main(const struct iptables_restore_cb *cb,
+ int argc, char *argv[])
{
struct xtc_handle *handle = NULL;
+ struct argv_store av_store = {};
char buffer[10240];
int c, lock;
char curtable[XT_TABLE_MAXNAMELEN + 1] = {};
@@ -125,7 +126,7 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
break;
case 'h':
print_usage(xt_params->program_name,
- IPTABLES_VERSION);
+ PACKAGE_VERSION);
exit(0);
case 'n':
noflush = 1;
@@ -207,12 +208,11 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
table = strtok(buffer+1, " \t\n");
DEBUGP("line %u, table '%s'\n", line, table);
- if (!table) {
+ if (!table)
xtables_error(PARAMETER_PROBLEM,
"%s: line %u table name invalid\n",
xt_params->program_name, line);
- exit(1);
- }
+
strncpy(curtable, table, XT_TABLE_MAXNAMELEN);
curtable[XT_TABLE_MAXNAMELEN] = '\0';
@@ -248,12 +248,10 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
chain = strtok(buffer+1, " \t\n");
DEBUGP("line %u, chain '%s'\n", line, chain);
- if (!chain) {
+ if (!chain)
xtables_error(PARAMETER_PROBLEM,
"%s: line %u chain name invalid\n",
xt_params->program_name, line);
- exit(1);
- }
if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
@@ -281,12 +279,10 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
policy = strtok(NULL, " \t\n");
DEBUGP("line %u, policy '%s'\n", line, policy);
- if (!policy) {
+ if (!policy)
xtables_error(PARAMETER_PROBLEM,
"%s: line %u policy invalid\n",
xt_params->program_name, line);
- exit(1);
- }
if (strcmp(policy, "-") != 0) {
struct xt_counters count = {};
@@ -316,61 +312,31 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
ret = 1;
} else if (in_table) {
- int a;
char *pcnt = NULL;
char *bcnt = NULL;
- char *parsestart;
-
- if (buffer[0] == '[') {
- /* we have counters in our input */
- char *ptr = strchr(buffer, ']');
-
- if (!ptr)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need ]\n",
- line);
-
- pcnt = strtok(buffer+1, ":");
- if (!pcnt)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need :\n",
- line);
-
- bcnt = strtok(NULL, "]");
- if (!bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need ]\n",
- line);
-
- /* start command parsing after counter */
- parsestart = ptr + 1;
- } else {
- /* start command parsing at start of line */
- parsestart = buffer;
- }
+ char *parsestart = buffer;
- add_argv(argv[0], 0);
- add_argv("-t", 0);
- add_argv(curtable, 0);
+ add_argv(&av_store, argv[0], 0);
+ add_argv(&av_store, "-t", 0);
+ add_argv(&av_store, curtable, 0);
+ tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line);
if (counters && pcnt && bcnt) {
- add_argv("--set-counters", 0);
- add_argv((char *) pcnt, 0);
- add_argv((char *) bcnt, 0);
+ add_argv(&av_store, "--set-counters", 0);
+ add_argv(&av_store, pcnt, 0);
+ add_argv(&av_store, bcnt, 0);
}
- add_param_to_argv(parsestart, line);
+ add_param_to_argv(&av_store, parsestart, line);
DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
- newargc, curtable);
-
- for (a = 0; a < newargc; a++)
- DEBUGP("argv[%u]: %s\n", a, newargv[a]);
+ av_store.argc, curtable);
+ debug_print_argv(&av_store);
- ret = cb->do_command(newargc, newargv,
- &newargv[2], &handle, true);
+ ret = cb->do_command(av_store.argc, av_store.argv,
+ &av_store.argv[2], &handle, true);
- free_argv();
+ free_argv(&av_store);
fflush(stdout);
}
if (tablename && strcmp(tablename, curtable) != 0)
@@ -393,7 +359,7 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
#if defined ENABLE_IPV4
-struct iptables_restore_cb ipt_restore_cb = {
+static const struct iptables_restore_cb ipt_restore_cb = {
.ops = &iptc_ops,
.for_each_chain = for_each_chain4,
.flush_entries = flush_entries4,
@@ -424,7 +390,7 @@ iptables_restore_main(int argc, char *argv[])
#endif
#if defined ENABLE_IPV6
-struct iptables_restore_cb ip6t_restore_cb = {
+static const struct iptables_restore_cb ip6t_restore_cb = {
.ops = &ip6tc_ops,
.for_each_chain = for_each_chain6,
.flush_entries = flush_entries6,
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index 826cb1e4..c7251e35 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -5,6 +5,7 @@
* This code is distributed under the terms of GNU GPL v2
*
*/
+#include "config.h"
#include <getopt.h>
#include <errno.h>
#include <stdio.h>
@@ -90,7 +91,7 @@ static int do_output(struct iptables_save_cb *cb, const char *tablename)
time_t now = time(NULL);
printf("# Generated by %s v%s on %s",
- xt_params->program_name, IPTABLES_VERSION, ctime(&now));
+ xt_params->program_name, PACKAGE_VERSION, ctime(&now));
printf("*%s\n", tablename);
/* Dump out chain names first,
diff --git a/iptables/iptables-xml.c b/iptables/iptables-xml.c
index 07300efc..98d03dda 100644
--- a/iptables/iptables-xml.c
+++ b/iptables/iptables-xml.c
@@ -5,7 +5,7 @@
*
* This code is distributed under the terms of GNU GPL v2
*/
-
+#include "config.h"
#include <getopt.h>
#include <errno.h>
#include <string.h>
@@ -20,7 +20,7 @@
struct xtables_globals iptables_xml_globals = {
.option_offset = 0,
- .program_version = IPTABLES_VERSION,
+ .program_version = PACKAGE_VERSION,
.program_name = "iptables-xml",
};
#define prog_name iptables_xml_globals.program_name
@@ -208,12 +208,11 @@ needChain(char *chain)
static void
saveChain(char *chain, char *policy, struct xt_counters *ctr)
{
- if (nextChain >= maxChains) {
+ if (nextChain >= maxChains)
xtables_error(PARAMETER_PROBLEM,
"%s: line %u chain name invalid\n",
prog_name, line);
- exit(1);
- };
+
chains[nextChain].chain = strdup(chain);
chains[nextChain].policy = strdup(policy);
chains[nextChain].count = *ctr;
@@ -441,7 +440,7 @@ do_rule_part(char *leveltag1, char *leveltag2, int part, int argc,
}
static int
-compareRules(void)
+compareRules(int newargc, char *newargv[], int oldargc, char *oldargv[])
{
/* Compare arguments up to -j or -g for match.
* NOTE: We don't want to combine actions if there were no criteria
@@ -490,11 +489,13 @@ compareRules(void)
/* has a nice parsed rule starting with -A */
static void
-do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
+do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[],
+ int oldargc, char *oldargv[])
{
/* are these conditions the same as the previous rule?
* If so, skip arg straight to -j or -g */
- if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) {
+ if (combine && argc > 2 && !isTarget(argv[2]) &&
+ compareRules(argc, argv, oldargc, oldargv)) {
xmlComment("Combine action from next rule");
} else {
@@ -540,6 +541,7 @@ do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
int
iptables_xml_main(int argc, char *argv[])
{
+ struct argv_store last_rule = {}, cur_rule = {};
char buffer[10240];
int c;
FILE *in;
@@ -557,7 +559,7 @@ iptables_xml_main(int argc, char *argv[])
verbose = 1;
break;
case 'h':
- print_usage("iptables-xml", IPTABLES_VERSION);
+ print_usage("iptables-xml", PACKAGE_VERSION);
break;
}
}
@@ -606,12 +608,11 @@ iptables_xml_main(int argc, char *argv[])
table = strtok(buffer + 1, " \t\n");
DEBUGP("line %u, table '%s'\n", line, table);
- if (!table) {
+ if (!table)
xtables_error(PARAMETER_PROBLEM,
"%s: line %u table name invalid\n",
prog_name, line);
- exit(1);
- }
+
openTable(table);
ret = 1;
@@ -623,23 +624,19 @@ iptables_xml_main(int argc, char *argv[])
chain = strtok(buffer + 1, " \t\n");
DEBUGP("line %u, chain '%s'\n", line, chain);
- if (!chain) {
+ if (!chain)
xtables_error(PARAMETER_PROBLEM,
"%s: line %u chain name invalid\n",
prog_name, line);
- exit(1);
- }
DEBUGP("Creating new chain '%s'\n", chain);
policy = strtok(NULL, " \t\n");
DEBUGP("line %u, policy '%s'\n", line, policy);
- if (!policy) {
+ if (!policy)
xtables_error(PARAMETER_PROBLEM,
"%s: line %u policy invalid\n",
prog_name, line);
- exit(1);
- }
ctrs = strtok(NULL, " \t\n");
parse_counters(ctrs, &count);
@@ -650,126 +647,32 @@ iptables_xml_main(int argc, char *argv[])
unsigned int a;
char *pcnt = NULL;
char *bcnt = NULL;
- char *parsestart;
+ char *parsestart = buffer;
char *chain = NULL;
- /* the parser */
- char *param_start, *curchar;
- int quote_open, quoted;
- char param_buffer[1024];
-
- if (buffer[0] == '[') {
- /* we have counters in our input */
- char *ptr = strchr(buffer, ']');
-
- if (!ptr)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need ]\n",
- line);
-
- pcnt = strtok(buffer + 1, ":");
- if (!pcnt)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need :\n",
- line);
-
- bcnt = strtok(NULL, "]");
- if (!bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need ]\n",
- line);
-
- /* start command parsing after counter */
- parsestart = ptr + 1;
- } else {
- /* start command parsing at start of line */
- parsestart = buffer;
- }
-
-
- /* This is a 'real' parser crafted in artist mode
- * not hacker mode. If the author can live with that
- * then so can everyone else */
-
- quote_open = 0;
- /* We need to know which args were quoted so we
- can preserve quote */
- quoted = 0;
- param_start = parsestart;
-
- for (curchar = parsestart; *curchar; curchar++) {
- if (*curchar == '"') {
- /* quote_open cannot be true if there
- * was no previous character. Thus,
- * curchar-1 has to be within bounds */
- if (quote_open &&
- *(curchar - 1) != '\\') {
- quote_open = 0;
- *curchar = ' ';
- } else {
- quote_open = 1;
- quoted = 1;
- param_start++;
- }
- }
- if (*curchar == ' '
- || *curchar == '\t' || *curchar == '\n') {
- int param_len = curchar - param_start;
-
- if (quote_open)
- continue;
-
- if (!param_len) {
- /* two spaces? */
- param_start++;
- continue;
- }
-
- /* end of one parameter */
- strncpy(param_buffer, param_start,
- param_len);
- *(param_buffer + param_len) = '\0';
-
- /* check if table name specified */
- if ((param_buffer[0] == '-' &&
- param_buffer[1] != '-' &&
- strchr(param_buffer, 't')) ||
- (!strncmp(param_buffer, "--t", 3) &&
- !strncmp(param_buffer, "--table", strlen(param_buffer)))) {
- xtables_error(PARAMETER_PROBLEM,
- "Line %u seems to have a "
- "-t table option.\n",
- line);
- exit(1);
- }
-
- add_argv(param_buffer, quoted);
- if (newargc >= 2
- && 0 ==
- strcmp(newargv[newargc - 2], "-A"))
- chain = newargv[newargc - 1];
- quoted = 0;
- param_start += param_len + 1;
- } else {
- /* regular character, skip */
- }
- }
+ tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line);
+ add_param_to_argv(&cur_rule, parsestart, line);
DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
- newargc, curTable);
-
- for (a = 0; a < newargc; a++)
- DEBUGP("argv[%u]: %s\n", a, newargv[a]);
+ cur_rule.argc, curTable);
+ debug_print_argv(&cur_rule);
+ for (a = 1; a < cur_rule.argc; a++) {
+ if (strcmp(cur_rule.argv[a - 1], "-A"))
+ continue;
+ chain = cur_rule.argv[a];
+ break;
+ }
if (!chain) {
fprintf(stderr, "%s: line %u failed - no chain found\n",
prog_name, line);
exit(1);
}
needChain(chain);// Should we explicitly look for -A
- do_rule(pcnt, bcnt, newargc, newargv, newargvattr);
+ do_rule(pcnt, bcnt, cur_rule.argc, cur_rule.argv,
+ cur_rule.argvattr, last_rule.argc, last_rule.argv);
- save_argv();
+ save_argv(&last_rule, &cur_rule);
ret = 1;
}
if (!ret) {
@@ -786,7 +689,7 @@ iptables_xml_main(int argc, char *argv[])
fclose(in);
printf("</iptables-rules>\n");
- free_argv();
+ free_argv(&last_rule);
return 0;
}
diff --git a/iptables/iptables.c b/iptables/iptables.c
index 38c4bfe8..88ef6cf6 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -24,7 +24,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
+#include "config.h"
#include <getopt.h>
#include <string.h>
#include <netdb.h>
@@ -41,33 +41,6 @@
#include <fcntl.h>
#include "xshared.h"
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#define CMD_NONE 0x0000U
-#define CMD_INSERT 0x0001U
-#define CMD_DELETE 0x0002U
-#define CMD_DELETE_NUM 0x0004U
-#define CMD_REPLACE 0x0008U
-#define CMD_APPEND 0x0010U
-#define CMD_LIST 0x0020U
-#define CMD_FLUSH 0x0040U
-#define CMD_ZERO 0x0080U
-#define CMD_NEW_CHAIN 0x0100U
-#define CMD_DELETE_CHAIN 0x0200U
-#define CMD_SET_POLICY 0x0400U
-#define CMD_RENAME_CHAIN 0x0800U
-#define CMD_LIST_RULES 0x1000U
-#define CMD_ZERO_NUM 0x2000U
-#define CMD_CHECK 0x4000U
-#define NUMBER_OF_CMD 16
-static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
- 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
-
#define OPT_FRAGMENT 0x00800U
#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
static const char optflags[]
@@ -120,7 +93,7 @@ void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __a
struct xtables_globals iptables_globals = {
.option_offset = 0,
- .program_version = IPTABLES_VERSION,
+ .program_version = PACKAGE_VERSION,
.orig_opts = original_opts,
.exit_err = iptables_exit_error,
.compat_rev = xtables_compatible_revision,
@@ -335,27 +308,6 @@ opt2char(int option)
return *ptr;
}
-static char
-cmd2char(int option)
-{
- const char *ptr;
- for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
-static void
-add_command(unsigned int *cmd, const int newcmd, const int othercmds,
- int invert)
-{
- if (invert)
- xtables_error(PARAMETER_PROBLEM, "unexpected ! flag");
- if (*cmd & (~othercmds))
- xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
- cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
- *cmd |= newcmd;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
@@ -366,18 +318,6 @@ add_command(unsigned int *cmd, const int newcmd, const int othercmds,
*/
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
-/* Can't be zero. */
-static int
-parse_rulenumber(const char *rule)
-{
- unsigned int rulenum;
-
- if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid rule number `%s'", rule);
-
- return rulenum;
-}
static void
parse_chain(const char *chainname)
@@ -1217,6 +1157,7 @@ int do_command4(int argc, char *argv[], char **table,
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 */
@@ -1494,7 +1435,12 @@ int do_command4(int argc, char *argv[], char **table,
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':
@@ -1564,7 +1510,7 @@ int do_command4(int argc, char *argv[], char **table,
xtables_error(PARAMETER_PROBLEM,
"multiple consecutive ! not"
" allowed");
- cs.invert = TRUE;
+ cs.invert = true;
optarg[0] = '\0';
continue;
}
@@ -1577,7 +1523,7 @@ int do_command4(int argc, char *argv[], char **table,
continue;
break;
}
- cs.invert = FALSE;
+ cs.invert = false;
}
if (!wait && wait_interval_set)
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 9805bbe0..d4a86610 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -114,29 +114,6 @@ mask_to_dotted(const struct in_addr *mask)
return buf;
}
-static void print_mac(const unsigned char *mac, int l)
-{
- int j;
-
- for (j = 0; j < l; j++)
- printf("%02x%s", mac[j],
- (j==l-1) ? "" : ":");
-}
-
-static void print_mac_and_mask(const unsigned char *mac, const unsigned char *mask, int l)
-{
- int i;
-
- print_mac(mac, l);
- for (i = 0; i < l ; i++)
- if (mask[i] != 255)
- break;
- if (i == l)
- return;
- printf("/");
- print_mac(mask, l);
-}
-
static bool need_devaddr(struct arpt_devaddr_info *info)
{
int i;
@@ -149,7 +126,7 @@ static bool need_devaddr(struct arpt_devaddr_info *info)
return false;
}
-static int nft_arp_add(struct nftnl_rule *r, void *data)
+static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
{
struct iptables_command_state *cs = data;
struct arpt_entry *fw = &cs->arp;
@@ -506,8 +483,8 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCDEVADDR
? "! " : "");
printf("--src-mac ");
- print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
- (unsigned char *)fw->arp.src_devaddr.mask, ETH_ALEN);
+ xtables_print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
+ (unsigned char *)fw->arp.src_devaddr.mask);
sep = " ";
after_devsrc:
@@ -532,8 +509,8 @@ after_devsrc:
printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTDEVADDR
? "! " : "");
printf("--dst-mac ");
- print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
- (unsigned char *)fw->arp.tgt_devaddr.mask, ETH_ALEN);
+ xtables_print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
+ (unsigned char *)fw->arp.tgt_devaddr.mask);
sep = " ";
after_devdst:
@@ -605,14 +582,15 @@ nft_arp_save_rule(const void *data, unsigned int format)
}
static void
-nft_arp_print_rule(struct nftnl_rule *r, unsigned int num, unsigned int format)
+nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r,
+ unsigned int num, unsigned int format)
{
struct iptables_command_state cs = {};
if (format & FMT_LINENUMBERS)
printf("%u ", num);
- nft_rule_to_iptables_command_state(r, &cs);
+ nft_rule_to_iptables_command_state(h, r, &cs);
nft_arp_print_rule_details(&cs, format);
print_matches_and_target(&cs, format);
@@ -655,7 +633,7 @@ static bool nft_arp_is_same(const void *data_a,
(unsigned char *)b->arp.outiface_mask);
}
-static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
+static bool nft_arp_rule_find(struct nft_handle *h, struct nftnl_rule *r,
void *data)
{
const struct iptables_command_state *cs = data;
@@ -663,7 +641,7 @@ static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
bool ret = false;
/* Delete by matching rule case */
- nft_rule_to_iptables_command_state(r, &this);
+ nft_rule_to_iptables_command_state(h, r, &this);
if (!nft_arp_is_same(&cs->arp, &this.arp))
goto out;
@@ -676,7 +654,7 @@ static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
ret = true;
out:
- ops->clear_cs(&this);
+ h->ops->clear_cs(&this);
return ret;
}
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index ddfbee16..3f85cbbf 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -17,12 +17,13 @@
#include <libiptc/libxtc.h>
#include <linux/netfilter/nf_tables.h>
+#include <libnftnl/set.h>
+
#include "nft-shared.h"
#include "nft-bridge.h"
+#include "nft-cache.h"
#include "nft.h"
-static bool ebt_legacy_counter_fmt;
-
void ebt_cs_clean(struct iptables_command_state *cs)
{
struct ebt_match *m, *nm;
@@ -128,7 +129,8 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
return add_action(r, cs, false);
}
-static int nft_bridge_add(struct nftnl_rule *r, void *data)
+static int nft_bridge_add(struct nft_handle *h,
+ struct nftnl_rule *r, void *data)
{
struct iptables_command_state *cs = data;
struct ebt_match *iter;
@@ -184,7 +186,7 @@ static int nft_bridge_add(struct nftnl_rule *r, void *data)
for (iter = cs->match_list; iter; iter = iter->next) {
if (iter->ismatch) {
- if (add_match(r, iter->u.match->m))
+ if (add_match(h, r, iter->u.match->m))
break;
} else {
if (add_target(r, iter->u.watcher->t))
@@ -292,6 +294,212 @@ static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto,
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)
+{
+ if (base != 0 || len != ETH_ALEN)
+ return -1;
+
+ switch (offset) {
+ case offsetof(struct ether_header, ether_dhost):
+ return 1;
+ case offsetof(struct ether_header, ether_shost):
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/* return 0 if saddr, 1 if daddr, -1 on error */
+static int
+lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len)
+{
+ if (base != 1 || len != 4)
+ return -1;
+
+ switch (offset) {
+ case offsetof(struct iphdr, daddr):
+ return 1;
+ case offsetof(struct iphdr, saddr):
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/* Make sure previous payload expression(s) is/are consistent and extract if
+ * matching on source or destination address and if matching on MAC and IP or
+ * only MAC address. */
+static int lookup_analyze_payloads(const struct nft_xt_ctx *ctx,
+ bool *dst, bool *ip)
+{
+ int val, val2 = -1;
+
+ if (ctx->flags & NFT_XT_CTX_PREV_PAYLOAD) {
+ val = lookup_check_ether_payload(ctx->prev_payload.base,
+ ctx->prev_payload.offset,
+ ctx->prev_payload.len);
+ if (val < 0) {
+ DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
+ ctx->prev_payload.base, ctx->prev_payload.offset,
+ ctx->prev_payload.len);
+ return -1;
+ }
+ if (!(ctx->flags & NFT_XT_CTX_PAYLOAD)) {
+ DEBUGP("Previous but no current payload?\n");
+ return -1;
+ }
+ val2 = lookup_check_iphdr_payload(ctx->payload.base,
+ ctx->payload.offset,
+ ctx->payload.len);
+ if (val2 < 0) {
+ DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
+ ctx->payload.base, ctx->payload.offset,
+ ctx->payload.len);
+ return -1;
+ } else if (val != val2) {
+ DEBUGP("mismatching payload match offsets\n");
+ return -1;
+ }
+ } else if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
+ val = lookup_check_ether_payload(ctx->payload.base,
+ ctx->payload.offset,
+ ctx->payload.len);
+ if (val < 0) {
+ DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
+ ctx->payload.base, ctx->payload.offset,
+ ctx->payload.len);
+ return -1;
+ }
+ } else {
+ DEBUGP("unknown LHS of lookup expression\n");
+ return -1;
+ }
+
+ if (dst)
+ *dst = (val == 1);
+ if (ip)
+ *ip = (val2 != -1);
+ return 0;
+}
+
+static int set_elems_to_among_pairs(struct nft_among_pair *pairs,
+ const struct nftnl_set *s, int cnt)
+{
+ struct nftnl_set_elems_iter *iter = nftnl_set_elems_iter_create(s);
+ struct nftnl_set_elem *elem;
+ size_t tmpcnt = 0;
+ const void *data;
+ uint32_t datalen;
+ int ret = -1;
+
+ if (!iter) {
+ fprintf(stderr, "BUG: set elems iter allocation failed\n");
+ return ret;
+ }
+
+ while ((elem = nftnl_set_elems_iter_next(iter))) {
+ data = nftnl_set_elem_get(elem, NFTNL_SET_ELEM_KEY, &datalen);
+ if (!data) {
+ fprintf(stderr, "BUG: set elem without key\n");
+ goto err;
+ }
+ if (datalen > sizeof(*pairs)) {
+ fprintf(stderr, "BUG: overlong set elem\n");
+ goto err;
+ }
+ nft_among_insert_pair(pairs, &tmpcnt, data);
+ }
+ ret = 0;
+err:
+ nftnl_set_elems_iter_destroy(iter);
+ return ret;
+}
+
+static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx,
+ const struct nftnl_expr *e)
+{
+ const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET);
+ struct nftnl_set_list *slist;
+
+ slist = nft_set_list_get(ctx->h, ctx->table, set_name);
+ if (slist)
+ return nftnl_set_list_lookup_byname(slist, set_name);
+
+ return NULL;
+}
+
+static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx,
+ struct nftnl_expr *e, void *data)
+{
+ struct xtables_match *match = NULL;
+ struct nft_among_data *among_data;
+ bool is_dst, have_ip, inv;
+ struct ebt_match *ematch;
+ struct nftnl_set *s;
+ size_t poff, size;
+ uint32_t cnt;
+
+ if (lookup_analyze_payloads(ctx, &is_dst, &have_ip))
+ return;
+
+ s = set_from_lookup_expr(ctx, e);
+ if (!s)
+ xtables_error(OTHER_PROBLEM,
+ "BUG: lookup expression references unknown set");
+
+ cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE);
+
+ for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) {
+ if (!ematch->ismatch || strcmp(ematch->u.match->name, "among"))
+ continue;
+
+ match = ematch->u.match;
+ among_data = (struct nft_among_data *)match->m->data;
+
+ size = cnt + among_data->src.cnt + among_data->dst.cnt;
+ size *= sizeof(struct nft_among_pair);
+
+ size += XT_ALIGN(sizeof(struct xt_entry_match)) +
+ sizeof(struct nft_among_data);
+
+ match->m = xtables_realloc(match->m, size);
+ break;
+ }
+ if (!match) {
+ match = xtables_find_match("among", XTF_TRY_LOAD,
+ &ctx->cs->matches);
+
+ size = cnt * sizeof(struct nft_among_pair);
+ size += XT_ALIGN(sizeof(struct xt_entry_match)) +
+ sizeof(struct nft_among_data);
+
+ match->m = xtables_calloc(1, size);
+ strcpy(match->m->u.user.name, match->name);
+ match->m->u.user.revision = match->revision;
+ xs_init_match(match);
+
+ if (ctx->h->ops->parse_match != NULL)
+ ctx->h->ops->parse_match(match, ctx->cs);
+ }
+ if (!match)
+ return;
+
+ match->m->u.match_size = size;
+
+ inv = !!(nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_FLAGS) &
+ NFT_LOOKUP_F_INV);
+
+ among_data = (struct nft_among_data *)match->m->data;
+ poff = nft_among_prepare_data(among_data, is_dst, cnt, inv, have_ip);
+ if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt))
+ xtables_error(OTHER_PROBLEM,
+ "ebtables among pair parsing failed");
+
+ ctx->flags &= ~(NFT_XT_CTX_PAYLOAD | NFT_XT_CTX_PREV_PAYLOAD);
+}
+
static void parse_watcher(void *object, struct ebt_match **match_list,
bool ismatch)
{
@@ -334,11 +542,12 @@ static void nft_bridge_parse_target(struct xtables_target *t, void *data)
cs->target = t;
}
-static void nft_rule_to_ebtables_command_state(const struct nftnl_rule *r,
+static void nft_rule_to_ebtables_command_state(struct nft_handle *h,
+ const struct nftnl_rule *r,
struct iptables_command_state *cs)
{
cs->eb.bitmask = EBT_NOPROTO;
- nft_rule_to_iptables_command_state(r, cs);
+ nft_rule_to_iptables_command_state(h, r, cs);
}
static void print_iface(const char *option, const char *name, bool invert)
@@ -422,22 +631,6 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
printf("%s ", ent->e_name);
}
-static void nft_bridge_save_counters(const void *data)
-{
- const char *ctr;
-
- if (ebt_legacy_counter_fmt)
- return;
-
- ctr = getenv("EBTABLES_SAVE_COUNTER");
- if (ctr) {
- ebt_legacy_counter_fmt = true;
- return;
- }
-
- save_counters(data);
-}
-
static void nft_bridge_save_rule(const void *data, unsigned int format)
{
const struct iptables_command_state *cs = data;
@@ -474,29 +667,30 @@ static void nft_bridge_save_rule(const void *data, unsigned int format)
cs->target->print(&cs->fw, cs->target->t, format & FMT_NUMERIC);
}
- if (format & FMT_EBT_SAVE)
- printf(" -c %"PRIu64" %"PRIu64"",
- (uint64_t)cs->counters.pcnt,
- (uint64_t)cs->counters.bcnt);
-
- if (!(format & FMT_NOCOUNTS))
- printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"",
- (uint64_t)cs->counters.pcnt,
- (uint64_t)cs->counters.bcnt);
+ if ((format & (FMT_NOCOUNTS | FMT_C_COUNTS)) == FMT_C_COUNTS) {
+ if (format & FMT_EBT_SAVE)
+ printf(" -c %"PRIu64" %"PRIu64"",
+ (uint64_t)cs->counters.pcnt,
+ (uint64_t)cs->counters.bcnt);
+ else
+ printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"",
+ (uint64_t)cs->counters.pcnt,
+ (uint64_t)cs->counters.bcnt);
+ }
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
}
-static void nft_bridge_print_rule(struct nftnl_rule *r, unsigned int num,
- unsigned int format)
+static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r,
+ unsigned int num, unsigned int format)
{
struct iptables_command_state cs = {};
if (format & FMT_LINENUMBERS)
printf("%d ", num);
- nft_rule_to_ebtables_command_state(r, &cs);
+ nft_rule_to_ebtables_command_state(h, r, &cs);
nft_bridge_save_rule(&cs, format);
ebt_cs_clean(&cs);
}
@@ -553,14 +747,14 @@ static bool nft_bridge_is_same(const void *data_a, const void *data_b)
return strcmp(a->in, b->in) == 0 && strcmp(a->out, b->out) == 0;
}
-static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
+static bool nft_bridge_rule_find(struct nft_handle *h, struct nftnl_rule *r,
void *data)
{
struct iptables_command_state *cs = data;
struct iptables_command_state this = {};
bool ret = false;
- nft_rule_to_ebtables_command_state(r, &this);
+ nft_rule_to_ebtables_command_state(h, r, &this);
DEBUGP("comparing with... ");
@@ -584,7 +778,7 @@ static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nftnl_rule *
ret = true;
out:
- ops->clear_cs(&this);
+ h->ops->clear_cs(&this);
return ret;
}
@@ -757,13 +951,14 @@ struct nft_family_ops nft_family_ops_bridge = {
.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,
.print_table_header = nft_bridge_print_table_header,
.print_header = nft_bridge_print_header,
.print_rule = nft_bridge_print_rule,
.save_rule = nft_bridge_save_rule,
- .save_counters = nft_bridge_save_counters,
+ .save_counters = save_counters,
.save_chain = nft_bridge_save_chain,
.post_parse = NULL,
.rule_to_cs = nft_rule_to_ebtables_command_state,
diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h
index d90066f1..eb1b3928 100644
--- a/iptables/nft-bridge.h
+++ b/iptables/nft-bridge.h
@@ -122,4 +122,60 @@ void ebt_add_watcher(struct xtables_target *watcher,
struct iptables_command_state *cs);
int ebt_command_default(struct iptables_command_state *cs);
+struct nft_among_pair {
+ struct ether_addr ether;
+ struct in_addr in __attribute__((aligned (4)));
+};
+
+struct nft_among_data {
+ struct {
+ size_t cnt;
+ bool inv;
+ bool ip;
+ } src, dst;
+ /* first source, then dest pairs */
+ struct nft_among_pair pairs[0];
+};
+
+/* initialize fields, return offset into pairs array to write pairs to */
+static inline size_t
+nft_among_prepare_data(struct nft_among_data *data, bool dst,
+ size_t cnt, bool inv, bool ip)
+{
+ size_t poff;
+
+ if (dst) {
+ data->dst.cnt = cnt;
+ data->dst.inv = inv;
+ data->dst.ip = ip;
+ poff = data->src.cnt;
+ } else {
+ data->src.cnt = cnt;
+ data->src.inv = inv;
+ data->src.ip = ip;
+ poff = 0;
+ memmove(data->pairs + cnt, data->pairs,
+ data->dst.cnt * sizeof(*data->pairs));
+ }
+ return poff;
+}
+
+static inline void
+nft_among_insert_pair(struct nft_among_pair *pairs,
+ size_t *pcount, const struct nft_among_pair *new)
+{
+ int i;
+
+ /* nftables automatically sorts set elements from smallest to largest,
+ * insert sorted so extension comparison works */
+
+ for (i = 0; i < *pcount; i++) {
+ if (memcmp(new, &pairs[i], sizeof(*new)) < 0)
+ break;
+ }
+ memmove(&pairs[i + 1], &pairs[i], sizeof(*pairs) * (*pcount - i));
+ memcpy(&pairs[i], new, sizeof(*new));
+ (*pcount)++;
+}
+
#endif
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
new file mode 100644
index 00000000..7345a27e
--- /dev/null
+++ b/iptables/nft-cache.c
@@ -0,0 +1,688 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * 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 code has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <xtables.h>
+
+#include <linux/netfilter/nf_tables.h>
+
+#include <libmnl/libmnl.h>
+#include <libnftnl/gen.h>
+#include <libnftnl/set.h>
+#include <libnftnl/table.h>
+
+#include "nft.h"
+#include "nft-cache.h"
+
+static int genid_cb(const struct nlmsghdr *nlh, void *data)
+{
+ uint32_t *genid = data;
+ struct nftnl_gen *gen;
+
+ gen = nftnl_gen_alloc();
+ if (!gen)
+ return MNL_CB_ERROR;
+
+ if (nftnl_gen_nlmsg_parse(nlh, gen) < 0)
+ goto out;
+
+ *genid = nftnl_gen_get_u32(gen, NFTNL_GEN_ID);
+
+ nftnl_gen_free(gen);
+ return MNL_CB_STOP;
+out:
+ nftnl_gen_free(gen);
+ return MNL_CB_ERROR;
+}
+
+static void mnl_genid_get(struct nft_handle *h, uint32_t *genid)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ int ret;
+
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, 0, 0, h->seq);
+ ret = mnl_talk(h, nlh, genid_cb, genid);
+ if (ret == 0)
+ return;
+
+ xtables_error(RESOURCE_PROBLEM,
+ "Could not fetch rule set generation id: %s\n", nft_strerror(errno));
+}
+
+static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_table *t;
+ struct nftnl_table_list *list = data;
+
+ t = nftnl_table_alloc();
+ if (t == NULL)
+ goto err;
+
+ if (nftnl_table_nlmsg_parse(nlh, t) < 0)
+ goto out;
+
+ nftnl_table_list_add_tail(t, list);
+
+ return MNL_CB_OK;
+out:
+ nftnl_table_free(t);
+err:
+ return MNL_CB_OK;
+}
+
+static int fetch_table_cache(struct nft_handle *h)
+{
+ char buf[16536];
+ struct nlmsghdr *nlh;
+ struct nftnl_table_list *list;
+ int ret;
+
+ if (h->cache->tables)
+ return 0;
+
+ list = nftnl_table_list_alloc();
+ if (list == NULL)
+ return 0;
+
+ nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
+ NLM_F_DUMP, h->seq);
+
+ ret = mnl_talk(h, nlh, nftnl_table_list_cb, list);
+ if (ret < 0 && errno == EINTR)
+ assert(nft_restart(h) >= 0);
+
+ h->cache->tables = list;
+
+ return 1;
+}
+
+struct nftnl_chain_list_cb_data {
+ struct nft_handle *h;
+ const struct builtin_table *t;
+};
+
+static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_chain_list_cb_data *d = data;
+ const struct builtin_table *t = d->t;
+ struct nftnl_chain_list *list;
+ struct nft_handle *h = d->h;
+ const char *tname, *cname;
+ struct nftnl_chain *c;
+
+ c = nftnl_chain_alloc();
+ if (c == NULL)
+ goto err;
+
+ if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
+ goto out;
+
+ tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
+
+ if (!t) {
+ t = nft_table_builtin_find(h, tname);
+ if (!t)
+ goto out;
+ } else if (strcmp(t->name, tname)) {
+ goto out;
+ }
+
+ list = h->cache->table[t->type].chains;
+ cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+
+ if (nftnl_chain_list_lookup_byname(list, cname))
+ goto out;
+
+ nftnl_chain_list_add_tail(c, list);
+
+ return MNL_CB_OK;
+out:
+ nftnl_chain_free(c);
+err:
+ return MNL_CB_OK;
+}
+
+struct nftnl_set_list_cb_data {
+ struct nft_handle *h;
+ const struct builtin_table *t;
+};
+
+static int nftnl_set_list_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_set_list_cb_data *d = data;
+ const struct builtin_table *t = d->t;
+ struct nftnl_set_list *list;
+ struct nft_handle *h = d->h;
+ const char *tname, *sname;
+ struct nftnl_set *s;
+
+ s = nftnl_set_alloc();
+ if (s == NULL)
+ return MNL_CB_OK;
+
+ if (nftnl_set_nlmsg_parse(nlh, s) < 0)
+ goto out_free;
+
+ tname = nftnl_set_get_str(s, NFTNL_SET_TABLE);
+
+ if (!t)
+ t = nft_table_builtin_find(h, tname);
+ else if (strcmp(t->name, tname))
+ goto out_free;
+
+ if (!t)
+ goto out_free;
+
+ list = h->cache->table[t->type].sets;
+ sname = nftnl_set_get_str(s, NFTNL_SET_NAME);
+
+ if (nftnl_set_list_lookup_byname(list, sname))
+ goto out_free;
+
+ nftnl_set_list_add_tail(s, list);
+
+ return MNL_CB_OK;
+out_free:
+ nftnl_set_free(s);
+ return MNL_CB_OK;
+}
+
+static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
+{
+ return nftnl_set_elems_nlmsg_parse(nlh, data) ? -1 : MNL_CB_OK;
+}
+
+static bool set_has_elements(struct nftnl_set *s)
+{
+ struct nftnl_set_elems_iter *iter;
+ bool ret = false;
+
+ iter = nftnl_set_elems_iter_create(s);
+ if (iter) {
+ ret = !!nftnl_set_elems_iter_cur(iter);
+ nftnl_set_elems_iter_destroy(iter);
+ }
+ return ret;
+}
+
+static int set_fetch_elem_cb(struct nftnl_set *s, void *data)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nft_handle *h = data;
+ struct nlmsghdr *nlh;
+
+ if (set_has_elements(s))
+ return 0;
+
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM, h->family,
+ NLM_F_DUMP, h->seq);
+ nftnl_set_elems_nlmsg_build_payload(nlh, s);
+
+ return mnl_talk(h, nlh, set_elem_cb, s);
+}
+
+static int fetch_set_cache(struct nft_handle *h,
+ const struct builtin_table *t, const char *set)
+{
+ struct nftnl_set_list_cb_data d = {
+ .h = h,
+ .t = t,
+ };
+ struct nlmsghdr *nlh;
+ char buf[16536];
+ int i, ret;
+
+ if (!t) {
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ enum nft_table_type type = h->tables[i].type;
+
+ if (!h->tables[i].name)
+ continue;
+
+ h->cache->table[type].sets = nftnl_set_list_alloc();
+ if (!h->cache->table[type].sets)
+ return -1;
+ }
+ } else if (!h->cache->table[t->type].sets) {
+ h->cache->table[t->type].sets = nftnl_set_list_alloc();
+ }
+
+ if (t && set) {
+ struct nftnl_set *s = nftnl_set_alloc();
+
+ if (!s)
+ return -1;
+
+ nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, h->family,
+ NLM_F_ACK, h->seq);
+ nftnl_set_set_str(s, NFTNL_SET_TABLE, t->name);
+ nftnl_set_set_str(s, NFTNL_SET_NAME, set);
+ nftnl_set_nlmsg_build_payload(nlh, s);
+ nftnl_set_free(s);
+ } else {
+ nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, h->family,
+ NLM_F_DUMP, h->seq);
+ }
+
+ ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d);
+ if (ret < 0 && errno == EINTR) {
+ assert(nft_restart(h) >= 0);
+ return ret;
+ }
+
+ if (t && set) {
+ struct nftnl_set *s;
+
+ s = nftnl_set_list_lookup_byname(h->cache->table[t->type].sets,
+ set);
+ set_fetch_elem_cb(s, h);
+ } else if (t) {
+ nftnl_set_list_foreach(h->cache->table[t->type].sets,
+ set_fetch_elem_cb, h);
+ } else {
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ enum nft_table_type type = h->tables[i].type;
+
+ if (!h->tables[i].name)
+ continue;
+
+ nftnl_set_list_foreach(h->cache->table[type].sets,
+ set_fetch_elem_cb, h);
+ }
+ }
+ return ret;
+}
+
+static int fetch_chain_cache(struct nft_handle *h,
+ const struct builtin_table *t,
+ const char *chain)
+{
+ struct nftnl_chain_list_cb_data d = {
+ .h = h,
+ .t = t,
+ };
+ char buf[16536];
+ struct nlmsghdr *nlh;
+ int i, ret;
+
+ if (!t) {
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ enum nft_table_type type = h->tables[i].type;
+
+ if (!h->tables[i].name)
+ continue;
+
+ if (h->cache->table[type].chains)
+ continue;
+
+ h->cache->table[type].chains = nftnl_chain_list_alloc();
+ if (!h->cache->table[type].chains)
+ return -1;
+ }
+ } else if (!h->cache->table[t->type].chains) {
+ h->cache->table[t->type].chains = nftnl_chain_list_alloc();
+ if (!h->cache->table[t->type].chains)
+ return -1;
+ }
+
+ if (t && chain) {
+ struct nftnl_chain *c = nftnl_chain_alloc();
+
+ if (!c)
+ return -1;
+
+ nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN,
+ h->family, NLM_F_ACK,
+ h->seq);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, t->name);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
+ nftnl_chain_nlmsg_build_payload(nlh, c);
+ nftnl_chain_free(c);
+ } else {
+ nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN,
+ h->family, NLM_F_DUMP,
+ h->seq);
+ }
+
+ ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
+ if (ret < 0 && errno == EINTR)
+ assert(nft_restart(h) >= 0);
+
+ return ret;
+}
+
+static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_chain *c = data;
+ struct nftnl_rule *r;
+
+ r = nftnl_rule_alloc();
+ if (r == NULL)
+ return MNL_CB_OK;
+
+ if (nftnl_rule_nlmsg_parse(nlh, r) < 0) {
+ nftnl_rule_free(r);
+ return MNL_CB_OK;
+ }
+
+ nftnl_chain_rule_add_tail(r, c);
+ return MNL_CB_OK;
+}
+
+static int nft_rule_list_update(struct nftnl_chain *c, void *data)
+{
+ struct nft_handle *h = data;
+ char buf[16536];
+ struct nlmsghdr *nlh;
+ struct nftnl_rule *rule;
+ int ret;
+
+ if (nftnl_rule_lookup_byindex(c, 0))
+ return 0;
+
+ rule = nftnl_rule_alloc();
+ if (!rule)
+ return -1;
+
+ nftnl_rule_set_str(rule, NFTNL_RULE_TABLE,
+ nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
+ nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN,
+ nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
+
+ nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
+ NLM_F_DUMP, h->seq);
+ nftnl_rule_nlmsg_build_payload(nlh, rule);
+
+ ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
+ if (ret < 0 && errno == EINTR)
+ assert(nft_restart(h) >= 0);
+
+ nftnl_rule_free(rule);
+
+ if (h->family == NFPROTO_BRIDGE)
+ nft_bridge_chain_postprocess(h, c);
+
+ return 0;
+}
+
+static int fetch_rule_cache(struct nft_handle *h,
+ const struct builtin_table *t, const char *chain)
+{
+ int i;
+
+ if (t) {
+ struct nftnl_chain_list *list;
+ struct nftnl_chain *c;
+
+ list = h->cache->table[t->type].chains;
+
+ if (chain) {
+ c = nftnl_chain_list_lookup_byname(list, chain);
+ return nft_rule_list_update(c, h);
+ }
+ return nftnl_chain_list_foreach(list, nft_rule_list_update, h);
+ }
+
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ enum nft_table_type type = h->tables[i].type;
+
+ if (!h->tables[i].name)
+ continue;
+
+ if (nftnl_chain_list_foreach(h->cache->table[type].chains,
+ nft_rule_list_update, h))
+ return -1;
+ }
+ return 0;
+}
+
+static void
+__nft_build_cache(struct nft_handle *h, enum nft_cache_level level,
+ const struct builtin_table *t, const char *set,
+ const char *chain)
+{
+ uint32_t genid_start, genid_stop;
+
+ if (level <= h->cache_level)
+ return;
+retry:
+ mnl_genid_get(h, &genid_start);
+
+ if (h->cache_level && genid_start != h->nft_genid)
+ flush_chain_cache(h, NULL);
+
+ switch (h->cache_level) {
+ case NFT_CL_NONE:
+ fetch_table_cache(h);
+ if (level == NFT_CL_TABLES)
+ break;
+ /* fall through */
+ case NFT_CL_TABLES:
+ fetch_chain_cache(h, t, chain);
+ if (level == NFT_CL_CHAINS)
+ break;
+ /* fall through */
+ case NFT_CL_CHAINS:
+ fetch_set_cache(h, t, set);
+ if (level == NFT_CL_SETS)
+ break;
+ /* fall through */
+ case NFT_CL_SETS:
+ fetch_rule_cache(h, t, chain);
+ if (level == NFT_CL_RULES)
+ break;
+ /* fall through */
+ case NFT_CL_RULES:
+ break;
+ }
+
+ mnl_genid_get(h, &genid_stop);
+ if (genid_start != genid_stop) {
+ flush_chain_cache(h, NULL);
+ goto retry;
+ }
+
+ if (!t && !chain)
+ h->cache_level = level;
+ else if (h->cache_level < NFT_CL_TABLES)
+ h->cache_level = NFT_CL_TABLES;
+
+ h->nft_genid = genid_start;
+}
+
+void nft_build_cache(struct nft_handle *h, struct nftnl_chain *c)
+{
+ const struct builtin_table *t;
+ const char *table, *chain;
+
+ if (!c)
+ return __nft_build_cache(h, NFT_CL_RULES, NULL, NULL, NULL);
+
+ table = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
+ chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ t = nft_table_builtin_find(h, table);
+ __nft_build_cache(h, NFT_CL_RULES, t, NULL, chain);
+}
+
+void nft_fake_cache(struct nft_handle *h)
+{
+ int i;
+
+ fetch_table_cache(h);
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ enum nft_table_type type = h->tables[i].type;
+
+ if (!h->tables[i].name)
+ continue;
+
+ h->cache->table[type].chains = nftnl_chain_list_alloc();
+ }
+ h->cache_level = NFT_CL_RULES;
+ mnl_genid_get(h, &h->nft_genid);
+}
+
+static void __nft_flush_cache(struct nft_handle *h)
+{
+ if (!h->cache_index) {
+ h->cache_index++;
+ h->cache = &h->__cache[h->cache_index];
+ } else {
+ flush_chain_cache(h, NULL);
+ }
+}
+
+static int ____flush_rule_cache(struct nftnl_rule *r, void *data)
+{
+ nftnl_rule_list_del(r);
+ nftnl_rule_free(r);
+
+ return 0;
+}
+
+static int __flush_rule_cache(struct nftnl_chain *c, void *data)
+{
+ return nftnl_rule_foreach(c, ____flush_rule_cache, NULL);
+}
+
+int flush_rule_cache(struct nft_handle *h, const char *table,
+ struct nftnl_chain *c)
+{
+ const struct builtin_table *t;
+
+ if (c)
+ return __flush_rule_cache(c, NULL);
+
+ t = nft_table_builtin_find(h, table);
+ if (!t || !h->cache->table[t->type].chains)
+ return 0;
+
+ return nftnl_chain_list_foreach(h->cache->table[t->type].chains,
+ __flush_rule_cache, NULL);
+}
+
+static int __flush_chain_cache(struct nftnl_chain *c, void *data)
+{
+ nftnl_chain_list_del(c);
+ nftnl_chain_free(c);
+
+ return 0;
+}
+
+static int __flush_set_cache(struct nftnl_set *s, void *data)
+{
+ nftnl_set_list_del(s);
+ nftnl_set_free(s);
+
+ return 0;
+}
+
+static int flush_cache(struct nft_handle *h, struct nft_cache *c,
+ const char *tablename)
+{
+ const struct builtin_table *table;
+ int i;
+
+ if (tablename) {
+ table = nft_table_builtin_find(h, tablename);
+ if (!table)
+ return 0;
+ if (c->table[table->type].chains)
+ nftnl_chain_list_foreach(c->table[table->type].chains,
+ __flush_chain_cache, NULL);
+ if (c->table[table->type].sets)
+ nftnl_set_list_foreach(c->table[table->type].sets,
+ __flush_set_cache, NULL);
+ return 0;
+ }
+
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ if (h->tables[i].name == NULL)
+ continue;
+
+ if (!c->table[i].chains)
+ continue;
+
+ nftnl_chain_list_free(c->table[i].chains);
+ c->table[i].chains = NULL;
+ if (c->table[i].sets)
+ nftnl_set_list_free(c->table[i].sets);
+ c->table[i].sets = NULL;
+ }
+ nftnl_table_list_free(c->tables);
+ c->tables = NULL;
+
+ return 1;
+}
+
+void flush_chain_cache(struct nft_handle *h, const char *tablename)
+{
+ if (!h->cache_level)
+ return;
+
+ if (flush_cache(h, h->cache, tablename))
+ h->cache_level = NFT_CL_NONE;
+}
+
+void nft_rebuild_cache(struct nft_handle *h)
+{
+ enum nft_cache_level level = h->cache_level;
+
+ if (h->cache_level)
+ __nft_flush_cache(h);
+
+ h->cache_level = NFT_CL_NONE;
+ __nft_build_cache(h, level, NULL, NULL, NULL);
+}
+
+void nft_release_cache(struct nft_handle *h)
+{
+ if (h->cache_index)
+ flush_cache(h, &h->__cache[0], NULL);
+}
+
+struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
+{
+ __nft_build_cache(h, NFT_CL_TABLES, NULL, NULL, NULL);
+
+ return h->cache->tables;
+}
+
+struct nftnl_set_list *
+nft_set_list_get(struct nft_handle *h, const char *table, const char *set)
+{
+ const struct builtin_table *t;
+
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return NULL;
+
+ __nft_build_cache(h, NFT_CL_RULES, t, set, NULL);
+
+ return h->cache->table[t->type].sets;
+}
+
+struct nftnl_chain_list *
+nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain)
+{
+ const struct builtin_table *t;
+
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return NULL;
+
+ __nft_build_cache(h, NFT_CL_CHAINS, t, NULL, chain);
+
+ return h->cache->table[t->type].chains;
+}
+
diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h
new file mode 100644
index 00000000..ed498835
--- /dev/null
+++ b/iptables/nft-cache.h
@@ -0,0 +1,20 @@
+#ifndef _NFT_CACHE_H_
+#define _NFT_CACHE_H_
+
+struct nft_handle;
+
+void nft_fake_cache(struct nft_handle *h);
+void nft_build_cache(struct nft_handle *h, struct nftnl_chain *c);
+void nft_rebuild_cache(struct nft_handle *h);
+void nft_release_cache(struct nft_handle *h);
+void flush_chain_cache(struct nft_handle *h, const char *tablename);
+int flush_rule_cache(struct nft_handle *h, const char *table,
+ struct nftnl_chain *c);
+
+struct nftnl_chain_list *
+nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain);
+struct nftnl_set_list *
+nft_set_list_get(struct nft_handle *h, const char *table, const char *set);
+struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h);
+
+#endif /* _NFT_CACHE_H_ */
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 4497eb9b..70634f8f 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -26,7 +26,7 @@
#include "nft.h"
#include "nft-shared.h"
-static int nft_ipv4_add(struct nftnl_rule *r, void *data)
+static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
{
struct iptables_command_state *cs = data;
struct xtables_rule_match *matchp;
@@ -77,7 +77,7 @@ static int nft_ipv4_add(struct nftnl_rule *r, void *data)
add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO);
for (matchp = cs->matches; matchp; matchp = matchp->next) {
- ret = add_match(r, matchp->match->m);
+ ret = add_match(h, r, matchp->match->m);
if (ret < 0)
return ret;
}
@@ -261,12 +261,12 @@ static void print_fragment(unsigned int flags, unsigned int invflags,
fputc(' ', stdout);
}
-static void nft_ipv4_print_rule(struct nftnl_rule *r, unsigned int num,
- unsigned int format)
+static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
+ unsigned int num, unsigned int format)
{
struct iptables_command_state cs = {};
- nft_rule_to_iptables_command_state(r, &cs);
+ 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);
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index cacb1c9e..d01491bf 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -25,7 +25,7 @@
#include "nft.h"
#include "nft-shared.h"
-static int nft_ipv6_add(struct nftnl_rule *r, void *data)
+static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
{
struct iptables_command_state *cs = data;
struct xtables_rule_match *matchp;
@@ -66,7 +66,7 @@ static int nft_ipv6_add(struct nftnl_rule *r, void *data)
add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO);
for (matchp = cs->matches; matchp; matchp = matchp->next) {
- ret = add_match(r, matchp->match->m);
+ ret = add_match(h, r, matchp->match->m);
if (ret < 0)
return ret;
}
@@ -187,12 +187,12 @@ static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto,
cs->fw6.ipv6.flags |= IP6T_F_GOTO;
}
-static void nft_ipv6_print_rule(struct nftnl_rule *r, unsigned int num,
- unsigned int format)
+static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
+ unsigned int num, unsigned int format)
{
struct iptables_command_state cs = {};
- nft_rule_to_iptables_command_state(r, &cs);
+ 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,
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 1c09277d..78e42278 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -69,7 +69,7 @@ void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base)
}
/* bitwise operation is = sreg & mask ^ xor */
-void add_bitwise_u16(struct nftnl_rule *r, int mask, int xor)
+void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor)
{
struct nftnl_expr *expr;
@@ -310,7 +310,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;
- struct nft_family_ops *ops;
void *data = ctx->cs;
target = xtables_find_target(targname, XTF_TRY_LOAD);
@@ -327,8 +326,7 @@ static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
target->t = t;
- ops = nft_family_ops_lookup(ctx->family);
- ops->parse_target(target, data);
+ ctx->h->ops->parse_target(target, data);
}
static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
@@ -339,9 +337,8 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
struct xtables_match *match;
struct xtables_rule_match **matches;
struct xt_entry_match *m;
- struct nft_family_ops *ops;
- switch (ctx->family) {
+ switch (ctx->h->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
case NFPROTO_BRIDGE:
@@ -349,7 +346,7 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
break;
default:
fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n",
- ctx->family);
+ ctx->h->family);
exit(EXIT_FAILURE);
}
@@ -365,9 +362,8 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
match->m = m;
- ops = nft_family_ops_lookup(ctx->family);
- if (ops->parse_match != NULL)
- ops->parse_match(match, ctx->cs);
+ if (ctx->h->ops->parse_match != NULL)
+ ctx->h->ops->parse_match(match, ctx->cs);
}
void print_proto(uint16_t proto, int invert)
@@ -400,7 +396,6 @@ void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
{
- const struct nft_family_ops *ops;
struct xtables_target *target;
struct xt_entry_target *t;
unsigned int size;
@@ -429,8 +424,7 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
target->t = t;
- ops = nft_family_ops_lookup(ctx->family);
- ops->parse_target(target, ctx->cs);
+ ctx->h->ops->parse_target(target, ctx->cs);
}
static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
@@ -451,8 +445,16 @@ static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
+ if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
+ memcpy(&ctx->prev_payload, &ctx->payload,
+ sizeof(ctx->prev_payload));
+ ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD;
+ }
+
ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_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);
ctx->flags |= NFT_XT_CTX_PAYLOAD;
}
@@ -474,7 +476,6 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
- struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family);
void *data = ctx->cs;
uint32_t reg;
@@ -483,12 +484,12 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
return;
if (ctx->flags & NFT_XT_CTX_META) {
- ops->parse_meta(ctx, e, data);
+ ctx->h->ops->parse_meta(ctx, e, data);
ctx->flags &= ~NFT_XT_CTX_META;
}
/* bitwise context is interpreted from payload */
if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
- ops->parse_payload(ctx, e, data);
+ ctx->h->ops->parse_payload(ctx, e, data);
ctx->flags &= ~NFT_XT_CTX_PAYLOAD;
}
}
@@ -502,7 +503,6 @@ 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);
- struct nft_family_ops *ops;
const char *jumpto = NULL;
bool nft_goto = false;
void *data = ctx->cs;
@@ -544,8 +544,7 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
break;
}
- ops = nft_family_ops_lookup(ctx->family);
- ops->parse_immediate(jumpto, nft_goto, data);
+ ctx->h->ops->parse_immediate(jumpto, nft_goto, data);
}
static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
@@ -555,19 +554,18 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
__u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE);
struct xtables_rule_match **matches;
struct xtables_match *match;
- struct nft_family_ops *ops;
struct xt_rateinfo *rinfo;
size_t size;
- switch (ctx->family) {
+ switch (ctx->h->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
case NFPROTO_BRIDGE:
matches = &ctx->cs->matches;
break;
default:
- fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n",
- ctx->family);
+ fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n",
+ ctx->h->family);
exit(EXIT_FAILURE);
}
@@ -586,20 +584,27 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
rinfo->avg = XT_LIMIT_SCALE * unit / rate;
rinfo->burst = burst;
- ops = nft_family_ops_lookup(ctx->family);
- if (ops->parse_match != NULL)
- ops->parse_match(match, ctx->cs);
+ if (ctx->h->ops->parse_match != NULL)
+ ctx->h->ops->parse_match(match, 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);
}
-void nft_rule_to_iptables_command_state(const struct nftnl_rule *r,
+void nft_rule_to_iptables_command_state(struct nft_handle *h,
+ const struct nftnl_rule *r,
struct iptables_command_state *cs)
{
struct nftnl_expr_iter *iter;
struct nftnl_expr *expr;
- int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
struct nft_xt_ctx ctx = {
.cs = cs,
- .family = family,
+ .h = h,
+ .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE),
};
iter = nftnl_expr_iter_create(r);
@@ -630,6 +635,8 @@ void nft_rule_to_iptables_command_state(const struct nftnl_rule *r,
nft_parse_target(&ctx, expr);
else if (strcmp(name, "limit") == 0)
nft_parse_limit(&ctx, expr);
+ else if (strcmp(name, "lookup") == 0)
+ nft_parse_lookup(&ctx, h, expr);
expr = nftnl_expr_iter_next(iter);
}
@@ -982,19 +989,18 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data)
cs->target = t;
}
-bool nft_ipv46_rule_find(struct nft_family_ops *ops,
- struct nftnl_rule *r, void *data)
+bool nft_ipv46_rule_find(struct nft_handle *h, struct nftnl_rule *r, void *data)
{
struct iptables_command_state *cs = data, this = {};
bool ret = false;
- nft_rule_to_iptables_command_state(r, &this);
+ nft_rule_to_iptables_command_state(h, r, &this);
DEBUGP("comparing with... ");
#ifdef DEBUG_DEL
nft_rule_print_save(r, NFT_RULE_APPEND, 0);
#endif
- if (!ops->is_same(cs, &this))
+ if (!h->ops->is_same(cs, &this))
goto out;
if (!compare_matches(cs->matches, this.matches)) {
@@ -1014,7 +1020,7 @@ bool nft_ipv46_rule_find(struct nft_family_ops *ops,
ret = true;
out:
- ops->clear_cs(&this);
+ h->ops->clear_cs(&this);
return ret;
}
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index de889ead..bee99a7d 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -35,6 +35,7 @@
#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
struct xtables_args;
+struct nft_handle;
struct xt_xlate;
enum {
@@ -42,19 +43,22 @@ enum {
NFT_XT_CTX_META = (1 << 1),
NFT_XT_CTX_BITWISE = (1 << 2),
NFT_XT_CTX_IMMEDIATE = (1 << 3),
+ NFT_XT_CTX_PREV_PAYLOAD = (1 << 4),
};
struct nft_xt_ctx {
struct iptables_command_state *cs;
struct nftnl_expr_iter *iter;
- int family;
+ struct nft_handle *h;
uint32_t flags;
+ const char *table;
uint32_t reg;
struct {
+ uint32_t base;
uint32_t offset;
uint32_t len;
- } payload;
+ } payload, prev_payload;
struct {
uint32_t key;
} meta;
@@ -69,7 +73,7 @@ struct nft_xt_ctx {
};
struct nft_family_ops {
- int (*add)(struct nftnl_rule *r, void *data);
+ int (*add)(struct nft_handle *h, struct nftnl_rule *r, void *data);
bool (*is_same)(const void *data_a,
const void *data_b);
void (*print_payload)(struct nftnl_expr *e,
@@ -82,6 +86,8 @@ struct nft_family_ops {
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);
void (*print_table_header)(const char *tablename);
@@ -89,8 +95,8 @@ struct nft_family_ops {
const char *pol,
const struct xt_counters *counters, bool basechain,
uint32_t refs, uint32_t entries);
- void (*print_rule)(struct nftnl_rule *r, unsigned int num,
- unsigned int format);
+ 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_counters)(const void *data);
void (*save_chain)(const struct nftnl_chain *c, const char *policy);
@@ -100,10 +106,10 @@ struct nft_family_ops {
struct xtables_args *args);
void (*parse_match)(struct xtables_match *m, void *data);
void (*parse_target)(struct xtables_target *t, void *data);
- void (*rule_to_cs)(const struct nftnl_rule *r,
+ 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);
- bool (*rule_find)(struct nft_family_ops *ops, struct nftnl_rule *r,
+ bool (*rule_find)(struct nft_handle *h, struct nftnl_rule *r,
void *data);
int (*xlate)(const void *data, struct xt_xlate *xl);
};
@@ -111,7 +117,7 @@ struct nft_family_ops {
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, int mask, int xor);
+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);
@@ -137,7 +143,8 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
unsigned char *outiface_mask, uint8_t *invflags);
void print_proto(uint16_t proto, int invert);
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv);
-void nft_rule_to_iptables_command_state(const struct nftnl_rule *r,
+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,
@@ -163,9 +170,8 @@ void save_matches_and_target(const struct iptables_command_state *cs,
struct nft_family_ops *nft_family_ops_lookup(int family);
-struct nft_handle;
void nft_ipv46_parse_target(struct xtables_target *t, void *data);
-bool nft_ipv46_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
+bool nft_ipv46_rule_find(struct nft_handle *h, struct nftnl_rule *r,
void *data);
bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2);
@@ -199,23 +205,6 @@ struct xtables_args {
unsigned long long pcnt_cnt, bcnt_cnt;
};
-#define CMD_NONE 0x0000U
-#define CMD_INSERT 0x0001U
-#define CMD_DELETE 0x0002U
-#define CMD_DELETE_NUM 0x0004U
-#define CMD_REPLACE 0x0008U
-#define CMD_APPEND 0x0010U
-#define CMD_LIST 0x0020U
-#define CMD_FLUSH 0x0040U
-#define CMD_ZERO 0x0080U
-#define CMD_NEW_CHAIN 0x0100U
-#define CMD_DELETE_CHAIN 0x0200U
-#define CMD_SET_POLICY 0x0400U
-#define CMD_RENAME_CHAIN 0x0800U
-#define CMD_LIST_RULES 0x1000U
-#define CMD_ZERO_NUM 0x2000U
-#define CMD_CHECK 0x4000U
-
struct nft_xt_cmd_parse {
unsigned int command;
unsigned int rulenum;
@@ -232,19 +221,10 @@ 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 nft_xt_restore_parse {
- FILE *in;
- int testing;
- const char *tablename;
- bool commit;
-};
-
struct nftnl_chain_list;
struct nft_xt_restore_cb {
void (*table_new)(struct nft_handle *h, const char *table);
- struct nftnl_chain_list *(*chain_list)(struct nft_handle *h,
- const char *table);
int (*chain_set)(struct nft_handle *h, const char *table,
const char *chain, const char *policy,
const struct xt_counters *counters);
@@ -260,10 +240,16 @@ struct nft_xt_restore_cb {
int (*abort)(struct nft_handle *h);
};
+struct nft_xt_restore_parse {
+ FILE *in;
+ int testing;
+ const char *tablename;
+ bool commit;
+ const struct nft_xt_restore_cb *cb;
+};
+
void xtables_restore_parse(struct nft_handle *h,
- struct nft_xt_restore_parse *p,
- struct nft_xt_restore_cb *cb,
- int argc, char *argv[]);
+ const struct nft_xt_restore_parse *p);
void nft_check_xt_legacy(int family, bool is_ipt_save);
#endif
diff --git a/iptables/nft.c b/iptables/nft.c
index 2c615214..3f2a62ae 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -55,48 +55,18 @@
#include "nft.h"
#include "xshared.h" /* proto_to_name */
+#include "nft-cache.h"
#include "nft-shared.h"
#include "nft-bridge.h" /* EBT_NOPROTO */
-#include "xtables-config-parser.h"
static void *nft_fn;
-static int genid_cb(const struct nlmsghdr *nlh, void *data)
-{
- uint32_t *genid = data;
- struct nftnl_gen *gen;
-
- gen = nftnl_gen_alloc();
- if (!gen)
- return MNL_CB_ERROR;
-
- if (nftnl_gen_nlmsg_parse(nlh, gen) < 0)
- goto out;
-
- *genid = nftnl_gen_get_u32(gen, NFTNL_GEN_ID);
-
- nftnl_gen_free(gen);
- return MNL_CB_STOP;
-out:
- nftnl_gen_free(gen);
- return MNL_CB_ERROR;
-}
-
-static int mnl_genid_get(struct nft_handle *h, uint32_t *genid)
-{
- char buf[MNL_SOCKET_BUFFER_SIZE];
- struct nlmsghdr *nlh;
-
- nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, 0, 0, h->seq);
- return mnl_talk(h, nlh, genid_cb, genid);
-}
-
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
int (*cb)(const struct nlmsghdr *nlh, void *data),
void *data)
{
int ret;
- char buf[16536];
+ char buf[32768];
if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
return -1;
@@ -186,33 +156,42 @@ static void mnl_err_list_free(struct mnl_err *err)
free(err);
}
-static int nlbuffsiz;
-
-static void mnl_set_sndbuffer(const struct mnl_socket *nl,
- struct nftnl_batch *batch)
+static void mnl_set_sndbuffer(struct nft_handle *h)
{
- int newbuffsiz;
+ int newbuffsiz = nftnl_batch_iovec_len(h->batch) * BATCH_PAGE_SIZE;
- if (nftnl_batch_iovec_len(batch) * BATCH_PAGE_SIZE <= nlbuffsiz)
+ if (newbuffsiz <= h->nlsndbuffsiz)
return;
- newbuffsiz = nftnl_batch_iovec_len(batch) * BATCH_PAGE_SIZE;
-
/* Rise sender buffer length to avoid hitting -EMSGSIZE */
- if (setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUFFORCE,
+ if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_SNDBUFFORCE,
+ &newbuffsiz, sizeof(socklen_t)) < 0)
+ return;
+
+ h->nlsndbuffsiz = newbuffsiz;
+}
+
+static void mnl_set_rcvbuffer(struct nft_handle *h, int numcmds)
+{
+ int newbuffsiz = getpagesize() * numcmds;
+
+ if (newbuffsiz <= h->nlrcvbuffsiz)
+ return;
+
+ /* Rise receiver buffer length to avoid hitting -ENOBUFS */
+ if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_RCVBUFFORCE,
&newbuffsiz, sizeof(socklen_t)) < 0)
return;
- nlbuffsiz = newbuffsiz;
+ h->nlrcvbuffsiz = newbuffsiz;
}
-static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nf_sock,
- struct nftnl_batch *batch)
+static ssize_t mnl_nft_socket_sendmsg(struct nft_handle *h, int numcmds)
{
static const struct sockaddr_nl snl = {
.nl_family = AF_NETLINK
};
- uint32_t iov_len = nftnl_batch_iovec_len(batch);
+ uint32_t iov_len = nftnl_batch_iovec_len(h->batch);
struct iovec iov[iov_len];
struct msghdr msg = {
.msg_name = (struct sockaddr *) &snl,
@@ -221,16 +200,16 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nf_sock,
.msg_iovlen = iov_len,
};
- mnl_set_sndbuffer(nf_sock, batch);
- nftnl_batch_iovec(batch, iov, iov_len);
+ mnl_set_sndbuffer(h);
+ mnl_set_rcvbuffer(h, numcmds);
+ nftnl_batch_iovec(h->batch, iov, iov_len);
- return sendmsg(mnl_socket_get_fd(nf_sock), &msg, 0);
+ return sendmsg(mnl_socket_get_fd(h->nl), &msg, 0);
}
-static int mnl_batch_talk(const struct mnl_socket *nf_sock,
- struct nftnl_batch *batch, struct list_head *err_list)
+static int mnl_batch_talk(struct nft_handle *h, int numcmds)
{
- const struct mnl_socket *nl = nf_sock;
+ const struct mnl_socket *nl = h->nl;
int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl);
char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
fd_set readfds;
@@ -240,7 +219,7 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock,
};
int err = 0;
- ret = mnl_nft_socket_sendmsg(nf_sock, batch);
+ ret = mnl_nft_socket_sendmsg(h, numcmds);
if (ret == -1)
return -1;
@@ -262,7 +241,8 @@ static int mnl_batch_talk(const struct mnl_socket *nf_sock,
ret = mnl_cb_run(rcv_buf, ret, 0, portid, NULL, NULL);
/* Continue on error, make sure we get all acknowledgments */
if (ret == -1) {
- mnl_err_list_node_add(err_list, errno, nlh->nlmsg_seq);
+ mnl_err_list_node_add(&h->err_list, errno,
+ nlh->nlmsg_seq);
err = -1;
}
@@ -291,6 +271,7 @@ enum obj_update_type {
NFT_COMPAT_RULE_REPLACE,
NFT_COMPAT_RULE_DELETE,
NFT_COMPAT_RULE_FLUSH,
+ NFT_COMPAT_SET_ADD,
};
enum obj_action {
@@ -308,6 +289,7 @@ struct obj_update {
struct nftnl_table *table;
struct nftnl_chain *chain;
struct nftnl_rule *rule;
+ struct nftnl_set *set;
void *ptr;
};
struct {
@@ -335,6 +317,7 @@ static int mnl_append_error(const struct nft_handle *h,
[NFT_COMPAT_RULE_REPLACE] = "RULE_REPLACE",
[NFT_COMPAT_RULE_DELETE] = "RULE_DELETE",
[NFT_COMPAT_RULE_FLUSH] = "RULE_FLUSH",
+ [NFT_COMPAT_SET_ADD] = "SET_ADD",
};
char errmsg[256];
char tcr[128];
@@ -371,10 +354,14 @@ static int mnl_append_error(const struct nft_handle *h,
nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN));
#if 0
{
- nft_rule_print_save(o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS);
+ nft_rule_print_save(h, o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS);
}
#endif
break;
+ case NFT_COMPAT_SET_ADD:
+ snprintf(tcr, sizeof(tcr), "set %s",
+ nftnl_set_get_str(o->set, NFTNL_SET_NAME));
+ break;
}
return snprintf(buf, len, "%s: %s", errmsg, tcr);
@@ -404,6 +391,13 @@ batch_table_add(struct nft_handle *h, enum obj_update_type type,
return batch_add(h, type, t);
}
+static struct obj_update *
+batch_set_add(struct nft_handle *h, enum obj_update_type type,
+ struct nftnl_set *s)
+{
+ return batch_add(h, type, s);
+}
+
static int batch_chain_add(struct nft_handle *h, enum obj_update_type type,
struct nftnl_chain *c)
{
@@ -647,7 +641,7 @@ static int nft_table_builtin_add(struct nft_handle *h,
if (t == NULL)
return -1;
- nftnl_table_set(t, NFTNL_TABLE_NAME, (char *)_t->name);
+ nftnl_table_set_str(t, NFTNL_TABLE_NAME, _t->name);
ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1;
@@ -664,12 +658,12 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
if (c == NULL)
return NULL;
- nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table->name);
- nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain->name);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table->name);
+ 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);
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
- nftnl_chain_set(c, NFTNL_CHAIN_TYPE, (char *)chain->type);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, chain->type);
return c;
}
@@ -688,31 +682,25 @@ static void nft_chain_builtin_add(struct nft_handle *h,
nftnl_chain_list_add_tail(c, h->cache->table[table->type].chains);
}
-static const struct builtin_table *
-__nft_table_builtin_find(const struct builtin_table *tables, const char *table)
+/* find if built-in table already exists */
+const struct builtin_table *
+nft_table_builtin_find(struct nft_handle *h, const char *table)
{
int i;
bool found = false;
for (i = 0; i < NFT_TABLE_MAX; i++) {
- if (tables[i].name == NULL)
+ if (h->tables[i].name == NULL)
continue;
- if (strcmp(tables[i].name, table) != 0)
+ if (strcmp(h->tables[i].name, table) != 0)
continue;
found = true;
break;
}
- return found ? &tables[i] : NULL;
-}
-
-/* find if built-in table already exists */
-const struct builtin_table *
-nft_table_builtin_find(struct nft_handle *h, const char *table)
-{
- return __nft_table_builtin_find(h->tables, table);
+ return found ? &h->tables[i] : NULL;
}
/* find if built-in chain already exists */
@@ -735,15 +723,16 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
static void nft_chain_builtin_init(struct nft_handle *h,
const struct builtin_table *table)
{
- struct nftnl_chain_list *list = nft_chain_list_get(h, table->name);
+ struct nftnl_chain_list *list;
struct nftnl_chain *c;
int i;
- if (!list)
- return;
-
/* Initialize built-in chains if they don't exist yet */
for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
+ list = nft_chain_list_get(h, table->name,
+ table->chains[i].name);
+ if (!list)
+ continue;
c = nftnl_chain_list_lookup_byname(list, table->chains[i].name);
if (c != NULL)
@@ -782,7 +771,7 @@ static bool nft_chain_builtin(struct nftnl_chain *c)
return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
}
-static int nft_restart(struct nft_handle *h)
+int nft_restart(struct nft_handle *h)
{
mnl_socket_close(h->nl);
@@ -794,7 +783,8 @@ static int nft_restart(struct nft_handle *h)
return -1;
h->portid = mnl_socket_get_portid(h->nl);
- nlbuffsiz = 0;
+ h->nlsndbuffsiz = 0;
+ h->nlrcvbuffsiz = 0;
return 0;
}
@@ -820,67 +810,6 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t)
return 0;
}
-static int __flush_rule_cache(struct nftnl_rule *r, void *data)
-{
- nftnl_rule_list_del(r);
- nftnl_rule_free(r);
-
- return 0;
-}
-
-static void flush_rule_cache(struct nftnl_chain *c)
-{
- nftnl_rule_foreach(c, __flush_rule_cache, NULL);
-}
-
-static int __flush_chain_cache(struct nftnl_chain *c, void *data)
-{
- nftnl_chain_list_del(c);
- nftnl_chain_free(c);
-
- return 0;
-}
-
-static int flush_cache(struct nft_cache *c, const struct builtin_table *tables,
- const char *tablename)
-{
- const struct builtin_table *table;
- int i;
-
- if (tablename) {
- table = __nft_table_builtin_find(tables, tablename);
- if (!table || !c->table[table->type].chains)
- return 0;
- nftnl_chain_list_foreach(c->table[table->type].chains,
- __flush_chain_cache, NULL);
- return 0;
- }
-
- for (i = 0; i < NFT_TABLE_MAX; i++) {
- if (tables[i].name == NULL)
- continue;
-
- if (!c->table[i].chains)
- continue;
-
- nftnl_chain_list_free(c->table[i].chains);
- c->table[i].chains = NULL;
- }
- nftnl_table_list_free(c->tables);
- c->tables = NULL;
-
- return 1;
-}
-
-static void flush_chain_cache(struct nft_handle *h, const char *tablename)
-{
- if (!h->have_cache)
- return;
-
- if (flush_cache(h->cache, h->tables, tablename))
- h->have_cache = false;
-}
-
void nft_fini(struct nft_handle *h)
{
flush_chain_cache(h, NULL);
@@ -1015,13 +944,163 @@ static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
return 0;
}
-int add_match(struct nftnl_rule *r, struct xt_entry_match *m)
+static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
+ uint32_t flags, uint32_t key_type,
+ uint32_t key_len, uint32_t size)
+{
+ static uint32_t set_id = 0;
+ struct nftnl_set *s;
+
+ s = nftnl_set_alloc();
+ if (!s)
+ return NULL;
+
+ nftnl_set_set_u32(s, NFTNL_SET_FAMILY, h->family);
+ nftnl_set_set_str(s, NFTNL_SET_TABLE, table);
+ nftnl_set_set_str(s, NFTNL_SET_NAME, "__set%d");
+ nftnl_set_set_u32(s, NFTNL_SET_ID, ++set_id);
+ nftnl_set_set_u32(s, NFTNL_SET_FLAGS,
+ NFT_SET_ANONYMOUS | NFT_SET_CONSTANT | flags);
+ nftnl_set_set_u32(s, NFTNL_SET_KEY_TYPE, key_type);
+ nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, key_len);
+ nftnl_set_set_u32(s, NFTNL_SET_DESC_SIZE, size);
+
+ return batch_set_add(h, NFT_COMPAT_SET_ADD, s) ? s : NULL;
+}
+
+static struct nftnl_expr *
+gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint32_t dreg)
+{
+ 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);
+ return e;
+}
+
+static struct nftnl_expr *
+gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags)
+{
+ struct nftnl_expr *e = nftnl_expr_alloc("lookup");
+
+ if (!e)
+ return NULL;
+ nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
+ nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set_name);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SET_ID, set_id);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_FLAGS, flags);
+ return e;
+}
+
+/* simplified nftables:include/netlink.h, netlink_padded_len() */
+#define NETLINK_ALIGN 4
+
+/* from nftables:include/datatype.h, TYPE_BITS */
+#define CONCAT_TYPE_BITS 6
+
+/* from nftables:include/datatype.h, enum datatypes */
+#define NFT_DATATYPE_IPADDR 7
+#define NFT_DATATYPE_ETHERADDR 9
+
+static int __add_nft_among(struct nft_handle *h, const char *table,
+ struct nftnl_rule *r, struct nft_among_pair *pairs,
+ int cnt, bool dst, bool inv, bool ip)
+{
+ uint32_t set_id, type = NFT_DATATYPE_ETHERADDR, len = ETH_ALEN;
+ /* { !dst, dst } */
+ static const int eth_addr_off[] = {
+ offsetof(struct ether_header, ether_shost),
+ offsetof(struct ether_header, ether_dhost)
+ };
+ static const int ip_addr_off[] = {
+ offsetof(struct iphdr, saddr),
+ offsetof(struct iphdr, daddr)
+ };
+ struct nftnl_expr *e;
+ struct nftnl_set *s;
+ int idx = 0;
+
+ if (ip) {
+ type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR;
+ len += sizeof(struct in_addr) + NETLINK_ALIGN - 1;
+ len &= ~(NETLINK_ALIGN - 1);
+ }
+
+ s = add_anon_set(h, table, 0, type, len, cnt);
+ if (!s)
+ return -ENOMEM;
+ set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
+
+ for (idx = 0; idx < cnt; idx++) {
+ struct nftnl_set_elem *elem = nftnl_set_elem_alloc();
+
+ if (!elem)
+ return -ENOMEM;
+ nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY,
+ &pairs[idx], len);
+ nftnl_set_elem_add(s, elem);
+ }
+
+ e = gen_payload(NFT_PAYLOAD_LL_HEADER,
+ eth_addr_off[dst], ETH_ALEN, NFT_REG_1);
+ 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);
+ if (!e)
+ return -ENOMEM;
+ nftnl_rule_add_expr(r, e);
+ }
+
+ e = gen_lookup(NFT_REG_1, "__set%d", set_id, inv);
+ if (!e)
+ return -ENOMEM;
+ nftnl_rule_add_expr(r, e);
+
+ return 0;
+}
+
+static int add_nft_among(struct nft_handle *h,
+ struct nftnl_rule *r, struct xt_entry_match *m)
+{
+ struct nft_among_data *data = (struct nft_among_data *)m->data;
+ const char *table = nftnl_rule_get(r, NFTNL_RULE_TABLE);
+
+ if ((data->src.cnt && data->src.ip) ||
+ (data->dst.cnt && data->dst.ip)) {
+ uint16_t eth_p_ip = htons(ETH_P_IP);
+
+ add_meta(r, NFT_META_PROTOCOL);
+ add_cmp_ptr(r, NFT_CMP_EQ, &eth_p_ip, 2);
+ }
+
+ if (data->src.cnt)
+ __add_nft_among(h, table, r, data->pairs, data->src.cnt,
+ false, data->src.inv, data->src.ip);
+ if (data->dst.cnt)
+ __add_nft_among(h, table, r, data->pairs + data->src.cnt,
+ data->dst.cnt, true, data->dst.inv,
+ data->dst.ip);
+ return 0;
+}
+
+int add_match(struct nft_handle *h,
+ struct nftnl_rule *r, struct xt_entry_match *m)
{
struct nftnl_expr *expr;
int ret;
if (!strcmp(m->u.user.name, "limit"))
return add_nft_limit(r, m);
+ else if (!strcmp(m->u.user.name, "among"))
+ return add_nft_among(h, r, m);
expr = nftnl_expr_alloc("match");
if (expr == NULL)
@@ -1234,10 +1313,10 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
return NULL;
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family);
- nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table);
- nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain);
+ nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
+ nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
- if (h->ops->add(r, data) < 0)
+ if (h->ops->add(h, r, data) < 0)
goto err;
return r;
@@ -1257,9 +1336,15 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
struct nftnl_rule *r;
int type;
- /* If built-in chains don't exist for this table, create them */
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table);
+
+ /* Since ebtables user-defined chain policies are implemented as last
+ * rule in nftables, rule cache is required here to treat them right. */
+ if (h->family == NFPROTO_BRIDGE) {
+ c = nft_chain_find(h, table, chain);
+ if (c && !nft_chain_builtin(c))
+ nft_build_cache(h, c);
+ }
nft_fn = nft_rule_append;
@@ -1280,7 +1365,7 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
}
if (verbose)
- h->ops->print_rule(r, 0, FMT_PRINT_RULE);
+ h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
if (ref) {
nftnl_chain_rule_insert_at(r, ref);
@@ -1298,16 +1383,14 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
}
void
-nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
- unsigned int format)
+nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
+ enum nft_rule_print type, unsigned int format)
{
const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
- int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
struct iptables_command_state cs = {};
- struct nft_family_ops *ops;
+ struct nft_family_ops *ops = h->ops;
- ops = nft_family_ops_lookup(family);
- ops->rule_to_cs(r, &cs);
+ ops->rule_to_cs(h, r, &cs);
if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)) && ops->save_counters)
ops->save_counters(&cs);
@@ -1329,106 +1412,6 @@ nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
ops->clear_cs(&cs);
}
-static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
-{
- struct nft_handle *h = data;
- const struct builtin_table *t;
- struct nftnl_chain *c;
-
- c = nftnl_chain_alloc();
- if (c == NULL)
- goto err;
-
- if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
- goto out;
-
- t = nft_table_builtin_find(h,
- nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
- if (!t)
- goto out;
-
- nftnl_chain_list_add_tail(c, h->cache->table[t->type].chains);
-
- return MNL_CB_OK;
-out:
- nftnl_chain_free(c);
-err:
- return MNL_CB_OK;
-}
-
-static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
-{
- struct nftnl_table *t;
- struct nftnl_table_list *list = data;
-
- t = nftnl_table_alloc();
- if (t == NULL)
- goto err;
-
- if (nftnl_table_nlmsg_parse(nlh, t) < 0)
- goto out;
-
- nftnl_table_list_add_tail(t, list);
-
- return MNL_CB_OK;
-out:
- nftnl_table_free(t);
-err:
- return MNL_CB_OK;
-}
-
-static int fetch_table_cache(struct nft_handle *h)
-{
- char buf[16536];
- struct nlmsghdr *nlh;
- struct nftnl_table_list *list;
- int ret;
-
- list = nftnl_table_list_alloc();
- if (list == NULL)
- return 0;
-
- nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
- NLM_F_DUMP, h->seq);
-
- ret = mnl_talk(h, nlh, nftnl_table_list_cb, list);
- if (ret < 0 && errno == EINTR)
- assert(nft_restart(h) >= 0);
-
- h->cache->tables = list;
-
- return 1;
-}
-
-static int fetch_chain_cache(struct nft_handle *h)
-{
- char buf[16536];
- struct nlmsghdr *nlh;
- int i, ret;
-
- fetch_table_cache(h);
-
- for (i = 0; i < NFT_TABLE_MAX; i++) {
- enum nft_table_type type = h->tables[i].type;
-
- if (!h->tables[i].name)
- continue;
-
- h->cache->table[type].chains = nftnl_chain_list_alloc();
- if (!h->cache->table[type].chains)
- return -1;
- }
-
- nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
- NLM_F_DUMP, h->seq);
-
- ret = mnl_talk(h, nlh, nftnl_chain_list_cb, h);
- if (ret < 0 && errno == EINTR)
- assert(nft_restart(h) >= 0);
-
- return ret;
-}
-
static bool nft_rule_is_policy_rule(struct nftnl_rule *r)
{
const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
@@ -1467,8 +1450,8 @@ static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c)
return last;
}
-static void nft_bridge_chain_postprocess(struct nft_handle *h,
- struct nftnl_chain *c)
+void nft_bridge_chain_postprocess(struct nft_handle *h,
+ struct nftnl_chain *c)
{
struct nftnl_rule *last = nft_chain_last_rule(c);
struct nftnl_expr_iter *iter;
@@ -1509,138 +1492,6 @@ static void nft_bridge_chain_postprocess(struct nft_handle *h,
out_iter:
nftnl_expr_iter_destroy(iter);
}
-
-static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
-{
- struct nftnl_chain *c = data;
- struct nftnl_rule *r;
-
- r = nftnl_rule_alloc();
- if (r == NULL)
- return MNL_CB_OK;
-
- if (nftnl_rule_nlmsg_parse(nlh, r) < 0) {
- nftnl_rule_free(r);
- return MNL_CB_OK;
- }
-
- nftnl_chain_rule_add_tail(r, c);
- return MNL_CB_OK;
-}
-
-static int nft_rule_list_update(struct nftnl_chain *c, void *data)
-{
- struct nft_handle *h = data;
- char buf[16536];
- struct nlmsghdr *nlh;
- struct nftnl_rule *rule;
- int ret;
-
- rule = nftnl_rule_alloc();
- if (!rule)
- return -1;
-
- nftnl_rule_set_str(rule, NFTNL_RULE_TABLE,
- nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
- nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN,
- nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
-
- nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
- NLM_F_DUMP, h->seq);
- nftnl_rule_nlmsg_build_payload(nlh, rule);
-
- ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
- if (ret < 0 && errno == EINTR)
- assert(nft_restart(h) >= 0);
-
- nftnl_rule_free(rule);
-
- if (h->family == NFPROTO_BRIDGE)
- nft_bridge_chain_postprocess(h, c);
-
- return 0;
-}
-
-static int fetch_rule_cache(struct nft_handle *h)
-{
- int i;
-
- for (i = 0; i < NFT_TABLE_MAX; i++) {
- enum nft_table_type type = h->tables[i].type;
-
- if (!h->tables[i].name)
- continue;
-
- if (nftnl_chain_list_foreach(h->cache->table[type].chains,
- nft_rule_list_update, h))
- return -1;
- }
- return 0;
-}
-
-static void __nft_build_cache(struct nft_handle *h)
-{
- uint32_t genid_start, genid_stop;
-
-retry:
- mnl_genid_get(h, &genid_start);
- fetch_chain_cache(h);
- fetch_rule_cache(h);
- h->have_cache = true;
- mnl_genid_get(h, &genid_stop);
-
- if (genid_start != genid_stop) {
- flush_chain_cache(h, NULL);
- goto retry;
- }
-
- h->nft_genid = genid_start;
-}
-
-void nft_build_cache(struct nft_handle *h)
-{
- if (!h->have_cache)
- __nft_build_cache(h);
-}
-
-static void __nft_flush_cache(struct nft_handle *h)
-{
- if (!h->cache_index) {
- h->cache_index++;
- h->cache = &h->__cache[h->cache_index];
- } else {
- flush_chain_cache(h, NULL);
- }
-}
-
-static void nft_rebuild_cache(struct nft_handle *h)
-{
- if (h->have_cache)
- __nft_flush_cache(h);
-
- __nft_build_cache(h);
-}
-
-static void nft_release_cache(struct nft_handle *h)
-{
- if (h->cache_index)
- flush_cache(&h->__cache[0], h->tables, NULL);
-}
-
-struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
- const char *table)
-{
- const struct builtin_table *t;
-
- t = nft_table_builtin_find(h, table);
- if (!t)
- return NULL;
-
- nft_build_cache(h);
-
- return h->cache->table[t->type].chains;
-}
-
static const char *policy_name[NF_ACCEPT+1] = {
[NF_DROP] = "DROP",
[NF_ACCEPT] = "ACCEPT",
@@ -1648,12 +1499,10 @@ static const char *policy_name[NF_ACCEPT+1] = {
int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list)
{
+ struct nft_family_ops *ops = h->ops;
struct nftnl_chain_list_iter *iter;
- struct nft_family_ops *ops;
struct nftnl_chain *c;
- ops = nft_family_ops_lookup(h->family);
-
iter = nftnl_chain_list_iter_create(list);
if (iter == NULL)
return 0;
@@ -1702,7 +1551,7 @@ static int nft_chain_save_rules(struct nft_handle *h,
r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- nft_rule_print_save(r, NFT_RULE_APPEND, format);
+ nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
r = nftnl_rule_iter_next(iter);
}
@@ -1717,7 +1566,7 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
struct nftnl_chain *c;
int ret = 0;
- list = nft_chain_list_get(h, table);
+ list = nft_chain_list_get(h, table, NULL);
if (!list)
return 0;
@@ -1727,6 +1576,7 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
c = nftnl_chain_list_iter_next(iter);
while (c) {
+ nft_build_cache(h, c);
ret = nft_chain_save_rules(h, c, format);
if (ret != 0)
break;
@@ -1747,15 +1597,16 @@ __nft_rule_flush(struct nft_handle *h, const char *table,
struct obj_update *obj;
struct nftnl_rule *r;
- if (verbose)
+ if (verbose && chain)
fprintf(stdout, "Flushing chain `%s'\n", chain);
r = nftnl_rule_alloc();
if (r == NULL)
return;
- nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table);
- nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain);
+ nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
+ if (chain)
+ nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
obj = batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r);
if (!obj) {
@@ -1769,29 +1620,34 @@ __nft_rule_flush(struct nft_handle *h, const char *table,
int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
bool verbose)
{
- int ret = 0;
- struct nftnl_chain_list *list;
struct nftnl_chain_list_iter *iter;
- struct nftnl_chain *c;
+ struct nftnl_chain_list *list;
+ struct nftnl_chain *c = NULL;
+ int ret = 0;
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table);
nft_fn = nft_rule_flush;
- list = nft_chain_list_get(h, table);
- if (list == NULL) {
- ret = 1;
- goto err;
+ if (chain || verbose) {
+ list = nft_chain_list_get(h, table, chain);
+ if (list == NULL) {
+ ret = 1;
+ goto err;
+ }
}
if (chain) {
c = nftnl_chain_list_lookup_byname(list, chain);
- if (!c)
+ if (!c) {
+ errno = ENOENT;
return 0;
+ }
+ }
+ if (chain || !verbose) {
__nft_rule_flush(h, table, chain, verbose, false);
- flush_rule_cache(c);
+ flush_rule_cache(h, table, c);
return 1;
}
@@ -1803,11 +1659,10 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
c = nftnl_chain_list_iter_next(iter);
while (c != NULL) {
- const char *chain_name =
- nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- __nft_rule_flush(h, table, chain_name, verbose, false);
- flush_rule_cache(c);
+ __nft_rule_flush(h, table, chain, verbose, false);
+ flush_rule_cache(h, table, c);
c = nftnl_chain_list_iter_next(iter);
}
nftnl_chain_list_iter_destroy(iter);
@@ -1824,9 +1679,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
nft_fn = nft_chain_user_add;
- /* If built-in chains don't exist for this table, create them */
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table);
if (nft_chain_exists(h, table, chain)) {
errno = EEXIST;
@@ -1837,14 +1690,14 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (c == NULL)
return 0;
- nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
- nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
if (h->family == NFPROTO_BRIDGE)
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
- list = nft_chain_list_get(h, table);
+ list = nft_chain_list_get(h, table, chain);
if (list)
nftnl_chain_list_add(c, list);
@@ -1871,8 +1724,8 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
if (!c)
return -1;
- nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
- nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
created = true;
}
@@ -1884,7 +1737,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
- list = nft_chain_list_get(h, table);
+ list = nft_chain_list_get(h, table, chain);
if (list)
nftnl_chain_list_add(c, list);
@@ -1916,6 +1769,10 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
fprintf(stdout, "Deleting chain `%s'\n",
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
+ /* This triggers required policy rule deletion. */
+ if (h->family == NFPROTO_BRIDGE)
+ nft_build_cache(h, c);
+
/* XXX This triggers a fast lookup from the kernel. */
nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c);
@@ -1939,7 +1796,7 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
nft_fn = nft_chain_user_del;
- list = nft_chain_list_get(h, table);
+ list = nft_chain_list_get(h, table, chain);
if (list == NULL)
return 0;
@@ -1967,7 +1824,7 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
{
struct nftnl_chain_list *list;
- list = nft_chain_list_get(h, table);
+ list = nft_chain_list_get(h, table, chain);
if (list == NULL)
return NULL;
@@ -2003,9 +1860,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return 0;
}
- /* If built-in chains don't exist for this table, create them */
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table);
/* Config load changed errno. Ensure genuine info for our callers. */
errno = 0;
@@ -2023,8 +1878,8 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
if (c == NULL)
return 0;
- nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
- nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)newname);
+ 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);
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c);
@@ -2033,13 +1888,6 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return ret == 0 ? 1 : 0;
}
-static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
-{
- nft_build_cache(h);
-
- return h->cache->tables;
-}
-
bool nft_table_find(struct nft_handle *h, const char *tablename)
{
struct nftnl_table_list_iter *iter;
@@ -2075,8 +1923,8 @@ err:
}
int nft_for_each_table(struct nft_handle *h,
- int (*func)(struct nft_handle *h, const char *tablename, bool counters),
- bool counters)
+ int (*func)(struct nft_handle *h, const char *tablename, void *data),
+ void *data)
{
struct nftnl_table_list *list;
struct nftnl_table_list_iter *iter;
@@ -2095,7 +1943,7 @@ int nft_for_each_table(struct nft_handle *h,
const char *tablename =
nftnl_table_get(t, NFTNL_TABLE_NAME);
- func(h, tablename, counters);
+ func(h, tablename, data);
t = nftnl_table_list_iter_next(iter);
}
@@ -2179,8 +2027,7 @@ err_out:
void nft_table_new(struct nft_handle *h, const char *table)
{
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table);
}
static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
@@ -2189,6 +2036,9 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
nftnl_rule_list_del(r);
+ if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE))
+ nftnl_rule_set_u32(r, NFTNL_RULE_ID, ++h->rule_id);
+
obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
if (!obj) {
nftnl_rule_free(r);
@@ -2204,6 +2054,8 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen
struct nftnl_rule_iter *iter;
bool found = false;
+ nft_build_cache(h, c);
+
if (rulenum >= 0)
/* Delete by rule number case */
return nftnl_rule_lookup_byindex(c, rulenum);
@@ -2214,7 +2066,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen
r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- found = h->ops->rule_find(h->ops, r, data);
+ found = h->ops->rule_find(h, r, data);
if (found)
break;
r = nftnl_rule_iter_next(iter);
@@ -2242,7 +2094,7 @@ int nft_rule_check(struct nft_handle *h, const char *chain,
goto fail_enoent;
if (verbose)
- h->ops->print_rule(r, 0, FMT_PRINT_RULE);
+ h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
return 1;
fail_enoent:
@@ -2271,7 +2123,7 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
if (ret < 0)
errno = ENOMEM;
if (verbose)
- h->ops->print_rule(r, 0, FMT_PRINT_RULE);
+ h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
} else
errno = ENOENT;
@@ -2312,7 +2164,7 @@ nft_rule_add(struct nft_handle *h, const char *chain,
}
if (verbose)
- h->ops->print_rule(r, 0, FMT_PRINT_RULE);
+ h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
return r;
}
@@ -2323,9 +2175,7 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
struct nftnl_rule *r = NULL, *new_rule;
struct nftnl_chain *c;
- /* If built-in chains don't exist for this table, create them */
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table);
nft_fn = nft_rule_insert;
@@ -2423,8 +2273,8 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
static int
__nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
int rulenum, unsigned int format,
- void (*cb)(struct nftnl_rule *r, unsigned int num,
- unsigned int format))
+ void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
+ unsigned int num, unsigned int format))
{
struct nftnl_rule_iter *iter;
struct nftnl_rule *r;
@@ -2437,7 +2287,7 @@ __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
* valid chain but invalid rule number
*/
return 1;
- cb(r, rulenum, format);
+ cb(h, r, rulenum, format);
return 1;
}
@@ -2447,7 +2297,7 @@ __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- cb(r, ++rule_ctr, format);
+ cb(h, r, ++rule_ctr, format);
r = nftnl_rule_iter_next(iter);
}
@@ -2476,7 +2326,6 @@ static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
}
static void __nft_print_header(struct nft_handle *h,
- const struct nft_family_ops *ops,
struct nftnl_chain *c, unsigned int format)
{
const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
@@ -2492,31 +2341,23 @@ static void __nft_print_header(struct nft_handle *h,
if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
- ops->print_header(format, chain_name, pname,
+ h->ops->print_header(format, chain_name, pname,
&ctrs, basechain, refs - entries, entries);
}
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
int rulenum, unsigned int format)
{
- const struct nft_family_ops *ops;
+ const struct nft_family_ops *ops = h->ops;
struct nftnl_chain_list *list;
struct nftnl_chain_list_iter *iter;
struct nftnl_chain *c;
bool found = false;
- /* If built-in chains don't exist for this table, create them */
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table);
+ nft_assert_table_compatible(h, table, chain);
- ops = nft_family_ops_lookup(h->family);
-
- if (!nft_is_table_compatible(h, table)) {
- xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table);
- return 0;
- }
-
- list = nft_chain_list_get(h, table);
+ list = nft_chain_list_get(h, table, chain);
if (!list)
return 0;
@@ -2528,7 +2369,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if (!rulenum) {
if (ops->print_table_header)
ops->print_table_header(table);
- __nft_print_header(h, ops, c, format);
+ __nft_print_header(h, c, format);
}
__nft_rule_list(h, c, rulenum, format, ops->print_rule);
return 1;
@@ -2546,7 +2387,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if (found)
printf("\n");
- __nft_print_header(h, ops, c, format);
+ __nft_print_header(h, c, format);
__nft_rule_list(h, c, rulenum, format, ops->print_rule);
found = true;
@@ -2557,9 +2398,10 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
}
static void
-list_save(struct nftnl_rule *r, unsigned int num, unsigned int format)
+list_save(struct nft_handle *h, struct nftnl_rule *r,
+ unsigned int num, unsigned int format)
{
- nft_rule_print_save(r, NFT_RULE_APPEND, format);
+ nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
}
static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data)
@@ -2612,16 +2454,10 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
struct nftnl_chain *c;
int ret = 0;
- /* If built-in chains don't exist for this table, create them */
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table);
+ nft_assert_table_compatible(h, table, chain);
- if (!nft_is_table_compatible(h, table)) {
- xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table);
- return 0;
- }
-
- list = nft_chain_list_get(h, table);
+ list = nft_chain_list_get(h, table, chain);
if (!list)
return 0;
@@ -2677,7 +2513,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
goto error;
}
- nft_rule_to_iptables_command_state(r, &cs);
+ nft_rule_to_iptables_command_state(h, r, &cs);
cs.counters.pcnt = cs.counters.bcnt = 0;
@@ -2698,6 +2534,39 @@ static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
nftnl_table_nlmsg_build_payload(nlh, table);
}
+static void nft_compat_set_batch_add(struct nft_handle *h, uint16_t type,
+ uint16_t flags, uint32_t seq,
+ struct nftnl_set *set)
+{
+ struct nlmsghdr *nlh;
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
+ type, h->family, flags, seq);
+ nftnl_set_nlmsg_build_payload(nlh, set);
+}
+
+static void nft_compat_setelem_batch_add(struct nft_handle *h, uint16_t type,
+ uint16_t flags, uint32_t *seq,
+ struct nftnl_set *set)
+{
+ struct nftnl_set_elems_iter *iter;
+ struct nlmsghdr *nlh;
+
+ iter = nftnl_set_elems_iter_create(set);
+ if (!iter)
+ return;
+
+ while (nftnl_set_elems_iter_cur(iter)) {
+ (*seq)++;
+ mnl_nft_batch_continue(h->batch);
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
+ type, h->family, flags, *seq);
+ if (nftnl_set_elems_nlmsg_build_payload_iter(nlh, iter) <= 0)
+ break;
+ }
+ nftnl_set_elems_iter_destroy(iter);
+}
+
static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
uint16_t flags, uint32_t seq,
struct nftnl_chain *chain)
@@ -2747,6 +2616,9 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
case NFT_COMPAT_RULE_FLUSH:
nftnl_rule_free(o->rule);
break;
+ case NFT_COMPAT_SET_ADD:
+ nftnl_set_free(o->set);
+ break;
}
h->obj_list_num--;
list_del(&o->head);
@@ -2813,6 +2685,7 @@ static void nft_refresh_transaction(struct nft_handle *h)
case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH:
+ case NFT_COMPAT_SET_ADD:
break;
}
}
@@ -2903,6 +2776,13 @@ retry:
nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
n->seq, n->rule);
break;
+ case NFT_COMPAT_SET_ADD:
+ nft_compat_set_batch_add(h, NFT_MSG_NEWSET,
+ NLM_F_CREATE, n->seq, n->set);
+ nft_compat_setelem_batch_add(h, NFT_MSG_NEWSETELEM,
+ NLM_F_CREATE, &n->seq, n->set);
+ seq = n->seq;
+ break;
}
mnl_nft_batch_continue(h->batch);
@@ -2917,7 +2797,7 @@ retry:
}
errno = 0;
- ret = mnl_batch_talk(h->nl, h->batch, &h->err_list);
+ ret = mnl_batch_talk(h, seq);
if (ret && errno == ERESTART) {
nft_rebuild_cache(h);
@@ -3039,6 +2919,8 @@ int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
else
return 0;
+ nft_build_cache(h, c);
+
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval);
return 1;
}
@@ -3065,11 +2947,15 @@ static void nft_bridge_commit_prepare(struct nft_handle *h)
int nft_commit(struct nft_handle *h)
{
- if (h->family == NFPROTO_BRIDGE)
- nft_bridge_commit_prepare(h);
return nft_action(h, NFT_COMPAT_COMMIT);
}
+int nft_bridge_commit(struct nft_handle *h)
+{
+ nft_bridge_commit_prepare(h);
+ return nft_commit(h);
+}
+
int nft_abort(struct nft_handle *h)
{
return nft_action(h, NFT_COMPAT_ABORT);
@@ -3204,7 +3090,7 @@ const char *nft_strerror(int err)
{ NULL, ENOENT, "No chain/target/match by that name" },
};
- for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
+ for (i = 0; i < ARRAY_SIZE(table); i++) {
if ((!table[i].fn || table[i].fn == nft_fn)
&& table[i].err == err)
return table[i].message;
@@ -3213,136 +3099,42 @@ const char *nft_strerror(int err)
return strerror(err);
}
-static void xtables_config_perror(uint32_t flags, const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
-
- if (flags & NFT_LOAD_VERBOSE)
- vfprintf(stderr, fmt, args);
-
- va_end(args);
-}
-
-static int __nft_xtables_config_load(struct nft_handle *h, const char *filename,
- uint32_t flags)
+static int recover_rule_compat(struct nftnl_rule *r)
{
- struct nftnl_table_list *table_list = NULL;
- struct nftnl_chain_list *chain_list = NULL;
- struct nftnl_table_list_iter *titer = NULL;
- struct nftnl_chain_list_iter *citer = NULL;
- struct nftnl_table *table;
- struct nftnl_chain *chain;
- uint32_t table_family, chain_family;
- bool found = false;
-
- table_list = nftnl_table_list_alloc();
- chain_list = nftnl_chain_list_alloc();
-
- if (xtables_config_parse(filename, table_list, chain_list) < 0) {
- if (errno == ENOENT) {
- xtables_config_perror(flags,
- "configuration file `%s' does not exists\n",
- filename);
- } else {
- xtables_config_perror(flags,
- "Fatal error parsing config file: %s\n",
- strerror(errno));
- }
- goto err;
- }
-
- /* Stage 1) create tables */
- titer = nftnl_table_list_iter_create(table_list);
- while ((table = nftnl_table_list_iter_next(titer)) != NULL) {
- table_family = nftnl_table_get_u32(table,
- NFTNL_TABLE_FAMILY);
- if (h->family != table_family)
- continue;
-
- found = true;
-
- if (batch_table_add(h, NFT_COMPAT_TABLE_ADD, table) < 0) {
- if (errno == EEXIST) {
- xtables_config_perror(flags,
- "table `%s' already exists, skipping\n",
- (char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
- } else {
- xtables_config_perror(flags,
- "table `%s' cannot be create, reason `%s'. Exitting\n",
- (char *)nftnl_table_get(table, NFTNL_TABLE_NAME),
- strerror(errno));
- goto err;
- }
- continue;
- }
- xtables_config_perror(flags, "table `%s' has been created\n",
- (char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
- }
- nftnl_table_list_iter_destroy(titer);
- nftnl_table_list_free(table_list);
-
- if (!found)
- goto err;
-
- /* Stage 2) create chains */
- citer = nftnl_chain_list_iter_create(chain_list);
- while ((chain = nftnl_chain_list_iter_next(citer)) != NULL) {
- chain_family = nftnl_chain_get_u32(chain,
- NFTNL_CHAIN_TABLE);
- if (h->family != chain_family)
- continue;
-
- if (batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, chain) < 0) {
- if (errno == EEXIST) {
- xtables_config_perror(flags,
- "chain `%s' already exists in table `%s', skipping\n",
- (char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
- (char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE));
- } else {
- xtables_config_perror(flags,
- "chain `%s' cannot be create, reason `%s'. Exitting\n",
- (char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
- strerror(errno));
- goto err;
- }
- continue;
- }
-
- xtables_config_perror(flags,
- "chain `%s' in table `%s' has been created\n",
- (char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
- (char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE));
- }
- nftnl_chain_list_iter_destroy(citer);
- nftnl_chain_list_free(chain_list);
-
- h->config_done = 1;
+ struct nftnl_expr_iter *iter;
+ struct nftnl_expr *e;
+ uint32_t reg;
+ int ret = -1;
- return 0;
+ iter = nftnl_expr_iter_create(r);
+ if (!iter)
+ return -1;
-err:
- nftnl_table_list_free(table_list);
- nftnl_chain_list_free(chain_list);
+next_expr:
+ e = nftnl_expr_iter_next(iter);
+ if (!e)
+ goto out;
- if (titer != NULL)
- nftnl_table_list_iter_destroy(titer);
- if (citer != NULL)
- nftnl_chain_list_iter_destroy(citer);
+ if (strcmp("meta", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
+ nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) != NFT_META_L4PROTO)
+ goto next_expr;
- h->config_done = -1;
+ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
- return -1;
-}
+ e = nftnl_expr_iter_next(iter);
+ if (!e)
+ goto out;
-int nft_xtables_config_load(struct nft_handle *h, const char *filename,
- uint32_t flags)
-{
- if (!h->config_done)
- return __nft_xtables_config_load(h, filename, flags);
+ if (strcmp("cmp", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
+ reg != nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG))
+ goto next_expr;
- return h->config_done;
+ add_compat(r, nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA),
+ nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ);
+ ret = 0;
+out:
+ nftnl_expr_iter_destroy(iter);
+ return ret;
}
struct chain_zero_data {
@@ -3370,6 +3162,8 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
return -1;
}
+ nft_build_cache(h, c);
+
iter = nftnl_rule_iter_create(c);
if (iter == NULL)
return -1;
@@ -3407,6 +3201,7 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
* Unset RULE_POSITION for older kernels, we want to replace
* rule based on its handle only.
*/
+ recover_rule_compat(r);
nftnl_rule_unset(r, NFTNL_RULE_POSITION);
if (!batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r)) {
nftnl_rule_iter_destroy(iter);
@@ -3431,7 +3226,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
struct nftnl_chain *c;
int ret = 0;
- list = nft_chain_list_get(h, table);
+ list = nft_chain_list_get(h, table, chain);
if (list == NULL)
goto err;
@@ -3460,9 +3255,7 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag)
return NFT_CMP_EQ;
}
-#define NFT_COMPAT_EXPR_MAX 8
-
-static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
+static const char *supported_exprs[] = {
"match",
"target",
"payload",
@@ -3470,7 +3263,8 @@ static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
"cmp",
"bitwise",
"counter",
- "immediate"
+ "immediate",
+ "lookup",
};
@@ -3479,7 +3273,7 @@ static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
int i;
- for (i = 0; i < NFT_COMPAT_EXPR_MAX; i++) {
+ for (i = 0; i < ARRAY_SIZE(supported_exprs); i++) {
if (strcmp(supported_exprs[i], name) == 0)
return 0;
}
@@ -3506,6 +3300,8 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
enum nf_inet_hooks hook;
int prio;
+ nft_build_cache(h, c);
+
if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL))
return -1;
@@ -3533,11 +3329,12 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
return 0;
}
-bool nft_is_table_compatible(struct nft_handle *h, const char *tablename)
+bool nft_is_table_compatible(struct nft_handle *h,
+ const char *table, const char *chain)
{
struct nftnl_chain_list *clist;
- clist = nft_chain_list_get(h, tablename);
+ clist = nft_chain_list_get(h, table, chain);
if (clist == NULL)
return false;
@@ -3546,3 +3343,22 @@ bool nft_is_table_compatible(struct nft_handle *h, const char *tablename)
return true;
}
+
+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))
+ return;
+
+ if (chain) {
+ pfx = "chain `";
+ sfx = "' in ";
+ } else {
+ chain = "";
+ }
+ xtables_error(OTHER_PROBLEM,
+ "%s%s%stable `%s' is incompatible, use 'nft' tool.\n",
+ pfx, chain, sfx, table);
+}
diff --git a/iptables/nft.h b/iptables/nft.h
index 43eb8a39..51b56603 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -27,10 +27,19 @@ struct builtin_table {
struct builtin_chain chains[NF_INET_NUMHOOKS];
};
+enum nft_cache_level {
+ NFT_CL_NONE,
+ NFT_CL_TABLES,
+ NFT_CL_CHAINS,
+ NFT_CL_SETS,
+ NFT_CL_RULES
+};
+
struct nft_cache {
struct nftnl_table_list *tables;
struct {
struct nftnl_chain_list *chains;
+ struct nftnl_set_list *sets;
bool initialized;
} table[NFT_TABLE_MAX];
};
@@ -38,6 +47,8 @@ struct nft_cache {
struct nft_handle {
int family;
struct mnl_socket *nl;
+ int nlsndbuffsiz;
+ int nlrcvbuffsiz;
uint32_t portid;
uint32_t seq;
uint32_t nft_genid;
@@ -51,7 +62,7 @@ struct nft_handle {
unsigned int cache_index;
struct nft_cache __cache[2];
struct nft_cache *cache;
- bool have_cache;
+ enum nft_cache_level cache_level;
bool restore;
bool noflush;
int8_t config_done;
@@ -71,7 +82,7 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
void *data);
int nft_init(struct nft_handle *h, const struct builtin_table *t);
void nft_fini(struct nft_handle *h);
-void nft_build_cache(struct nft_handle *h);
+int nft_restart(struct nft_handle *h);
/*
* Operations with tables.
@@ -79,7 +90,7 @@ void nft_build_cache(struct nft_handle *h);
struct nftnl_table;
struct nftnl_chain_list;
-int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, const char *tablename, bool counters), bool counters);
+int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, const char *tablename, void *data), void *data);
bool nft_table_find(struct nft_handle *h, const char *tablename);
int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nftnl_chain_list *list);
int nft_table_flush(struct nft_handle *h, const char *table);
@@ -92,8 +103,6 @@ const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const c
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);
-struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h,
- const char *table);
int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list);
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);
@@ -102,6 +111,9 @@ int nft_chain_user_rename(struct nft_handle *h, const char *chain, const char *t
int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose);
const struct builtin_chain *nft_chain_builtin_find(const struct builtin_table *t, const char *chain);
bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain);
+void nft_bridge_chain_postprocess(struct nft_handle *h,
+ struct nftnl_chain *c);
+
/*
* Operations with rule-set.
@@ -125,7 +137,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, const char *
*/
int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes);
int add_verdict(struct nftnl_rule *r, int verdict);
-int add_match(struct nftnl_rule *r, struct xt_entry_match *m);
+int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m);
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);
@@ -136,8 +148,8 @@ enum nft_rule_print {
NFT_RULE_DEL,
};
-void nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
- unsigned int format);
+void nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
+ enum nft_rule_print type, unsigned int format);
uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
@@ -145,6 +157,7 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
* global commit and abort
*/
int nft_commit(struct nft_handle *h);
+int nft_bridge_commit(struct nft_handle *h);
int nft_abort(struct nft_handle *h);
int nft_abort_policy_rule(struct nft_handle *h, const char *table);
@@ -169,22 +182,6 @@ int ebt_get_current_chain(const char *chain);
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
/*
- * Parse config for tables and chain helper functions
- */
-#define XTABLES_CONFIG_DEFAULT "/etc/xtables.conf"
-
-struct nftnl_table_list;
-struct nftnl_chain_list;
-
-extern int xtables_config_parse(const char *filename, struct nftnl_table_list *table_list, struct nftnl_chain_list *chain_list);
-
-enum {
- NFT_LOAD_VERBOSE = (1 << 0),
-};
-
-int nft_xtables_config_load(struct nft_handle *h, const char *filename, uint32_t flags);
-
-/*
* Translation from iptables to nft
*/
struct xt_buf;
@@ -211,7 +208,10 @@ int nft_arp_rule_insert(struct nft_handle *h, const char *chain,
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 *name);
+bool nft_is_table_compatible(struct nft_handle *h,
+ const char *table, const char *chain);
+void nft_assert_table_compatible(struct nft_handle *h,
+ const char *table, const char *chain);
int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
const char *chain, const char *policy);
diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh
index 7bef09f7..d71c1372 100755
--- a/iptables/tests/shell/run-tests.sh
+++ b/iptables/tests/shell/run-tests.sh
@@ -38,6 +38,14 @@ while [ -n "$1" ]; do
HOST=y
shift
;;
+ -l|--legacy)
+ LEGACY_ONLY=y
+ shift
+ ;;
+ -n|--nft)
+ NFT_ONLY=y
+ shift
+ ;;
*${RETURNCODE_SEPARATOR}+([0-9]))
SINGLE+=" $1"
VERBOSE=y
@@ -98,19 +106,23 @@ do_test() {
}
echo ""
-for testfile in $(find_tests);do
- do_test "$testfile" "$XTABLES_LEGACY_MULTI"
-done
-msg_info "legacy results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
+if [ "$NFT_ONLY" != "y" ]; then
+ for testfile in $(find_tests);do
+ do_test "$testfile" "$XTABLES_LEGACY_MULTI"
+ done
+ msg_info "legacy results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
+fi
legacy_ok=$ok
legacy_fail=$failed
ok=0
failed=0
-for testfile in $(find_tests);do
- do_test "$testfile" "$XTABLES_NFT_MULTI"
-done
-msg_info "nft results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
+if [ "$LEGACY_ONLY" != "y" ]; then
+ for testfile in $(find_tests);do
+ do_test "$testfile" "$XTABLES_NFT_MULTI"
+ done
+ msg_info "nft results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
+fi
ok=$((legacy_ok+ok))
failed=$((legacy_fail+failed))
diff --git a/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0 b/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
index e10f61cc..bf04dc0a 100755
--- a/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
+++ b/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
@@ -50,13 +50,12 @@ DUMP='*filter
-A foo -j MARK --set-mark 12345
-A foo -j ACCEPT --opcode 1
-A foo -j ACCEPT --proto-type 0x800
--A foo -j ACCEPT -i lo --opcode 1 --proto-type 0x800
-'
+-A foo -j ACCEPT -i lo --opcode 1 --proto-type 0x800'
-diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save)
+diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save | grep -v "^#")
# make sure dump can be restored and check it didn't change
$XT_MULTI arptables -F
$XT_MULTI arptables-restore <<<$DUMP
-diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save)
+diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save | grep -v "^#")
diff --git a/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0 b/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
index b2ed95e8..38d387f3 100755
--- a/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
+++ b/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
@@ -11,8 +11,7 @@ set -e
DUMP='*filter
:OUTPUT ACCEPT
-A OUTPUT -j mangle --mangle-ip-s 10.0.0.1
--A OUTPUT -j mangle --mangle-ip-d 10.0.0.2
-'
+-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2'
# note how mangle-ip-s is unset in second rule
@@ -20,8 +19,7 @@ EXPECT='*filter
:INPUT ACCEPT
:OUTPUT ACCEPT
-A OUTPUT -j mangle --mangle-ip-s 10.0.0.1
--A OUTPUT -j mangle --mangle-ip-d 10.0.0.2
-'
+-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2'
$XT_MULTI arptables -F
$XT_MULTI arptables-restore <<<$DUMP
diff --git a/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0 b/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
index 3a9807a1..10c5ec33 100755
--- a/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
+++ b/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
@@ -58,7 +58,6 @@ EXPECT='*filter
-A INPUT -j MARK -i eth23 --set-mark 42
-A OUTPUT -j CLASSIFY -o eth23 --set-class 23:42
-A OUTPUT -j foo -o eth23
--A foo -j mangle -o eth23 --mangle-ip-s 10.0.0.1
-'
+-A foo -j mangle -o eth23 --mangle-ip-s 10.0.0.1'
-diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI arptables-save)
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI arptables-save | grep -v '^#')
diff --git a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
index b0db216a..c7f24a38 100755
--- a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
+++ b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
@@ -1,5 +1,9 @@
#!/bin/sh
+get_entries_count() { # (chain)
+ $XT_MULTI ebtables -L $1 | sed -n 's/.*entries: \([0-9]*\).*/\1/p'
+}
+
set -x
case "$XT_MULTI" in
*/xtables-nft-multi)
@@ -28,32 +32,32 @@ case "$XT_MULTI" in
exit 1
fi
- $XT_MULTI ebtables -L FOO | grep -q 'entries: 0'
- if [ $? -ne 0 ]; then
- echo "Unexpected entries count in empty unreferenced chain"
+ entries=$(get_entries_count FOO)
+ if [ $entries -ne 0 ]; then
+ echo "Unexpected entries count in empty unreferenced chain (expected 0, have $entries)"
$XT_MULTI ebtables -L
exit 1
fi
$XT_MULTI ebtables -A FORWARD -j FOO
- $XT_MULTI ebtables -L FORWARD | grep -q 'entries: 1'
- if [ $? -ne 0 ]; then
- echo "Unexpected entries count in FORWARD chain"
+ entries=$(get_entries_count FORWARD)
+ if [ $entries -ne 1 ]; then
+ echo "Unexpected entries count in FORWARD chain (expected 1, have $entries)"
$XT_MULTI ebtables -L
exit 1
fi
- $XT_MULTI ebtables -L FOO | grep -q 'entries: 0'
- if [ $? -ne 0 ]; then
- echo "Unexpected entries count in empty referenced chain"
+ entries=$(get_entries_count FOO)
+ if [ $entries -ne 0 ]; then
+ echo "Unexpected entries count in empty referenced chain (expected 0, have $entries)"
$XT_MULTI ebtables -L
exit 1
fi
$XT_MULTI ebtables -A FOO -j ACCEPT
- $XT_MULTI ebtables -L FOO | grep -q 'entries: 1'
- if [ $? -ne 0 ]; then
- echo "Unexpected entries count in non-empty referenced chain"
+ entries=$(get_entries_count FOO)
+ if [ $entries -ne 1 ]; then
+ echo "Unexpected entries count in non-empty referenced chain (expected 1, have $entries)"
$XT_MULTI ebtables -L
exit 1
fi
diff --git a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
index 080ba49a..e18d4655 100755
--- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
+++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
@@ -99,7 +99,6 @@ DUMP='*filter
-A foo --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT
-A foo --pkttype-type multicast --log-level notice --log-prefix "" -j CONTINUE
-A foo --pkttype-type multicast --limit 100/sec --limit-burst 5 -j ACCEPT
-
*nat
:PREROUTING ACCEPT
:OUTPUT DROP
@@ -107,8 +106,7 @@ DUMP='*filter
:nat_foo DROP
-A PREROUTING -j redirect
-A OUTPUT -j ACCEPT
--A POSTROUTING -j ACCEPT
-'
+-A POSTROUTING -j ACCEPT'
diff -u <(echo -e "$DUMP") <($XT_MULTI ebtables-save | grep -v '^#')
diff --git a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
index c8580547..62d22413 100755
--- a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
+++ b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
@@ -13,8 +13,7 @@ DUMP='*filter
-A FORWARD --limit 100 --limit-burst 42 -j ACCEPT
-A FORWARD --limit 1000 -j ACCEPT
-A FORWARD --log --log-prefix "foobar"
--A FORWARD --log
-'
+-A FORWARD --log'
# note how limit-burst is 5 in second rule and log-prefix empty in fourth one
@@ -25,8 +24,7 @@ EXPECT='*filter
-A FORWARD --limit 100/sec --limit-burst 42 -j ACCEPT
-A FORWARD --limit 1000/sec --limit-burst 5 -j ACCEPT
-A FORWARD --log-level notice --log-prefix "foobar" -j CONTINUE
--A FORWARD --log-level notice --log-prefix "" -j CONTINUE
-'
+-A FORWARD --log-level notice --log-prefix "" -j CONTINUE'
$XT_MULTI ebtables --init-table
$XT_MULTI ebtables-restore <<<$DUMP
diff --git a/iptables/tests/shell/testcases/ebtables/0004-save-counters_0 b/iptables/tests/shell/testcases/ebtables/0004-save-counters_0
new file mode 100755
index 00000000..46966f43
--- /dev/null
+++ b/iptables/tests/shell/testcases/ebtables/0004-save-counters_0
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+set -e
+
+# there is no legacy backend to test
+[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+
+$XT_MULTI ebtables --init-table
+$XT_MULTI ebtables -A FORWARD -i nodev123 -o nodev432 -j ACCEPT
+$XT_MULTI ebtables -A FORWARD -i nodev432 -o nodev123 -j ACCEPT
+
+EXPECT='Bridge table: filter
+
+Bridge chain: FORWARD, entries: 2, policy: ACCEPT
+-i nodev123 -o nodev432 -j ACCEPT
+-i nodev432 -o nodev123 -j ACCEPT'
+
+echo "ebtables -L FORWARD"
+diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables -L FORWARD)
+
+EXPECT='Bridge table: filter
+
+Bridge chain: FORWARD, entries: 2, policy: ACCEPT
+-i nodev123 -o nodev432 -j ACCEPT , pcnt = 0 -- bcnt = 0
+-i nodev432 -o nodev123 -j ACCEPT , pcnt = 0 -- bcnt = 0'
+
+echo "ebtables -L FORWARD --Lc"
+diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables -L FORWARD --Lc)
+
+EXPECT='*filter
+:INPUT ACCEPT
+:FORWARD ACCEPT
+:OUTPUT ACCEPT
+-A FORWARD -i nodev123 -o nodev432 -j ACCEPT
+-A FORWARD -i nodev432 -o nodev123 -j ACCEPT'
+
+echo "ebtables-save"
+diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
+
+EXPECT='*filter
+:INPUT ACCEPT
+:FORWARD ACCEPT
+:OUTPUT ACCEPT
+[0:0] -A FORWARD -i nodev123 -o nodev432 -j ACCEPT
+[0:0] -A FORWARD -i nodev432 -o nodev123 -j ACCEPT'
+
+echo "ebtables-save -c"
+diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save -c | grep -v '^#')
+
+export EBTABLES_SAVE_COUNTER=yes
+
+# -c flag overrides EBTABLES_SAVE_COUNTER variable
+echo "EBTABLES_SAVE_COUNTER=yes ebtables-save -c"
+diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save -c | grep -v '^#')
+
+EXPECT='*filter
+:INPUT ACCEPT
+:FORWARD ACCEPT
+:OUTPUT ACCEPT
+-A FORWARD -i nodev123 -o nodev432 -j ACCEPT -c 0 0
+-A FORWARD -i nodev432 -o nodev123 -j ACCEPT -c 0 0'
+
+echo "EBTABLES_SAVE_COUNTER=yes ebtables-save"
+diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
diff --git a/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0 b/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0
new file mode 100755
index 00000000..2163d364
--- /dev/null
+++ b/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -e
+
+# there is no legacy backend to test
+[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+
+EXPECT='*filter
+:INPUT ACCEPT
+:FORWARD ACCEPT
+:OUTPUT ACCEPT
+:PVEFW-FORWARD ACCEPT
+:PVEFW-FWBR-OUT ACCEPT
+-A FORWARD -j PVEFW-FORWARD
+-A PVEFW-FORWARD -p IPv4 -j ACCEPT
+-A PVEFW-FORWARD -p IPv6 -j ACCEPT
+-A PVEFW-FORWARD -i fwln+ -j ACCEPT
+-A PVEFW-FORWARD -o fwln+ -j PVEFW-FWBR-OUT'
+
+$XT_MULTI ebtables-restore <<<$EXPECT
+exec diff -u <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
diff --git a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
index 51f2422e..3f1d229e 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
@@ -14,7 +14,7 @@ ipt_show() {
$XT_MULTI iptables-restore <<EOF
*filter
--A FORWARD -m comment --comment "appended rule" -j ACCEPT
+-A FORWARD -m comment --comment "rule 4" -j ACCEPT
-I FORWARD 1 -m comment --comment "rule 1" -j ACCEPT
-I FORWARD 2 -m comment --comment "rule 2" -j ACCEPT
-I FORWARD 3 -m comment --comment "rule 3" -j ACCEPT
@@ -24,7 +24,7 @@ EOF
EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
-A FORWARD -m comment --comment "rule 2" -j ACCEPT
-A FORWARD -m comment --comment "rule 3" -j ACCEPT
--A FORWARD -m comment --comment "appended rule" -j ACCEPT'
+-A FORWARD -m comment --comment "rule 4" -j ACCEPT'
diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
@@ -32,11 +32,14 @@ diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
$XT_MULTI iptables-restore --noflush <<EOF
*filter
+-A FORWARD -m comment --comment "rule 5" -j ACCEPT
-I FORWARD 1 -m comment --comment "rule 0.5" -j ACCEPT
-I FORWARD 3 -m comment --comment "rule 1.5" -j ACCEPT
-I FORWARD 5 -m comment --comment "rule 2.5" -j ACCEPT
-I FORWARD 7 -m comment --comment "rule 3.5" -j ACCEPT
--I FORWARD 9 -m comment --comment "appended rule 2" -j ACCEPT
+-I FORWARD 9 -m comment --comment "rule 4.5" -j ACCEPT
+-I FORWARD 11 -m comment --comment "rule 5.5" -j ACCEPT
+-A FORWARD -m comment --comment "rule 6" -j ACCEPT
COMMIT
EOF
@@ -47,8 +50,11 @@ EXPECT='-A FORWARD -m comment --comment "rule 0.5" -j ACCEPT
-A FORWARD -m comment --comment "rule 2.5" -j ACCEPT
-A FORWARD -m comment --comment "rule 3" -j ACCEPT
-A FORWARD -m comment --comment "rule 3.5" -j ACCEPT
--A FORWARD -m comment --comment "appended rule" -j ACCEPT
--A FORWARD -m comment --comment "appended rule 2" -j ACCEPT'
+-A FORWARD -m comment --comment "rule 4" -j ACCEPT
+-A FORWARD -m comment --comment "rule 4.5" -j ACCEPT
+-A FORWARD -m comment --comment "rule 5" -j ACCEPT
+-A FORWARD -m comment --comment "rule 5.5" -j ACCEPT
+-A FORWARD -m comment --comment "rule 6" -j ACCEPT'
diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
@@ -78,6 +84,8 @@ diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
$XT_MULTI iptables-restore --noflush <<EOF
*filter
+-A FORWARD -m comment --comment "appended rule 4" -j ACCEPT
+-D FORWARD 7
-D FORWARD -m comment --comment "appended rule 1" -j ACCEPT
-D FORWARD 3
-I FORWARD 3 -m comment --comment "manually replaced rule 2" -j ACCEPT
diff --git a/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0 b/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
index a92d18dc..96a5e66d 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
@@ -24,7 +24,7 @@ clean_tempfile()
trap clean_tempfile EXIT
-ENTRY_NUM=$((RANDOM%100))
+ENTRY_NUM=$((RANDOM%10))
UCHAIN_NUM=$((RANDOM%10))
get_target()
@@ -87,7 +87,7 @@ fi
case "$XT_MULTI" in
*/xtables-nft-multi)
- attempts=$((RANDOM%200))
+ attempts=$((RANDOM%10))
attempts=$((attempts+1))
;;
*)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0005-ipt-6_0 b/iptables/tests/shell/testcases/ipt-restore/0005-ipt-6_0
new file mode 100755
index 00000000..dd069771
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0005-ipt-6_0
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Make sure iptables-restore simply ignores
+# rules starting with -6
+
+set -e
+
+# show rules, drop uninteresting policy settings
+ipt_show() {
+ $XT_MULTI iptables -S | grep -v '^-P'
+}
+
+# issue reproducer for iptables-restore
+
+$XT_MULTI iptables-restore <<EOF
+*filter
+-A FORWARD -m comment --comment any -j ACCEPT
+-4 -A FORWARD -m comment --comment ipv4 -j ACCEPT
+-6 -A FORWARD -m comment --comment ipv6 -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='-A FORWARD -m comment --comment any -j ACCEPT
+-A FORWARD -m comment --comment ipv4 -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0006-ip6t-4_0 b/iptables/tests/shell/testcases/ipt-restore/0006-ip6t-4_0
new file mode 100755
index 00000000..a37253a9
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0006-ip6t-4_0
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Make sure ip6tables-restore simply ignores
+# rules starting with -4
+
+set -e
+
+# show rules, drop uninteresting policy settings
+ipt_show() {
+ $XT_MULTI ip6tables -S | grep -v '^-P'
+}
+
+# issue reproducer for ip6tables-restore
+
+$XT_MULTI ip6tables-restore <<EOF
+*filter
+-A FORWARD -m comment --comment any -j ACCEPT
+-4 -A FORWARD -m comment --comment ipv4 -j ACCEPT
+-6 -A FORWARD -m comment --comment ipv6 -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='-A FORWARD -m comment --comment any -j ACCEPT
+-A FORWARD -m comment --comment ipv6 -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0 b/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0
new file mode 100755
index 00000000..029db223
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+# Make sure iptables-restore without --noflush does not flush tables other than
+# those contained in the dump it's reading from
+
+set -e
+
+$XT_MULTI iptables-restore <<EOF
+*nat
+-A POSTROUTING -j ACCEPT
+COMMIT
+EOF
+
+EXPECT="*nat
+:PREROUTING ACCEPT [0:0]
+:INPUT ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+:POSTROUTING ACCEPT [0:0]
+-A POSTROUTING -j ACCEPT
+COMMIT"
+diff -u -Z <(echo -e "$EXPECT" | sort) <($XT_MULTI iptables-save | grep -v '^#' | sort)
+
+$XT_MULTI iptables-restore <<EOF
+*filter
+-A FORWARD -j ACCEPT
+COMMIT
+EOF
+
+EXPECT="*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+-A FORWARD -j ACCEPT
+COMMIT
+*nat
+:PREROUTING ACCEPT [0:0]
+:INPUT ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+:POSTROUTING ACCEPT [0:0]
+-A POSTROUTING -j ACCEPT
+COMMIT"
+diff -u -Z <(echo -e "$EXPECT" | sort) <($XT_MULTI iptables-save | grep -v '^#' | sort)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0 b/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0
new file mode 100755
index 00000000..5ac70682
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+
+DUMP="*filter
+:foo - [23:42]
+[13:37] -A foo -j ACCEPT
+COMMIT
+"
+
+EXPECT=":foo - [0:0]
+[0:0] -A foo -j ACCEPT"
+
+$XT_MULTI iptables-restore <<< "$DUMP"
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save --counters | grep foo)
+
+# iptables-*-restore ignores custom chain counters :(
+EXPECT=":foo - [0:0]
+[13:37] -A foo -j ACCEPT"
+
+$XT_MULTI iptables-restore --counters <<< "$DUMP"
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save --counters | grep foo)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0009-table-name-comment_0 b/iptables/tests/shell/testcases/ipt-restore/0009-table-name-comment_0
new file mode 100755
index 00000000..e9614075
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0009-table-name-comment_0
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# when restoring a ruleset, *tables-restore prefixes each rule with
+# '-t <tablename>' so standard rule parsing routines may be used. This means
+# that it has to detect and reject rules which already contain a table option.
+
+families="ip ip6"
+[[ $(basename $XT_MULTI) == xtables-nft-multi ]] && families+=" eb"
+
+for fam in $families; do
+ $XT_MULTI ${fam}tables-restore <<EOF
+*filter
+-t nat -A FORWARD -j ACCEPT
+COMMIT
+EOF
+ [[ $? != 0 ]] || {
+ echo "${fam}tables-restore did not fail when it should have"
+ exit 1
+ }
+
+ $XT_MULTI ${fam}tables-restore <<EOF
+*filter
+-A FORWARD -j ACCEPT
+COMMIT
+EOF
+ [[ $? == 0 ]] || {
+ echo "${fam}tables-restore failed when it should not have"
+ exit 1
+ }
+done
diff --git a/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0 b/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0
new file mode 100755
index 00000000..50c0cae8
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+case "$(basename $XT_MULTI)" in
+ xtables-legacy-multi)
+ ;;
+ *)
+ echo "skip $XT_MULTI"
+ exit 0
+ ;;
+esac
+
+dump=$(dirname $0)/dumps/fedora27-iptables
+diff -u -Z <(cat ${dump}.xml) <($XT_MULTI iptables-xml <$dump)
diff --git a/iptables/tests/shell/testcases/ipt-save/dumps/fedora27-iptables.xml b/iptables/tests/shell/testcases/ipt-save/dumps/fedora27-iptables.xml
new file mode 100644
index 00000000..400be032
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-save/dumps/fedora27-iptables.xml
@@ -0,0 +1,925 @@
+<iptables-rules version="1.0">
+<!-- # Completed on Sat Feb 17 10:50:33 2018 -->
+<!-- # Generated by iptables*-save v1.6.1 on Sat Feb 17 10:50:33 2018 -->
+ <table name="mangle" >
+ <chain name="PREROUTING" policy="ACCEPT" packet-count="0" byte-count="0" >
+ <rule packet-count="1" byte-count="2" >
+ <actions>
+ <call >
+ <PREROUTING_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="3" byte-count="4" >
+ <actions>
+ <call >
+ <PREROUTING_ZONES_SOURCE />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PREROUTING_ZONES />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="INPUT" policy="ACCEPT" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <INPUT_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="FORWARD" policy="ACCEPT" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FORWARD_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="OUTPUT" policy="ACCEPT" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <OUTPUT_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="POSTROUTING" policy="ACCEPT" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <o >virbr0</o>
+ <p >udp</p>
+ </match>
+ <udp >
+ <dport >68</dport>
+ </udp>
+ </conditions>
+ <actions>
+ <CHECKSUM >
+ <checksum-fill />
+ </CHECKSUM>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <POSTROUTING_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="PREROUTING_ZONES" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >wlp58s0</i>
+ </match>
+ </conditions>
+ <actions>
+ <goto >
+ <PRE_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <goto >
+ <PRE_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="PRE_FedoraWorkstation" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PRE_FedoraWorkstation_log />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PRE_FedoraWorkstation_deny />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PRE_FedoraWorkstation_allow />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="FORWARD_direct" packet-count="0" byte-count="0" />
+ <chain name="INPUT_direct" packet-count="0" byte-count="0" />
+ <chain name="OUTPUT_direct" packet-count="0" byte-count="0" />
+ <chain name="POSTROUTING_direct" packet-count="0" byte-count="0" />
+ <chain name="PREROUTING_ZONES_SOURCE" packet-count="0" byte-count="0" />
+ <chain name="PREROUTING_direct" packet-count="0" byte-count="0" />
+ <chain name="PRE_FedoraWorkstation_allow" packet-count="0" byte-count="0" />
+ <chain name="PRE_FedoraWorkstation_deny" packet-count="0" byte-count="0" />
+ <chain name="PRE_FedoraWorkstation_log" packet-count="0" byte-count="0" />
+ </table>
+<!-- # Completed on Sat Feb 17 10:50:33 2018 -->
+<!-- # Generated by iptables*-save v1.6.1 on Sat Feb 17 10:50:33 2018 -->
+ <table name="raw" >
+ <chain name="PREROUTING" policy="ACCEPT" packet-count="1681" byte-count="2620433" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PREROUTING_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PREROUTING_ZONES_SOURCE />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PREROUTING_ZONES />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="OUTPUT" policy="ACCEPT" packet-count="1619" byte-count="171281" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <OUTPUT_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="PREROUTING_ZONES" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >wlp58s0</i>
+ </match>
+ </conditions>
+ <actions>
+ <goto >
+ <PRE_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <goto >
+ <PRE_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="PRE_FedoraWorkstation" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PRE_FedoraWorkstation_log />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PRE_FedoraWorkstation_deny />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <PRE_FedoraWorkstation_allow />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="PRE_FedoraWorkstation_allow" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <p >udp</p>
+ </match>
+ <udp >
+ <dport >137</dport>
+ </udp>
+ </conditions>
+ <actions>
+ <CT >
+ <helper >netbios-ns</helper>
+ </CT>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="OUTPUT_direct" packet-count="0" byte-count="0" />
+ <chain name="PREROUTING_ZONES_SOURCE" packet-count="0" byte-count="0" />
+ <chain name="PREROUTING_direct" packet-count="0" byte-count="0" />
+ <chain name="PRE_FedoraWorkstation_deny" packet-count="0" byte-count="0" />
+ <chain name="PRE_FedoraWorkstation_log" packet-count="0" byte-count="0" />
+ </table>
+<!-- # Completed on Sat Feb 17 10:50:33 2018 -->
+<!-- # Generated by iptables*-save v1.6.1 on Sat Feb 17 10:50:33 2018 -->
+ <table name="filter" >
+ <chain name="INPUT" policy="ACCEPT" packet-count="0" byte-count="0" >
+ <rule packet-count="5" byte-count="6" >
+ <conditions>
+ <match >
+ <i >virbr0</i>
+ <p >udp</p>
+ </match>
+ <udp >
+ <dport >53</dport>
+ </udp>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="123456789" >
+ <conditions>
+ <match >
+ <i >virbr0</i>
+ <p >tcp</p>
+ </match>
+ <tcp >
+ <dport >53</dport>
+ </tcp>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >virbr0</i>
+ <p >udp</p>
+ </match>
+ <udp >
+ <dport >67</dport>
+ </udp>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >virbr0</i>
+ <p >tcp</p>
+ </match>
+ <tcp >
+ <dport >67</dport>
+ </tcp>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <conntrack >
+ <ctstate >RELATED,ESTABLISHED</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >lo</i>
+ </match>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <INPUT_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <INPUT_ZONES_SOURCE />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <INPUT_ZONES />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <conntrack >
+ <ctstate >INVALID</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <DROP />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <REJECT >
+ <reject-with >icmp-host-prohibited</reject-with>
+ </REJECT>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="FORWARD" policy="ACCEPT" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <d >192.168.122.0/24</d>
+ <o >virbr0</o>
+ </match>
+ <conntrack >
+ <ctstate >RELATED,ESTABLISHED</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <s >192.168.122.0/24</s>
+ <i >virbr0</i>
+ </match>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >virbr0</i>
+ <o >virbr0</o>
+ </match>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <o >virbr0</o>
+ </match>
+ </conditions>
+ <actions>
+ <REJECT >
+ <reject-with >icmp-port-unreachable</reject-with>
+ </REJECT>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >virbr0</i>
+ </match>
+ </conditions>
+ <actions>
+ <REJECT >
+ <reject-with >icmp-port-unreachable</reject-with>
+ </REJECT>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <conntrack >
+ <ctstate >RELATED,ESTABLISHED</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >lo</i>
+ </match>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FORWARD_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FORWARD_IN_ZONES_SOURCE />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FORWARD_IN_ZONES />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FORWARD_OUT_ZONES_SOURCE />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FORWARD_OUT_ZONES />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <conntrack >
+ <ctstate >INVALID</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <DROP />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <REJECT >
+ <reject-with >icmp-host-prohibited</reject-with>
+ </REJECT>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="OUTPUT" policy="ACCEPT" packet-count="1619" byte-count="171281" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <o >virbr0</o>
+ <p >udp</p>
+ </match>
+ <udp >
+ <dport >68</dport>
+ </udp>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <OUTPUT_direct />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="FORWARD_IN_ZONES" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >wlp58s0</i>
+ </match>
+ </conditions>
+ <actions>
+ <goto >
+ <FWDI_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <goto >
+ <FWDI_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="FORWARD_OUT_ZONES" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <o >wlp58s0</o>
+ </match>
+ </conditions>
+ <actions>
+ <goto >
+ <FWDO_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <goto >
+ <FWDO_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="FWDI_FedoraWorkstation" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FWDI_FedoraWorkstation_log />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FWDI_FedoraWorkstation_deny />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FWDI_FedoraWorkstation_allow />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <p >icmp</p>
+ </match>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="FWDO_FedoraWorkstation" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FWDO_FedoraWorkstation_log />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FWDO_FedoraWorkstation_deny />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <FWDO_FedoraWorkstation_allow />
+ </call>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="INPUT_ZONES" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <i >wlp58s0</i>
+ </match>
+ </conditions>
+ <actions>
+ <goto >
+ <IN_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <goto >
+ <IN_FedoraWorkstation />
+ </goto>
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="IN_FedoraWorkstation" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <IN_FedoraWorkstation_log />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <IN_FedoraWorkstation_deny />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <actions>
+ <call >
+ <IN_FedoraWorkstation_allow />
+ </call>
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <p >icmp</p>
+ </match>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="IN_FedoraWorkstation_allow" packet-count="0" byte-count="0" >
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <p >udp</p>
+ </match>
+ <udp >
+ <dport >137</dport>
+ </udp>
+ <conntrack >
+ <ctstate >NEW</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <p >udp</p>
+ </match>
+ <udp >
+ <dport >138</dport>
+ </udp>
+ <conntrack >
+ <ctstate >NEW</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <p >tcp</p>
+ </match>
+ <tcp >
+ <dport >22</dport>
+ </tcp>
+ <conntrack >
+ <ctstate >NEW</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <d >224.0.0.251/32</d>
+ <p >udp</p>
+ </match>
+ <udp >
+ <dport >5353</dport>
+ </udp>
+ <conntrack >
+ <ctstate >NEW</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="0" byte-count="0" >
+ <conditions>
+ <match >
+ <p >udp</p>
+ </match>
+ <udp >
+ <dport >1025:65535</dport>
+ </udp>
+ <conntrack >
+ <ctstate >NEW</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ <rule packet-count="7" byte-count="8" >
+ <conditions>
+ <match >
+ <p >tcp</p>
+ </match>
+ <tcp >
+ <dport >1025:65535</dport>
+ </tcp>
+ <conntrack >
+ <ctstate >NEW</ctstate>
+ </conntrack>
+ </conditions>
+ <actions>
+ <ACCEPT />
+ </actions>
+
+ </rule>
+
+ </chain>
+ <chain name="FORWARD_IN_ZONES_SOURCE" packet-count="0" byte-count="0" />
+ <chain name="FORWARD_OUT_ZONES_SOURCE" packet-count="0" byte-count="0" />
+ <chain name="FORWARD_direct" packet-count="0" byte-count="0" />
+ <chain name="FWDI_FedoraWorkstation_allow" packet-count="0" byte-count="0" />
+ <chain name="FWDI_FedoraWorkstation_deny" packet-count="0" byte-count="0" />
+ <chain name="FWDI_FedoraWorkstation_log" packet-count="0" byte-count="0" />
+ <chain name="FWDO_FedoraWorkstation_allow" packet-count="0" byte-count="0" />
+ <chain name="FWDO_FedoraWorkstation_deny" packet-count="0" byte-count="0" />
+ <chain name="FWDO_FedoraWorkstation_log" packet-count="0" byte-count="0" />
+ <chain name="INPUT_ZONES_SOURCE" packet-count="0" byte-count="0" />
+ <chain name="INPUT_direct" packet-count="0" byte-count="0" />
+ <chain name="IN_FedoraWorkstation_deny" packet-count="0" byte-count="0" />
+ <chain name="IN_FedoraWorkstation_log" packet-count="0" byte-count="0" />
+ <chain name="OUTPUT_direct" packet-count="0" byte-count="0" />
+ </table>
+<!-- # Completed on Sat Feb 17 10:50:33 2018 -->
+</iptables-rules>
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 36a2ec5f..16c58914 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -181,7 +181,6 @@ int command_default(struct iptables_command_state *cs,
xtables_error(PARAMETER_PROBLEM, "unknown option "
"\"%s\"", cs->argv[optind-1]);
xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg);
- return 0;
}
static mainfunc_t subcmd_get(const char *cmd, const struct subcommand *cb)
@@ -374,6 +373,43 @@ int parse_counters(const char *string, struct xt_counters *ctr)
return ret == 2;
}
+/* Tokenize counters argument of typical iptables-restore format rule.
+ *
+ * If *bufferp contains counters, update *pcntp and *bcntp to point at them,
+ * change bytes after counters in *bufferp to nul-bytes, update *bufferp to
+ * point to after the counters and return true.
+ * If *bufferp does not contain counters, return false.
+ * If syntax is wrong in *bufferp, call xtables_error() and hence exit().
+ * */
+bool tokenize_rule_counters(char **bufferp, char **pcntp, char **bcntp, int line)
+{
+ char *ptr, *buffer = *bufferp, *pcnt, *bcnt;
+
+ if (buffer[0] != '[')
+ return false;
+
+ /* we have counters in our input */
+
+ ptr = strchr(buffer, ']');
+ if (!ptr)
+ xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
+
+ pcnt = strtok(buffer+1, ":");
+ if (!pcnt)
+ xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :\n", line);
+
+ bcnt = strtok(NULL, "]");
+ if (!bcnt)
+ xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
+
+ *pcntp = pcnt;
+ *bcntp = bcnt;
+ /* start command parsing after counter */
+ *bufferp = ptr + 1;
+
+ return true;
+}
+
inline bool xs_has_arg(int argc, char *argv[])
{
return optind < argc &&
@@ -381,56 +417,48 @@ inline bool xs_has_arg(int argc, char *argv[])
argv[optind][0] != '!';
}
-/* global new argv and argc */
-char *newargv[255];
-int newargc = 0;
-
-/* saved newargv and newargc from save_argv() */
-char *oldargv[255];
-int oldargc = 0;
-
-/* arg meta data, were they quoted, frinstance */
-int newargvattr[255];
-
-/* function adding one argument to newargv, updating newargc
- * returns true if argument added, false otherwise */
-int add_argv(const char *what, int quoted)
+/* function adding one argument to store, updating argc
+ * returns if argument added, does not return otherwise */
+void add_argv(struct argv_store *store, const char *what, int quoted)
{
DEBUGP("add_argv: %s\n", what);
- if (what && newargc + 1 < ARRAY_SIZE(newargv)) {
- newargv[newargc] = strdup(what);
- newargvattr[newargc] = quoted;
- newargv[++newargc] = NULL;
- return 1;
- } else {
+
+ if (store->argc + 1 >= MAX_ARGC)
xtables_error(PARAMETER_PROBLEM,
"Parser cannot handle more arguments\n");
- }
+ if (!what)
+ xtables_error(PARAMETER_PROBLEM,
+ "Trying to store NULL argument\n");
+
+ store->argv[store->argc] = strdup(what);
+ store->argvattr[store->argc] = quoted;
+ store->argv[++store->argc] = NULL;
}
-void free_argv(void)
+void free_argv(struct argv_store *store)
{
- while (newargc)
- free(newargv[--newargc]);
- while (oldargc)
- free(oldargv[--oldargc]);
+ while (store->argc) {
+ store->argc--;
+ free(store->argv[store->argc]);
+ store->argvattr[store->argc] = 0;
+ }
}
/* Save parsed rule for comparison with next rule to perform action aggregation
* on duplicate conditions.
*/
-void save_argv(void)
+void save_argv(struct argv_store *dst, struct argv_store *src)
{
- unsigned int i;
-
- while (oldargc)
- free(oldargv[--oldargc]);
+ int i;
- oldargc = newargc;
- newargc = 0;
- for (i = 0; i < oldargc; i++) {
- oldargv[i] = newargv[i];
+ free_argv(dst);
+ for (i = 0; i < src->argc; i++) {
+ dst->argvattr[i] = src->argvattr[i];
+ dst->argv[i] = src->argv[i];
+ src->argv[i] = NULL;
}
+ dst->argc = src->argc;
+ src->argc = 0;
}
struct xt_param_buf {
@@ -446,9 +474,9 @@ static void add_param(struct xt_param_buf *param, const char *curchar)
"Parameter too long!");
}
-void add_param_to_argv(char *parsestart, int line)
+void add_param_to_argv(struct argv_store *store, char *parsestart, int line)
{
- int quote_open = 0, escaped = 0;
+ int quote_open = 0, escaped = 0, quoted = 0;
struct xt_param_buf param = {};
char *curchar;
@@ -475,6 +503,7 @@ void add_param_to_argv(char *parsestart, int line)
} else {
if (*curchar == '"') {
quote_open = 1;
+ quoted = 1;
continue;
}
}
@@ -497,23 +526,26 @@ void add_param_to_argv(char *parsestart, int line)
}
param.buffer[param.len] = '\0';
-
- /* check if table name specified */
- if ((param.buffer[0] == '-' &&
- param.buffer[1] != '-' &&
- strchr(param.buffer, 't')) ||
- (!strncmp(param.buffer, "--t", 3) &&
- !strncmp(param.buffer, "--table", strlen(param.buffer)))) {
- xtables_error(PARAMETER_PROBLEM,
- "The -t option (seen in line %u) cannot be used in %s.\n",
- line, xt_params->program_name);
- }
-
- add_argv(param.buffer, 0);
+ add_argv(store, param.buffer, quoted);
param.len = 0;
+ quoted = 0;
+ }
+ if (param.len) {
+ param.buffer[param.len] = '\0';
+ add_argv(store, param.buffer, 0);
}
}
+#ifdef DEBUG
+void debug_print_argv(struct argv_store *store)
+{
+ int i;
+
+ for (i = 0; i < store->argc; i++)
+ fprintf(stderr, "argv[%d]: %s\n", i, store->argv[i]);
+}
+#endif
+
static const char *ipv4_addr_to_string(const struct in_addr *addr,
const struct in_addr *mask,
unsigned int format)
@@ -704,3 +736,42 @@ void command_jump(struct iptables_command_state *cs, const char *jumpto)
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
xt_params->opts = opts;
}
+
+char cmd2char(int option)
+{
+ /* cmdflags index corresponds with position of bit in CMD_* values */
+ static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
+ 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
+ int i;
+
+ for (i = 0; option > 1; option >>= 1, i++)
+ ;
+ if (i >= ARRAY_SIZE(cmdflags))
+ xtables_error(OTHER_PROBLEM,
+ "cmd2char(): Invalid command number %u.\n",
+ 1 << i);
+ return cmdflags[i];
+}
+
+void add_command(unsigned int *cmd, const int newcmd,
+ const int othercmds, int invert)
+{
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag");
+ if (*cmd & (~othercmds))
+ xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
+ cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
+ *cmd |= newcmd;
+}
+
+/* Can't be zero. */
+int parse_rulenumber(const char *rule)
+{
+ unsigned int rulenum;
+
+ if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid rule number `%s'", rule);
+
+ return rulenum;
+}
diff --git a/iptables/xshared.h b/iptables/xshared.h
index ec31f2f0..c41bd054 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -12,7 +12,7 @@
#include <linux/netfilter_ipv6/ip6_tables.h>
#ifdef DEBUG
-#define DEBUGP(x, args...) fprintf(stdout, x, ## args)
+#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
#else
#define DEBUGP(x, args...)
#endif
@@ -30,8 +30,35 @@ enum {
OPT_VIANAMEOUT = 1 << 8,
OPT_LINENUMBERS = 1 << 9,
OPT_COUNTERS = 1 << 10,
+ /* below are for arptables only */
+ OPT_S_MAC = 1 << 11,
+ OPT_D_MAC = 1 << 12,
+ OPT_H_LENGTH = 1 << 13,
+ OPT_OPCODE = 1 << 14,
+ OPT_H_TYPE = 1 << 15,
+ OPT_P_TYPE = 1 << 16,
};
+enum {
+ CMD_NONE = 0,
+ CMD_INSERT = 1 << 0,
+ CMD_DELETE = 1 << 1,
+ CMD_DELETE_NUM = 1 << 2,
+ CMD_REPLACE = 1 << 3,
+ CMD_APPEND = 1 << 4,
+ CMD_LIST = 1 << 5,
+ CMD_FLUSH = 1 << 6,
+ CMD_ZERO = 1 << 7,
+ CMD_NEW_CHAIN = 1 << 8,
+ CMD_DELETE_CHAIN = 1 << 9,
+ CMD_SET_POLICY = 1 << 10,
+ CMD_RENAME_CHAIN = 1 << 11,
+ CMD_LIST_RULES = 1 << 12,
+ CMD_ZERO_NUM = 1 << 13,
+ CMD_CHECK = 1 << 14,
+};
+#define NUMBER_OF_CMD 16
+
struct xtables_globals;
struct xtables_rule_match;
struct xtables_target;
@@ -152,22 +179,27 @@ extern int xtables_lock_or_exit(int wait, struct timeval *tv);
int parse_wait_time(int argc, char *argv[]);
void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval);
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[]);
extern const struct xtables_afinfo *afinfo;
-extern char *newargv[];
-extern int newargc;
-
-extern char *oldargv[];
-extern int oldargc;
-
-extern int newargvattr[];
+#define MAX_ARGC 255
+struct argv_store {
+ int argc;
+ char *argv[MAX_ARGC];
+ int argvattr[MAX_ARGC];
+};
-int add_argv(const char *what, int quoted);
-void free_argv(void);
-void save_argv(void);
-void add_param_to_argv(char *parsestart, int line);
+void add_argv(struct argv_store *store, const char *what, int quoted);
+void free_argv(struct argv_store *store);
+void save_argv(struct argv_store *dst, struct argv_store *src);
+void add_param_to_argv(struct argv_store *store, char *parsestart, int line);
+#ifdef DEBUG
+void debug_print_argv(struct argv_store *store);
+#else
+# define debug_print_argv(...) /* nothing */
+#endif
void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format);
void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format);
@@ -179,4 +211,9 @@ void command_match(struct iptables_command_state *cs);
const char *xt_parse_target(const char *targetname);
void command_jump(struct iptables_command_state *cs, const char *jumpto);
+char cmd2char(int option);
+void add_command(unsigned int *cmd, const int newcmd,
+ const int othercmds, int invert);
+int parse_rulenumber(const char *rule);
+
#endif /* IPTABLES_XSHARED_H */
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index d3cb9df8..9cfad762 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -27,7 +27,7 @@
This tool is not luser-proof: you can specify an Ethernet source address
and set hardware length to something different than 6, f.e.
*/
-
+#include "config.h"
#include <getopt.h>
#include <string.h>
#include <netdb.h>
@@ -53,56 +53,6 @@
#include "nft-arp.h"
#include <linux/netfilter_arp/arp_tables.h>
-typedef char arpt_chainlabel[32];
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-/* XXX: command defined by nft-shared.h do not overlap with these two */
-#undef CMD_CHECK
-#undef CMD_RENAME_CHAIN
-
-#define CMD_NONE 0x0000U
-#define CMD_INSERT 0x0001U
-#define CMD_DELETE 0x0002U
-#define CMD_DELETE_NUM 0x0004U
-#define CMD_REPLACE 0x0008U
-#define CMD_APPEND 0x0010U
-#define CMD_LIST 0x0020U
-#define CMD_FLUSH 0x0040U
-#define CMD_ZERO 0x0080U
-#define CMD_NEW_CHAIN 0x0100U
-#define CMD_DELETE_CHAIN 0x0200U
-#define CMD_SET_POLICY 0x0400U
-#define CMD_CHECK 0x0800U
-#define CMD_RENAME_CHAIN 0x1000U
-#define NUMBER_OF_CMD 13
-static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
- 'N', 'X', 'P', 'E' };
-
-#define OPTION_OFFSET 256
-
-#define OPT_NONE 0x00000U
-#define OPT_NUMERIC 0x00001U
-#define OPT_S_IP 0x00002U
-#define OPT_D_IP 0x00004U
-#define OPT_S_MAC 0x00008U
-#define OPT_D_MAC 0x00010U
-#define OPT_H_LENGTH 0x00020U
-#define OPT_P_LENGTH 0x00040U
-#define OPT_OPCODE 0x00080U
-#define OPT_H_TYPE 0x00100U
-#define OPT_P_TYPE 0x00200U
-#define OPT_JUMP 0x00400U
-#define OPT_VERBOSE 0x00800U
-#define OPT_VIANAMEIN 0x01000U
-#define OPT_VIANAMEOUT 0x02000U
-#define OPT_LINENUMBERS 0x04000U
-#define OPT_COUNTERS 0x08000U
#define NUMBER_OF_OPT 16
static const char optflags[NUMBER_OF_OPT]
= { 'n', 's', 'd', 2, 3, 7, 8, 4, 5, 6, 'j', 'v', 'i', 'o', '0', 'c'};
@@ -148,85 +98,39 @@ static struct option original_opts[] = {
{ 0 }
};
-int RUNTIME_NF_ARP_NUMHOOKS = 3;
-
#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 = IPTABLES_VERSION,
+ .program_version = PACKAGE_VERSION,
.orig_opts = original_opts,
.exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o -f --line */
-/*INSERT*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*DELETE*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*DELETE_NUM*/{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*REPLACE*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*APPEND*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*LIST*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*FLUSH*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*ZERO*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*NEW_CHAIN*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*DEL_CHAIN*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*SET_POLICY*/{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*CHECK*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
-/*RENAME*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}
-};
-
-static int inverse_for_options[NUMBER_OF_OPT] =
+/* index relates to bit of each OPT_* value */
+static int inverse_for_options[] =
{
/* -n */ 0,
/* -s */ ARPT_INV_SRCIP,
/* -d */ ARPT_INV_TGTIP,
-/* 2 */ ARPT_INV_SRCDEVADDR,
-/* 3 */ ARPT_INV_TGTDEVADDR,
-/* -l */ ARPT_INV_ARPHLN,
-/* 8 */ 0,
-/* 4 */ ARPT_INV_ARPOP,
-/* 5 */ ARPT_INV_ARPHRD,
-/* 6 */ ARPT_INV_ARPPRO,
+/* -p */ 0,
/* -j */ 0,
/* -v */ 0,
+/* -x */ 0,
/* -i */ ARPT_INV_VIA_IN,
/* -o */ ARPT_INV_VIA_OUT,
/*--line*/ 0,
/* -c */ 0,
+/* 2 */ ARPT_INV_SRCDEVADDR,
+/* 3 */ ARPT_INV_TGTDEVADDR,
+/* -l */ ARPT_INV_ARPHLN,
+/* 4 */ ARPT_INV_ARPOP,
+/* 5 */ ARPT_INV_ARPHRD,
+/* 6 */ ARPT_INV_ARPPRO,
};
-/* A few hardcoded protocols for 'all' and in case the user has no
- /etc/protocols */
-struct pprot {
- char *name;
- u_int8_t num;
-};
-
-/* Primitive headers... */
-/* defined in netinet/in.h */
-#if 0
-#ifndef IPPROTO_ESP
-#define IPPROTO_ESP 50
-#endif
-#ifndef IPPROTO_AH
-#define IPPROTO_AH 51
-#endif
-#endif
-
/***********************************************/
/* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */
/***********************************************/
@@ -317,89 +221,10 @@ static int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base)
return 0;
}
-static int
-string_to_number(const char *s, unsigned int min, unsigned int max,
- unsigned int *ret)
-{
- long number;
- char *end;
-
- /* Handle hex, octal, etc. */
- errno = 0;
- number = strtol(s, &end, 0);
- if (*end == '\0' && end != s) {
- /* we parsed a number, let's see if we want this */
- if (errno != ERANGE && min <= number && number <= max) {
- *ret = number;
- return 0;
- }
- }
- return -1;
-}
-
/*********************************************/
/* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */
/*********************************************/
-static struct in_addr *
-dotted_to_addr(const char *dotted)
-{
- static struct in_addr addr;
- unsigned char *addrp;
- char *p, *q;
- unsigned int onebyte;
- int i;
- char buf[20];
-
- /* copy dotted string, because we need to modify it */
- strncpy(buf, dotted, sizeof(buf) - 1);
- addrp = (unsigned char *) &(addr.s_addr);
-
- p = buf;
- for (i = 0; i < 3; i++) {
- if ((q = strchr(p, '.')) == NULL)
- return (struct in_addr *) NULL;
-
- *q = '\0';
- if (string_to_number(p, 0, 255, &onebyte) == -1)
- return (struct in_addr *) NULL;
-
- addrp[i] = (unsigned char) onebyte;
- p = q + 1;
- }
-
- /* we've checked 3 bytes, now we check the last one */
- if (string_to_number(p, 0, 255, &onebyte) == -1)
- return (struct in_addr *) NULL;
-
- addrp[3] = (unsigned char) onebyte;
-
- return &addr;
-}
-
-static struct in_addr *
-network_to_addr(const char *name)
-{
- struct netent *net;
- static struct in_addr addr;
-
- if ((net = getnetbyname(name)) != NULL) {
- if (net->n_addrtype != AF_INET)
- return (struct in_addr *) NULL;
- addr.s_addr = htonl((unsigned long) net->n_net);
- return &addr;
- }
-
- return (struct in_addr *) NULL;
-}
-
-static void
-inaddrcpy(struct in_addr *dst, struct in_addr *src)
-{
- /* memcpy(dst, src, sizeof(struct in_addr)); */
- dst->s_addr = src->s_addr;
-}
-
static void
exit_tryhelp(int status)
{
@@ -503,42 +328,6 @@ exit_printhelp(void)
exit(0);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
static char
opt2char(int option)
{
@@ -548,26 +337,6 @@ opt2char(int option)
return *ptr;
}
-static char
-cmd2char(int option)
-{
- const char *ptr;
- for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
-static void
-add_command(unsigned int *cmd, const int newcmd, const unsigned int othercmds, int invert)
-{
- if (invert)
- xtables_error(PARAMETER_PROBLEM, "unexpected ! flag");
- if (*cmd & (~othercmds))
- xtables_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n",
- cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
- *cmd |= newcmd;
-}
-
static int
check_inverse(const char option[], int *invert, int *optidx, int argc)
{
@@ -575,7 +344,7 @@ check_inverse(const char option[], int *invert, int *optidx, int argc)
if (*invert)
xtables_error(PARAMETER_PROBLEM,
"Multiple `!' flags not allowed");
- *invert = TRUE;
+ *invert = true;
if (optidx) {
*optidx = *optidx+1;
if (argc && *optidx > argc)
@@ -583,181 +352,9 @@ check_inverse(const char option[], int *invert, int *optidx, int argc)
"no argument following `!'");
}
- return TRUE;
+ return true;
}
- return FALSE;
-}
-
-static struct in_addr *
-host_to_addr(const char *name, unsigned int *naddr)
-{
- struct in_addr *addr;
- struct addrinfo hints = {
- .ai_flags = AI_CANONNAME,
- .ai_family = AF_INET,
- .ai_socktype = SOCK_RAW,
- };;
- struct addrinfo *res, *p;
- int err;
- unsigned int i;
-
- *naddr = 0;
- err = getaddrinfo(name, NULL, &hints, &res);
- if (err != 0)
- return NULL;
- else {
- for (p = res; p != NULL; p = p->ai_next)
- (*naddr)++;
- addr = xtables_calloc(*naddr, sizeof(struct in_addr));
- for (i = 0, p = res; p != NULL; p = p->ai_next)
- memcpy(&addr[i++],
- &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
- sizeof(struct in_addr));
- freeaddrinfo(res);
- return addr;
- }
-
- return (struct in_addr *) NULL;
-}
-
-/*
- * All functions starting with "parse" should succeed, otherwise
- * the program fails.
- * Most routines return pointers to static data that may change
- * between calls to the same or other routines with a few exceptions:
- * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
- * return global static data.
-*/
-
-static struct in_addr *
-parse_hostnetwork(const char *name, unsigned int *naddrs)
-{
- struct in_addr *addrp, *addrptmp;
-
- if ((addrptmp = dotted_to_addr(name)) != NULL ||
- (addrptmp = network_to_addr(name)) != NULL) {
- addrp = xtables_malloc(sizeof(struct in_addr));
- inaddrcpy(addrp, addrptmp);
- *naddrs = 1;
- return addrp;
- }
- if ((addrp = host_to_addr(name, naddrs)) != NULL)
- return addrp;
-
- xtables_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
-}
-
-static struct in_addr *
-parse_mask(char *mask)
-{
- static struct in_addr maskaddr;
- struct in_addr *addrp;
- unsigned int bits;
-
- if (mask == NULL) {
- /* no mask at all defaults to 32 bits */
- maskaddr.s_addr = 0xFFFFFFFF;
- return &maskaddr;
- }
- if ((addrp = dotted_to_addr(mask)) != NULL)
- /* dotted_to_addr already returns a network byte order addr */
- return addrp;
- if (string_to_number(mask, 0, 32, &bits) == -1)
- xtables_error(PARAMETER_PROBLEM,
- "invalid mask `%s' specified", mask);
- if (bits != 0) {
- maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
- return &maskaddr;
- }
-
- maskaddr.s_addr = 0L;
- return &maskaddr;
-}
-
-static void
-parse_hostnetworkmask(const char *name, struct in_addr **addrpp,
- struct in_addr *maskp, unsigned int *naddrs)
-{
- struct in_addr *addrp;
- char buf[256];
- char *p;
- int i, j, k, n;
-
- strncpy(buf, name, sizeof(buf) - 1);
- if ((p = strrchr(buf, '/')) != NULL) {
- *p = '\0';
- addrp = parse_mask(p + 1);
- } else
- addrp = parse_mask(NULL);
- inaddrcpy(maskp, addrp);
-
- /* if a null mask is given, the name is ignored, like in "any/0" */
- if (maskp->s_addr == 0L)
- strcpy(buf, "0.0.0.0");
-
- addrp = *addrpp = parse_hostnetwork(buf, naddrs);
- n = *naddrs;
- for (i = 0, j = 0; i < n; i++) {
- addrp[j++].s_addr &= maskp->s_addr;
- for (k = 0; k < j - 1; k++) {
- if (addrp[k].s_addr == addrp[j - 1].s_addr) {
- (*naddrs)--;
- j--;
- break;
- }
- }
- }
-}
-
-static void
-parse_interface(const char *arg, char *vianame, unsigned char *mask)
-{
- int vialen = strlen(arg);
- unsigned int i;
-
- memset(mask, 0, IFNAMSIZ);
- memset(vianame, 0, IFNAMSIZ);
-
- if (vialen + 1 > IFNAMSIZ)
- xtables_error(PARAMETER_PROBLEM,
- "interface name `%s' must be shorter than IFNAMSIZ"
- " (%i)", arg, IFNAMSIZ-1);
-
- strcpy(vianame, arg);
- if (vialen == 0)
- memset(mask, 0, IFNAMSIZ);
- else if (vianame[vialen - 1] == '+') {
- memset(mask, 0xFF, vialen - 1);
- memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
- /* Don't remove `+' here! -HW */
- } else {
- /* Include nul-terminator in match */
- memset(mask, 0xFF, vialen + 1);
- memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
- for (i = 0; vianame[i]; i++) {
- if (!isalnum(vianame[i])
- && vianame[i] != '_'
- && vianame[i] != '.') {
- printf("Warning: weird character in interface"
- " `%s' (No aliases, :, ! or *).\n",
- vianame);
- break;
- }
- }
- }
-}
-
-/* Can't be zero. */
-static int
-parse_rulenumber(const char *rule)
-{
- unsigned int rulenum;
-
- if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid rule number `%s'", rule);
-
- return rulenum;
+ return false;
}
static void
@@ -814,8 +411,10 @@ append_entry(struct nft_handle *h,
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;
@@ -823,8 +422,10 @@ append_entry(struct nft_handle *h,
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_rule_append(h, chain, table, cs, NULL,
verbose);
@@ -844,11 +445,15 @@ replace_entry(const char *chain,
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_rule_replace(h, chain, table, cs, rulenum, verbose);
}
@@ -859,8 +464,10 @@ delete_entry(const char *chain,
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;
@@ -868,8 +475,10 @@ delete_entry(const char *chain,
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_rule_delete(h, chain, table, cs, verbose);
}
}
@@ -919,7 +528,8 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
};
int invert = 0;
unsigned int nsaddrs = 0, ndaddrs = 0;
- struct in_addr *saddrs = NULL, *daddrs = NULL;
+ struct in_addr *saddrs = NULL, *smasks = NULL;
+ struct in_addr *daddrs = NULL, *dmasks = NULL;
int c, verbose = 0;
const char *chain = NULL;
@@ -1067,14 +677,14 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
break;
case 's':
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_S_IP, &cs.arp.arp.invflags,
+ 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_D_IP, &cs.arp.arp.invflags,
+ set_option(&options, OPT_DESTINATION, &cs.arp.arp.invflags,
invert);
dhostnetworkmask = argv[optind-1];
break;
@@ -1168,18 +778,18 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
check_inverse(optarg, &invert, &optind, argc);
set_option(&options, OPT_VIANAMEIN, &cs.arp.arp.invflags,
invert);
- parse_interface(argv[optind-1],
- cs.arp.arp.iniface,
- cs.arp.arp.iniface_mask);
+ 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);
- parse_interface(argv[optind-1],
- cs.arp.arp.outiface,
- cs.arp.arp.outiface_mask);
+ xtables_parse_interface(argv[optind-1],
+ cs.arp.arp.outiface,
+ cs.arp.arp.outiface_mask);
break;
case 'v':
@@ -1255,7 +865,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
xtables_error(PARAMETER_PROBLEM,
"multiple consecutive ! not"
" allowed");
- invert = TRUE;
+ invert = true;
optarg[0] = '\0';
continue;
}
@@ -1269,7 +879,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
}
break;
}
- invert = FALSE;
+ invert = false;
}
if (cs.target)
@@ -1285,19 +895,19 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
"nothing appropriate following !");
if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
- if (!(options & OPT_D_IP))
+ if (!(options & OPT_DESTINATION))
dhostnetworkmask = "0.0.0.0/0";
- if (!(options & OPT_S_IP))
+ if (!(options & OPT_SOURCE))
shostnetworkmask = "0.0.0.0/0";
}
if (shostnetworkmask)
- parse_hostnetworkmask(shostnetworkmask, &saddrs,
- &(cs.arp.arp.smsk), &nsaddrs);
+ xtables_ipparse_multiple(shostnetworkmask, &saddrs,
+ &smasks, &nsaddrs);
if (dhostnetworkmask)
- parse_hostnetworkmask(dhostnetworkmask, &daddrs,
- &(cs.arp.arp.tmsk), &ndaddrs);
+ xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
+ &dmasks, &ndaddrs);
if ((nsaddrs > 1 || ndaddrs > 1) &&
(cs.arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
@@ -1308,8 +918,6 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
"specify a unique address");
- generic_opt_check(command, options);
-
if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
"chain name `%s' too long (must be under %i chars)",
@@ -1343,12 +951,14 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
switch (command) {
case CMD_APPEND:
ret = append_entry(h, chain, *table, &cs, 0,
- nsaddrs, saddrs, ndaddrs, daddrs,
+ nsaddrs, saddrs, smasks,
+ ndaddrs, daddrs, dmasks,
options&OPT_VERBOSE, true);
break;
case CMD_DELETE:
ret = delete_entry(chain, *table, &cs,
- nsaddrs, saddrs, ndaddrs, daddrs,
+ nsaddrs, saddrs, smasks,
+ ndaddrs, daddrs, dmasks,
options&OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
@@ -1356,11 +966,13 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
break;
case CMD_REPLACE:
ret = replace_entry(chain, *table, &cs, rulenum - 1,
- saddrs, daddrs, options&OPT_VERBOSE, h);
+ saddrs, smasks, daddrs, dmasks,
+ options&OPT_VERBOSE, h);
break;
case CMD_INSERT:
ret = append_entry(h, chain, *table, &cs, rulenum - 1,
- nsaddrs, saddrs, ndaddrs, daddrs,
+ nsaddrs, saddrs, smasks,
+ ndaddrs, daddrs, dmasks,
options&OPT_VERBOSE, false);
break;
case CMD_LIST:
@@ -1409,10 +1021,10 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
exit_tryhelp(2);
}
- if (nsaddrs)
- free(saddrs);
- if (ndaddrs)
- free(daddrs);
+ free(saddrs);
+ free(smasks);
+ free(daddrs);
+ free(dmasks);
if (cs.target)
free(cs.target->t);
diff --git a/iptables/xtables-config-parser.y b/iptables/xtables-config-parser.y
deleted file mode 100644
index 89bfee73..00000000
--- a/iptables/xtables-config-parser.y
+++ /dev/null
@@ -1,248 +0,0 @@
-%{
-/*
- * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
- *
- * 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 software has been sponsored by Sophos Astaro <http://www.sophos.com>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <libiptc/linux_list.h>
-#include <libnftnl/table.h>
-#include <libnftnl/chain.h>
-
-#include <netinet/in.h>
-#include <linux/netfilter.h>
-
-extern char *yytext;
-extern int yylineno;
-
-static LIST_HEAD(xtables_stack);
-
-struct stack_elem {
- struct list_head head;
- int token;
- size_t size;
- char data[];
-};
-
-static void *stack_push(int token, size_t size)
-{
- struct stack_elem *e;
-
- e = calloc(1, sizeof(struct stack_elem) + size);
-
- e->token = token;
- e->size = size;
-
- list_add(&e->head, &xtables_stack);
-
- return e->data;
-}
-
-static struct stack_elem *stack_pop(void)
-{
- struct stack_elem *e;
-
- e = list_entry(xtables_stack.next, struct stack_elem, head);
-
- if (&e->head == &xtables_stack)
- return NULL;
-
- list_del(&e->head);
- return e;
-}
-
-static inline void stack_put_i32(void *data, int value)
-{
- memcpy(data, &value, sizeof(int));
-}
-
-static inline void stack_put_str(void *data, const char *str)
-{
- memcpy(data, str, strlen(str));
-}
-
-static void stack_free(struct stack_elem *e)
-{
- free(e);
-}
-
-%}
-
-%union {
- int val;
- char *string;
-}
-
-%token T_FAMILY
-%token T_TABLE
-%token T_CHAIN
-%token T_HOOK
-%token T_PRIO
-
-%token <string> T_STRING
-%token <val> T_INTEGER
-
-%%
-
-configfile :
- | lines
- ;
-
-lines : line
- | lines line
- ;
-
-line : family
- ;
-
-family : T_FAMILY T_STRING '{' tables '}'
- {
- void *data = stack_push(T_FAMILY, strlen($2)+1);
- stack_put_str(data, $2);
- }
- ;
-
-tables : table
- | tables table
- ;
-
-table : T_TABLE T_STRING '{' chains '}'
- {
- /* added in reverse order to pop it in order */
- void *data = stack_push(T_TABLE, strlen($2)+1);
- stack_put_str(data, $2);
- }
- ;
-
-chains : chain
- | chains chain
- ;
-
-chain : T_CHAIN T_STRING T_HOOK T_STRING T_PRIO T_INTEGER
- {
- /* added in reverse order to pop it in order */
- void *data = stack_push(T_PRIO, sizeof(int32_t));
- stack_put_i32(data, $6);
- data = stack_push(T_HOOK, strlen($4)+1);
- stack_put_str(data, $4);
- data = stack_push(T_CHAIN, strlen($2)+1);
- stack_put_str(data, $2);
- }
- ;
-
-%%
-
-int __attribute__((noreturn))
-yyerror(char *msg)
-{
- fprintf(stderr, "parsing config file in line (%d), symbol '%s': %s\n",
- yylineno, yytext, msg);
- exit(EXIT_FAILURE);
-}
-
-static int hooknametonum(const char *hookname)
-{
- if (strcmp(hookname, "NF_INET_LOCAL_IN") == 0)
- return NF_INET_LOCAL_IN;
- else if (strcmp(hookname, "NF_INET_FORWARD") == 0)
- return NF_INET_FORWARD;
- else if (strcmp(hookname, "NF_INET_LOCAL_OUT") == 0)
- return NF_INET_LOCAL_OUT;
- else if (strcmp(hookname, "NF_INET_PRE_ROUTING") == 0)
- return NF_INET_PRE_ROUTING;
- else if (strcmp(hookname, "NF_INET_POST_ROUTING") == 0)
- return NF_INET_POST_ROUTING;
-
- return -1;
-}
-
-static int32_t familytonumber(const char *family)
-{
- if (strcmp(family, "ipv4") == 0)
- return AF_INET;
- else if (strcmp(family, "ipv6") == 0)
- return AF_INET6;
-
- return -1;
-}
-
-int xtables_config_parse(char *filename, struct nftnl_table_list *table_list,
- struct nftnl_chain_list *chain_list)
-{
- FILE *fp;
- struct stack_elem *e;
- struct nftnl_table *table = NULL;
- struct nftnl_chain *chain = NULL;
- int prio = 0;
- int32_t family = 0;
-
- fp = fopen(filename, "r");
- if (!fp)
- return -1;
-
- yyrestart(fp);
- yyparse();
- fclose(fp);
-
- for (e = stack_pop(); e != NULL; e = stack_pop()) {
- switch(e->token) {
- case T_FAMILY:
- family = familytonumber(e->data);
- if (family == -1)
- return -1;
- break;
- case T_TABLE:
- table = nftnl_table_alloc();
- if (table == NULL)
- return -1;
-
- nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family);
- nftnl_table_set(table, NFTNL_TABLE_NAME, e->data);
- /* This is intentionally prepending, instead of
- * appending, since the elements in the stack are in
- * the reverse order that chains appear in the
- * configuration file.
- */
- nftnl_table_list_add(table, table_list);
- break;
- case T_PRIO:
- memcpy(&prio, e->data, sizeof(int32_t));
- break;
- case T_CHAIN:
- chain = nftnl_chain_alloc();
- if (chain == NULL)
- return -1;
-
- nftnl_chain_set(chain, NFTNL_CHAIN_TABLE,
- (char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
- nftnl_chain_set_u32(chain, NFTNL_CHAIN_FAMILY,
- nftnl_table_get_u32(table, NFTNL_TABLE_FAMILY));
- nftnl_chain_set_s32(chain, NFTNL_CHAIN_PRIO, prio);
- nftnl_chain_set(chain, NFTNL_CHAIN_NAME, e->data);
- /* Intentionally prepending, instead of appending */
- nftnl_chain_list_add(chain, chain_list);
- break;
- case T_HOOK:
- nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM,
- hooknametonum(e->data));
- break;
- default:
- printf("unknown token type %d\n", e->token);
- break;
- }
- stack_free(e);
- }
-
- return 0;
-}
diff --git a/iptables/xtables-config-syntax.l b/iptables/xtables-config-syntax.l
deleted file mode 100644
index a895c8bc..00000000
--- a/iptables/xtables-config-syntax.l
+++ /dev/null
@@ -1,54 +0,0 @@
-%{
-/*
- * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
- *
- * 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 software has been sponsored by Sophos Astaro <http://www.sophos.com>
- */
-
-#include <string.h>
-#include "xtables-config-parser.h"
-%}
-
-%option yylineno
-%option noinput
-%option nounput
-
-ws [ \t]+
-comment #.*$
-nl [\n\r]
-
-is_on [o|O][n|N]
-is_off [o|O][f|F][f|F]
-integer [\-\+]?[0-9]+
-string [a-zA-Z][a-zA-Z0-9\.\-\_]*
-
-%%
-"family" { return T_FAMILY; }
-"table" { return T_TABLE; }
-"chain" { return T_CHAIN; }
-"hook" { return T_HOOK; }
-"prio" { return T_PRIO; }
-
-{integer} { yylval.val = atoi(yytext); return T_INTEGER; }
-{string} { yylval.string = strdup(yytext); return T_STRING; }
-
-{comment} ;
-{ws} ;
-{nl} ;
-
-<<EOF>> { yyterminate(); }
-
-. { return yytext[0]; }
-
-%%
-
-int
-yywrap()
-{
- return 1;
-}
diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c
index fb3daba0..a9081c78 100644
--- a/iptables/xtables-eb-standalone.c
+++ b/iptables/xtables-eb-standalone.c
@@ -51,7 +51,7 @@ int xtables_eb_main(int argc, char *argv[])
ret = do_commandeb(&h, argc, argv, &table, false);
if (ret)
- ret = nft_commit(&h);
+ ret = nft_bridge_commit(&h);
if (!ret)
fprintf(stderr, "ebtables: %s\n", nft_strerror(errno));
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index bc71e122..15b971da 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -20,7 +20,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
+#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
@@ -197,7 +197,8 @@ int ebt_get_current_chain(const char *chain)
else if (strcmp(chain, "POSTROUTING") == 0)
return NF_BR_POST_ROUTING;
- return -1;
+ /* placeholder for user defined chain */
+ return NF_BR_NUMHOOKS;
}
/*
@@ -273,7 +274,7 @@ struct option ebt_original_options[] =
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 = IPTABLES_VERSION,
+ .program_version = PACKAGE_VERSION,
.orig_opts = ebt_original_options,
.exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
@@ -410,7 +411,7 @@ static int list_rules(struct nft_handle *h, const char *chain, const char *table
{
unsigned int format;
- format = FMT_OPTIONS;
+ format = FMT_OPTIONS | FMT_C_COUNTS;
if (verbose)
format |= FMT_VIA;
@@ -593,6 +594,7 @@ void ebt_load_match_extensions(void)
ebt_load_match("pkttype");
ebt_load_match("vlan");
ebt_load_match("stp");
+ ebt_load_match("among");
ebt_load_watcher("log");
ebt_load_watcher("nflog");
@@ -779,6 +781,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
int selected_chain = -1;
struct xtables_rule_match *xtrm_i;
struct ebt_match *match;
+ bool table_set = false;
/* prevent getopt to spoil our error reporting */
optind = 0;
@@ -946,11 +949,16 @@ print_zero:
break;
case 't': /* Table */
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);
*table = optarg;
+ table_set = true;
break;
case 'i': /* Input interface */
case 2 : /* Logical input interface */
@@ -1180,7 +1188,7 @@ print_zero:
if (ebt_command_default(&cs))
xtables_error(PARAMETER_PROBLEM,
"Unknown argument: '%s'",
- argv[optind - 1]);
+ argv[optind]);
if (command != 'A' && command != 'I' &&
command != 'D' && command != 'C')
@@ -1223,7 +1231,7 @@ print_zero:
cs.eb.ethproto = htons(cs.eb.ethproto);
if (command == 'P') {
- if (selected_chain < 0) {
+ if (selected_chain >= NF_BR_NUMHOOKS) {
ret = ebt_set_user_chain_policy(h, *table, chain, policy);
} else {
if (strcmp(policy, "RETURN") == 0) {
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index f835c5e5..a5245d14 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -10,6 +10,8 @@
*/
#define _GNU_SOURCE
+#include "config.h"
+#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
@@ -40,6 +42,7 @@
struct cb_arg {
uint32_t nfproto;
bool is_event;
+ struct nft_handle *h;
};
static int table_cb(const struct nlmsghdr *nlh, void *data)
@@ -105,7 +108,7 @@ static int rule_cb(const struct nlmsghdr *nlh, void *data)
}
printf("-t %s ", nftnl_rule_get_str(r, NFTNL_RULE_TABLE));
- nft_rule_print_save(r, type == NFT_MSG_NEWRULE ? NFT_RULE_APPEND :
+ nft_rule_print_save(arg->h, r, type == NFT_MSG_NEWRULE ? NFT_RULE_APPEND :
NFT_RULE_DEL,
counters ? 0 : FMT_NOCOUNTS);
err_free:
@@ -592,7 +595,10 @@ int xtables_monitor_main(int argc, char *argv[])
struct mnl_socket *nl;
char buf[MNL_SOCKET_BUFFER_SIZE];
uint32_t nfgroup = 0;
- struct cb_arg cb_arg = {};
+ struct nft_handle h = {};
+ struct cb_arg cb_arg = {
+ .h = &h,
+ };
int ret, c;
xtables_globals.program_name = "xtables-monitor";
@@ -609,6 +615,14 @@ int xtables_monitor_main(int argc, char *argv[])
init_extensions4();
#endif
+ if (nft_init(&h, xtables_ipv4)) {
+ fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
+ xtables_globals.program_name,
+ xtables_globals.program_version,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
opterr = 0;
while ((c = getopt_long(argc, argv, "ceht46V", options, NULL)) != -1) {
switch (c) {
@@ -631,10 +645,10 @@ int xtables_monitor_main(int argc, char *argv[])
cb_arg.nfproto = NFPROTO_IPV6;
break;
case 'V':
- printf("xtables-monitor %s\n", IPTABLES_VERSION);
+ printf("xtables-monitor %s\n", PACKAGE_VERSION);
exit(0);
default:
- fprintf(stderr, "xtables-monitor %s: Bad argument.\n", IPTABLES_VERSION);
+ fprintf(stderr, "xtables-monitor %s: Bad argument.\n", PACKAGE_VERSION);
fprintf(stderr, "Try `xtables-monitor -h' for more information.\n");
exit(PARAMETER_PROBLEM);
}
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index a6a331d3..2f0fe7d4 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -4,9 +4,10 @@
*
* This code is distributed under the terms of GNU GPL v2
*/
-
+#include "config.h"
#include <getopt.h>
#include <errno.h>
+#include <libgen.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
@@ -17,6 +18,7 @@
#include "xtables-multi.h"
#include "nft.h"
#include "nft-bridge.h"
+#include "nft-cache.h"
#include <libnftnl/chain.h>
static int counters, verbose;
@@ -43,7 +45,7 @@ static const struct option options[] = {
static void print_usage(const char *name, const char *version)
{
- fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-T table] [-M command] [-4] [-6]\n"
+ fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-T table] [-M command] [-4] [-6] [file]\n"
" [ --counters ]\n"
" [ --verbose ]\n"
" [ --version]\n"
@@ -51,25 +53,12 @@ static void print_usage(const char *name, const char *version)
" [ --help ]\n"
" [ --noflush ]\n"
" [ --table=<TABLE> ]\n"
- " [ --modprobe=<command> ]\n"
+ " [ --modprobe=<command> ]\n"
" [ --ipv4 ]\n"
" [ --ipv6 ]\n", name);
}
-static struct nftnl_chain_list *get_chain_list(struct nft_handle *h,
- const char *table)
-{
- struct nftnl_chain_list *chain_list;
-
- chain_list = nft_chain_list_get(h, table);
- if (chain_list == NULL)
- xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n");
-
- return chain_list;
-}
-
-struct nft_xt_restore_cb restore_cb = {
- .chain_list = get_chain_list,
+static const struct nft_xt_restore_cb restore_cb = {
.commit = nft_commit,
.abort = nft_abort,
.table_new = nft_table_new,
@@ -79,241 +68,285 @@ struct nft_xt_restore_cb restore_cb = {
.chain_restore = nft_chain_restore,
};
-static const struct xtc_ops xtc_ops = {
- .strerror = nft_strerror,
+struct nft_xt_restore_state {
+ const struct builtin_table *curtable;
+ struct argv_store av_store;
+ bool in_table;
};
-void xtables_restore_parse(struct nft_handle *h,
- struct nft_xt_restore_parse *p,
- struct nft_xt_restore_cb *cb,
- int argc, char *argv[])
+static void xtables_restore_parse_line(struct nft_handle *h,
+ const struct nft_xt_restore_parse *p,
+ struct nft_xt_restore_state *state,
+ char *buffer)
{
- const struct builtin_table *curtable = NULL;
- char buffer[10240];
- int in_table = 0;
- const struct xtc_ops *ops = &xtc_ops;
+ const struct nft_xt_restore_cb *cb = p->cb;
+ int ret = 0;
+
+ if (buffer[0] == '\n')
+ return;
+ else if (buffer[0] == '#') {
+ if (verbose)
+ fputs(buffer, stdout);
+ return;
+ } else if (state->in_table &&
+ (strncmp(buffer, "COMMIT", 6) == 0) &&
+ (buffer[6] == '\0' || buffer[6] == '\n')) {
+ if (!p->testing) {
+ /* Commit per table, although we support
+ * global commit at once, stick by now to
+ * the existing behaviour.
+ */
+ DEBUGP("Calling commit\n");
+ if (cb->commit)
+ ret = cb->commit(h);
+ } else {
+ DEBUGP("Not calling commit, testing\n");
+ if (cb->abort)
+ ret = cb->abort(h);
+ }
+ state->in_table = false;
+
+ } else if ((buffer[0] == '*') && (!state->in_table || !p->commit)) {
+ /* New table */
+ char *table;
+
+ table = strtok(buffer+1, " \t\n");
+ DEBUGP("line %u, table '%s'\n", line, table);
+ if (!table)
+ xtables_error(PARAMETER_PROBLEM,
+ "%s: line %u table name invalid\n",
+ xt_params->program_name, line);
+
+ state->curtable = nft_table_builtin_find(h, table);
+ if (!state->curtable)
+ xtables_error(PARAMETER_PROBLEM,
+ "%s: line %u table name '%s' invalid\n",
+ xt_params->program_name, line, table);
+
+ if (p->tablename && (strcmp(p->tablename, table) != 0))
+ return;
+
+ if (h->noflush == 0) {
+ DEBUGP("Cleaning all chains of table '%s'\n", table);
+ if (cb->table_flush)
+ cb->table_flush(h, table);
+ }
- line = 0;
+ ret = 1;
+ state->in_table = true;
+
+ if (cb->table_new)
+ cb->table_new(h, table);
+
+ } else if ((buffer[0] == ':') && state->in_table) {
+ /* New chain. */
+ char *policy, *chain = NULL;
+ struct xt_counters count = {};
+
+ chain = strtok(buffer+1, " \t\n");
+ DEBUGP("line %u, chain '%s'\n", line, chain);
+ if (!chain)
+ xtables_error(PARAMETER_PROBLEM,
+ "%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);
+
+ policy = strtok(NULL, " \t\n");
+ DEBUGP("line %u, policy '%s'\n", line, policy);
+ if (!policy)
+ xtables_error(PARAMETER_PROBLEM,
+ "%s: line %u policy invalid\n",
+ xt_params->program_name, line);
+
+ if (nft_chain_builtin_find(state->curtable, chain)) {
+ if (counters) {
+ char *ctrs;
+ ctrs = strtok(NULL, " \t\n");
+
+ if (!ctrs || !parse_counters(ctrs, &count))
+ xtables_error(PARAMETER_PROBLEM,
+ "invalid policy counters for chain '%s'\n",
+ chain);
- /* Grab standard input. */
- while (fgets(buffer, sizeof(buffer), p->in)) {
- int ret = 0;
-
- line++;
- h->error.lineno = line;
-
- if (buffer[0] == '\n')
- continue;
- else if (buffer[0] == '#') {
- if (verbose)
- fputs(buffer, stdout);
- continue;
- } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
- if (!p->testing) {
- /* Commit per table, although we support
- * global commit at once, stick by now to
- * the existing behaviour.
- */
- DEBUGP("Calling commit\n");
- if (cb->commit)
- ret = cb->commit(h);
- } else {
- DEBUGP("Not calling commit, testing\n");
- if (cb->abort)
- ret = cb->abort(h);
}
- in_table = 0;
-
- } else if ((buffer[0] == '*') && (!in_table || !p->commit)) {
- /* New table */
- char *table;
-
- table = strtok(buffer+1, " \t\n");
- DEBUGP("line %u, table '%s'\n", line, table);
- if (!table) {
- xtables_error(PARAMETER_PROBLEM,
- "%s: line %u table name invalid\n",
- xt_params->program_name, line);
- exit(1);
- }
- curtable = nft_table_builtin_find(h, table);
- if (!curtable)
- xtables_error(PARAMETER_PROBLEM,
- "%s: line %u table name '%s' invalid\n",
- xt_params->program_name, line, table);
-
- if (p->tablename && (strcmp(p->tablename, table) != 0))
- continue;
-
- nft_build_cache(h);
-
- if (h->noflush == 0) {
- DEBUGP("Cleaning all chains of table '%s'\n",
- table);
- if (cb->table_flush)
- cb->table_flush(h, table);
+ if (cb->chain_set &&
+ cb->chain_set(h, state->curtable->name,
+ chain, policy, &count) < 0) {
+ xtables_error(OTHER_PROBLEM,
+ "Can't set policy `%s' on `%s' line %u: %s\n",
+ policy, chain, line,
+ strerror(errno));
}
+ DEBUGP("Setting policy of chain %s to %s\n",
+ chain, policy);
+ } else if (cb->chain_restore(h, chain, state->curtable->name) < 0 &&
+ errno != EEXIST) {
+ xtables_error(PARAMETER_PROBLEM,
+ "cannot create chain '%s' (%s)\n",
+ chain, strerror(errno));
+ } else if (h->family == NFPROTO_BRIDGE &&
+ !ebt_set_user_chain_policy(h, state->curtable->name,
+ chain, policy)) {
+ xtables_error(OTHER_PROBLEM,
+ "Can't set policy `%s' on `%s' line %u: %s\n",
+ policy, chain, line,
+ strerror(errno));
+ }
+ ret = 1;
+ } else if (state->in_table) {
+ char *pcnt = NULL;
+ char *bcnt = NULL;
+ char *parsestart = buffer;
+
+ 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);
+
+ tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line);
+ if (counters && pcnt && bcnt) {
+ add_argv(&state->av_store, "--set-counters", 0);
+ add_argv(&state->av_store, pcnt, 0);
+ add_argv(&state->av_store, bcnt, 0);
+ }
- ret = 1;
- in_table = 1;
-
- if (cb->table_new)
- cb->table_new(h, table);
+ add_param_to_argv(&state->av_store, parsestart, line);
- } else if ((buffer[0] == ':') && (in_table)) {
- /* New chain. */
- char *policy, *chain = NULL;
- struct xt_counters count = {};
+ DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
+ state->av_store.argc, state->curtable->name);
+ debug_print_argv(&state->av_store);
- chain = strtok(buffer+1, " \t\n");
- DEBUGP("line %u, chain '%s'\n", line, chain);
- if (!chain) {
- xtables_error(PARAMETER_PROBLEM,
- "%s: line %u chain name invalid\n",
- xt_params->program_name, line);
- exit(1);
- }
+ ret = cb->do_command(h, state->av_store.argc,
+ state->av_store.argv,
+ &state->av_store.argv[2], true);
+ if (ret < 0) {
+ if (cb->abort)
+ ret = cb->abort(h);
+ else
+ ret = 0;
- if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s' "
- "(%u chars max)",
- chain, XT_EXTENSION_MAXNAMELEN - 1);
-
- policy = strtok(NULL, " \t\n");
- DEBUGP("line %u, policy '%s'\n", line, policy);
- if (!policy) {
- xtables_error(PARAMETER_PROBLEM,
- "%s: line %u policy invalid\n",
- xt_params->program_name, line);
- exit(1);
+ if (ret < 0) {
+ fprintf(stderr,
+ "failed to abort commit operation\n");
}
+ exit(1);
+ }
- if (nft_chain_builtin_find(curtable, chain)) {
- if (counters) {
- char *ctrs;
- ctrs = strtok(NULL, " \t\n");
-
- if (!ctrs || !parse_counters(ctrs, &count))
- xtables_error(PARAMETER_PROBLEM,
- "invalid policy counters "
- "for chain '%s'\n", chain);
-
- }
- if (cb->chain_set &&
- cb->chain_set(h, curtable->name,
- chain, policy, &count) < 0) {
- xtables_error(OTHER_PROBLEM,
- "Can't set policy `%s'"
- " on `%s' line %u: %s\n",
- policy, chain, line,
- ops->strerror(errno));
- }
- DEBUGP("Setting policy of chain %s to %s\n",
- chain, policy);
- } else if (cb->chain_restore(h, chain, curtable->name) < 0 &&
- errno != EEXIST) {
- xtables_error(PARAMETER_PROBLEM,
- "cannot create chain "
- "'%s' (%s)\n", chain,
- strerror(errno));
- } else if (h->family == NFPROTO_BRIDGE &&
- !ebt_set_user_chain_policy(h, curtable->name,
- chain, policy)) {
- xtables_error(OTHER_PROBLEM,
- "Can't set policy `%s'"
- " on `%s' line %u: %s\n",
- policy, chain, line,
- ops->strerror(errno));
- }
- ret = 1;
- } else if (in_table) {
- int a;
- char *pcnt = NULL;
- char *bcnt = NULL;
- char *parsestart;
+ free_argv(&state->av_store);
+ fflush(stdout);
+ }
+ if (p->tablename && state->curtable &&
+ (strcmp(p->tablename, state->curtable->name) != 0))
+ return;
+ if (!ret) {
+ fprintf(stderr, "%s: line %u failed\n",
+ xt_params->program_name, line);
+ exit(1);
+ }
+}
- /* reset the newargv */
- newargc = 0;
+/* Return true if given iptables-restore line will require a full cache.
+ * Typically these are commands referring to an existing rule
+ * (either by number or content) or commands listing the ruleset. */
+static bool cmd_needs_full_cache(char *cmd)
+{
+ char c, chain[32];
+ int rulenum, mcount;
+
+ mcount = sscanf(cmd, "-%c %31s %d", &c, chain, &rulenum);
+
+ if (mcount == 3)
+ return true;
+ if (mcount < 1)
+ return false;
+
+ switch (c) {
+ case 'D':
+ case 'C':
+ case 'S':
+ case 'L':
+ case 'Z':
+ return true;
+ }
- if (buffer[0] == '[') {
- /* we have counters in our input */
- char *ptr = strchr(buffer, ']');
+ return false;
+}
- if (!ptr)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need ]\n",
- line);
+#define PREBUFSIZ 65536
- pcnt = strtok(buffer+1, ":");
- if (!pcnt)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need :\n",
- line);
+void xtables_restore_parse(struct nft_handle *h,
+ const struct nft_xt_restore_parse *p)
+{
+ struct nft_xt_restore_state state = {};
+ char preload_buffer[PREBUFSIZ] = {}, buffer[10240], *ptr;
- bcnt = strtok(NULL, "]");
- if (!bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "Bad line %u: need ]\n",
- line);
-
- /* start command parsing after counter */
- parsestart = ptr + 1;
- } else {
- /* start command parsing at start of line */
- parsestart = buffer;
+ if (!h->noflush) {
+ nft_fake_cache(h);
+ } else {
+ ssize_t pblen = sizeof(preload_buffer);
+ bool do_cache = false;
+
+ ptr = preload_buffer;
+ while (fgets(buffer, sizeof(buffer), p->in)) {
+ size_t blen = strlen(buffer);
+
+ /* drop trailing newline; xtables_restore_parse_line()
+ * uses strtok() which replaces them by nul-characters,
+ * causing unpredictable string delimiting in
+ * preload_buffer */
+ if (buffer[blen - 1] == '\n')
+ buffer[blen - 1] = '\0';
+ else
+ blen++;
+
+ pblen -= blen;
+ if (pblen <= 0) {
+ /* buffer exhausted */
+ do_cache = true;
+ break;
}
- add_argv(argv[0], 0);
- add_argv("-t", 0);
- add_argv(curtable->name, 0);
-
- if (counters && pcnt && bcnt) {
- add_argv("--set-counters", 0);
- add_argv((char *) pcnt, 0);
- add_argv((char *) bcnt, 0);
+ if (cmd_needs_full_cache(buffer)) {
+ do_cache = true;
+ break;
}
- add_param_to_argv(parsestart, line);
-
- DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
- newargc, curtable->name);
-
- for (a = 0; a < newargc; a++)
- DEBUGP("argv[%u]: %s\n", a, newargv[a]);
+ /* copy string including terminating nul-char */
+ memcpy(ptr, buffer, blen);
+ ptr += blen;
+ buffer[0] = '\0';
+ }
- ret = cb->do_command(h, newargc, newargv,
- &newargv[2], true);
- if (ret < 0) {
- if (cb->abort)
- ret = cb->abort(h);
- else
- ret = 0;
-
- if (ret < 0) {
- fprintf(stderr, "failed to abort "
- "commit operation\n");
- }
- exit(1);
- }
+ if (do_cache)
+ nft_build_cache(h, NULL);
+ }
- free_argv();
- fflush(stdout);
- }
- if (p->tablename && curtable &&
- (strcmp(p->tablename, curtable->name) != 0))
- continue;
- if (!ret) {
- fprintf(stderr, "%s: line %u failed\n",
- xt_params->program_name, line);
- exit(1);
- }
+ line = 0;
+ ptr = preload_buffer;
+ while (*ptr) {
+ h->error.lineno = ++line;
+ DEBUGP("%s: buffered line %d: '%s'\n", __func__, line, ptr);
+ xtables_restore_parse_line(h, p, &state, ptr);
+ ptr += strlen(ptr) + 1;
+ }
+ if (*buffer) {
+ h->error.lineno = ++line;
+ DEBUGP("%s: overrun line %d: '%s'\n", __func__, line, buffer);
+ xtables_restore_parse_line(h, p, &state, buffer);
}
- if (in_table && p->commit) {
+ while (fgets(buffer, sizeof(buffer), p->in)) {
+ h->error.lineno = ++line;
+ DEBUGP("%s: input line %d: '%s'\n", __func__, line, buffer);
+ xtables_restore_parse_line(h, p, &state, buffer);
+ }
+ if (state.in_table && p->commit) {
fprintf(stderr, "%s: COMMIT expected at line %u\n",
xt_params->program_name, line + 1);
exit(1);
- } else if (in_table && cb->commit && !cb->commit(h)) {
+ } else if (state.in_table && p->cb->commit && !p->cb->commit(h)) {
xtables_error(OTHER_PROBLEM, "%s: final implicit COMMIT failed",
xt_params->program_name);
}
@@ -330,6 +363,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
int c;
struct nft_xt_restore_parse p = {
.commit = true,
+ .cb = &restore_cb,
};
line = 0;
@@ -361,8 +395,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
p.testing = 1;
break;
case 'h':
- print_usage("xtables-restore",
- IPTABLES_VERSION);
+ print_usage(prog_name, PACKAGE_VERSION);
exit(0);
case 'n':
h.noflush = 1;
@@ -387,7 +420,8 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
break;
default:
fprintf(stderr,
- "Try `xtables-restore -h' for more information.\n");
+ "Try `%s -h' for more information.\n",
+ prog_name);
exit(1);
}
}
@@ -434,7 +468,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
exit(EXIT_FAILURE);
}
- xtables_restore_parse(&h, &p, &restore_cb, argc, argv);
+ xtables_restore_parse(&h, &p);
nft_fini(&h);
fclose(p.in);
@@ -443,13 +477,13 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
int xtables_ip4_restore_main(int argc, char *argv[])
{
- return xtables_restore_main(NFPROTO_IPV4, "iptables-restore",
+ return xtables_restore_main(NFPROTO_IPV4, basename(*argv),
argc, argv);
}
int xtables_ip6_restore_main(int argc, char *argv[])
{
- return xtables_restore_main(NFPROTO_IPV6, "ip6tables-restore",
+ return xtables_restore_main(NFPROTO_IPV6, basename(*argv),
argc, argv);
}
@@ -460,9 +494,8 @@ static int ebt_table_flush(struct nft_handle *h, const char *table)
return nft_table_flush(h, table);
}
-struct nft_xt_restore_cb ebt_restore_cb = {
- .chain_list = get_chain_list,
- .commit = nft_commit,
+static const struct nft_xt_restore_cb ebt_restore_cb = {
+ .commit = nft_bridge_commit,
.table_new = nft_table_new,
.table_flush = ebt_table_flush,
.do_command = do_commandeb,
@@ -479,6 +512,7 @@ int xtables_eb_restore_main(int argc, char *argv[])
{
struct nft_xt_restore_parse p = {
.in = stdin,
+ .cb = &ebt_restore_cb,
};
bool noflush = false;
struct nft_handle h;
@@ -500,14 +534,13 @@ int xtables_eb_restore_main(int argc, char *argv[])
nft_init_eb(&h, "ebtables-restore");
h.noflush = noflush;
- xtables_restore_parse(&h, &p, &ebt_restore_cb, argc, argv);
+ xtables_restore_parse(&h, &p);
nft_fini(&h);
return 0;
}
-struct nft_xt_restore_cb arp_restore_cb = {
- .chain_list = get_chain_list,
+static const struct nft_xt_restore_cb arp_restore_cb = {
.commit = nft_commit,
.table_new = nft_table_new,
.table_flush = nft_table_flush,
@@ -520,11 +553,12 @@ int xtables_arp_restore_main(int argc, char *argv[])
{
struct nft_xt_restore_parse p = {
.in = stdin,
+ .cb = &arp_restore_cb,
};
struct nft_handle h;
nft_init_arp(&h, "arptables-restore");
- xtables_restore_parse(&h, &p, &arp_restore_cb, argc, argv);
+ xtables_restore_parse(&h, &p);
nft_fini(&h);
return 0;
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 2cc5a7c7..3a52f8c3 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -6,8 +6,10 @@
* This code is distributed under the terms of GNU GPL v2
*
*/
+#include "config.h"
#include <getopt.h>
#include <errno.h>
+#include <libgen.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -19,6 +21,7 @@
#include "iptables.h"
#include "xtables-multi.h"
#include "nft.h"
+#include "nft-cache.h"
#include <libnftnl/chain.h>
@@ -29,9 +32,8 @@
#define prog_name xtables_globals.program_name
#define prog_vers xtables_globals.program_version
-static bool show_counters = false;
-
-static const struct option options[] = {
+static const char *ipt_save_optstring = "bcdt:M:f:46V";
+static const struct option ipt_save_options[] = {
{.name = "counters", .has_arg = false, .val = 'c'},
{.name = "version", .has_arg = false, .val = 'V'},
{.name = "dump", .has_arg = false, .val = 'd'},
@@ -43,6 +45,7 @@ static const struct option options[] = {
{NULL},
};
+static const char *arp_save_optstring = "cM:V";
static const struct option arp_save_options[] = {
{.name = "counters", .has_arg = false, .val = 'c'},
{.name = "version", .has_arg = false, .val = 'V'},
@@ -50,6 +53,7 @@ static const struct option arp_save_options[] = {
{NULL},
};
+static const char *ebt_save_optstring = "ct:M:V";
static const struct option ebt_save_options[] = {
{.name = "counters", .has_arg = false, .val = 'c'},
{.name = "version", .has_arg = false, .val = 'V'},
@@ -58,49 +62,55 @@ static const struct option ebt_save_options[] = {
{NULL},
};
-static bool ebt_legacy_counter_format;
+struct do_output_data {
+ unsigned int format;
+ bool commit;
+};
static int
-__do_output(struct nft_handle *h, const char *tablename, bool counters)
+__do_output(struct nft_handle *h, const char *tablename, void *data)
{
struct nftnl_chain_list *chain_list;
+ struct do_output_data *d = data;
+ time_t now;
+ if (!nft_table_builtin_find(h, tablename))
+ return 0;
- if (!nft_is_table_compatible(h, tablename)) {
- if (!nft_table_builtin_find(h, tablename))
- printf("# Table `%s' is incompatible, use 'nft' tool.\n",
- tablename);
+ if (!nft_is_table_compatible(h, tablename, NULL)) {
+ printf("# Table `%s' is incompatible, use 'nft' tool.\n",
+ tablename);
return 0;
}
- chain_list = nft_chain_list_get(h, tablename);
+ chain_list = nft_chain_list_get(h, tablename, NULL);
if (!chain_list)
return 0;
- time_t now = time(NULL);
+ now = time(NULL);
+ printf("# Generated by %s v%s on %s", prog_name,
+ prog_vers, ctime(&now));
- printf("# Generated by xtables-save v%s on %s",
- IPTABLES_VERSION, ctime(&now));
printf("*%s\n", tablename);
-
/* Dump out chain names first,
* thereby preventing dependency conflicts */
nft_chain_save(h, chain_list);
- nft_rule_save(h, tablename, counters ? 0 : FMT_NOCOUNTS);
+ nft_rule_save(h, tablename, d->format);
+ if (d->commit)
+ printf("COMMIT\n");
now = time(NULL);
- printf("COMMIT\n");
printf("# Completed on %s", ctime(&now));
return 0;
}
static int
-do_output(struct nft_handle *h, const char *tablename, bool counters)
+do_output(struct nft_handle *h, const char *tablename, struct do_output_data *d)
{
int ret;
if (!tablename) {
- ret = nft_for_each_table(h, __do_output, counters);
+ ret = nft_for_each_table(h, __do_output, d);
nft_check_xt_legacy(h->family, true);
return !!ret;
}
@@ -111,7 +121,7 @@ do_output(struct nft_handle *h, const char *tablename, bool counters)
return 1;
}
- ret = __do_output(h, tablename, counters);
+ ret = __do_output(h, tablename, d);
nft_check_xt_legacy(h->family, true);
return ret;
}
@@ -121,10 +131,14 @@ do_output(struct nft_handle *h, const char *tablename, bool counters)
* rule
*/
static int
-xtables_save_main(int family, const char *progname, int argc, char *argv[])
+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,
+ };
bool dump = false;
struct nft_handle h = {
.family = family,
@@ -132,7 +146,7 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
FILE *file = NULL;
int ret, c;
- xtables_globals.program_name = progname;
+ xtables_globals.program_name = basename(*argv);;
c = xtables_init_all(&xtables_globals, family);
if (c < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
@@ -141,13 +155,13 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
exit(1);
}
- while ((c = getopt_long(argc, argv, "bcdt:M:f:46V", options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) {
switch (c) {
case 'b':
fprintf(stderr, "-b/--binary option is not implemented\n");
break;
case 'c':
- show_counters = true;
+ d.format &= ~FMT_NOCOUNTS;
break;
case 't':
@@ -206,13 +220,23 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
init_extensions4();
#endif
tables = xtables_ipv4;
+ d.commit = true;
break;
case NFPROTO_ARP:
tables = xtables_arp;
break;
- case NFPROTO_BRIDGE:
+ case NFPROTO_BRIDGE: {
+ const char *ctr = getenv("EBTABLES_SAVE_COUNTER");
+
+ if (!(d.format & FMT_NOCOUNTS)) {
+ d.format |= FMT_EBT_SAVE;
+ } else if (ctr && !strcmp(ctr, "yes")) {
+ d.format &= ~FMT_NOCOUNTS;
+ d.format |= FMT_C_COUNTS | FMT_EBT_SAVE;
+ }
tables = xtables_bridge;
break;
+ }
default:
fprintf(stderr, "Unknown family %d\n", family);
return 1;
@@ -225,8 +249,11 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
strerror(errno));
exit(EXIT_FAILURE);
}
+ h.ops = nft_family_ops_lookup(h.family);
+ if (!h.ops)
+ xtables_error(PARAMETER_PROBLEM, "Unknown family");
- ret = do_output(&h, tablename, show_counters);
+ ret = do_output(&h, tablename, &d);
nft_fini(&h);
if (dump)
exit(0);
@@ -236,178 +263,24 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
int xtables_ip4_save_main(int argc, char *argv[])
{
- return xtables_save_main(NFPROTO_IPV4, "iptables-save", argc, argv);
+ return xtables_save_main(NFPROTO_IPV4, argc, argv,
+ ipt_save_optstring, ipt_save_options);
}
int xtables_ip6_save_main(int argc, char *argv[])
{
- return xtables_save_main(NFPROTO_IPV6, "ip6tables-save", argc, argv);
-}
-
-static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters)
-{
- struct nftnl_chain_list *chain_list;
- unsigned int format = FMT_NOCOUNTS;
- static bool first = true;
- time_t now;
-
- if (!nft_table_find(h, tablename)) {
- printf("Table `%s' does not exist\n", tablename);
- return 1;
- }
-
- if (!nft_is_table_compatible(h, tablename)) {
- printf("# Table `%s' is incompatible, use 'nft' tool.\n", tablename);
- return 0;
- }
-
- chain_list = nft_chain_list_get(h, tablename);
-
- if (first) {
- now = time(NULL);
- printf("# Generated by ebtables-save v%s on %s",
- IPTABLES_VERSION, ctime(&now));
- first = false;
- }
- printf("*%s\n", tablename);
-
- if (counters)
- format = ebt_legacy_counter_format ? FMT_EBT_SAVE : 0;
-
- /* Dump out chain names first,
- * thereby preventing dependency conflicts */
- nft_chain_save(h, chain_list);
- nft_rule_save(h, tablename, format);
- printf("\n");
- return 0;
+ return xtables_save_main(NFPROTO_IPV6, argc, argv,
+ ipt_save_optstring, ipt_save_options);
}
-static int ebt_save(struct nft_handle *h, const char *tablename, bool counters)
+int xtables_eb_save_main(int argc, char *argv[])
{
- if (!tablename)
- return nft_for_each_table(h, __ebt_save, counters);
-
- return __ebt_save(h, tablename, counters);
+ return xtables_save_main(NFPROTO_BRIDGE, argc, argv,
+ ebt_save_optstring, ebt_save_options);
}
-int xtables_eb_save_main(int argc_, char *argv_[])
+int xtables_arp_save_main(int argc, char *argv[])
{
- const char *ctr = getenv("EBTABLES_SAVE_COUNTER");
- const char *tablename = NULL;
- struct nft_handle h = {
- .family = NFPROTO_BRIDGE,
- };
- int c;
-
- if (ctr) {
- if (strcmp(ctr, "yes") == 0) {
- ebt_legacy_counter_format = true;
- show_counters = true;
- }
- }
-
- xtables_globals.program_name = "ebtables-save";
- c = xtables_init_all(&xtables_globals, h.family);
- if (c < 0) {
- fprintf(stderr, "%s/%s Failed to initialize xtables\n",
- xtables_globals.program_name,
- xtables_globals.program_version);
- exit(1);
- }
-
- while ((c = getopt_long(argc_, argv_, "ct:M:V", ebt_save_options, NULL)) != -1) {
- switch (c) {
- case 'c':
- unsetenv("EBTABLES_SAVE_COUNTER");
- show_counters = true;
- ebt_legacy_counter_format = false;
- break;
- case 't':
- /* Select specific table. */
- tablename = optarg;
- break;
- case 'M':
- xtables_modprobe_program = optarg;
- break;
- case 'V':
- printf("%s v%s (nf_tables)\n", prog_name, prog_vers);
- exit(0);
- default:
- fprintf(stderr,
- "Look at manual page `%s.8' for more information.\n",
- prog_name);
- exit(1);
- }
- }
-
- if (nft_init(&h, xtables_bridge) < 0) {
- fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
- xtables_globals.program_name,
- xtables_globals.program_version,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- ebt_save(&h, tablename, show_counters);
- nft_fini(&h);
- return 0;
-}
-
-int xtables_arp_save_main(int argc, char **argv)
-{
- struct nft_handle h = {
- .family = NFPROTO_ARP,
- };
- int c;
-
- xtables_globals.program_name = "arptables-save";
- c = xtables_init_all(&xtables_globals, h.family);
- if (c < 0) {
- fprintf(stderr, "%s/%s Failed to initialize xtables\n",
- xtables_globals.program_name,
- xtables_globals.program_version);
- exit(1);
- }
-
- while ((c = getopt_long(argc, argv, "cM:V", arp_save_options, NULL)) != -1) {
- switch (c) {
- case 'c':
- show_counters = true;
- break;
- case 'M':
- xtables_modprobe_program = optarg;
- break;
- case 'V':
- printf("%s v%s (nf_tables)\n", prog_name, prog_vers);
- exit(0);
- default:
- fprintf(stderr,
- "Look at manual page `%s.8' for more information.\n",
- prog_name);
- exit(1);
- }
- }
-
- if (nft_init(&h, xtables_arp) < 0) {
- fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
- xtables_globals.program_name,
- xtables_globals.program_version,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- if (!nft_table_find(&h, "filter"))
- return 0;
-
- if (!nft_is_table_compatible(&h, "filter")) {
- printf("# Table `filter' is incompatible, use 'nft' tool.\n");
- return 0;
- }
-
- printf("*filter\n");
- nft_chain_save(&h, nft_chain_list_get(&h, "filter"));
- nft_rule_save(&h, "filter", show_counters ? 0 : FMT_NOCOUNTS);
- printf("\n");
- nft_fini(&h);
- return 0;
+ return xtables_save_main(NFPROTO_ARP, argc, argv,
+ arp_save_optstring, arp_save_options);
}
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index eb35890a..a42c60a3 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -6,7 +6,7 @@
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-
+#include "config.h"
#include <time.h>
#include "xtables-multi.h"
#include "nft.h"
@@ -413,7 +413,7 @@ static int dummy_compat_rev(const char *name, uint8_t rev, int opt)
return 1;
}
-static struct nft_xt_restore_cb cb_xlate = {
+static const struct nft_xt_restore_cb cb_xlate = {
.table_new = xlate_table_new,
.chain_set = xlate_chain_set,
.chain_restore = xlate_chain_user_restore,
@@ -498,7 +498,9 @@ static int xtables_restore_xlate_main(int family, const char *progname,
.family = family,
};
const char *file = NULL;
- struct nft_xt_restore_parse p = {};
+ struct nft_xt_restore_parse p = {
+ .cb = &cb_xlate,
+ };
time_t now = time(NULL);
int c;
@@ -510,20 +512,20 @@ static int xtables_restore_xlate_main(int family, const char *progname,
while ((c = getopt_long(argc, argv, "hf:V", options, NULL)) != -1) {
switch (c) {
case 'h':
- print_usage(argv[0], IPTABLES_VERSION);
+ print_usage(argv[0], PACKAGE_VERSION);
exit(0);
case 'f':
file = optarg;
break;
case 'V':
- printf("%s v%s\n", argv[0], IPTABLES_VERSION);
+ printf("%s v%s\n", argv[0], PACKAGE_VERSION);
exit(0);
}
}
if (file == NULL) {
fprintf(stderr, "ERROR: missing file name\n");
- print_usage(argv[0], IPTABLES_VERSION);
+ print_usage(argv[0], PACKAGE_VERSION);
exit(0);
}
@@ -534,8 +536,8 @@ static int xtables_restore_xlate_main(int family, const char *progname,
}
printf("# Translated by %s v%s on %s",
- argv[0], IPTABLES_VERSION, ctime(&now));
- xtables_restore_parse(&h, &p, &cb_xlate, argc, argv);
+ argv[0], PACKAGE_VERSION, ctime(&now));
+ xtables_restore_parse(&h, &p);
printf("# Completed on %s", ctime(&now));
nft_fini(&h);
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 44986a37..8f9dc628 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -24,7 +24,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
+#include "config.h"
#include <getopt.h>
#include <string.h>
#include <netdb.h>
@@ -43,17 +43,6 @@
#include "nft-shared.h"
#include "nft.h"
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#define NUMBER_OF_CMD 16
-static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
- 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
-
#define OPT_FRAGMENT 0x00800U
#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
static const char optflags[]
@@ -104,7 +93,7 @@ void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __at
struct xtables_globals xtables_globals = {
.option_offset = 0,
- .program_version = IPTABLES_VERSION,
+ .program_version = PACKAGE_VERSION,
.orig_opts = original_opts,
.exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
@@ -319,27 +308,6 @@ opt2char(int option)
return *ptr;
}
-static char
-cmd2char(int option)
-{
- const char *ptr;
- for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
-static void
-add_command(unsigned int *cmd, const int newcmd, const int othercmds,
- int invert)
-{
- if (invert)
- xtables_error(PARAMETER_PROBLEM, "unexpected ! flag");
- if (*cmd & (~othercmds))
- xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
- cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
- *cmd |= newcmd;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
@@ -350,18 +318,6 @@ add_command(unsigned int *cmd, const int newcmd, const int othercmds,
*/
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
-/* Can't be zero. */
-static int
-parse_rulenumber(const char *rule)
-{
- unsigned int rulenum;
-
- if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid rule number `%s'", rule);
-
- return rulenum;
-}
static void
set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
@@ -590,6 +546,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
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));
@@ -879,11 +836,16 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
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':
@@ -955,6 +917,9 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
break;
case '4':
+ if (p->restore && args->family == AF_INET6)
+ return;
+
if (args->family != AF_INET)
exit_tryhelp(2);
@@ -962,6 +927,9 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
break;
case '6':
+ if (p->restore && args->family == AF_INET)
+ return;
+
args->family = AF_INET6;
xtables_set_nfproto(AF_INET6);
@@ -977,7 +945,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
xtables_error(PARAMETER_PROBLEM,
"multiple consecutive ! not"
" allowed");
- cs->invert = TRUE;
+ cs->invert = true;
optarg[0] = '\0';
continue;
}
@@ -990,7 +958,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
continue;
break;
}
- cs->invert = FALSE;
+ cs->invert = false;
}
if (strcmp(p->table, "nat") == 0 &&
@@ -1174,6 +1142,9 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
case CMD_SET_POLICY:
ret = nft_chain_set(h, p.table, p.chain, p.policy, NULL);
break;
+ case CMD_NONE:
+ /* do_parse ignored the line (eg: -4 with ip6tables-restore) */
+ break;
default:
/* We should never reach this... */
exit_tryhelp(2);
diff --git a/libiptc/Makefile.am b/libiptc/Makefile.am
index 638295db..464a0696 100644
--- a/libiptc/Makefile.am
+++ b/libiptc/Makefile.am
@@ -5,11 +5,8 @@ AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}
pkgconfig_DATA = libiptc.pc libip4tc.pc libip6tc.pc
-lib_LTLIBRARIES = libip4tc.la libip6tc.la libiptc.la
-libiptc_la_SOURCES =
-libiptc_la_LIBADD = libip4tc.la libip6tc.la
-libiptc_la_LDFLAGS = -version-info 0:0:0 ${libiptc_LDFLAGS2}
+lib_LTLIBRARIES = libip4tc.la libip6tc.la
libip4tc_la_SOURCES = libip4tc.c
libip4tc_la_LDFLAGS = -version-info 2:0:0
libip6tc_la_SOURCES = libip6tc.c
-libip6tc_la_LDFLAGS = -version-info 2:0:0 ${libiptc_LDFLAGS2}
+libip6tc_la_LDFLAGS = -version-info 2:0:0
diff --git a/libiptc/libip4tc.c b/libiptc/libip4tc.c
index 2b029d40..08147055 100644
--- a/libiptc/libip4tc.c
+++ b/libiptc/libip4tc.c
@@ -308,178 +308,4 @@ check_entry(const STRUCT_ENTRY *e, unsigned int *i, unsigned int *off,
(*i)++;
return 0;
}
-
-#ifdef IPTC_DEBUG
-/* Do every conceivable sanity check on the handle */
-static void
-do_check(struct xtc_handle *h, unsigned int line)
-{
- unsigned int i, n;
- unsigned int user_offset; /* Offset of first user chain */
- int was_return;
-
- assert(h->changed == 0 || h->changed == 1);
- if (strcmp(h->info.name, "filter") == 0) {
- assert(h->info.valid_hooks
- == (1 << NF_IP_LOCAL_IN
- | 1 << NF_IP_FORWARD
- | 1 << NF_IP_LOCAL_OUT));
-
- /* Hooks should be first three */
- assert(h->info.hook_entry[NF_IP_LOCAL_IN] == 0);
-
- n = get_chain_end(h, 0);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_FORWARD] == n);
-
- n = get_chain_end(h, n);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
-
- user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
- } else if (strcmp(h->info.name, "nat") == 0) {
- assert((h->info.valid_hooks
- == (1 << NF_IP_PRE_ROUTING
- | 1 << NF_IP_POST_ROUTING
- | 1 << NF_IP_LOCAL_OUT)) ||
- (h->info.valid_hooks
- == (1 << NF_IP_PRE_ROUTING
- | 1 << NF_IP_LOCAL_IN
- | 1 << NF_IP_POST_ROUTING
- | 1 << NF_IP_LOCAL_OUT)));
-
- assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
-
- n = get_chain_end(h, 0);
-
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
- n = get_chain_end(h, n);
-
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
- user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
-
- if (h->info.valid_hooks & (1 << NF_IP_LOCAL_IN)) {
- n = get_chain_end(h, n);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_LOCAL_IN] == n);
- user_offset = h->info.hook_entry[NF_IP_LOCAL_IN];
- }
-
- } else if (strcmp(h->info.name, "mangle") == 0) {
- /* This code is getting ugly because linux < 2.4.18-pre6 had
- * two mangle hooks, linux >= 2.4.18-pre6 has five mangle hooks
- * */
- assert((h->info.valid_hooks
- == (1 << NF_IP_PRE_ROUTING
- | 1 << NF_IP_LOCAL_OUT)) ||
- (h->info.valid_hooks
- == (1 << NF_IP_PRE_ROUTING
- | 1 << NF_IP_LOCAL_IN
- | 1 << NF_IP_FORWARD
- | 1 << NF_IP_LOCAL_OUT
- | 1 << NF_IP_POST_ROUTING)));
-
- /* Hooks should be first five */
- assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
-
- n = get_chain_end(h, 0);
-
- if (h->info.valid_hooks & (1 << NF_IP_LOCAL_IN)) {
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_LOCAL_IN] == n);
- n = get_chain_end(h, n);
- }
-
- if (h->info.valid_hooks & (1 << NF_IP_FORWARD)) {
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_FORWARD] == n);
- n = get_chain_end(h, n);
- }
-
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
- user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
-
- if (h->info.valid_hooks & (1 << NF_IP_POST_ROUTING)) {
- n = get_chain_end(h, n);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
- user_offset = h->info.hook_entry[NF_IP_POST_ROUTING];
- }
- } else if (strcmp(h->info.name, "raw") == 0) {
- assert(h->info.valid_hooks
- == (1 << NF_IP_PRE_ROUTING
- | 1 << NF_IP_LOCAL_OUT));
-
- /* Hooks should be first three */
- assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
-
- n = get_chain_end(h, n);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
-
- user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
- } else {
- fprintf(stderr, "Unknown table `%s'\n", h->info.name);
- abort();
- }
-
- /* User chain == end of last builtin + policy entry */
- user_offset = get_chain_end(h, user_offset);
- user_offset += get_entry(h, user_offset)->next_offset;
-
- /* Overflows should be end of entry chains, and unconditional
- policy nodes. */
- for (i = 0; i < NUMHOOKS; i++) {
- STRUCT_ENTRY *e;
- STRUCT_STANDARD_TARGET *t;
-
- if (!(h->info.valid_hooks & (1 << i)))
- continue;
- assert(h->info.underflow[i]
- == get_chain_end(h, h->info.hook_entry[i]));
-
- e = get_entry(h, get_chain_end(h, h->info.hook_entry[i]));
- assert(unconditional(&e->ip));
- assert(e->target_offset == sizeof(*e));
- t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
- assert(t->target.u.target_size == ALIGN(sizeof(*t)));
- assert(e->next_offset == sizeof(*e) + ALIGN(sizeof(*t)));
-
- assert(strcmp(t->target.u.user.name, STANDARD_TARGET)==0);
- assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1);
-
- /* Hooks and underflows must be valid entries */
- entry2index(h, get_entry(h, h->info.hook_entry[i]));
- entry2index(h, get_entry(h, h->info.underflow[i]));
- }
-
- assert(h->info.size
- >= h->info.num_entries * (sizeof(STRUCT_ENTRY)
- +sizeof(STRUCT_STANDARD_TARGET)));
-
- assert(h->entries.size
- >= (h->new_number
- * (sizeof(STRUCT_ENTRY)
- + sizeof(STRUCT_STANDARD_TARGET))));
- assert(strcmp(h->info.name, h->entries.name) == 0);
-
- i = 0; n = 0;
- was_return = 0;
- /* Check all the entries. */
- ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
- check_entry, &i, &n, user_offset, &was_return, h);
-
- assert(i == h->new_number);
- assert(n == h->entries.size);
-
- /* Final entry must be error node */
- assert(strcmp(GET_TARGET(index2entry(h, h->new_number-1))
- ->u.user.name,
- ERROR_TARGET) == 0);
-}
-#endif /*IPTC_DEBUG*/
-
#endif
diff --git a/libiptc/libip6tc.c b/libiptc/libip6tc.c
index 4e47e698..91676c4a 100644
--- a/libiptc/libip6tc.c
+++ b/libiptc/libip6tc.c
@@ -244,6 +244,7 @@ is_same(const STRUCT_ENTRY *a, const STRUCT_ENTRY *b,
return mptr;
}
+#if 0
/* All zeroes == unconditional rule. */
static inline int
unconditional(const struct ip6t_ip6 *ipv6)
@@ -256,181 +257,4 @@ unconditional(const struct ip6t_ip6 *ipv6)
return (i == sizeof(*ipv6));
}
-
-#ifdef IPTC_DEBUG
-/* Do every conceivable sanity check on the handle */
-static void
-do_check(struct xtc_handle *h, unsigned int line)
-{
- unsigned int i, n;
- unsigned int user_offset; /* Offset of first user chain */
- int was_return;
-
- assert(h->changed == 0 || h->changed == 1);
- if (strcmp(h->info.name, "filter") == 0) {
- assert(h->info.valid_hooks
- == (1 << NF_IP6_LOCAL_IN
- | 1 << NF_IP6_FORWARD
- | 1 << NF_IP6_LOCAL_OUT));
-
- /* Hooks should be first three */
- assert(h->info.hook_entry[NF_IP6_LOCAL_IN] == 0);
-
- n = get_chain_end(h, 0);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_FORWARD] == n);
-
- n = get_chain_end(h, n);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_LOCAL_OUT] == n);
-
- user_offset = h->info.hook_entry[NF_IP6_LOCAL_OUT];
- } else if (strcmp(h->info.name, "nat") == 0) {
- assert((h->info.valid_hooks
- == (1 << NF_IP6_PRE_ROUTING
- | 1 << NF_IP6_LOCAL_OUT
- | 1 << NF_IP6_POST_ROUTING)) ||
- (h->info.valid_hooks
- == (1 << NF_IP6_PRE_ROUTING
- | 1 << NF_IP6_LOCAL_IN
- | 1 << NF_IP6_LOCAL_OUT
- | 1 << NF_IP6_POST_ROUTING)));
-
- assert(h->info.hook_entry[NF_IP6_PRE_ROUTING] == 0);
-
- n = get_chain_end(h, 0);
-
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_POST_ROUTING] == n);
- n = get_chain_end(h, n);
-
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_LOCAL_OUT] == n);
- user_offset = h->info.hook_entry[NF_IP6_LOCAL_OUT];
-
- if (h->info.valid_hooks & (1 << NF_IP6_LOCAL_IN)) {
- n = get_chain_end(h, n);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_LOCAL_IN] == n);
- user_offset = h->info.hook_entry[NF_IP6_LOCAL_IN];
- }
-
- } else if (strcmp(h->info.name, "mangle") == 0) {
- /* This code is getting ugly because linux < 2.4.18-pre6 had
- * two mangle hooks, linux >= 2.4.18-pre6 has five mangle hooks
- * */
- assert((h->info.valid_hooks
- == (1 << NF_IP6_PRE_ROUTING
- | 1 << NF_IP6_LOCAL_OUT)) ||
- (h->info.valid_hooks
- == (1 << NF_IP6_PRE_ROUTING
- | 1 << NF_IP6_LOCAL_IN
- | 1 << NF_IP6_FORWARD
- | 1 << NF_IP6_LOCAL_OUT
- | 1 << NF_IP6_POST_ROUTING)));
-
- /* Hooks should be first five */
- assert(h->info.hook_entry[NF_IP6_PRE_ROUTING] == 0);
-
- n = get_chain_end(h, 0);
-
- if (h->info.valid_hooks & (1 << NF_IP6_LOCAL_IN)) {
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_LOCAL_IN] == n);
- n = get_chain_end(h, n);
- }
-
- if (h->info.valid_hooks & (1 << NF_IP6_FORWARD)) {
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_FORWARD] == n);
- n = get_chain_end(h, n);
- }
-
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_LOCAL_OUT] == n);
- user_offset = h->info.hook_entry[NF_IP6_LOCAL_OUT];
-
- if (h->info.valid_hooks & (1 << NF_IP6_POST_ROUTING)) {
- n = get_chain_end(h, n);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_POST_ROUTING] == n);
- user_offset = h->info.hook_entry[NF_IP6_POST_ROUTING];
- }
- } else if (strcmp(h->info.name, "raw") == 0) {
- assert(h->info.valid_hooks
- == (1 << NF_IP6_PRE_ROUTING
- | 1 << NF_IP6_LOCAL_OUT));
-
- /* Hooks should be first three */
- assert(h->info.hook_entry[NF_IP6_PRE_ROUTING] == 0);
-
- n = get_chain_end(h, n);
- n += get_entry(h, n)->next_offset;
- assert(h->info.hook_entry[NF_IP6_LOCAL_OUT] == n);
-
- user_offset = h->info.hook_entry[NF_IP6_LOCAL_OUT];
- } else {
- fprintf(stderr, "Unknown table `%s'\n", h->info.name);
- abort();
- }
-
- /* User chain == end of last builtin + policy entry */
- user_offset = get_chain_end(h, user_offset);
- user_offset += get_entry(h, user_offset)->next_offset;
-
- /* Overflows should be end of entry chains, and unconditional
- policy nodes. */
- for (i = 0; i < NUMHOOKS; i++) {
- STRUCT_ENTRY *e;
- STRUCT_STANDARD_TARGET *t;
-
- if (!(h->info.valid_hooks & (1 << i)))
- continue;
- assert(h->info.underflow[i]
- == get_chain_end(h, h->info.hook_entry[i]));
-
- e = get_entry(h, get_chain_end(h, h->info.hook_entry[i]));
- assert(unconditional(&e->ipv6));
- assert(e->target_offset == sizeof(*e));
- t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
- printf("target_size=%u, align=%u\n",
- t->target.u.target_size, ALIGN(sizeof(*t)));
- assert(t->target.u.target_size == ALIGN(sizeof(*t)));
- assert(e->next_offset == sizeof(*e) + ALIGN(sizeof(*t)));
-
- assert(strcmp(t->target.u.user.name, STANDARD_TARGET)==0);
- assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1);
-
- /* Hooks and underflows must be valid entries */
- iptcb_entry2index(h, get_entry(h, h->info.hook_entry[i]));
- iptcb_entry2index(h, get_entry(h, h->info.underflow[i]));
- }
-
- assert(h->info.size
- >= h->info.num_entries * (sizeof(STRUCT_ENTRY)
- +sizeof(STRUCT_STANDARD_TARGET)));
-
- assert(h->entries.size
- >= (h->new_number
- * (sizeof(STRUCT_ENTRY)
- + sizeof(STRUCT_STANDARD_TARGET))));
- assert(strcmp(h->info.name, h->entries.name) == 0);
-
- i = 0; n = 0;
- was_return = 0;
-
-#if 0
- /* Check all the entries. */
- ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
- check_entry, &i, &n, user_offset, &was_return, h);
-
- assert(i == h->new_number);
- assert(n == h->entries.size);
-
- /* Final entry must be error node */
- assert(strcmp(GET_TARGET(index2entry(h, h->new_number-1))
- ->u.user.name,
- ERROR_TARGET) == 0);
#endif
-}
-#endif /*IPTC_DEBUG*/
diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c
index 9326d615..c3142424 100644
--- a/libiptc/libiptc.c
+++ b/libiptc/libiptc.c
@@ -167,7 +167,7 @@ static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
return NULL;
memset(c, 0, sizeof(*c));
- strncpy(c->name, name, TABLE_MAXNAMELEN);
+ strncpy(c->name, name, TABLE_MAXNAMELEN - 1);
c->hooknum = hooknum;
INIT_LIST_HEAD(&c->rules);
@@ -195,14 +195,6 @@ set_changed(struct xtc_handle *h)
h->changed = 1;
}
-#ifdef IPTC_DEBUG
-static void do_check(struct xtc_handle *h, unsigned int line);
-#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
-#else
-#define CHECK(h)
-#endif
-
-
/**********************************************************************
* iptc blob utility functions (iptcb_*)
**********************************************************************/
@@ -1377,7 +1369,6 @@ retry:
if (parse_table(h) < 0)
goto error;
- CHECK(h);
return h;
error:
TC_FREE(h);
@@ -1424,7 +1415,6 @@ void
TC_DUMP_ENTRIES(struct xtc_handle *const handle)
{
iptc_fn = TC_DUMP_ENTRIES;
- CHECK(handle);
printf("libiptc v%s. %u bytes.\n",
XTABLES_VERSION, handle->entries->size);
@@ -2159,7 +2149,6 @@ TC_READ_COUNTER(const IPT_CHAINLABEL chain,
struct rule_head *r;
iptc_fn = TC_READ_COUNTER;
- CHECK(*handle);
if (!(c = iptcc_find_label(chain, handle))) {
errno = ENOENT;
@@ -2183,7 +2172,6 @@ TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
struct rule_head *r;
iptc_fn = TC_ZERO_COUNTER;
- CHECK(handle);
if (!(c = iptcc_find_label(chain, handle))) {
errno = ENOENT;
@@ -2214,7 +2202,6 @@ TC_SET_COUNTER(const IPT_CHAINLABEL chain,
STRUCT_ENTRY *e;
iptc_fn = TC_SET_COUNTER;
- CHECK(handle);
if (!(c = iptcc_find_label(chain, handle))) {
errno = ENOENT;
@@ -2405,7 +2392,7 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
iptcc_chain_index_delete_chain(c, handle);
/* Change the name of the chain */
- strncpy(c->name, newname, sizeof(IPT_CHAINLABEL));
+ strncpy(c->name, newname, sizeof(IPT_CHAINLABEL) - 1);
/* Insert sorted into to list again */
iptc_insert_chain(handle, c);
@@ -2539,7 +2526,6 @@ TC_COMMIT(struct xtc_handle *handle)
unsigned int new_size;
iptc_fn = TC_COMMIT;
- CHECK(*handle);
/* Don't commit if nothing changed. */
if (!handle->changed)
diff --git a/m4/ax_check_linker_flags.m4 b/m4/ax_check_linker_flags.m4
deleted file mode 100644
index ba7bf3cf..00000000
--- a/m4/ax_check_linker_flags.m4
+++ /dev/null
@@ -1,78 +0,0 @@
-#http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_linker_flags.m4
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_check_linker_flags.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_CHECK_LINKER_FLAGS(FLAGS, [ACTION-SUCCESS], [ACTION-FAILURE])
-#
-# DESCRIPTION
-#
-# Check whether the given linker FLAGS work with the current language's
-# linker, or whether they give an error.
-#
-# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
-# success/failure.
-#
-# NOTE: Based on AX_CHECK_COMPILER_FLAGS.
-#
-# LICENSE
-#
-# Copyright (c) 2009 Mike Frysinger <vapier@gentoo.org>
-# Copyright (c) 2009 Steven G. Johnson <stevenj@alum.mit.edu>
-# Copyright (c) 2009 Matteo Frigo
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 6
-
-AC_DEFUN([AX_CHECK_LINKER_FLAGS],
-[AC_MSG_CHECKING([whether the linker accepts $1])
-dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname:
-AS_LITERAL_IF([$1],
- [AC_CACHE_VAL(AS_TR_SH(ax_cv_linker_flags_[$1]), [
- ax_save_FLAGS=$LDFLAGS
- LDFLAGS="$1"
- AC_LINK_IFELSE([AC_LANG_PROGRAM()],
- AS_TR_SH(ax_cv_linker_flags_[$1])=yes,
- AS_TR_SH(ax_cv_linker_flags_[$1])=no)
- LDFLAGS=$ax_save_FLAGS])],
- [ax_save_FLAGS=$LDFLAGS
- LDFLAGS="$1"
- AC_LINK_IFELSE([AC_LANG_PROGRAM()],
- eval AS_TR_SH(ax_cv_linker_flags_[$1])=yes,
- eval AS_TR_SH(ax_cv_linker_flags_[$1])=no)
- LDFLAGS=$ax_save_FLAGS])
-eval ax_check_linker_flags=$AS_TR_SH(ax_cv_linker_flags_[$1])
-AC_MSG_RESULT($ax_check_linker_flags)
-if test "x$ax_check_linker_flags" = xyes; then
- m4_default([$2], :)
-else
- m4_default([$3], :)
-fi
-])dnl AX_CHECK_LINKER_FLAGS
diff --git a/utils/nfnl_osf.c b/utils/nfnl_osf.c
index 0ea33fce..15d53197 100644
--- a/utils/nfnl_osf.c
+++ b/utils/nfnl_osf.c
@@ -343,31 +343,34 @@ static int osf_load_line(char *buffer, int len, int del)
pend = xt_osf_strchr(pbeg, OSFPDEL);
if (pend) {
*pend = '\0';
- snprintf(obuf, sizeof(obuf), "%s,", pbeg);
+ i = sizeof(obuf);
+ snprintf(obuf, i, "%.*s,", i - 2, pbeg);
pbeg = pend + 1;
}
pend = xt_osf_strchr(pbeg, OSFPDEL);
if (pend) {
*pend = '\0';
+ i = sizeof(f.genre);
if (pbeg[0] == '@' || pbeg[0] == '*')
- snprintf(f.genre, sizeof(f.genre), "%s", pbeg + 1);
- else
- snprintf(f.genre, sizeof(f.genre), "%s", pbeg);
+ pbeg++;
+ snprintf(f.genre, i, "%.*s", i - 1, pbeg);
pbeg = pend + 1;
}
pend = xt_osf_strchr(pbeg, OSFPDEL);
if (pend) {
*pend = '\0';
- snprintf(f.version, sizeof(f.version), "%s", pbeg);
+ i = sizeof(f.version);
+ snprintf(f.version, i, "%.*s", i - 1, pbeg);
pbeg = pend + 1;
}
pend = xt_osf_strchr(pbeg, OSFPDEL);
if (pend) {
*pend = '\0';
- snprintf(f.subtype, sizeof(f.subtype), "%s", pbeg);
+ i = sizeof(f.subtype);
+ snprintf(f.subtype, i, "%.*s", i - 1, pbeg);
}
xt_osf_parse_opt(f.opt, &f.opt_num, obuf, sizeof(obuf));