summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--configure.ac8
-rw-r--r--extensions/generic.txlate16
-rw-r--r--extensions/libebt_among.c243
-rw-r--r--extensions/libebt_among.t16
-rw-r--r--extensions/libip6t_DNPT.man2
-rw-r--r--extensions/libip6t_SNPT.man2
-rw-r--r--extensions/libip6t_srh.t4
-rw-r--r--extensions/libipt_CLUSTERIP.man3
-rw-r--r--extensions/libipt_ECN.man2
-rw-r--r--extensions/libipt_ULOG.c1
-rw-r--r--extensions/libxt_AUDIT.man2
-rw-r--r--extensions/libxt_CHECKSUM.man2
-rw-r--r--extensions/libxt_CT.c16
-rw-r--r--extensions/libxt_CT.man2
-rw-r--r--extensions/libxt_DSCP.man2
-rw-r--r--extensions/libxt_HMARK.man2
-rw-r--r--extensions/libxt_IDLETIMER.c99
-rw-r--r--extensions/libxt_IDLETIMER.t1
-rw-r--r--extensions/libxt_MARK.man4
-rw-r--r--extensions/libxt_NOTRACK.t3
-rw-r--r--extensions/libxt_NOTRACK.txlate2
-rw-r--r--extensions/libxt_SET.man2
-rw-r--r--extensions/libxt_TCPMSS.man2
-rw-r--r--extensions/libxt_TOS.man2
-rw-r--r--extensions/libxt_addrtype.c1
-rw-r--r--extensions/libxt_bpf.c26
-rw-r--r--extensions/libxt_bpf.man2
-rw-r--r--extensions/libxt_cluster.c2
-rw-r--r--extensions/libxt_cluster.man2
-rw-r--r--extensions/libxt_connlabel.c7
-rw-r--r--extensions/libxt_osf.c2
-rw-r--r--extensions/libxt_osf.man6
-rw-r--r--extensions/libxt_policy.man2
-rw-r--r--extensions/libxt_sctp.man1
-rw-r--r--extensions/libxt_set.man2
-rw-r--r--extensions/libxt_string.man2
-rw-r--r--extensions/libxt_time.c74
-rw-r--r--extensions/libxt_time.txlate26
-rw-r--r--include/linux/netfilter/xt_IDLETIMER.h12
-rw-r--r--include/linux/netfilter/xt_sctp.h6
-rw-r--r--include/xtables.h1
-rwxr-xr-xiptables-test.py7
-rw-r--r--iptables/Makefile.am9
-rw-r--r--iptables/ebtables-nft.862
-rw-r--r--iptables/ip6tables-apply.81
-rw-r--r--iptables/ip6tables-standalone.c2
-rwxr-xr-xiptables/iptables-apply302
-rw-r--r--iptables/iptables-apply.8.in46
-rw-r--r--iptables/iptables-restore.8.in2
-rw-r--r--iptables/iptables-restore.c18
-rw-r--r--iptables/iptables-save.8.in2
-rw-r--r--iptables/iptables-save.c14
-rw-r--r--iptables/iptables-standalone.c2
-rw-r--r--iptables/iptables.8.in4
-rw-r--r--iptables/nft-arp.c36
-rw-r--r--iptables/nft-bridge.c272
-rw-r--r--iptables/nft-bridge.h56
-rw-r--r--iptables/nft-cache.c485
-rw-r--r--iptables/nft-cache.h8
-rw-r--r--iptables/nft-cmd.c395
-rw-r--r--iptables/nft-cmd.h79
-rw-r--r--iptables/nft-ipv4.c14
-rw-r--r--iptables/nft-ipv6.c14
-rw-r--r--iptables/nft-shared.c105
-rw-r--r--iptables/nft-shared.h28
-rw-r--r--iptables/nft.c774
-rw-r--r--iptables/nft.h76
-rwxr-xr-xiptables/tests/shell/run-tests.sh47
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0001-arptables-save-restore_02
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_02
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_02
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0135
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_02
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_02
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0004-save-counters_02
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0005-ifnamechecks_02
-rwxr-xr-xiptables/tests/shell/testcases/firewalld-restore/0001-firewalld_02
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0004-return-codes_01
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0001load-specific-table_02
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0004-restore-race_07
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_011
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_016
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0012-dash-F_012
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0013-test-mode_07
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0004-return-codes_06
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0006-46-args_088
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0001compat_015
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0002invflags_02
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0003delete-with-comment_02
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0006-policy-override_029
-rw-r--r--iptables/xshared.c1
-rw-r--r--iptables/xshared.h1
-rw-r--r--iptables/xtables-arp-standalone.c1
-rw-r--r--iptables/xtables-arp.c49
-rw-r--r--iptables/xtables-eb-standalone.c2
-rw-r--r--iptables/xtables-eb.c56
-rw-r--r--iptables/xtables-monitor.c19
-rw-r--r--iptables/xtables-restore.c153
-rw-r--r--iptables/xtables-save.c21
-rw-r--r--iptables/xtables-standalone.c7
-rw-r--r--iptables/xtables-translate.c40
-rw-r--r--iptables/xtables.c95
-rw-r--r--libipq/ipq_set_verdict.32
-rw-r--r--libiptc/libip4tc.c2
-rw-r--r--libiptc/libip6tc.c2
-rw-r--r--libxtables/xtables.c47
-rw-r--r--utils/nfnl_osf.c21
108 files changed, 3307 insertions, 1036 deletions
diff --git a/.gitignore b/.gitignore
index 92eb178a..e5595264 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,6 @@ Makefile.in
/iptables/xtables-multi
/iptables/xtables-compat-multi
+
+# vim/nano swap file
+*.swp
diff --git a/configure.ac b/configure.ac
index eb70bd11..31a8bb26 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,9 @@
-AC_INIT([iptables], [1.8.3])
+AC_INIT([iptables], [1.8.5])
# See libtool.info "Libtool's versioning system"
-libxtables_vcurrent=14
-libxtables_vage=2
+libxtables_vcurrent=15
+libxtables_vage=3
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
@@ -131,7 +131,7 @@ if test "x$enable_nftables" = "xyes"; then
exit 1
fi
- PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.3], [nftables=1], [nftables=0])
+ PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.6], [nftables=1], [nftables=0])
if test "$nftables" = 0;
then
diff --git a/extensions/generic.txlate b/extensions/generic.txlate
index b38fbd1f..0e256c37 100644
--- a/extensions/generic.txlate
+++ b/extensions/generic.txlate
@@ -18,3 +18,19 @@ nft add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oi
ebtables-translate -I INPUT -p ip -d 1:2:3:4:5:6/ff:ff:ff:ff:00:00
nft insert rule bridge filter INPUT ether type 0x800 ether daddr 01:02:03:04:00:00 and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter
+
+# asterisk is not special in iptables and it is even a valid interface name
+iptables-translate -A FORWARD -i '*' -o 'eth*foo'
+nft add rule ip filter FORWARD iifname "\*" oifname "eth\*foo" counter
+
+# escape all asterisks but translate only the first plus character
+iptables-translate -A FORWARD -i 'eth*foo*+' -o 'eth++'
+nft add rule ip filter FORWARD iifname "eth\*foo\**" oifname "eth+*" counter
+
+# skip for always matching interface names
+iptables-translate -A FORWARD -i '+'
+nft add rule ip filter FORWARD counter
+
+# match against invalid interface name to simulate never matching rule
+iptables-translate -A FORWARD ! -i '+'
+nft add rule ip filter FORWARD iifname "INVAL/D" counter
diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c
new file mode 100644
index 00000000..2b9a1b65
--- /dev/null
+++ b/extensions/libebt_among.c
@@ -0,0 +1,243 @@
+/* ebt_among
+ *
+ * Authors:
+ * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
+ *
+ * August, 2003
+ */
+
+#include <errno.h>
+#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 (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);
+ if (fstat(fd, &stats) < 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "fstat(%s) failed: '%s'",
+ optarg, strerror(errno));
+ 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 (pairs[i].in.s_addr != INADDR_ANY)
+ 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..a02206f3
--- /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 c0:ff:ee:0:ba:be=192.168.1.1,de:ad:0:be:ee:ff;=;OK
diff --git a/extensions/libip6t_DNPT.man b/extensions/libip6t_DNPT.man
index 61beeee8..9b060f5b 100644
--- a/extensions/libip6t_DNPT.man
+++ b/extensions/libip6t_DNPT.man
@@ -23,7 +23,7 @@ ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64
.PP
You may need to enable IPv6 neighbor proxy:
.IP
-sysctl -w net.ipv6.conf.all.proxy_ndp=1
+sysctl \-w net.ipv6.conf.all.proxy_ndp=1
.PP
You also have to use the
.B NOTRACK
diff --git a/extensions/libip6t_SNPT.man b/extensions/libip6t_SNPT.man
index 78d644a7..97e0071b 100644
--- a/extensions/libip6t_SNPT.man
+++ b/extensions/libip6t_SNPT.man
@@ -23,7 +23,7 @@ ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64
.PP
You may need to enable IPv6 neighbor proxy:
.IP
-sysctl -w net.ipv6.conf.all.proxy_ndp=1
+sysctl \-w net.ipv6.conf.all.proxy_ndp=1
.PP
You also have to use the
.B NOTRACK
diff --git a/extensions/libip6t_srh.t b/extensions/libip6t_srh.t
index 07b54031..5b02a71b 100644
--- a/extensions/libip6t_srh.t
+++ b/extensions/libip6t_srh.t
@@ -23,6 +23,6 @@
-m srh ! --srh-tag 0;=;OK
-m srh --srh-next-hdr 17 --srh-segs-left-eq 1 --srh-last-entry-eq 4 --srh-tag 0;=;OK
-m srh ! --srh-next-hdr 17 ! --srh-segs-left-eq 0 --srh-tag 0;=;OK
--m srh --srh-psid A::/64 --srh-nsid B:: --srh-lsid C::/0;;OK
--m srh ! --srh-psid A::/64 ! --srh-nsid B:: ! --srh-lsid C::/0;;OK
+-m srh --srh-psid a::/64 --srh-nsid b::/128 --srh-lsid c::/0;=;OK
+-m srh ! --srh-psid a::/64 ! --srh-nsid b::/128 ! --srh-lsid c::/0;=;OK
-m srh;=;OK
diff --git a/extensions/libipt_CLUSTERIP.man b/extensions/libipt_CLUSTERIP.man
index 8ec6d6b6..768bb23e 100644
--- a/extensions/libipt_CLUSTERIP.man
+++ b/extensions/libipt_CLUSTERIP.man
@@ -2,6 +2,9 @@ This module allows you to configure a simple cluster of nodes that share
a certain IP and MAC address without an explicit load balancer in front of
them. Connections are statically distributed between the nodes in this
cluster.
+.PP
+Please note that CLUSTERIP target is considered deprecated in favour of cluster
+match which is more flexible and not limited to IPv4.
.TP
\fB\-\-new\fP
Create a new ClusterIP. You always have to set this on the first rule
diff --git a/extensions/libipt_ECN.man b/extensions/libipt_ECN.man
index a9cbe109..8ae7996e 100644
--- a/extensions/libipt_ECN.man
+++ b/extensions/libipt_ECN.man
@@ -1,4 +1,4 @@
-This target allows to selectively work around known ECN blackholes.
+This target selectively works around known ECN blackholes.
It can only be used in the mangle table.
.TP
\fB\-\-ecn\-tcp\-remove\fP
diff --git a/extensions/libipt_ULOG.c b/extensions/libipt_ULOG.c
index fafb220b..5163eea3 100644
--- a/extensions/libipt_ULOG.c
+++ b/extensions/libipt_ULOG.c
@@ -11,6 +11,7 @@
*/
#include <stdio.h>
#include <string.h>
+#include <strings.h>
#include <xtables.h>
/* For 64bit kernel / 32bit userspace */
#include <linux/netfilter_ipv4/ipt_ULOG.h>
diff --git a/extensions/libxt_AUDIT.man b/extensions/libxt_AUDIT.man
index 4f5562e8..8c513d22 100644
--- a/extensions/libxt_AUDIT.man
+++ b/extensions/libxt_AUDIT.man
@@ -1,4 +1,4 @@
-This target allows to create audit records for packets hitting the target.
+This target creates audit records for packets hitting the target.
It can be used to record accepted, dropped, and rejected packets. See
auditd(8) for additional details.
.TP
diff --git a/extensions/libxt_CHECKSUM.man b/extensions/libxt_CHECKSUM.man
index 92ae700f..726f4ea6 100644
--- a/extensions/libxt_CHECKSUM.man
+++ b/extensions/libxt_CHECKSUM.man
@@ -1,4 +1,4 @@
-This target allows to selectively work around broken/old applications.
+This target selectively works around broken/old applications.
It can only be used in the mangle table.
.TP
\fB\-\-checksum\-fill\fP
diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c
index 371b2176..fbbbe266 100644
--- a/extensions/libxt_CT.c
+++ b/extensions/libxt_CT.c
@@ -348,6 +348,20 @@ static void notrack_ct2_tg_init(struct xt_entry_target *target)
info->flags = XT_CT_NOTRACK | XT_CT_NOTRACK_ALIAS;
}
+static int xlate_ct1_tg(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ struct xt_ct_target_info_v1 *info =
+ (struct xt_ct_target_info_v1 *)params->target->data;
+
+ if (info->flags & XT_CT_NOTRACK)
+ xt_xlate_add(xl, "notrack");
+ else
+ return 0;
+
+ return 1;
+}
+
static struct xtables_target ct_target_reg[] = {
{
.family = NFPROTO_UNSPEC,
@@ -387,6 +401,7 @@ static struct xtables_target ct_target_reg[] = {
.alias = ct_print_name_alias,
.x6_parse = ct_parse_v1,
.x6_options = ct_opts_v1,
+ .xlate = xlate_ct1_tg,
},
{
.family = NFPROTO_UNSPEC,
@@ -418,6 +433,7 @@ static struct xtables_target ct_target_reg[] = {
.size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
.userspacesize = offsetof(struct xt_ct_target_info_v1, ct),
.init = notrack_ct2_tg_init,
+ .xlate = xlate_ct1_tg,
},
{
.family = NFPROTO_UNSPEC,
diff --git a/extensions/libxt_CT.man b/extensions/libxt_CT.man
index e992120a..fc692f9a 100644
--- a/extensions/libxt_CT.man
+++ b/extensions/libxt_CT.man
@@ -1,4 +1,4 @@
-The CT target allows to set parameters for a packet or its associated
+The CT target sets parameters for a packet or its associated
connection. The target attaches a "template" connection tracking entry to
the packet, which is then used by the conntrack core when initializing
a new ct entry. This target is thus only valid in the "raw" table.
diff --git a/extensions/libxt_DSCP.man b/extensions/libxt_DSCP.man
index 551ba2e1..5385c97a 100644
--- a/extensions/libxt_DSCP.man
+++ b/extensions/libxt_DSCP.man
@@ -1,4 +1,4 @@
-This target allows to alter the value of the DSCP bits within the TOS
+This target alters the value of the DSCP bits within the TOS
header of the IPv4 packet. As this manipulates a packet, it can only
be used in the mangle table.
.TP
diff --git a/extensions/libxt_HMARK.man b/extensions/libxt_HMARK.man
index e7b5426d..cd7ffd54 100644
--- a/extensions/libxt_HMARK.man
+++ b/extensions/libxt_HMARK.man
@@ -56,5 +56,5 @@ iptables \-t mangle \-A PREROUTING \-m conntrack \-\-ctstate NEW
\-j HMARK \-\-hmark-tuple ct,src,dst,proto \-\-hmark-offset 10000
\-\-hmark\-mod 10 \-\-hmark\-rnd 0xfeedcafe
.PP
-iptables \-t mangle \-A PREROUTING -j HMARK \-\-hmark\-offset 10000
+iptables \-t mangle \-A PREROUTING \-j HMARK \-\-hmark\-offset 10000
\-\-hmark-tuple src,dst,proto \-\-hmark-mod 10 \-\-hmark\-rnd 0xdeafbeef
diff --git a/extensions/libxt_IDLETIMER.c b/extensions/libxt_IDLETIMER.c
index 21004a4b..216b6257 100644
--- a/extensions/libxt_IDLETIMER.c
+++ b/extensions/libxt_IDLETIMER.c
@@ -27,6 +27,7 @@
enum {
O_TIMEOUT = 0,
O_LABEL,
+ O_ALARM,
};
#define s struct idletimer_tg_info
@@ -39,6 +40,17 @@ static const struct xt_option_entry idletimer_tg_opts[] = {
};
#undef s
+#define s struct idletimer_tg_info_v1
+static const struct xt_option_entry idletimer_tg_opts_v1[] = {
+ {.name = "timeout", .id = O_TIMEOUT, .type = XTTYPE_UINT32,
+ .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, timeout)},
+ {.name = "label", .id = O_LABEL, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, label)},
+ {.name = "alarm", .id = O_ALARM, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+#undef s
+
static void idletimer_tg_help(void)
{
printf(
@@ -48,6 +60,16 @@ static void idletimer_tg_help(void)
"\n");
}
+static void idletimer_tg_help_v1(void)
+{
+ printf(
+"IDLETIMER target options:\n"
+" --timeout time Timeout until the notification is sent (in seconds)\n"
+" --label string Unique rule identifier\n"
+" --alarm Use alarm instead of default timer\n"
+"\n");
+}
+
static void idletimer_tg_print(const void *ip,
const struct xt_entry_target *target,
int numeric)
@@ -59,6 +81,20 @@ static void idletimer_tg_print(const void *ip,
printf(" label:%s", info->label);
}
+static void idletimer_tg_print_v1(const void *ip,
+ const struct xt_entry_target *target,
+ int numeric)
+{
+ struct idletimer_tg_info_v1 *info =
+ (struct idletimer_tg_info_v1 *) target->data;
+
+ printf(" timeout:%u", info->timeout);
+ printf(" label:%s", info->label);
+ if (info->timer_type == XT_IDLETIMER_ALARM)
+ printf(" alarm");
+}
+
+
static void idletimer_tg_save(const void *ip,
const struct xt_entry_target *target)
{
@@ -69,21 +105,58 @@ static void idletimer_tg_save(const void *ip,
printf(" --label %s", info->label);
}
-static struct xtables_target idletimer_tg_reg = {
- .family = NFPROTO_UNSPEC,
- .name = "IDLETIMER",
- .version = XTABLES_VERSION,
- .revision = 0,
- .size = XT_ALIGN(sizeof(struct idletimer_tg_info)),
- .userspacesize = offsetof(struct idletimer_tg_info, timer),
- .help = idletimer_tg_help,
- .x6_parse = xtables_option_parse,
- .print = idletimer_tg_print,
- .save = idletimer_tg_save,
- .x6_options = idletimer_tg_opts,
+static void idletimer_tg_save_v1(const void *ip,
+ const struct xt_entry_target *target)
+{
+ struct idletimer_tg_info_v1 *info =
+ (struct idletimer_tg_info_v1 *) target->data;
+
+ printf(" --timeout %u", info->timeout);
+ printf(" --label %s", info->label);
+ if (info->timer_type == XT_IDLETIMER_ALARM)
+ printf(" --alarm");
+}
+
+static void idletimer_tg_parse_v1(struct xt_option_call *cb)
+{
+ struct idletimer_tg_info_v1 *info = cb->data;
+
+ xtables_option_parse(cb);
+ if (cb->entry->id == O_ALARM)
+ info->timer_type = XT_IDLETIMER_ALARM;
+}
+
+static struct xtables_target idletimer_tg_reg[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "IDLETIMER",
+ .version = XTABLES_VERSION,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct idletimer_tg_info)),
+ .userspacesize = offsetof(struct idletimer_tg_info, timer),
+ .help = idletimer_tg_help,
+ .x6_parse = xtables_option_parse,
+ .print = idletimer_tg_print,
+ .save = idletimer_tg_save,
+ .x6_options = idletimer_tg_opts,
+ },
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "IDLETIMER",
+ .version = XTABLES_VERSION,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct idletimer_tg_info_v1)),
+ .userspacesize = offsetof(struct idletimer_tg_info_v1, timer),
+ .help = idletimer_tg_help_v1,
+ .x6_parse = idletimer_tg_parse_v1,
+ .print = idletimer_tg_print_v1,
+ .save = idletimer_tg_save_v1,
+ .x6_options = idletimer_tg_opts_v1,
+ },
+
};
void _init(void)
{
- xtables_register_target(&idletimer_tg_reg);
+ xtables_register_targets(idletimer_tg_reg, ARRAY_SIZE(idletimer_tg_reg));
}
diff --git a/extensions/libxt_IDLETIMER.t b/extensions/libxt_IDLETIMER.t
index 6afd92c1..e8f306d2 100644
--- a/extensions/libxt_IDLETIMER.t
+++ b/extensions/libxt_IDLETIMER.t
@@ -2,3 +2,4 @@
-j IDLETIMER --timeout;;FAIL
-j IDLETIMER --timeout 42;;FAIL
-j IDLETIMER --timeout 42 --label foo;=;OK
+-j IDLETIMER --timeout 42 --label foo --alarm;;OK
diff --git a/extensions/libxt_MARK.man b/extensions/libxt_MARK.man
index 712fb76f..b2408597 100644
--- a/extensions/libxt_MARK.man
+++ b/extensions/libxt_MARK.man
@@ -1,7 +1,7 @@
This target is used to set the Netfilter mark value associated with the packet.
It can, for example, be used in conjunction with routing based on fwmark (needs
-iproute2). If you plan on doing so, note that the mark needs to be set in the
-PREROUTING chain of the mangle table to affect routing.
+iproute2). If you plan on doing so, note that the mark needs to be set in
+either the PREROUTING or the OUTPUT chain of the mangle table to affect routing.
The mark field is 32 bits wide.
.TP
\fB\-\-set\-xmark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
diff --git a/extensions/libxt_NOTRACK.t b/extensions/libxt_NOTRACK.t
index 585be82d..27c4734f 100644
--- a/extensions/libxt_NOTRACK.t
+++ b/extensions/libxt_NOTRACK.t
@@ -1,4 +1,3 @@
:PREROUTING,OUTPUT
*raw
-# ERROR: cannot find: iptables -I PREROUTING -t raw -j NOTRACK
-#-j NOTRACK;=;OK
+-j NOTRACK;=;OK
diff --git a/extensions/libxt_NOTRACK.txlate b/extensions/libxt_NOTRACK.txlate
new file mode 100644
index 00000000..9d35619d
--- /dev/null
+++ b/extensions/libxt_NOTRACK.txlate
@@ -0,0 +1,2 @@
+iptables-translate -A PREROUTING -t raw -j NOTRACK
+nft add rule ip raw PREROUTING counter notrack
diff --git a/extensions/libxt_SET.man b/extensions/libxt_SET.man
index 78a9ae0f..c4713378 100644
--- a/extensions/libxt_SET.man
+++ b/extensions/libxt_SET.man
@@ -42,5 +42,5 @@ and
\fB\-\-map\-queue\fP
flags can be used in the OUTPUT, FORWARD and POSTROUTING chains.
.PP
-Use of -j SET requires that ipset kernel support is provided, which, for
+Use of \-j SET requires that ipset kernel support is provided, which, for
standard kernels, is the case since Linux 2.6.39.
diff --git a/extensions/libxt_TCPMSS.man b/extensions/libxt_TCPMSS.man
index 8da8e761..25b480dd 100644
--- a/extensions/libxt_TCPMSS.man
+++ b/extensions/libxt_TCPMSS.man
@@ -1,4 +1,4 @@
-This target allows to alter the MSS value of TCP SYN packets, to control
+This target alters the MSS value of TCP SYN packets, to control
the maximum size for that connection (usually limiting it to your
outgoing interface's MTU minus 40 for IPv4 or 60 for IPv6, respectively).
Of course, it can only be used
diff --git a/extensions/libxt_TOS.man b/extensions/libxt_TOS.man
index 58118ec2..de2d22dc 100644
--- a/extensions/libxt_TOS.man
+++ b/extensions/libxt_TOS.man
@@ -32,5 +32,5 @@ longterm releases 2.6.32 (>=.42), 2.6.33 (>=.15), and 2.6.35 (>=.14), there is
a bug whereby IPv6 TOS mangling does not behave as documented and differs from
the IPv4 version. The TOS mask indicates the bits one wants to zero out, so it
needs to be inverted before applying it to the original TOS field. However, the
-aformentioned kernels forgo the inversion which breaks --set-tos and its
+aformentioned kernels forgo the inversion which breaks \-\-set\-tos and its
mnemonics.
diff --git a/extensions/libxt_addrtype.c b/extensions/libxt_addrtype.c
index 27485405..5cafa219 100644
--- a/extensions/libxt_addrtype.c
+++ b/extensions/libxt_addrtype.c
@@ -5,6 +5,7 @@
* This program is released under the terms of GNU GPL */
#include <stdio.h>
#include <string.h>
+#include <strings.h>
#include <xtables.h>
#include <linux/netfilter/xt_addrtype.h>
diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
index 92958247..eeae86e5 100644
--- a/extensions/libxt_bpf.c
+++ b/extensions/libxt_bpf.c
@@ -61,14 +61,26 @@ static const struct xt_option_entry bpf_opts_v1[] = {
XTOPT_TABLEEND,
};
-static int bpf_obj_get(const char *filepath)
+static int bpf_obj_get_readonly(const char *filepath)
{
#if defined HAVE_LINUX_BPF_H && defined __NR_bpf && defined BPF_FS_MAGIC
- union bpf_attr attr;
-
- memset(&attr, 0, sizeof(attr));
- attr.pathname = (__u64) filepath;
-
+ /* union bpf_attr includes this in an anonymous struct, but the
+ * file_flags field and the BPF_F_RDONLY constant are only present
+ * in Linux 4.15+ kernel headers (include/uapi/linux/bpf.h)
+ */
+ struct { // this part of union bpf_attr is for BPF_OBJ_* commands
+ __aligned_u64 pathname;
+ __u32 bpf_fd;
+ __u32 file_flags;
+ } attr = {
+ .pathname = (__u64)filepath,
+ .file_flags = (1U << 3), // BPF_F_RDONLY
+ };
+ int fd = syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+ if (fd >= 0) return fd;
+
+ /* on any error fallback to default R/W access for pre-4.15-rc1 kernels */
+ attr.file_flags = 0;
return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
#else
xtables_error(OTHER_PROBLEM,
@@ -125,7 +137,7 @@ static void bpf_parse_string(struct sock_filter *pc, __u16 *lenp, __u16 len_max,
static void bpf_parse_obj_pinned(struct xt_bpf_info_v1 *bi,
const char *filepath)
{
- bi->fd = bpf_obj_get(filepath);
+ bi->fd = bpf_obj_get_readonly(filepath);
if (bi->fd < 0)
xtables_error(PARAMETER_PROBLEM,
"bpf: failed to get bpf object");
diff --git a/extensions/libxt_bpf.man b/extensions/libxt_bpf.man
index 1d2aa9e6..d6da2043 100644
--- a/extensions/libxt_bpf.man
+++ b/extensions/libxt_bpf.man
@@ -17,7 +17,7 @@ iptables \-A OUTPUT \-m bpf \-\-object\-pinned ${BPF_MOUNT}/{PINNED_PATH} \-j AC
\fB\-\-bytecode\fP \fIcode\fP
Pass the BPF byte code format as generated by the \fBnfbpf_compile\fP utility.
.PP
-The code format is similar to the output of the tcpdump -ddd command: one line
+The code format is similar to the output of the tcpdump \-ddd command: one line
that stores the number of instructions, followed by one line for each
instruction. Instruction lines follow the pattern 'u16 u8 u8 u32' in decimal
notation. Fields encode the operation, jump offset if true, jump offset if
diff --git a/extensions/libxt_cluster.c b/extensions/libxt_cluster.c
index c9c35ee2..d164bf69 100644
--- a/extensions/libxt_cluster.c
+++ b/extensions/libxt_cluster.c
@@ -156,7 +156,7 @@ static int cluster_xlate(struct xt_xlate *xl,
xt_xlate_add(xl, "%s %u seed 0x%08x ", jhash_st,
info->total_nodes, info->hash_seed);
for (node = 0; node < 32; node++) {
- if (info->node_mask & (1 << node)) {
+ if (info->node_mask & (1u << node)) {
if (needs_set == 0) {
xt_xlate_add(xl, "{ ");
needs_set = 1;
diff --git a/extensions/libxt_cluster.man b/extensions/libxt_cluster.man
index 94b4b205..23448e26 100644
--- a/extensions/libxt_cluster.man
+++ b/extensions/libxt_cluster.man
@@ -27,7 +27,7 @@ iptables \-A PREROUTING \-t mangle \-i eth1 \-m cluster
iptables \-A PREROUTING \-t mangle \-i eth2 \-m cluster
\-\-cluster\-total\-nodes 2 \-\-cluster\-local\-node 1
\-\-cluster\-hash\-seed 0xdeadbeef
-\-j MARK -\-set\-mark 0xffff
+\-j MARK \-\-set\-mark 0xffff
.IP
iptables \-A PREROUTING \-t mangle \-i eth1
\-m mark ! \-\-mark 0xffff \-j DROP
diff --git a/extensions/libxt_connlabel.c b/extensions/libxt_connlabel.c
index 5a01fe72..565b8c79 100644
--- a/extensions/libxt_connlabel.c
+++ b/extensions/libxt_connlabel.c
@@ -70,18 +70,15 @@ static int connlabel_value_parse(const char *in)
static void connlabel_mt_parse(struct xt_option_call *cb)
{
struct xt_connlabel_mtinfo *info = cb->data;
- bool have_labelmap = !connlabel_open();
int tmp;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_LABEL:
- if (have_labelmap)
+ tmp = connlabel_value_parse(cb->arg);
+ if (tmp < 0 && !connlabel_open())
tmp = nfct_labelmap_get_bit(map, cb->arg);
- else
- tmp = connlabel_value_parse(cb->arg);
-
if (tmp < 0)
xtables_error(PARAMETER_PROBLEM,
"label '%s' not found or invalid value",
diff --git a/extensions/libxt_osf.c b/extensions/libxt_osf.c
index 496b4805..c567d9e0 100644
--- a/extensions/libxt_osf.c
+++ b/extensions/libxt_osf.c
@@ -40,7 +40,7 @@ static void osf_help(void)
"--ttl level Use some TTL check extensions to determine OS:\n"
" 0 true ip and fingerprint TTL comparison. Works for LAN.\n"
" 1 check if ip TTL is less than fingerprint one. Works for global addresses.\n"
- " 2 do not compare TTL at all. Allows to detect NMAP, but can produce false results.\n"
+ " 2 do not compare TTL at all. This allows NMAP detection, but can produce false results.\n"
"--log level Log determined genres into dmesg even if they do not match desired one:\n"
" 0 log all matched or unknown signatures.\n"
" 1 log only first one.\n"
diff --git a/extensions/libxt_osf.man b/extensions/libxt_osf.man
index 5ba92ce0..41103f29 100644
--- a/extensions/libxt_osf.man
+++ b/extensions/libxt_osf.man
@@ -1,4 +1,4 @@
-The osf module does passive operating system fingerprinting. This modules
+The osf module does passive operating system fingerprinting. This module
compares some data (Window Size, MSS, options and their order, TTL, DF,
and others) from packets with the SYN bit set.
.TP
@@ -35,11 +35,11 @@ Windows [2000:SP3:Windows XP Pro SP1, 2000 SP3]: 11.22.33.55:4024 ->
OS fingerprints are loadable using the \fBnfnl_osf\fP program. To load
fingerprints from a file, use:
.PP
-\fBnfnl_osf -f /usr/share/xtables/pf.os\fP
+\fBnfnl_osf \-f /usr/share/xtables/pf.os\fP
.PP
To remove them again,
.PP
-\fBnfnl_osf -f /usr/share/xtables/pf.os -d\fP
+\fBnfnl_osf \-f /usr/share/xtables/pf.os \-d\fP
.PP
The fingerprint database can be downloaded from
http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os .
diff --git a/extensions/libxt_policy.man b/extensions/libxt_policy.man
index 1b834fa0..12c01b43 100644
--- a/extensions/libxt_policy.man
+++ b/extensions/libxt_policy.man
@@ -1,4 +1,4 @@
-This modules matches the policy used by IPsec for handling a packet.
+This module matches the policy used by IPsec for handling a packet.
.TP
\fB\-\-dir\fP {\fBin\fP|\fBout\fP}
Used to select whether to match the policy used for decapsulation or the
diff --git a/extensions/libxt_sctp.man b/extensions/libxt_sctp.man
index 9c0bd8c3..3779d05a 100644
--- a/extensions/libxt_sctp.man
+++ b/extensions/libxt_sctp.man
@@ -1,3 +1,4 @@
+This module matches Stream Control Transmission Protocol headers.
.TP
[\fB!\fP] \fB\-\-source\-port\fP,\fB\-\-sport\fP \fIport\fP[\fB:\fP\fIport\fP]
.TP
diff --git a/extensions/libxt_set.man b/extensions/libxt_set.man
index dbc1586b..5c6f64e3 100644
--- a/extensions/libxt_set.man
+++ b/extensions/libxt_set.man
@@ -61,5 +61,5 @@ when the set was defined without counter support.
The option \fB\-\-match\-set\fP can be replaced by \fB\-\-set\fP if that does
not clash with an option of other extensions.
.PP
-Use of -m set requires that ipset kernel support is provided, which, for
+Use of \-m set requires that ipset kernel support is provided, which, for
standard kernels, is the case since Linux 2.6.39.
diff --git a/extensions/libxt_string.man b/extensions/libxt_string.man
index 54c03a3a..5f1a993c 100644
--- a/extensions/libxt_string.man
+++ b/extensions/libxt_string.man
@@ -1,4 +1,4 @@
-This modules matches a given string by using some pattern matching strategy. It requires a linux kernel >= 2.6.14.
+This module matches a given string by using some pattern matching strategy. It requires a linux kernel >= 2.6.14.
.TP
\fB\-\-algo\fP {\fBbm\fP|\fBkmp\fP}
Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)
diff --git a/extensions/libxt_time.c b/extensions/libxt_time.c
index 5a8cc5de..d27d84ca 100644
--- a/extensions/libxt_time.c
+++ b/extensions/libxt_time.c
@@ -258,6 +258,16 @@ static unsigned int time_parse_weekdays(const char *arg)
return ret;
}
+static unsigned int time_count_weekdays(unsigned int weekdays_mask)
+{
+ unsigned int ret;
+
+ for (ret = 0; weekdays_mask; weekdays_mask >>= 1)
+ ret += weekdays_mask & 1;
+
+ return ret;
+}
+
static void time_parse(struct xt_option_call *cb)
{
struct xt_time_info *info = cb->data;
@@ -330,7 +340,7 @@ static void time_print_monthdays(uint32_t mask, bool human_readable)
printf(" ");
for (i = 1; i <= 31; ++i)
- if (mask & (1 << i)) {
+ if (mask & (1u << i)) {
if (nbdays++ > 0)
printf(",");
printf("%u", i);
@@ -450,6 +460,67 @@ static void time_check(struct xt_fcheck_call *cb)
"time: --contiguous only makes sense when stoptime is smaller than starttime");
}
+static int time_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_time_info *info =
+ (const struct xt_time_info *)params->match->data;
+ unsigned int h, m, s,
+ i, sep, mask, count;
+ time_t tt_start, tt_stop;
+ struct tm *t_start, *t_stop;
+
+ if (info->date_start != 0 ||
+ info->date_stop != INT_MAX) {
+ tt_start = (time_t) info->date_start;
+ tt_stop = (time_t) info->date_stop;
+
+ xt_xlate_add(xl, "meta time ");
+ t_start = gmtime(&tt_start);
+ xt_xlate_add(xl, "\"%04u-%02u-%02u %02u:%02u:%02u\"",
+ t_start->tm_year + 1900, t_start->tm_mon + 1,
+ t_start->tm_mday, t_start->tm_hour,
+ t_start->tm_min, t_start->tm_sec);
+ t_stop = gmtime(&tt_stop);
+ xt_xlate_add(xl, "-\"%04u-%02u-%02u %02u:%02u:%02u\"",
+ t_stop->tm_year + 1900, t_stop->tm_mon + 1,
+ t_stop->tm_mday, t_stop->tm_hour,
+ t_stop->tm_min, t_stop->tm_sec);
+ }
+ if (info->daytime_start != XT_TIME_MIN_DAYTIME ||
+ info->daytime_stop != XT_TIME_MAX_DAYTIME) {
+ divide_time(info->daytime_start, &h, &m, &s);
+ xt_xlate_add(xl, " meta hour \"%02u:%02u:%02u\"", h, m, s);
+ divide_time(info->daytime_stop, &h, &m, &s);
+ xt_xlate_add(xl, "-\"%02u:%02u:%02u\"", h, m, s);
+ }
+ /* nft_time does not support --monthdays */
+ if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS)
+ return 0;
+ if (info->weekdays_match != XT_TIME_ALL_WEEKDAYS) {
+ sep = 0;
+ mask = info->weekdays_match;
+ count = time_count_weekdays(mask);
+
+ xt_xlate_add(xl, " meta day ");
+ if (count > 1)
+ xt_xlate_add(xl, "{");
+ for (i = 1; i <= 7; ++i)
+ if (mask & (1 << i)) {
+ if (sep)
+ xt_xlate_add(xl, ",%u", i%7);
+ else {
+ xt_xlate_add(xl, "%u", i%7);
+ ++sep;
+ }
+ }
+ if (count > 1)
+ xt_xlate_add(xl, "}");
+ }
+
+ return 1;
+}
+
static struct xtables_match time_match = {
.name = "time",
.family = NFPROTO_UNSPEC,
@@ -463,6 +534,7 @@ static struct xtables_match time_match = {
.x6_parse = time_parse,
.x6_fcheck = time_check,
.x6_options = time_opts,
+ .xlate = time_xlate,
};
void _init(void)
diff --git a/extensions/libxt_time.txlate b/extensions/libxt_time.txlate
new file mode 100644
index 00000000..ff4a7b88
--- /dev/null
+++ b/extensions/libxt_time.txlate
@@ -0,0 +1,26 @@
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --weekdays Sa,Su -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta day {6,0} counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestart 12:00 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestop 12:00 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2021 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "2021-01-01 00:00:00"-"2038-01-19 03:14:07" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-01 00:00:00" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021-01-29T00:00:00 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-29 00:00:00" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {1,2,3,4,5} counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 ! --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {6,0} counter reject
diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/linux/netfilter/xt_IDLETIMER.h
index 208ae938..49ddcdc6 100644
--- a/include/linux/netfilter/xt_IDLETIMER.h
+++ b/include/linux/netfilter/xt_IDLETIMER.h
@@ -32,6 +32,7 @@
#include <linux/types.h>
#define MAX_IDLETIMER_LABEL_SIZE 28
+#define XT_IDLETIMER_ALARM 0x01
struct idletimer_tg_info {
__u32 timeout;
@@ -42,4 +43,15 @@ struct idletimer_tg_info {
struct idletimer_tg *timer __attribute__((aligned(8)));
};
+struct idletimer_tg_info_v1 {
+ __u32 timeout;
+
+ char label[MAX_IDLETIMER_LABEL_SIZE];
+
+ __u8 send_nl_msg; /* unused: for compatibility with Android */
+ __u8 timer_type;
+
+ /* for kernel module internal use only */
+ struct idletimer_tg *timer __attribute__((aligned(8)));
+};
#endif
diff --git a/include/linux/netfilter/xt_sctp.h b/include/linux/netfilter/xt_sctp.h
index a501e619..5b28525a 100644
--- a/include/linux/netfilter/xt_sctp.h
+++ b/include/linux/netfilter/xt_sctp.h
@@ -40,19 +40,19 @@ struct xt_sctp_info {
#define SCTP_CHUNKMAP_SET(chunkmap, type) \
do { \
(chunkmap)[type / bytes(__u32)] |= \
- 1 << (type % bytes(__u32)); \
+ 1u << (type % bytes(__u32)); \
} while (0)
#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
do { \
(chunkmap)[type / bytes(__u32)] &= \
- ~(1 << (type % bytes(__u32))); \
+ ~(1u << (type % bytes(__u32))); \
} while (0)
#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
({ \
((chunkmap)[type / bytes (__u32)] & \
- (1 << (type % bytes (__u32)))) ? 1: 0; \
+ (1u << (type % bytes (__u32)))) ? 1: 0; \
})
#define SCTP_CHUNKMAP_RESET(chunkmap) \
diff --git a/include/xtables.h b/include/xtables.h
index 4aa084a1..5044dd08 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -448,6 +448,7 @@ extern struct xtables_match *xtables_matches;
extern struct xtables_target *xtables_targets;
extern void xtables_init(void);
+extern void xtables_fini(void);
extern void xtables_set_nfproto(uint8_t);
extern void *xtables_calloc(size_t, size_t);
extern void *xtables_malloc(size_t);
diff --git a/iptables-test.py b/iptables-test.py
index fdb4e6a3..6b6eb611 100755
--- a/iptables-test.py
+++ b/iptables-test.py
@@ -119,8 +119,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
elif splitted[0] == EBTABLES:
command = EBTABLES_SAVE
- path = os.path.abspath(os.path.curdir) + "/iptables/" + EXECUTEABLE
- command = path + " " + command
+ command = EXECUTEABLE + " " + command
if netns:
command = "ip netns exec ____iptables-container-test " + command
@@ -165,7 +164,7 @@ def execute_cmd(cmd, filename, lineno):
'''
global log_file
if cmd.startswith('iptables ') or cmd.startswith('ip6tables ') or cmd.startswith('ebtables ') or cmd.startswith('arptables '):
- cmd = os.path.abspath(os.path.curdir) + "/iptables/" + EXECUTEABLE + " " + cmd
+ cmd = EXECUTEABLE + " " + cmd
print("command: {}".format(cmd), file=log_file)
ret = subprocess.call(cmd, shell=True, universal_newlines=True,
@@ -222,7 +221,7 @@ def run_test_file(filename, netns):
execute_cmd("ip netns add ____iptables-container-test", filename, 0)
for lineno, line in enumerate(f):
- if line[0] == "#":
+ if line[0] == "#" or len(line.strip()) == 0:
continue
if line[0] == ":":
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index fc834e0f..dc66b3cc 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -38,7 +38,7 @@ xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \
nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \
xtables-monitor.c nft-cache.c \
xtables-arp-standalone.c xtables-arp.c \
- nft-bridge.c \
+ nft-bridge.c nft-cmd.c \
xtables-eb-standalone.c xtables-eb.c \
xtables-eb-translate.c \
xtables-translate.c
@@ -53,7 +53,11 @@ 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
+ ip6tables-save.8 iptables-extensions.8 \
+ iptables-apply.8 ip6tables-apply.8
+
+sbin_SCRIPT = iptables-apply
+
if ENABLE_NFTABLES
man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
iptables-translate.8 ip6tables-translate.8 \
@@ -106,3 +110,4 @@ install-exec-hook:
for i in ${v4_sbin_links}; do ${LN_S} -f xtables-legacy-multi "${DESTDIR}${sbindir}/$$i"; done;
for i in ${v6_sbin_links}; do ${LN_S} -f xtables-legacy-multi "${DESTDIR}${sbindir}/$$i"; done;
for i in ${x_sbin_links}; do ${LN_S} -f xtables-nft-multi "${DESTDIR}${sbindir}/$$i"; done;
+ ${LN_S} -f iptables-apply "${DESTDIR}${sbindir}/ip6tables-apply"
diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8
index db8b2ab2..1fa5ad93 100644
--- a/iptables/ebtables-nft.8
+++ b/iptables/ebtables-nft.8
@@ -522,35 +522,35 @@ 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."
.SS arp
Specify (R)ARP fields. The protocol must be specified as
.IR ARP " or " RARP .
@@ -1108,8 +1108,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-apply.8 b/iptables/ip6tables-apply.8
new file mode 100644
index 00000000..994b487a
--- /dev/null
+++ b/iptables/ip6tables-apply.8
@@ -0,0 +1 @@
+.so man8/iptables-apply.8
diff --git a/iptables/ip6tables-standalone.c b/iptables/ip6tables-standalone.c
index 35d2d9a5..105b83ba 100644
--- a/iptables/ip6tables-standalone.c
+++ b/iptables/ip6tables-standalone.c
@@ -64,6 +64,8 @@ ip6tables_main(int argc, char *argv[])
ip6tc_free(handle);
}
+ xtables_fini();
+
if (!ret) {
if (errno == EINVAL) {
fprintf(stderr, "ip6tables: %s. "
diff --git a/iptables/iptables-apply b/iptables/iptables-apply
index 819ca4a4..4683b1b4 100755
--- a/iptables/iptables-apply
+++ b/iptables/iptables-apply
@@ -1,174 +1,294 @@
#!/bin/bash
-#
# iptables-apply -- a safer way to update iptables remotely
#
-# Copyright © Martin F. Krafft <madduck@madduck.net>
+# Usage:
+# iptables-apply [-hV] [-t timeout] [-w savefile] {[rulesfile]|-c [runcmd]}
+#
+# Versions:
+# * 1.0 Copyright 2006 Martin F. Krafft <madduck@madduck.net>
+# Original version
+# * 1.1 Copyright 2010 GW <gw.2010@tnode.com or http://gw.tnode.com/>
+# Added parameter -c (run command)
+# Added parameter -w (save successfully applied rules to file)
+# Major code cleanup
+#
# Released under the terms of the Artistic Licence 2.0
#
set -eu
-PROGNAME="${0##*/}";
-VERSION=1.0
+PROGNAME="${0##*/}"
+VERSION=1.1
+
+
+### Default settings
+
+DEF_TIMEOUT=10
+
+MODE=0 # apply rulesfile mode
+# MODE=1 # run command mode
+
+case "$PROGNAME" in
+ (*6*)
+ SAVE=ip6tables-save
+ RESTORE=ip6tables-restore
+ DEF_RULESFILE="/etc/network/ip6tables.up.rules"
+ DEF_SAVEFILE="$DEF_RULESFILE"
+ DEF_RUNCMD="/etc/network/ip6tables.up.run"
+ ;;
+ (*)
+ SAVE=iptables-save
+ RESTORE=iptables-restore
+ DEF_RULESFILE="/etc/network/iptables.up.rules"
+ DEF_SAVEFILE="$DEF_RULESFILE"
+ DEF_RUNCMD="/etc/network/iptables.up.run"
+ ;;
+esac
+
-TIMEOUT=10
+### Functions
-function blurb()
-{
- cat <<-_eof
+function blurb() {
+ cat <<-__EOF__
$PROGNAME $VERSION -- a safer way to update iptables remotely
- _eof
+ __EOF__
}
-function copyright()
-{
- cat <<-_eof
- $PROGNAME is C Martin F. Krafft <madduck@madduck.net>.
+function copyright() {
+ cat <<-__EOF__
+ $PROGNAME has been published under the terms of the Artistic Licence 2.0.
- The program has been published under the terms of the Artistic Licence 2.0
- _eof
+ Original version - Copyright 2006 Martin F. Krafft <madduck@madduck.net>.
+ Version 1.1 - Copyright 2010 GW <gw.2010@tnode.com or http://gw.tnode.com/>.
+ __EOF__
}
-function about()
-{
+function about() {
blurb
echo
copyright
}
-function usage()
-{
- cat <<-_eof
- Usage: $PROGNAME [options] ruleset
+function usage() {
+ blurb
+ echo
+ cat <<-__EOF__
+ Usage:
+ $PROGNAME [-hV] [-t timeout] [-w savefile] {[rulesfile]|-c [runcmd]}
+
+ The script will try to apply a new rulesfile (as output by iptables-save,
+ read by iptables-restore) or run a command to configure iptables and then
+ prompt the user whether the changes are okay. If the new iptables rules cut
+ the existing connection, the user will not be able to answer affirmatively.
+ In this case, the script rolls back to the previous working iptables rules
+ after the timeout expires.
+
+ Successfully applied rules can also be written to savefile and later used
+ to roll back to this state. This can be used to implement a store last good
+ configuration mechanism when experimenting with an iptables setup script:
+ $PROGNAME -w $DEF_SAVEFILE -c $DEF_RUNCMD
- The script will try to apply a new ruleset (as output by iptables-save/read
- by iptables-restore) to iptables, then prompt the user whether the changes
- are okay. If the new ruleset cut the existing connection, the user will not
- be able to answer affirmatively. In this case, the script rolls back to the
- previous ruleset.
+ When called as ip6tables-apply, the script will use ip6tables-save/-restore
+ and IPv6 default values instead. Default value for rulesfile is
+ '$DEF_RULESFILE'.
+
+ Options:
+
+ -t seconds, --timeout seconds
+ Specify the timeout in seconds (default: $DEF_TIMEOUT).
+ -w savefile, --write savefile
+ Specify the savefile where successfully applied rules will be written to
+ (default if empty string is given: $DEF_SAVEFILE).
+ -c runcmd, --command runcmd
+ Run command runcmd to configure iptables instead of applying a rulesfile
+ (default: $DEF_RUNCMD).
+ -h, --help
+ Display this help text.
+ -V, --version
+ Display version information.
+
+ __EOF__
+}
- The following options may be specified, using standard conventions:
+function checkcommands() {
+ for cmd in "${COMMANDS[@]}"; do
+ if ! command -v "$cmd" >/dev/null; then
+ echo "Error: needed command not found: $cmd" >&2
+ exit 127
+ fi
+ done
+}
- -t | --timeout Specify the timeout in seconds (default: $TIMEOUT)
- -V | --version Display version information
- -h | --help Display this help text
- _eof
+function revertrules() {
+ echo -n "Reverting to old iptables rules... "
+ "$RESTORE" <"$TMPFILE"
+ echo "done."
}
-SHORTOPTS="t:Vh";
-LONGOPTS="timeout:,version,help";
+
+### Parsing and checking parameters
+
+TIMEOUT="$DEF_TIMEOUT"
+SAVEFILE=""
+
+SHORTOPTS="t:w:chV";
+LONGOPTS="timeout:,write:,command,help,version";
OPTS=$(getopt -s bash -o "$SHORTOPTS" -l "$LONGOPTS" -n "$PROGNAME" -- "$@") || exit $?
for opt in $OPTS; do
case "$opt" in
- (-*) unset OPT_STATE;;
+ (-*)
+ unset OPT_STATE
+ ;;
(*)
case "${OPT_STATE:-}" in
- (SET_TIMEOUT)
- eval TIMEOUT=$opt
- case "$TIMEOUT" in
- ([0-9]*) :;;
- (*)
- echo "E: non-numeric timeout value." >&2
- exit 1
- ;;
- esac
+ (SET_TIMEOUT) eval TIMEOUT=$opt;;
+ (SET_SAVEFILE)
+ eval SAVEFILE=$opt
+ [ -z "$SAVEFILE" ] && SAVEFILE="$DEF_SAVEFILE"
;;
esac
;;
esac
case "$opt" in
+ (-t|--timeout) OPT_STATE="SET_TIMEOUT";;
+ (-w|--write) OPT_STATE="SET_SAVEFILE";;
+ (-c|--command) MODE=1;;
(-h|--help) usage >&2; exit 0;;
(-V|--version) about >&2; exit 0;;
- (-t|--timeout) OPT_STATE=SET_TIMEOUT;;
(--) break;;
esac
shift
done
-case "$PROGNAME" in
- (*6*)
- SAVE=ip6tables-save
- RESTORE=ip6tables-restore
- DEFAULT_FILE=/etc/network/ip6tables
- ;;
- (*)
- SAVE=iptables-save
- RESTORE=iptables-restore
- DEFAULT_FILE=/etc/network/iptables
- ;;
-esac
-
-FILE="${1:-$DEFAULT_FILE}";
-
-if [[ -z "$FILE" ]]; then
- echo "E: missing file argument." >&2
+# Validate parameters
+if [ "$TIMEOUT" -ge 0 ] 2>/dev/null; then
+ TIMEOUT=$(($TIMEOUT))
+else
+ echo "Error: timeout must be a positive number" >&2
exit 1
fi
-if [[ ! -r "$FILE" ]]; then
- echo "E: cannot read $FILE" >&2
- exit 2
+if [ -n "$SAVEFILE" -a -e "$SAVEFILE" -a ! -w "$SAVEFILE" ]; then
+ echo "Error: savefile not writable: $SAVEFILE" >&2
+ exit 8
fi
-COMMANDS=(tempfile "$SAVE" "$RESTORE")
+case "$MODE" in
+ (1)
+ # Treat parameter as runcmd (run command mode)
+ RUNCMD="${1:-$DEF_RUNCMD}"
+ if [ ! -x "$RUNCMD" ]; then
+ echo "Error: runcmd not executable: $RUNCMD" >&2
+ exit 6
+ fi
+
+ # Needed commands
+ COMMANDS=(mktemp "$SAVE" "$RESTORE" "$RUNCMD")
+ checkcommands
+ ;;
+ (*)
+ # Treat parameter as rulesfile (apply rulesfile mode)
+ RULESFILE="${1:-$DEF_RULESFILE}";
+ if [ ! -r "$RULESFILE" ]; then
+ echo "Error: rulesfile not readable: $RULESFILE" >&2
+ exit 2
+ fi
+
+ # Needed commands
+ COMMANDS=(mktemp "$SAVE" "$RESTORE")
+ checkcommands
+ ;;
+esac
-for cmd in "${COMMANDS[@]}"; do
- if ! command -v $cmd >/dev/null; then
- echo "E: command not found: $cmd" >&2
- exit 127
- fi
-done
-umask 0700
+### Begin work
-TMPFILE=$(tempfile -p iptap)
+# Store old iptables rules to temporary file
+TMPFILE=`mktemp /tmp/$PROGNAME-XXXXXXXX`
trap "rm -f $TMPFILE" EXIT HUP INT QUIT ILL TRAP ABRT BUS \
FPE USR1 SEGV USR2 PIPE ALRM TERM
if ! "$SAVE" >"$TMPFILE"; then
+ # An error occured
if ! grep -q ipt /proc/modules 2>/dev/null; then
- echo "E: iptables support lacking from the kernel." >&2
+ echo "Error: iptables support lacking from the kernel" >&2
exit 3
else
- echo "E: unknown error saving current iptables ruleset." >&2
+ echo "Error: unknown error saving old iptables rules: $TMPFILE" >&2
exit 4
fi
fi
+# Legacy to stop the fail2ban daemon if present
[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban stop
-echo -n "Applying new ruleset... "
-if ! "$RESTORE" <"$FILE"; then
- echo "failed."
- echo "E: unknown error applying new iptables ruleset." >&2
- exit 5
-else
- echo "done."
-fi
+# Configure iptables
+case "$MODE" in
+ (1)
+ # Run command in background and kill it if it times out
+ echo -n "Running command '$RUNCMD'... "
+ "$RUNCMD" &
+ CMD_PID=$!
+ ( sleep "$TIMEOUT"; kill "$CMD_PID" 2>/dev/null; exit 0 ) &
+ CMDTIMEOUT_PID=$!
+ if ! wait "$CMD_PID"; then
+ echo "failed."
+ echo "Error: unknown error running command: $RUNCMD" >&2
+ revertrules
+ exit 7
+ else
+ echo "done."
+ fi
+ ;;
+ (*)
+ # Apply iptables rulesfile
+ echo -n "Applying new iptables rules from '$RULESFILE'... "
+ if ! "$RESTORE" <"$RULESFILE"; then
+ echo "failed."
+ echo "Error: unknown error applying new iptables rules: $RULESFILE" >&2
+ revertrules
+ exit 5
+ else
+ echo "done."
+ fi
+ ;;
+esac
+# Prompt user for confirmation
echo -n "Can you establish NEW connections to the machine? (y/N) "
-read -n1 -t "${TIMEOUT:-15}" ret 2>&1 || :
+read -n1 -t "$TIMEOUT" ret 2>&1 || :
case "${ret:-}" in
(y*|Y*)
+ # Success
echo
+
+ if [ ! -z "$SAVEFILE" ]; then
+ # Write successfully applied rules to the savefile
+ echo "Writing successfully applied rules to '$SAVEFILE'..."
+ if ! "$SAVE" >"$SAVEFILE"; then
+ echo "Error: unknown error writing successfully applied rules: $SAVEFILE" >&2
+ exit 9
+ fi
+ fi
+
echo "... then my job is done. See you next time."
;;
(*)
- if [[ -z "${ret:-}" ]]; then
- echo "apparently not..."
+ # Failed
+ echo
+ if [ -z "${ret:-}" ]; then
+ echo "Timeout! Something happened (or did not). Better play it safe..."
else
- echo
+ echo "No affirmative response! Better play it safe..."
fi
- echo "Timeout. Something happened (or did not). Better play it safe..."
- echo -n "Reverting to old ruleset... "
- "$RESTORE" <"$TMPFILE";
- echo "done."
+ revertrules
exit 255
;;
esac
+# Legacy to start the fail2ban daemon again
[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban start
exit 0
diff --git a/iptables/iptables-apply.8.in b/iptables/iptables-apply.8.in
index cdc9c447..f0ed4e5f 100644
--- a/iptables/iptables-apply.8.in
+++ b/iptables/iptables-apply.8.in
@@ -1,6 +1,6 @@
.\" Title: iptables-apply
-.\" Author: Martin F. Krafft
-.\" Date: Jun 04, 2006
+.\" Author: Martin F. Krafft, GW
+.\" Date: May 10, 2010
.\"
.TH IPTABLES\-APPLY 8 "" "@PACKAGE_STRING@" "@PACKAGE_STRING@"
.\" disable hyphenation
@@ -8,23 +8,37 @@
.SH NAME
iptables-apply \- a safer way to update iptables remotely
.SH SYNOPSIS
-\fBiptables\-apply\fP [\-\fBhV\fP] [\fB-t\fP \fItimeout\fP] \fIruleset\-file\fP
+\fBiptables\-apply\fP [\-\fBhV\fP] [\fB-t\fP \fItimeout\fP] [\fB-w\fP \fIsavefile\fP] {[\fIrulesfile]|-c [runcmd]}\fP
.SH "DESCRIPTION"
.PP
-iptables\-apply will try to apply a new ruleset (as output by
-iptables\-save/read by iptables\-restore) to iptables, then prompt the
-user whether the changes are okay. If the new ruleset cut the existing
-connection, the user will not be able to answer affirmatively. In this
-case, the script rolls back to the previous ruleset after the timeout
-expired. The timeout can be set with \fB\-t\fP.
+iptables\-apply will try to apply a new rulesfile (as output by
+iptables-save, read by iptables-restore) or run a command to configure
+iptables and then prompt the user whether the changes are okay. If the
+new iptables rules cut the existing connection, the user will not be
+able to answer affirmatively. In this case, the script rolls back to
+the previous working iptables rules after the timeout expires.
.PP
-When called as \fBip6tables\-apply\fP, the script will use
-ip6tables\-save/\-restore instead.
+Successfully applied rules can also be written to savefile and later used
+to roll back to this state. This can be used to implement a store last good
+configuration mechanism when experimenting with an iptables setup script:
+iptables-apply \-w /etc/network/iptables.up.rules \-c /etc/network/iptables.up.run
+.PP
+When called as ip6tables\-apply, the script will use
+ip6tables\-save/\-restore and IPv6 default values instead. Default
+value for rulesfile is '/etc/network/iptables.up.rules'.
.SH OPTIONS
.TP
\fB\-t\fP \fIseconds\fR, \fB\-\-timeout\fP \fIseconds\fR
-Sets the timeout after which the script will roll back to the previous
-ruleset.
+Sets the timeout in seconds after which the script will roll back
+to the previous ruleset (default: 10).
+.TP
+\fB\-w\fP \fIsavefile\fR, \fB\-\-write\fP \fIsavefile\fR
+Specify the savefile where successfully applied rules will be written to
+(default if empty string is given: /etc/network/iptables.up.rules).
+.TP
+\fB\-c\fP \fIruncmd\fR, \fB\-\-command\fP \fIruncmd\fR
+Run command runcmd to configure iptables instead of applying a rulesfile
+(default: /etc/network/iptables.up.run).
.TP
\fB\-h\fP, \fB\-\-help\fP
Display usage information.
@@ -36,9 +50,11 @@ Display version information.
\fBiptables-restore\fP(8), \fBiptables-save\fP(8), \fBiptables\fR(8).
.SH LEGALESE
.PP
-iptables\-apply is copyright by Martin F. Krafft.
+Original iptables-apply - Copyright 2006 Martin F. Krafft <madduck@madduck.net>.
+Version 1.1 - Copyright 2010 GW <gw.2010@tnode.com or http://gw.tnode.com/>.
.PP
-This manual page was written by Martin F. Krafft <madduck@madduck.net>
+This manual page was written by Martin F. Krafft <madduck@madduck.net> and
+extended by GW <gw.2010@tnode.com or http://gw.tnode.com/>.
.PP
Permission is granted to copy, distribute and/or modify this document
under the terms of the Artistic License 2.0.
diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in
index f751492d..b4b62f92 100644
--- a/iptables/iptables-restore.8.in
+++ b/iptables/iptables-restore.8.in
@@ -87,7 +87,7 @@ from Rusty Russell.
.br
Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-restore.
.SH SEE ALSO
-\fBiptables\-save\fP(8), \fBiptables\fP(8)
+\fBiptables\-apply\fP(8),\fBiptables\-save\fP(8), \fBiptables\fP(8)
.PP
The iptables-HOWTO, which details more iptables usage, the NAT-HOWTO,
which details NAT, and the netfilter-hacking-HOWTO which details the
diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c
index b0a51d49..cc2c2b8b 100644
--- a/iptables/iptables-restore.c
+++ b/iptables/iptables-restore.c
@@ -178,8 +178,10 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
if (buffer[0] == '\n')
continue;
else if (buffer[0] == '#') {
- if (verbose)
+ if (verbose) {
fputs(buffer, stdout);
+ fflush(stdout);
+ }
continue;
} else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
if (!testing) {
@@ -370,7 +372,7 @@ static const struct iptables_restore_cb ipt_restore_cb = {
int
iptables_restore_main(int argc, char *argv[])
{
- int c;
+ int c, ret;
iptables_globals.program_name = "iptables-restore";
c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
@@ -385,7 +387,10 @@ iptables_restore_main(int argc, char *argv[])
init_extensions4();
#endif
- return ip46tables_restore_main(&ipt_restore_cb, argc, argv);
+ ret = ip46tables_restore_main(&ipt_restore_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif
@@ -401,7 +406,7 @@ static const struct iptables_restore_cb ip6t_restore_cb = {
int
ip6tables_restore_main(int argc, char *argv[])
{
- int c;
+ int c, ret;
ip6tables_globals.program_name = "ip6tables-restore";
c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
@@ -416,6 +421,9 @@ ip6tables_restore_main(int argc, char *argv[])
init_extensions6();
#endif
- return ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
+ ret = ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif
diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in
index 29ef2829..7683fd37 100644
--- a/iptables/iptables-save.8.in
+++ b/iptables/iptables-save.8.in
@@ -62,7 +62,7 @@ Rusty Russell <rusty@rustcorp.com.au>
.br
Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-save.
.SH SEE ALSO
-\fBiptables\-restore\fP(8), \fBiptables\fP(8)
+\fBiptables\-apply\fP(8),\fBiptables\-restore\fP(8), \fBiptables\fP(8)
.PP
The iptables-HOWTO, which details more iptables usage, the NAT-HOWTO,
which details NAT, and the netfilter-hacking-HOWTO which details the
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index c7251e35..4efd6667 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -218,6 +218,8 @@ struct iptables_save_cb ipt_save_cb = {
int
iptables_save_main(int argc, char *argv[])
{
+ int ret;
+
iptables_globals.program_name = "iptables-save";
if (xtables_init_all(&iptables_globals, NFPROTO_IPV4) < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
@@ -230,7 +232,10 @@ iptables_save_main(int argc, char *argv[])
init_extensions4();
#endif
- return do_iptables_save(&ipt_save_cb, argc, argv);
+ ret = do_iptables_save(&ipt_save_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif /* ENABLE_IPV4 */
@@ -259,6 +264,8 @@ struct iptables_save_cb ip6t_save_cb = {
int
ip6tables_save_main(int argc, char *argv[])
{
+ int ret;
+
ip6tables_globals.program_name = "ip6tables-save";
if (xtables_init_all(&ip6tables_globals, NFPROTO_IPV6) < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
@@ -271,6 +278,9 @@ ip6tables_save_main(int argc, char *argv[])
init_extensions6();
#endif
- return do_iptables_save(&ip6t_save_cb, argc, argv);
+ ret = do_iptables_save(&ip6t_save_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif /* ENABLE_IPV6 */
diff --git a/iptables/iptables-standalone.c b/iptables/iptables-standalone.c
index c211fb73..8c67ea4d 100644
--- a/iptables/iptables-standalone.c
+++ b/iptables/iptables-standalone.c
@@ -64,6 +64,8 @@ iptables_main(int argc, char *argv[])
iptc_free(handle);
}
+ xtables_fini();
+
if (!ret) {
if (errno == EINVAL) {
fprintf(stderr, "iptables: %s. "
diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in
index 78df8f08..054564b3 100644
--- a/iptables/iptables.8.in
+++ b/iptables/iptables.8.in
@@ -245,13 +245,13 @@ add, delete, insert, replace and append commands).
This option has no effect in iptables and iptables-restore.
If a rule using the \fB\-4\fP option is inserted with (and only with)
ip6tables-restore, it will be silently ignored. Any other uses will throw an
-error. This option allows to put both IPv4 and IPv6 rules in a single rule file
+error. This option allows IPv4 and IPv6 rules in a single rule file
for use with both iptables-restore and ip6tables-restore.
.TP
\fB\-6\fP, \fB\-\-ipv6\fP
If a rule using the \fB\-6\fP option is inserted with (and only with)
iptables-restore, it will be silently ignored. Any other uses will throw an
-error. This option allows to put both IPv4 and IPv6 rules in a single rule file
+error. This option allows IPv4 and IPv6 rules in a single rule file
for use with both iptables-restore and ip6tables-restore.
This option has no effect in ip6tables and ip6tables-restore.
.TP
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 7068f82c..67f4529d 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -126,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;
@@ -582,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);
@@ -603,6 +604,8 @@ nft_arp_print_rule(struct nftnl_rule *r, unsigned int num, unsigned int format)
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
+
+ nft_clear_iptables_command_state(&cs);
}
static bool nft_arp_is_same(const void *data_a,
@@ -632,31 +635,6 @@ 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,
- void *data)
-{
- const struct iptables_command_state *cs = data;
- struct iptables_command_state this = {};
- bool ret = false;
-
- /* Delete by matching rule case */
- nft_rule_to_iptables_command_state(r, &this);
-
- if (!nft_arp_is_same(&cs->arp, &this.arp))
- goto out;
-
- if (!compare_targets(cs->target, this.target))
- goto out;
-
- if (this.jumpto && strcmp(cs->jumpto, this.jumpto) != 0)
- goto out;
-
- ret = true;
-out:
- ops->clear_cs(&this);
- return ret;
-}
-
static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
{
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
@@ -674,11 +652,9 @@ struct nft_family_ops nft_family_ops_arp = {
.print_header = nft_arp_print_header,
.print_rule = nft_arp_print_rule,
.save_rule = nft_arp_save_rule,
- .save_counters = save_counters,
.save_chain = nft_arp_save_chain,
.post_parse = NULL,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
- .rule_find = nft_arp_rule_find,
.parse_target = nft_ipv46_parse_target,
};
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index 2e4b309b..dbf11eb5 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -17,8 +17,11 @@
#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"
void ebt_cs_clean(struct iptables_command_state *cs)
@@ -126,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;
@@ -182,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))
@@ -290,6 +294,221 @@ 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);
+ uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID);
+ struct nftnl_set_list *slist;
+ struct nftnl_set *set;
+
+ slist = nft_set_list_get(ctx->h, ctx->table, set_name);
+ if (slist) {
+ set = nftnl_set_list_lookup_byname(slist, set_name);
+ if (set)
+ return set;
+
+ set = nft_set_batch_lookup_byid(ctx->h, set_id);
+ if (set)
+ return set;
+ }
+
+ 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)
{
@@ -332,11 +551,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)
@@ -471,15 +691,15 @@ static void nft_bridge_save_rule(const void *data, unsigned int format)
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);
}
@@ -536,41 +756,6 @@ 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,
- void *data)
-{
- struct iptables_command_state *cs = data;
- struct iptables_command_state this = {};
- bool ret = false;
-
- nft_rule_to_ebtables_command_state(r, &this);
-
- DEBUGP("comparing with... ");
-
- if (!nft_bridge_is_same(cs, &this))
- goto out;
-
- if (!compare_matches(cs->matches, this.matches)) {
- DEBUGP("Different matches\n");
- goto out;
- }
-
- if (!compare_targets(cs->target, this.target)) {
- DEBUGP("Different target\n");
- goto out;
- }
-
- if (cs->jumpto != NULL && strcmp(cs->jumpto, this.jumpto) != 0) {
- DEBUGP("Different verdict\n");
- goto out;
- }
-
- ret = true;
-out:
- ops->clear_cs(&this);
- return ret;
-}
-
static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xlate *xl)
{
int ret = 1, numeric = cs->options & OPT_NUMERIC;
@@ -740,17 +925,16 @@ 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 = save_counters,
.save_chain = nft_bridge_save_chain,
.post_parse = NULL,
.rule_to_cs = nft_rule_to_ebtables_command_state,
.clear_cs = ebt_cs_clean,
- .rule_find = nft_bridge_rule_find,
.xlate = nft_bridge_xlate,
};
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
index c55970d0..638b18bc 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -11,6 +11,7 @@
#include <assert.h>
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
#include <xtables.h>
@@ -18,11 +19,58 @@
#include <libmnl/libmnl.h>
#include <libnftnl/gen.h>
+#include <libnftnl/set.h>
#include <libnftnl/table.h>
#include "nft.h"
#include "nft-cache.h"
+static void cache_chain_list_insert(struct list_head *list, const char *name)
+{
+ struct cache_chain *pos = NULL, *new;
+
+ list_for_each_entry(pos, list, head) {
+ int cmp = strcmp(pos->name, name);
+
+ if (!cmp)
+ return;
+ if (cmp > 0)
+ break;
+ }
+
+ new = xtables_malloc(sizeof(*new));
+ new->name = strdup(name);
+ list_add_tail(&new->head, pos ? &pos->head : list);
+}
+
+void nft_cache_level_set(struct nft_handle *h, int level,
+ const struct nft_cmd *cmd)
+{
+ struct nft_cache_req *req = &h->cache_req;
+
+ if (level > req->level)
+ req->level = level;
+
+ if (!cmd || !cmd->table || req->all_chains)
+ return;
+
+ if (!req->table)
+ req->table = strdup(cmd->table);
+ else
+ assert(!strcmp(req->table, cmd->table));
+
+ if (!cmd->chain) {
+ req->all_chains = true;
+ return;
+ }
+
+ cache_chain_list_insert(&req->chain_list, cmd->chain);
+ if (cmd->rename)
+ cache_chain_list_insert(&req->chain_list, cmd->rename);
+ if (cmd->jumpto)
+ cache_chain_list_insert(&req->chain_list, cmd->jumpto);
+}
+
static int genid_cb(const struct nlmsghdr *nlh, void *data)
{
uint32_t *genid = data;
@@ -85,7 +133,7 @@ static int fetch_table_cache(struct nft_handle *h)
char buf[16536];
struct nlmsghdr *nlh;
struct nftnl_table_list *list;
- int ret;
+ int i, ret;
if (h->cache->tables)
return 0;
@@ -103,6 +151,21 @@ static int fetch_table_cache(struct nft_handle *h)
h->cache->tables = list;
+ 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 0;
+
+ h->cache->table[type].sets = nftnl_set_list_alloc();
+ if (!h->cache->table[type].sets)
+ return 0;
+ }
+
return 1;
}
@@ -152,56 +215,158 @@ err:
return MNL_CB_OK;
}
-static int fetch_chain_cache(struct nft_handle *h,
- const struct builtin_table *t,
- const char *chain)
+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_chain_list_cb_data d = {
+ 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,
};
- char buf[16536];
+ uint16_t flags = NLM_F_DUMP;
+ struct nftnl_set *s = NULL;
struct nlmsghdr *nlh;
+ char buf[16536];
int i, ret;
- if (!t) {
+ if (t) {
+ s = nftnl_set_alloc();
+ if (!s)
+ return -1;
+
+ nftnl_set_set_str(s, NFTNL_SET_TABLE, t->name);
+
+ if (set) {
+ nftnl_set_set_str(s, NFTNL_SET_NAME, set);
+ flags = NLM_F_ACK;
+ }
+ }
+
+ nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET,
+ h->family, flags, h->seq);
+
+ if (s) {
+ nftnl_set_nlmsg_build_payload(nlh, s);
+ nftnl_set_free(s);
+ }
+
+ ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d);
+ if (ret < 0 && errno == EINTR) {
+ assert(nft_restart(h) >= 0);
+ return ret;
+ }
+
+ 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;
- if (h->cache->table[type].chains)
- continue;
-
- h->cache->table[type].chains = nftnl_chain_list_alloc();
- if (!h->cache->table[type].chains)
- return -1;
+ nftnl_set_list_foreach(h->cache->table[type].sets,
+ set_fetch_elem_cb, h);
}
- } 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;
}
+ return ret;
+}
- if (t && chain) {
- struct nftnl_chain *c = nftnl_chain_alloc();
-
- if (!c)
- return -1;
+static int __fetch_chain_cache(struct nft_handle *h,
+ const struct builtin_table *t,
+ const struct nftnl_chain *c)
+{
+ struct nftnl_chain_list_cb_data d = {
+ .h = h,
+ .t = t,
+ };
+ char buf[16536];
+ struct nlmsghdr *nlh;
+ int ret;
- 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);
+ nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
+ c ? NLM_F_ACK : NLM_F_DUMP, h->seq);
+ if (c)
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)
@@ -210,6 +375,36 @@ static int fetch_chain_cache(struct nft_handle *h,
return ret;
}
+static int fetch_chain_cache(struct nft_handle *h,
+ const struct builtin_table *t,
+ struct list_head *chains)
+{
+ struct cache_chain *cc;
+ struct nftnl_chain *c;
+ int rc, ret = 0;
+
+ if (!chains)
+ return __fetch_chain_cache(h, t, NULL);
+
+ assert(t);
+
+ c = nftnl_chain_alloc();
+ if (!c)
+ return -1;
+
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, t->name);
+
+ list_for_each_entry(cc, chains, head) {
+ nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, cc->name);
+ rc = __fetch_chain_cache(h, t, c);
+ if (rc)
+ ret = rc;
+ }
+
+ nftnl_chain_free(c);
+ return ret;
+}
+
static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_chain *c = data;
@@ -265,20 +460,14 @@ static int nft_rule_list_update(struct nftnl_chain *c, void *data)
}
static int fetch_rule_cache(struct nft_handle *h,
- const struct builtin_table *t, const char *chain)
+ const struct builtin_table *t)
{
int i;
if (t) {
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
+ struct nftnl_chain_list *list =
+ h->cache->table[t->type].chains;
- 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);
}
@@ -295,83 +484,46 @@ static int fetch_rule_cache(struct nft_handle *h,
return 0;
}
+static int flush_cache(struct nft_handle *h, struct nft_cache *c,
+ const char *tablename);
+
static void
-__nft_build_cache(struct nft_handle *h, enum nft_cache_level level,
- const struct builtin_table *t, const char *chain)
+__nft_build_cache(struct nft_handle *h)
{
- uint32_t genid_start, genid_stop;
+ struct nft_cache_req *req = &h->cache_req;
+ const struct builtin_table *t = NULL;
+ struct list_head *chains = NULL;
+ uint32_t genid_check;
- if (level <= h->cache_level)
+ if (h->cache_init)
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_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 (req->table) {
+ t = nft_table_builtin_find(h, req->table);
+ if (!req->all_chains)
+ chains = &req->chain_list;
}
- 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);
-
- 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, 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_init = true;
+retry:
+ mnl_genid_get(h, &h->nft_genid);
- h->cache->table[type].chains = nftnl_chain_list_alloc();
+ if (req->level >= NFT_CL_TABLES)
+ fetch_table_cache(h);
+ if (req->level == NFT_CL_FAKE)
+ return;
+ if (req->level >= NFT_CL_CHAINS)
+ fetch_chain_cache(h, t, chains);
+ if (req->level >= NFT_CL_SETS)
+ fetch_set_cache(h, t, NULL);
+ if (req->level >= NFT_CL_RULES)
+ fetch_rule_cache(h, t);
+
+ mnl_genid_get(h, &genid_check);
+ if (h->nft_genid != genid_check) {
+ flush_cache(h, h->cache, NULL);
+ goto retry;
}
- h->cache_level = NFT_CL_RULES;
- mnl_genid_get(h, &h->nft_genid);
}
static void __nft_flush_cache(struct nft_handle *h)
@@ -421,6 +573,14 @@ static int __flush_chain_cache(struct nftnl_chain *c, void *data)
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)
{
@@ -429,10 +589,14 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
if (tablename) {
table = nft_table_builtin_find(h, tablename);
- if (!table || !c->table[table->type].chains)
+ if (!table)
return 0;
- nftnl_chain_list_foreach(c->table[table->type].chains,
- __flush_chain_cache, NULL);
+ 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;
}
@@ -440,51 +604,108 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
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].chains) {
+ 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;
+ }
+ }
+ if (c->tables) {
+ nftnl_table_list_free(c->tables);
+ c->tables = 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)
+ if (!h->cache_init)
return;
if (flush_cache(h, h->cache, tablename))
- h->cache_level = NFT_CL_NONE;
+ h->cache_init = false;
}
void nft_rebuild_cache(struct nft_handle *h)
{
- enum nft_cache_level level = h->cache_level;
-
- if (h->cache_level)
+ if (h->cache_init) {
__nft_flush_cache(h);
+ h->cache_init = false;
+ }
+
+ __nft_build_cache(h);
+}
+
+void nft_cache_build(struct nft_handle *h)
+{
+ struct nft_cache_req *req = &h->cache_req;
+ const struct builtin_table *t = NULL;
+ int i;
+
+ if (req->table)
+ t = nft_table_builtin_find(h, req->table);
+
+ /* fetch builtin chains as well (if existing) so nft_xt_builtin_init()
+ * doesn't override policies by accident */
+ if (t && !req->all_chains) {
+ for (i = 0; i < NF_INET_NUMHOOKS; i++) {
+ const char *cname = t->chains[i].name;
+
+ if (!cname)
+ break;
+ cache_chain_list_insert(&req->chain_list, cname);
+ }
+ }
- h->cache_level = NFT_CL_NONE;
- __nft_build_cache(h, level, NULL, NULL);
+ __nft_build_cache(h);
}
void nft_release_cache(struct nft_handle *h)
{
- if (h->cache_index)
- flush_cache(h, &h->__cache[0], NULL);
+ struct nft_cache_req *req = &h->cache_req;
+ struct cache_chain *cc, *cc_tmp;
+
+ while (h->cache_index)
+ flush_cache(h, &h->__cache[h->cache_index--], NULL);
+ flush_cache(h, &h->__cache[0], NULL);
+ h->cache = &h->__cache[0];
+ h->cache_init = false;
+
+ if (req->level != NFT_CL_FAKE)
+ req->level = NFT_CL_TABLES;
+ if (req->table) {
+ free(req->table);
+ req->table = NULL;
+ }
+ req->all_chains = false;
+ list_for_each_entry_safe(cc, cc_tmp, &req->chain_list, head) {
+ list_del(&cc->head);
+ free(cc->name);
+ free(cc);
+ }
}
struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
{
- __nft_build_cache(h, NFT_CL_TABLES, 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;
+
+ 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)
{
@@ -494,8 +715,6 @@ nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain)
if (!t)
return NULL;
- __nft_build_cache(h, NFT_CL_CHAINS, t, chain);
-
return h->cache->table[t->type].chains;
}
diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h
index cb7a7688..f4291180 100644
--- a/iptables/nft-cache.h
+++ b/iptables/nft-cache.h
@@ -2,17 +2,21 @@
#define _NFT_CACHE_H_
struct nft_handle;
+struct nft_cmd;
-void nft_fake_cache(struct nft_handle *h);
-void nft_build_cache(struct nft_handle *h, struct nftnl_chain *c);
+void nft_cache_level_set(struct nft_handle *h, int level,
+ const struct nft_cmd *cmd);
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);
+void nft_cache_build(struct nft_handle *h);
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-cmd.c b/iptables/nft-cmd.c
new file mode 100644
index 00000000..9c0901e7
--- /dev/null
+++ b/iptables/nft-cmd.c
@@ -0,0 +1,395 @@
+/*
+ * (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 <stdlib.h>
+#include <string.h>
+#include "nft.h"
+#include "nft-cmd.h"
+
+struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
+ const char *table, const char *chain,
+ struct iptables_command_state *state,
+ int rulenum, bool verbose)
+{
+ struct nftnl_rule *rule;
+ struct nft_cmd *cmd;
+
+ cmd = calloc(1, sizeof(struct nft_cmd));
+ if (!cmd)
+ return NULL;
+
+ cmd->command = command;
+ cmd->table = strdup(table);
+ if (chain)
+ cmd->chain = strdup(chain);
+ cmd->rulenum = rulenum;
+ cmd->verbose = verbose;
+
+ if (state) {
+ rule = nft_rule_new(h, chain, table, state);
+ if (!rule)
+ return NULL;
+
+ cmd->obj.rule = rule;
+
+ if (!state->target && strlen(state->jumpto) > 0)
+ cmd->jumpto = strdup(state->jumpto);
+ }
+
+ list_add_tail(&cmd->head, &h->cmd_list);
+
+ return cmd;
+}
+
+void nft_cmd_free(struct nft_cmd *cmd)
+{
+ free((void *)cmd->table);
+ free((void *)cmd->chain);
+ free((void *)cmd->policy);
+ free((void *)cmd->rename);
+ free((void *)cmd->jumpto);
+
+ switch (cmd->command) {
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_RULE_DELETE:
+ if (cmd->obj.rule)
+ nftnl_rule_free(cmd->obj.rule);
+ break;
+ default:
+ break;
+ }
+
+ list_del(&cmd->head);
+ free(cmd);
+}
+
+static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd)
+{
+ const struct builtin_table *t;
+
+ t = nft_table_builtin_find(h, cmd->table);
+ if (!t)
+ return;
+
+ /* 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 &&
+ !nft_chain_builtin_find(t, cmd->chain))
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+}
+
+int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ void *ref, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_APPEND, table, chain, state, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cmd_rule_bridge(h, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ int rulenum, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_INSERT, table, chain, state,
+ rulenum, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cmd_rule_bridge(h, cmd);
+
+ if (cmd->rulenum > 0)
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, state,
+ -1, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, NULL,
+ rulenum, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_FLUSH, table, chain, NULL, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ if (chain || verbose)
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_TABLES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_ZERO, table, chain, NULL, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
+ const char *table)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_ADD, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_DEL, table, chain, NULL, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ /* This triggers nft_bridge_chain_postprocess() when fetching the
+ * rule cache.
+ */
+ if (h->family == NFPROTO_BRIDGE)
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
+ const char *table, const char *newname)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RENAME, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->rename = strdup(newname);
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, unsigned int format)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_LIST, table, chain, NULL, rulenum,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->format = format;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
+ const char *table, void *data, int rulenum,
+ bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_REPLACE, table, chain, data,
+ rulenum, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
+ const char *table, void *data, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_CHECK, table, chain, data, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_set(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy,
+ const struct xt_counters *counters)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_UPDATE, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->policy = strdup(policy);
+ if (counters)
+ cmd->counters = *counters;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_table_flush(struct nft_handle *h, const char *table)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_TABLES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
+ const char *table)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RESTORE, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_ZERO, table, chain, NULL, rulenum,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, int counters)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_SAVE, table, chain, NULL, rulenum,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->counters_save = counters;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE, table, chain,
+ NULL, -1, false);
+ if (!cmd)
+ return 0;
+
+ cmd->policy = strdup(policy);
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+void nft_cmd_table_new(struct nft_handle *h, const char *table)
+{
+ nft_cmd_new(h, NFT_COMPAT_TABLE_NEW, table, NULL, NULL, -1, false);
+}
diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h
new file mode 100644
index 00000000..0e1776ce
--- /dev/null
+++ b/iptables/nft-cmd.h
@@ -0,0 +1,79 @@
+#ifndef _NFT_CMD_H_
+#define _NFT_CMD_H_
+
+#include <libiptc/linux_list.h>
+#include <stdbool.h>
+#include "nft.h"
+
+struct nftnl_rule;
+
+struct nft_cmd {
+ struct list_head head;
+ int command;
+ const char *table;
+ const char *chain;
+ const char *jumpto;
+ int rulenum;
+ bool verbose;
+ unsigned int format;
+ struct {
+ struct nftnl_rule *rule;
+ struct nftnl_set *set;
+ } obj;
+ const char *policy;
+ struct xt_counters counters;
+ const char *rename;
+ int counters_save;
+};
+
+struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
+ const char *table, const char *chain,
+ struct iptables_command_state *state,
+ int rulenum, bool verbose);
+void nft_cmd_free(struct nft_cmd *cmd);
+
+int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ void *ref, bool verbose);
+int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ int rulenum, bool verbose);
+int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ bool verbose);
+int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, bool verbose);
+int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
+ const char *table);
+int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, unsigned int format);
+int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
+ const char *table, void *data, bool verbose);
+int nft_cmd_chain_set(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy,
+ const struct xt_counters *counters);
+int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
+ const char *table, const char *newname);
+int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
+ const char *table, void *data, int rulenum,
+ bool verbose);
+int nft_cmd_table_flush(struct nft_handle *h, const char *table);
+int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
+ const char *table);
+int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum);
+int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, int counters);
+int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy);
+void nft_cmd_table_new(struct nft_handle *h, const char *table);
+
+#endif /* _NFT_CMD_H_ */
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 4497eb9b..afdecf97 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);
@@ -288,7 +288,7 @@ static void nft_ipv4_print_rule(struct nftnl_rule *r, unsigned int num,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
- xtables_rule_matches_free(&cs.matches);
+ nft_clear_iptables_command_state(&cs);
}
static void save_ipv4_addr(char letter, const struct in_addr *addr,
@@ -450,13 +450,11 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.print_header = print_header,
.print_rule = nft_ipv4_print_rule,
.save_rule = nft_ipv4_save_rule,
- .save_counters = save_counters,
.save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv4_proto_parse,
.post_parse = nft_ipv4_post_parse,
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
- .rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv4_xlate,
};
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index cacb1c9e..4008b7ea 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,
@@ -217,7 +217,7 @@ static void nft_ipv6_print_rule(struct nftnl_rule *r, unsigned int num,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
- xtables_rule_matches_free(&cs.matches);
+ nft_clear_iptables_command_state(&cs);
}
static void save_ipv6_addr(char letter, const struct in6_addr *addr,
@@ -402,13 +402,11 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.print_header = print_header,
.print_rule = nft_ipv6_print_rule,
.save_rule = nft_ipv6_save_rule,
- .save_counters = save_counters,
.save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv6_proto_parse,
.post_parse = nft_ipv6_post_parse,
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
- .rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv6_xlate,
};
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 6fd8ade5..c5a8f3fc 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -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,11 +554,10 @@ 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:
@@ -567,7 +565,7 @@ static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
break;
default:
fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n",
- ctx->family);
+ 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);
}
@@ -824,14 +831,6 @@ void save_rule_details(const struct iptables_command_state *cs,
}
}
-void save_counters(const void *data)
-{
- const struct iptables_command_state *cs = data;
-
- printf("[%llu:%llu] ", (unsigned long long)cs->counters.pcnt,
- (unsigned long long)cs->counters.bcnt);
-}
-
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy)
{
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
@@ -982,42 +981,6 @@ 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)
-{
- struct iptables_command_state *cs = data, this = {};
- bool ret = false;
-
- nft_rule_to_iptables_command_state(r, &this);
-
- DEBUGP("comparing with... ");
-#ifdef DEBUG_DEL
- nft_rule_print_save(r, NFT_RULE_APPEND, 0);
-#endif
- if (!ops->is_same(cs, &this))
- goto out;
-
- if (!compare_matches(cs->matches, this.matches)) {
- DEBUGP("Different matches\n");
- goto out;
- }
-
- if (!compare_targets(cs->target, this.target)) {
- DEBUGP("Different target\n");
- goto out;
- }
-
- if (strcmp(cs->jumpto, this.jumpto) != 0) {
- DEBUGP("Different verdict\n");
- goto out;
- }
-
- ret = true;
-out:
- ops->clear_cs(&this);
- return ret;
-}
-
void nft_check_xt_legacy(int family, bool is_ipt_save)
{
static const char tables6[] = "/proc/net/ip6_tables_names";
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 4ca551bd..94437ffe 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,10 +95,9 @@ 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);
void (*proto_parse)(struct iptables_command_state *cs,
struct xtables_args *args);
@@ -100,11 +105,9 @@ 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,
- void *data);
int (*xlate)(const void *data, struct xt_xlate *xl);
};
@@ -137,7 +140,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,
@@ -155,7 +159,6 @@ void save_rule_details(const struct iptables_command_state *cs,
unsigned const char *iniface_mask,
const char *outiface,
unsigned const char *outiface_mask);
-void save_counters(const void *data);
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy);
void save_matches_and_target(const struct iptables_command_state *cs,
bool goto_flag, const void *fw,
@@ -163,10 +166,7 @@ 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,
- void *data);
bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2);
bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2);
diff --git a/iptables/nft.c b/iptables/nft.c
index 83cf5fb7..0c5a74fc 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -256,23 +256,6 @@ static int mnl_batch_talk(struct nft_handle *h, int numcmds)
return err;
}
-enum obj_update_type {
- NFT_COMPAT_TABLE_ADD,
- NFT_COMPAT_TABLE_FLUSH,
- NFT_COMPAT_CHAIN_ADD,
- NFT_COMPAT_CHAIN_USER_ADD,
- NFT_COMPAT_CHAIN_USER_DEL,
- NFT_COMPAT_CHAIN_USER_FLUSH,
- NFT_COMPAT_CHAIN_UPDATE,
- NFT_COMPAT_CHAIN_RENAME,
- NFT_COMPAT_CHAIN_ZERO,
- NFT_COMPAT_RULE_APPEND,
- NFT_COMPAT_RULE_INSERT,
- NFT_COMPAT_RULE_REPLACE,
- NFT_COMPAT_RULE_DELETE,
- NFT_COMPAT_RULE_FLUSH,
-};
-
enum obj_action {
NFT_COMPAT_COMMIT,
NFT_COMPAT_ABORT,
@@ -288,6 +271,7 @@ struct obj_update {
struct nftnl_table *table;
struct nftnl_chain *chain;
struct nftnl_rule *rule;
+ struct nftnl_set *set;
void *ptr;
};
struct {
@@ -315,6 +299,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];
@@ -351,10 +336,23 @@ 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;
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ case NFT_COMPAT_TABLE_NEW:
+ assert(0);
+ break;
}
return snprintf(buf, len, "%s: %s", errmsg, tcr);
@@ -384,6 +382,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)
{
@@ -397,6 +402,38 @@ batch_rule_add(struct nft_handle *h, enum obj_update_type type,
return batch_add(h, type, r);
}
+static void batch_obj_del(struct nft_handle *h, struct obj_update *o);
+
+static void batch_chain_flush(struct nft_handle *h,
+ const char *table, const char *chain)
+{
+ struct obj_update *obj, *tmp;
+
+ list_for_each_entry_safe(obj, tmp, &h->obj_list, head) {
+ struct nftnl_rule *r = obj->ptr;
+
+ switch (obj->type) {
+ case NFT_COMPAT_RULE_APPEND:
+ case NFT_COMPAT_RULE_INSERT:
+ case NFT_COMPAT_RULE_REPLACE:
+ case NFT_COMPAT_RULE_DELETE:
+ break;
+ default:
+ continue;
+ }
+
+ if (table &&
+ strcmp(table, nftnl_rule_get_str(r, NFTNL_RULE_TABLE)))
+ continue;
+
+ if (chain &&
+ strcmp(chain, nftnl_rule_get_str(r, NFTNL_RULE_CHAIN)))
+ continue;
+
+ batch_obj_del(h, obj);
+ }
+}
+
const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
[NFT_TABLE_RAW] = {
.name = "raw",
@@ -732,6 +769,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
{
const struct builtin_table *t;
+ if (!h->cache_init)
+ return 0;
+
t = nft_table_builtin_find(h, table);
if (t == NULL)
return -1;
@@ -742,6 +782,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
if (nft_table_builtin_add(h, t) < 0)
return -1;
+ if (h->cache_req.level < NFT_CL_CHAINS)
+ return 0;
+
nft_chain_builtin_init(h, t);
h->cache->table[t->type].initialized = true;
@@ -775,8 +818,10 @@ int nft_restart(struct nft_handle *h)
return 0;
}
-int nft_init(struct nft_handle *h, const struct builtin_table *t)
+int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
{
+ memset(h, 0, sizeof(*h));
+
h->nl = mnl_socket_open(NETLINK_NETFILTER);
if (h->nl == NULL)
return -1;
@@ -786,19 +831,37 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t)
return -1;
}
+ h->ops = nft_family_ops_lookup(family);
+ if (!h->ops)
+ xtables_error(PARAMETER_PROBLEM, "Unknown family");
+
h->portid = mnl_socket_get_portid(h->nl);
h->tables = t;
h->cache = &h->__cache[0];
+ h->family = family;
INIT_LIST_HEAD(&h->obj_list);
INIT_LIST_HEAD(&h->err_list);
+ INIT_LIST_HEAD(&h->cmd_list);
+ INIT_LIST_HEAD(&h->cache_req.chain_list);
return 0;
}
void nft_fini(struct nft_handle *h)
{
- flush_chain_cache(h, NULL);
+ struct list_head *pos, *n;
+
+ list_for_each_safe(pos, n, &h->cmd_list)
+ nft_cmd_free(list_entry(pos, struct nft_cmd, head));
+
+ list_for_each_safe(pos, n, &h->obj_list)
+ batch_obj_del(h, list_entry(pos, struct obj_update, head));
+
+ list_for_each_safe(pos, n, &h->err_list)
+ mnl_err_list_free(list_entry(pos, struct mnl_err, head));
+
+ nft_release_cache(h);
mnl_socket_close(h->nl);
}
@@ -930,13 +993,189 @@ 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;
+ struct nft_cmd *cmd;
+
+ 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);
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_SET_ADD, table, NULL, NULL, -1, false);
+ if (!cmd) {
+ nftnl_set_free(s);
+ return NULL;
+ }
+ cmd->obj.set = s;
+
+ return s;
+}
+
+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;
+ uint32_t flags = 0;
+ 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);
+ flags = NFT_SET_INTERVAL;
+ }
+
+ s = add_anon_set(h, table, flags, type, len, cnt);
+ if (!s)
+ return -ENOMEM;
+ set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
+
+ if (ip) {
+ uint8_t field_len[2] = { ETH_ALEN, sizeof(struct in_addr) };
+
+ nftnl_set_set_data(s, NFTNL_SET_DESC_CONCAT,
+ field_len, sizeof(field_len));
+ }
+
+ 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);
+ if (ip) {
+ struct in_addr tmp = pairs[idx].in;
+
+ if (tmp.s_addr == INADDR_ANY)
+ pairs[idx].in.s_addr = INADDR_BROADCAST;
+ nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY_END,
+ &pairs[idx], len);
+ pairs[idx].in = tmp;
+ }
+ 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)
@@ -1138,7 +1377,7 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
inv ? NFT_RULE_COMPAT_F_INV : 0);
}
-static struct nftnl_rule *
+struct nftnl_rule *
nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
void *data)
{
@@ -1152,7 +1391,7 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
- if (h->ops->add(r, data) < 0)
+ if (h->ops->add(h, r, data) < 0)
goto err;
return r;
@@ -1166,28 +1405,15 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
int
nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
- void *data, struct nftnl_rule *ref, bool verbose)
+ struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose)
{
struct nftnl_chain *c;
- struct nftnl_rule *r;
int type;
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;
- r = nft_rule_new(h, chain, table, data);
- if (r == NULL)
- return 0;
-
if (ref) {
nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE,
nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE));
@@ -1195,17 +1421,16 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
} else
type = NFT_COMPAT_RULE_APPEND;
- if (batch_rule_add(h, type, r) == NULL) {
- nftnl_rule_free(r);
+ if (batch_rule_add(h, type, r) == NULL)
return 0;
- }
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);
- nftnl_chain_rule_del(r);
+ nftnl_chain_rule_del(ref);
+ nftnl_rule_free(ref);
} else {
c = nft_chain_find(h, table, chain);
if (!c) {
@@ -1219,19 +1444,18 @@ 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);
+ if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)))
+ printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt,
+ (unsigned long long)cs.counters.bcnt);
/* print chain name */
switch(type) {
@@ -1337,12 +1561,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;
@@ -1391,7 +1613,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);
}
@@ -1416,7 +1638,6 @@ 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;
@@ -1430,6 +1651,20 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
return ret == 0 ? 1 : 0;
}
+struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
+ uint32_t set_id)
+{
+ struct obj_update *n;
+
+ list_for_each_entry(n, &h->obj_list, head) {
+ if (n->type == NFT_COMPAT_SET_ADD &&
+ nftnl_set_get_u32(n->set, NFTNL_SET_ID) == set_id)
+ return n->set;
+ }
+
+ return NULL;
+}
+
static void
__nft_rule_flush(struct nft_handle *h, const char *table,
const char *chain, bool verbose, bool implicit)
@@ -1486,6 +1721,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
}
if (chain || !verbose) {
+ batch_chain_flush(h, table, chain);
__nft_rule_flush(h, table, chain, verbose, false);
flush_rule_cache(h, table, c);
return 1;
@@ -1501,6 +1737,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
while (c != NULL) {
chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ batch_chain_flush(h, table, chain);
__nft_rule_flush(h, table, chain, verbose, false);
flush_rule_cache(h, table, c);
c = nftnl_chain_list_iter_next(iter);
@@ -1562,7 +1799,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
} else {
c = nftnl_chain_alloc();
if (!c)
- return -1;
+ return 0;
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
@@ -1573,7 +1810,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
if (!created)
- return 0;
+ return 1;
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
@@ -1581,7 +1818,8 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
if (list)
nftnl_chain_list_add(c, list);
- return ret;
+ /* the core expects 1 for success and 0 for error */
+ return ret == 0 ? 1 : 0;
}
/* From linux/netlink.h */
@@ -1609,10 +1847,6 @@ 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);
@@ -1887,15 +2121,53 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
return 1;
}
+static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r,
+ struct nftnl_rule *rule)
+{
+ struct iptables_command_state _cs = {}, this = {}, *cs = &_cs;
+ bool ret = false;
+
+ h->ops->rule_to_cs(h, r, &this);
+ h->ops->rule_to_cs(h, rule, cs);
+
+ DEBUGP("comparing with... ");
+#ifdef DEBUG_DEL
+ nft_rule_print_save(h, r, NFT_RULE_APPEND, 0);
+#endif
+ if (!h->ops->is_same(cs, &this))
+ goto out;
+
+ if (!compare_matches(cs->matches, this.matches)) {
+ DEBUGP("Different matches\n");
+ goto out;
+ }
+
+ if (!compare_targets(cs->target, this.target)) {
+ DEBUGP("Different target\n");
+ goto out;
+ }
+
+ if ((!cs->target || !this.target) &&
+ strcmp(cs->jumpto, this.jumpto) != 0) {
+ DEBUGP("Different verdict\n");
+ goto out;
+ }
+
+ ret = true;
+out:
+ h->ops->clear_cs(&this);
+ h->ops->clear_cs(cs);
+ return ret;
+}
+
static struct nftnl_rule *
-nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum)
+nft_rule_find(struct nft_handle *h, struct nftnl_chain *c,
+ struct nftnl_rule *rule, int rulenum)
{
struct nftnl_rule *r;
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);
@@ -1906,7 +2178,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 = nft_rule_cmp(h, r, rule);
if (found)
break;
r = nftnl_rule_iter_next(iter);
@@ -1918,7 +2190,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen
}
int nft_rule_check(struct nft_handle *h, const char *chain,
- const char *table, void *data, bool verbose)
+ const char *table, struct nftnl_rule *rule, bool verbose)
{
struct nftnl_chain *c;
struct nftnl_rule *r;
@@ -1929,12 +2201,12 @@ int nft_rule_check(struct nft_handle *h, const char *chain,
if (!c)
goto fail_enoent;
- r = nft_rule_find(h, c, data, -1);
+ r = nft_rule_find(h, c, rule, -1);
if (r == NULL)
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:
@@ -1943,7 +2215,7 @@ fail_enoent:
}
int nft_rule_delete(struct nft_handle *h, const char *chain,
- const char *table, void *data, bool verbose)
+ const char *table, struct nftnl_rule *rule, bool verbose)
{
int ret = 0;
struct nftnl_chain *c;
@@ -1957,13 +2229,13 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
return 0;
}
- r = nft_rule_find(h, c, data, -1);
+ r = nft_rule_find(h, c, rule, -1);
if (r != NULL) {
ret =__nft_rule_del(h, r);
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;
@@ -1972,16 +2244,11 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
static struct nftnl_rule *
nft_rule_add(struct nft_handle *h, const char *chain,
- const char *table, struct iptables_command_state *cs,
+ const char *table, struct nftnl_rule *r,
struct nftnl_rule *ref, bool verbose)
{
- struct nftnl_rule *r;
uint64_t ref_id;
- r = nft_rule_new(h, chain, table, cs);
- if (r == NULL)
- return NULL;
-
if (ref) {
ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
if (ref_id > 0) {
@@ -1998,21 +2265,20 @@ nft_rule_add(struct nft_handle *h, const char *chain,
}
}
- if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) {
- nftnl_rule_free(r);
+ if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r))
return NULL;
- }
if (verbose)
- h->ops->print_rule(r, 0, FMT_PRINT_RULE);
+ h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
return r;
}
int nft_rule_insert(struct nft_handle *h, const char *chain,
- const char *table, void *data, int rulenum, bool verbose)
+ const char *table, struct nftnl_rule *new_rule, int rulenum,
+ bool verbose)
{
- struct nftnl_rule *r = NULL, *new_rule;
+ struct nftnl_rule *r = NULL;
struct nftnl_chain *c;
nft_xt_builtin_init(h, table);
@@ -2026,22 +2292,22 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
}
if (rulenum > 0) {
- r = nft_rule_find(h, c, data, rulenum);
+ r = nft_rule_find(h, c, new_rule, rulenum);
if (r == NULL) {
/* special case: iptables allows to insert into
* rule_count + 1 position.
*/
- r = nft_rule_find(h, c, data, rulenum - 1);
+ r = nft_rule_find(h, c, new_rule, rulenum - 1);
if (r != NULL)
- return nft_rule_append(h, chain, table, data,
- NULL, verbose);
+ return nft_rule_append(h, chain, table,
+ new_rule, NULL, verbose);
errno = E2BIG;
goto err;
}
}
- new_rule = nft_rule_add(h, chain, table, data, r, verbose);
+ new_rule = nft_rule_add(h, chain, table, new_rule, r, verbose);
if (!new_rule)
goto err;
@@ -2083,7 +2349,8 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
}
int nft_rule_replace(struct nft_handle *h, const char *chain,
- const char *table, void *data, int rulenum, bool verbose)
+ const char *table, struct nftnl_rule *rule,
+ int rulenum, bool verbose)
{
int ret = 0;
struct nftnl_chain *c;
@@ -2097,13 +2364,13 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
return 0;
}
- r = nft_rule_find(h, c, data, rulenum);
+ r = nft_rule_find(h, c, rule, rulenum);
if (r != NULL) {
DEBUGP("replacing rule with handle=%llu\n",
(unsigned long long)
nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
- ret = nft_rule_append(h, chain, table, data, r, verbose);
+ ret = nft_rule_append(h, chain, table, rule, r, verbose);
} else
errno = E2BIG;
@@ -2113,8 +2380,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;
@@ -2127,7 +2394,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;
}
@@ -2137,7 +2404,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);
}
@@ -2166,7 +2433,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);
@@ -2182,14 +2448,14 @@ 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;
@@ -2198,8 +2464,6 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
nft_xt_builtin_init(h, table);
nft_assert_table_compatible(h, table, chain);
- ops = nft_family_ops_lookup(h->family);
-
list = nft_chain_list_get(h, table, chain);
if (!list)
return 0;
@@ -2212,7 +2476,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;
@@ -2230,7 +2494,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;
@@ -2241,9 +2505,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)
@@ -2338,8 +2603,8 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
const char *table, int rulenum)
{
struct iptables_command_state cs = {};
+ struct nftnl_rule *r, *new_rule;
struct nftnl_chain *c;
- struct nftnl_rule *r;
int ret = 0;
nft_fn = nft_rule_delete;
@@ -2355,11 +2620,14 @@ 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;
+ new_rule = nft_rule_new(h, chain, table, &cs);
+ if (!new_rule)
+ return 1;
- ret = nft_rule_append(h, chain, table, &cs, r, false);
+ ret = nft_rule_append(h, chain, table, new_rule, r, false);
error:
return ret;
@@ -2376,6 +2644,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)
@@ -2420,11 +2721,23 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
case NFT_COMPAT_RULE_APPEND:
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
- case NFT_COMPAT_RULE_DELETE:
break;
+ case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH:
nftnl_rule_free(o->rule);
break;
+ case NFT_COMPAT_SET_ADD:
+ nftnl_set_free(o->set);
+ break;
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ case NFT_COMPAT_TABLE_NEW:
+ assert(0);
+ break;
}
h->obj_list_num--;
list_del(&o->head);
@@ -2491,6 +2804,14 @@ 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:
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ case NFT_COMPAT_TABLE_NEW:
break;
}
}
@@ -2581,6 +2902,21 @@ 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;
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ case NFT_COMPAT_TABLE_NEW:
+ assert(0);
}
mnl_nft_batch_continue(h->batch);
@@ -2601,7 +2937,6 @@ retry:
nft_refresh_transaction(h);
- i=0;
list_for_each_entry_safe(err, ne, &h->err_list, head)
mnl_err_list_free(err);
@@ -2676,27 +3011,33 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
+ ebt_cs_clean(&cs);
+
if (!r)
return -1;
udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
if (!udata)
- return -1;
+ goto err_free_rule;
if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1))
- return -1;
+ goto err_free_rule;
nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
nftnl_udata_buf_data(udata),
nftnl_udata_buf_len(udata));
nftnl_udata_buf_free(udata);
- if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r)) {
- nftnl_rule_free(r);
- return -1;
- }
+ if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r))
+ goto err_free_rule;
+
+ /* add the rule to chain so it is freed later */
+ nftnl_chain_rule_add_tail(r, c);
return 0;
+err_free_rule:
+ nftnl_rule_free(r);
+ return -1;
}
int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
@@ -2717,8 +3058,6 @@ 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;
}
@@ -2743,41 +3082,152 @@ static void nft_bridge_commit_prepare(struct nft_handle *h)
}
}
-int nft_commit(struct nft_handle *h)
+static void assert_chain_exists(struct nft_handle *h,
+ const char *table, const char *chain)
{
- return nft_action(h, NFT_COMPAT_COMMIT);
+ if (chain && !nft_chain_exists(h, table, chain))
+ xtables_error(PARAMETER_PROBLEM,
+ "Chain '%s' does not exist", chain);
}
-int nft_bridge_commit(struct nft_handle *h)
+static int nft_prepare(struct nft_handle *h)
{
- nft_bridge_commit_prepare(h);
- return nft_commit(h);
+ struct nft_cmd *cmd, *next;
+ int ret = 1;
+
+ nft_cache_build(h);
+
+ list_for_each_entry_safe(cmd, next, &h->cmd_list, head) {
+ switch (cmd->command) {
+ case NFT_COMPAT_TABLE_FLUSH:
+ ret = nft_table_flush(h, cmd->table);
+ break;
+ case NFT_COMPAT_CHAIN_USER_ADD:
+ ret = nft_chain_user_add(h, cmd->chain, cmd->table);
+ break;
+ case NFT_COMPAT_CHAIN_USER_DEL:
+ ret = nft_chain_user_del(h, cmd->chain, cmd->table,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_CHAIN_RESTORE:
+ ret = nft_chain_restore(h, cmd->chain, cmd->table);
+ break;
+ case NFT_COMPAT_CHAIN_UPDATE:
+ ret = nft_chain_set(h, cmd->table, cmd->chain,
+ cmd->policy, &cmd->counters);
+ break;
+ case NFT_COMPAT_CHAIN_RENAME:
+ ret = nft_chain_user_rename(h, cmd->chain, cmd->table,
+ cmd->rename);
+ break;
+ case NFT_COMPAT_CHAIN_ZERO:
+ ret = nft_chain_zero_counters(h, cmd->chain, cmd->table,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_APPEND:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_append(h, cmd->chain, cmd->table,
+ cmd->obj.rule, NULL, cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_INSERT:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_insert(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->rulenum,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_REPLACE:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_replace(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->rulenum,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_DELETE:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ if (cmd->rulenum >= 0)
+ ret = nft_rule_delete_num(h, cmd->chain,
+ cmd->table,
+ cmd->rulenum,
+ cmd->verbose);
+ else
+ ret = nft_rule_delete(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_FLUSH:
+ ret = nft_rule_flush(h, cmd->chain, cmd->table,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_LIST:
+ ret = nft_rule_list(h, cmd->chain, cmd->table,
+ cmd->rulenum, cmd->format);
+ break;
+ case NFT_COMPAT_RULE_CHECK:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_check(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->rulenum);
+ break;
+ case NFT_COMPAT_RULE_ZERO:
+ ret = nft_rule_zero_counters(h, cmd->chain, cmd->table,
+ cmd->rulenum);
+ break;
+ case NFT_COMPAT_RULE_SAVE:
+ ret = nft_rule_list_save(h, cmd->chain, cmd->table,
+ cmd->rulenum,
+ cmd->counters_save);
+ break;
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ ret = ebt_set_user_chain_policy(h, cmd->table,
+ cmd->chain, cmd->policy);
+ break;
+ case NFT_COMPAT_TABLE_NEW:
+ nft_xt_builtin_init(h, cmd->table);
+ ret = 1;
+ break;
+ case NFT_COMPAT_SET_ADD:
+ nft_xt_builtin_init(h, cmd->table);
+ batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set);
+ ret = 1;
+ break;
+ case NFT_COMPAT_TABLE_ADD:
+ case NFT_COMPAT_CHAIN_ADD:
+ assert(0);
+ break;
+ }
+
+ nft_cmd_free(cmd);
+
+ if (ret == 0)
+ return 0;
+ }
+
+ return 1;
}
-int nft_abort(struct nft_handle *h)
+int nft_commit(struct nft_handle *h)
{
- return nft_action(h, NFT_COMPAT_ABORT);
+ if (!nft_prepare(h))
+ return 0;
+
+ return nft_action(h, NFT_COMPAT_COMMIT);
}
-int nft_abort_policy_rule(struct nft_handle *h, const char *table)
+int nft_bridge_commit(struct nft_handle *h)
{
- struct obj_update *n, *tmp;
+ if (!nft_prepare(h))
+ return 0;
- list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
- if (n->type != NFT_COMPAT_RULE_APPEND &&
- n->type != NFT_COMPAT_RULE_DELETE)
- continue;
+ nft_bridge_commit_prepare(h);
- if (strcmp(table,
- nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE)))
- continue;
+ return nft_action(h, NFT_COMPAT_COMMIT);
+}
- if (!nft_rule_is_policy_rule(n->rule))
- continue;
+int nft_abort(struct nft_handle *h)
+{
+ struct nft_cmd *cmd, *next;
- batch_obj_del(h, n);
- }
- return 0;
+ list_for_each_entry_safe(cmd, next, &h->cmd_list, head)
+ nft_cmd_free(cmd);
+
+ return nft_action(h, NFT_COMPAT_ABORT);
}
int nft_compatible_revision(const char *name, uint8_t rev, int opt)
@@ -2897,6 +3347,44 @@ const char *nft_strerror(int err)
return strerror(err);
}
+static int recover_rule_compat(struct nftnl_rule *r)
+{
+ struct nftnl_expr_iter *iter;
+ struct nftnl_expr *e;
+ uint32_t reg;
+ int ret = -1;
+
+ iter = nftnl_expr_iter_create(r);
+ if (!iter)
+ return -1;
+
+next_expr:
+ e = nftnl_expr_iter_next(iter);
+ if (!e)
+ goto out;
+
+ 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;
+
+ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
+
+ e = nftnl_expr_iter_next(iter);
+ if (!e)
+ goto out;
+
+ if (strcmp("cmp", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
+ reg != nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG))
+ goto next_expr;
+
+ 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 {
struct nft_handle *handle;
bool verbose;
@@ -2922,8 +3410,6 @@ 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;
@@ -2961,6 +3447,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);
@@ -3022,7 +3509,8 @@ static const char *supported_exprs[] = {
"cmp",
"bitwise",
"counter",
- "immediate"
+ "immediate",
+ "lookup",
};
@@ -3058,8 +3546,6 @@ 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;
diff --git a/iptables/nft.h b/iptables/nft.h
index 4b8b3033..bd783231 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -3,6 +3,8 @@
#include "xshared.h"
#include "nft-shared.h"
+#include "nft-cache.h"
+#include "nft-cmd.h"
#include <libiptc/linux_list.h>
enum nft_table_type {
@@ -28,20 +30,59 @@ struct builtin_table {
};
enum nft_cache_level {
- NFT_CL_NONE,
NFT_CL_TABLES,
NFT_CL_CHAINS,
- NFT_CL_RULES
+ NFT_CL_SETS,
+ NFT_CL_RULES,
+ NFT_CL_FAKE /* must be last entry */
};
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];
};
+enum obj_update_type {
+ NFT_COMPAT_TABLE_ADD,
+ NFT_COMPAT_TABLE_FLUSH,
+ NFT_COMPAT_CHAIN_ADD,
+ NFT_COMPAT_CHAIN_USER_ADD,
+ NFT_COMPAT_CHAIN_USER_DEL,
+ NFT_COMPAT_CHAIN_USER_FLUSH,
+ NFT_COMPAT_CHAIN_UPDATE,
+ NFT_COMPAT_CHAIN_RENAME,
+ NFT_COMPAT_CHAIN_ZERO,
+ NFT_COMPAT_RULE_APPEND,
+ NFT_COMPAT_RULE_INSERT,
+ NFT_COMPAT_RULE_REPLACE,
+ NFT_COMPAT_RULE_DELETE,
+ NFT_COMPAT_RULE_FLUSH,
+ NFT_COMPAT_SET_ADD,
+ NFT_COMPAT_RULE_LIST,
+ NFT_COMPAT_RULE_CHECK,
+ NFT_COMPAT_CHAIN_RESTORE,
+ NFT_COMPAT_RULE_SAVE,
+ NFT_COMPAT_RULE_ZERO,
+ NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE,
+ NFT_COMPAT_TABLE_NEW,
+};
+
+struct cache_chain {
+ struct list_head head;
+ char *name;
+};
+
+struct nft_cache_req {
+ enum nft_cache_level level;
+ char *table;
+ bool all_chains;
+ struct list_head chain_list;
+};
+
struct nft_handle {
int family;
struct mnl_socket *nl;
@@ -60,10 +101,12 @@ struct nft_handle {
unsigned int cache_index;
struct nft_cache __cache[2];
struct nft_cache *cache;
- enum nft_cache_level cache_level;
+ struct nft_cache_req cache_req;
bool restore;
bool noflush;
int8_t config_done;
+ struct list_head cmd_list;
+ bool cache_init;
/* meta data, for error reporting */
struct {
@@ -78,7 +121,7 @@ extern const struct builtin_table xtables_bridge[NFT_TABLE_MAX];
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
int (*cb)(const struct nlmsghdr *nlh, void *data),
void *data);
-int nft_init(struct nft_handle *h, const struct builtin_table *t);
+int nft_init(struct nft_handle *h, int family, const struct builtin_table *t);
void nft_fini(struct nft_handle *h);
int nft_restart(struct nft_handle *h);
@@ -114,16 +157,23 @@ void nft_bridge_chain_postprocess(struct nft_handle *h,
/*
+ * Operations with sets.
+ */
+struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
+ uint32_t set_id);
+
+/*
* Operations with rule-set.
*/
struct nftnl_rule;
-int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, void *data, struct nftnl_rule *ref, bool verbose);
-int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose);
-int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose);
-int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose);
+struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data);
+int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose);
+int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
+int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
+int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose);
-int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose);
+int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int rulenum, unsigned int format);
int nft_rule_list_save(struct nft_handle *h, const char *chain, const char *table, int rulenum, int counters);
int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format);
@@ -135,7 +185,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);
@@ -146,8 +196,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);
@@ -157,7 +207,6 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
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);
/*
* revision compatibility.
@@ -176,6 +225,7 @@ int nft_init_arp(struct nft_handle *h, const char *pname);
int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
/* For xtables-eb.c */
int nft_init_eb(struct nft_handle *h, const char *pname);
+void nft_fini_eb(struct nft_handle *h);
int ebt_get_current_chain(const char *chain);
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh
index d71c1372..2125e2cb 100755
--- a/iptables/tests/shell/run-tests.sh
+++ b/iptables/tests/shell/run-tests.sh
@@ -46,6 +46,10 @@ while [ -n "$1" ]; do
NFT_ONLY=y
shift
;;
+ -V|--valgrind)
+ VALGRIND=y
+ shift
+ ;;
*${RETURNCODE_SEPARATOR}+([0-9]))
SINGLE+=" $1"
VERBOSE=y
@@ -67,6 +71,49 @@ else
XTABLES_LEGACY_MULTI="xtables-legacy-multi"
fi
+printscript() { # (cmd, tmpd)
+ cat <<EOF
+#!/bin/bash
+
+CMD="$1"
+
+# note: valgrind man page warns about --log-file with --trace-children, the
+# last child executed overwrites previous reports unless %p or %q is used.
+# Since libtool wrapper calls exec but none of the iptables tools do, this is
+# perfect for us as it effectively hides bash-related errors
+
+valgrind --log-file=$2/valgrind.log --trace-children=yes \
+ --leak-check=full --show-leak-kinds=all \$CMD "\$@"
+RC=\$?
+
+# don't keep uninteresting logs
+if grep -q 'no leaks are possible' $2/valgrind.log; then
+ rm $2/valgrind.log
+else
+ mv $2/valgrind.log $2/valgrind_\$\$.log
+fi
+
+# drop logs for failing commands for now
+[ \$RC -eq 0 ] || rm $2/valgrind_\$\$.log
+
+exit \$RC
+EOF
+}
+
+if [ "$VALGRIND" == "y" ]; then
+ tmpd=$(mktemp -d)
+ msg_info "writing valgrind logs to $tmpd"
+ chmod a+rx $tmpd
+ printscript "$XTABLES_NFT_MULTI" "$tmpd" >${tmpd}/xtables-nft-multi
+ printscript "$XTABLES_LEGACY_MULTI" "$tmpd" >${tmpd}/xtables-legacy-multi
+ trap "rm ${tmpd}/xtables-*-multi" EXIT
+ chmod a+x ${tmpd}/xtables-nft-multi ${tmpd}/xtables-legacy-multi
+
+ XTABLES_NFT_MULTI="${tmpd}/xtables-nft-multi"
+ XTABLES_LEGACY_MULTI="${tmpd}/xtables-legacy-multi"
+
+fi
+
find_tests() {
if [ ! -z "$SINGLE" ] ; then
echo $SINGLE
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 bf04dc0a..e64e9142 100755
--- a/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
+++ b/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
@@ -4,7 +4,7 @@ set -e
#set -x
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# fill arptables manually
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 38d387f3..afd0fcb4 100755
--- a/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
+++ b/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
@@ -3,7 +3,7 @@
set -e
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# arptables-restore reuses preloaded targets and matches, make sure defaults
# apply to consecutive rules using the same target/match as a previous one
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 10c5ec33..952cfa78 100755
--- a/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
+++ b/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
@@ -4,7 +4,7 @@ set -e
set -x
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
$XT_MULTI arptables -N foo
diff --git a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
index c7f24a38..0c1eb4ca 100755
--- a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
+++ b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
@@ -1,86 +1,89 @@
#!/bin/sh
+case "$XT_MULTI" in
+*xtables-nft-multi)
+ ;;
+*)
+ echo "skip $XT_MULTI"
+ exit 0
+ ;;
+esac
+
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)
- for t in filter nat;do
- $XT_MULTI ebtables -t $t -L || exit 1
- $XT_MULTI ebtables -t $t -X || exit 1
- $XT_MULTI ebtables -t $t -F || exit 1
- done
-
- for t in broute foobar ;do
- $XT_MULTI ebtables -t $t -L &&
- $XT_MULTI ebtables -t $t -X &&
- $XT_MULTI ebtables -t $t -F
- if [ $? -eq 0 ]; then
- echo "Expect nonzero return for unsupported table"
- exit 1
- fi
- done
+for t in filter nat;do
+ $XT_MULTI ebtables -t $t -L || exit 1
+ $XT_MULTI ebtables -t $t -X || exit 1
+ $XT_MULTI ebtables -t $t -F || exit 1
+done
- $XT_MULTI ebtables -t filter -N FOO || exit 1
- $XT_MULTI ebtables -t filter -N FOO
+for t in broute foobar ;do
+ $XT_MULTI ebtables -t $t -L &&
+ $XT_MULTI ebtables -t $t -X &&
+ $XT_MULTI ebtables -t $t -F
if [ $? -eq 0 ]; then
- echo "Duplicate chain FOO"
- $XT_MULTI ebtables -t filter -L
+ echo "Expect nonzero return for unsupported table"
exit 1
fi
+done
- 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
- 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 -t filter -N FOO || exit 1
+$XT_MULTI ebtables -t filter -N FOO
+if [ $? -eq 0 ]; then
+ echo "Duplicate chain FOO"
+ $XT_MULTI ebtables -t filter -L
+ exit 1
+fi
- 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
+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 FOO -j ACCEPT
- 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
+$XT_MULTI ebtables -A FORWARD -j FOO
+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 -t filter -N BAR || exit 1
- $XT_MULTI ebtables -t filter -N BAZ || exit 1
+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 -t filter -L | grep -q FOO || exit 1
- $XT_MULTI ebtables -t filter -L | grep -q BAR || exit 1
- $XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1
+$XT_MULTI ebtables -A FOO -j ACCEPT
+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
- $XT_MULTI ebtables -t filter -L BAZ || exit 1
- $XT_MULTI ebtables -t filter -X BAZ || exit 1
- $XT_MULTI ebtables -t filter -L BAZ | grep -q BAZ
- if [ $? -eq 0 ]; then
- echo "Deleted chain -L BAZ ok, expected failure"
- $XT_MULTI ebtables -t filter -L
- exit 1
- fi
+$XT_MULTI ebtables -t filter -N BAR || exit 1
+$XT_MULTI ebtables -t filter -N BAZ || exit 1
- $XT_MULTI ebtables -t $t -F || exit 0
- ;;
-*)
- echo "skip $XT_MULTI"
- ;;
-esac
+$XT_MULTI ebtables -t filter -L | grep -q FOO || exit 1
+$XT_MULTI ebtables -t filter -L | grep -q BAR || exit 1
+$XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1
+
+$XT_MULTI ebtables -t filter -L BAZ || exit 1
+$XT_MULTI ebtables -t filter -X BAZ || exit 1
+$XT_MULTI ebtables -t filter -L BAZ | grep -q BAZ
+if [ $? -eq 0 ]; then
+ echo "Deleted chain -L BAZ ok, expected failure"
+ $XT_MULTI ebtables -t filter -L
+ exit 1
+fi
+
+$XT_MULTI ebtables -t $t -F || exit 0
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 e18d4655..b84f63a7 100755
--- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
+++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
@@ -4,7 +4,7 @@ set -e
#set -x
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# fill ebtables manually
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 62d22413..63891c1b 100755
--- a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
+++ b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
@@ -3,7 +3,7 @@
set -e
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# ebtables-restore reuses preloaded targets and matches, make sure defaults
# apply to consecutive rules using the same target/match as a previous one
diff --git a/iptables/tests/shell/testcases/ebtables/0004-save-counters_0 b/iptables/tests/shell/testcases/ebtables/0004-save-counters_0
index 46966f43..d52db900 100755
--- a/iptables/tests/shell/testcases/ebtables/0004-save-counters_0
+++ b/iptables/tests/shell/testcases/ebtables/0004-save-counters_0
@@ -3,7 +3,7 @@
set -e
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $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
diff --git a/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0 b/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0
index 2163d364..0b3acfd7 100755
--- a/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0
+++ b/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0
@@ -3,7 +3,7 @@
set -e
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
EXPECT='*filter
:INPUT ACCEPT
diff --git a/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0 b/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0
index 8bf0c2c6..0174b03f 100755
--- a/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0
+++ b/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0
@@ -231,7 +231,7 @@ for table in nat mangle raw filter;do
done
case "$XT_MULTI" in
-*/xtables-nft-multi)
+*xtables-nft-multi)
# nft-multi displays chain names in different order, work around this for now
tmpfile2=$(mktemp)
sort "$tmpfile" > "$tmpfile2"
diff --git a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
index f023b791..c583b0eb 100755
--- a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
@@ -26,6 +26,7 @@ cmd 1 ip6tables -N foo
# test rule adding
cmd 0 ip6tables -A INPUT -j ACCEPT
cmd 1 ip6tables -A noexist -j ACCEPT
+cmd 2 ip6tables -I INPUT -j foobar
# test rule checking
cmd 0 ip6tables -C INPUT -j ACCEPT
diff --git a/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0 b/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0
index ce3bef3a..3f443a98 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0
@@ -22,7 +22,7 @@ do_simple()
table="${2}"
dumpfile="$(dirname "${0}")/dumps/${iptables}.dump"
- "$XT_MULTI" "${iptables}-restore" --table="${table}" <"${dumpfile}"; rv=$?
+ "$XT_MULTI" "${iptables}-restore" --table="${table}" "${dumpfile}"; rv=$?
if [ "${rv}" -ne 0 ]; then
RET=1
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 96a5e66d..a7fae41d 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
@@ -45,8 +45,7 @@ get_target()
make_dummy_rules()
{
-
- echo "*filter"
+ echo "*${1:-filter}"
echo ":INPUT ACCEPT [0:0]"
echo ":FORWARD ACCEPT [0:0]"
echo ":OUTPUT ACCEPT [0:0]"
@@ -74,7 +73,7 @@ make_dummy_rules()
tmpfile=$(mktemp) || exit 1
dumpfile=$(mktemp) || exit 1
-make_dummy_rules > $dumpfile
+(make_dummy_rules; make_dummy_rules security) > $dumpfile
$XT_MULTI iptables-restore -w < $dumpfile
LINES1=$(wc -l < $dumpfile)
$XT_MULTI iptables-save | grep -v '^#' > $dumpfile
@@ -86,7 +85,7 @@ if [ $LINES1 -ne $LINES2 ]; then
fi
case "$XT_MULTI" in
-*/xtables-nft-multi)
+*xtables-nft-multi)
attempts=$((RANDOM%10))
attempts=$((attempts+1))
;;
diff --git a/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0 b/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0
new file mode 100755
index 00000000..2817376e
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+# assert input feed from buffer doesn't trip over
+# added nul-chars from parsing chain line.
+
+$XT_MULTI iptables-restore --noflush <<EOF
+*filter
+:foobar - [0:0]
+-A foobar -j ACCEPT
+COMMIT
+EOF
diff --git a/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0
new file mode 100755
index 00000000..bea1a690
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0
@@ -0,0 +1,16 @@
+#!/bin/bash -e
+
+# make sure empty lines won't break --noflush
+
+cat <<EOF | $XT_MULTI iptables-restore --noflush
+# just a comment followed by innocent empty line
+
+*filter
+-A FORWARD -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='Chain FORWARD (policy ACCEPT)
+target prot opt source destination
+ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 '
+diff -u <(echo "$EXPECT") <($XT_MULTI iptables -n -L FORWARD)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0012-dash-F_0 b/iptables/tests/shell/testcases/ipt-restore/0012-dash-F_0
new file mode 100755
index 00000000..fd82afa1
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0012-dash-F_0
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+# make sure -F lines don't cause segfaults
+
+RULESET='*nat
+-F PREROUTING
+-A PREROUTING -j ACCEPT
+-F PREROUTING
+COMMIT'
+
+echo -e "$RULESET" | $XT_MULTI iptables-restore
+echo -e "$RULESET" | $XT_MULTI iptables-restore -n
diff --git a/iptables/tests/shell/testcases/ipt-restore/0013-test-mode_0 b/iptables/tests/shell/testcases/ipt-restore/0013-test-mode_0
new file mode 100755
index 00000000..65c3b9a1
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0013-test-mode_0
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -e
+
+# segfault with --test reported in nfbz#1391
+
+printf '%s\nCOMMIT\n' '*nat' '*raw' '*filter' | $XT_MULTI iptables-restore --test
diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
index ce02e0bc..f730bede 100755
--- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
@@ -54,10 +54,16 @@ cmd 1 "$ENOENT" iptables -Z bar
# test chain rename
cmd 0 iptables -E foo bar
cmd 1 "$EEXIST_F" iptables -E foo bar
+cmd 1 "$ENOENT" iptables -E foo bar2
+cmd 0 iptables -N foo2
+cmd 1 "$EEXIST_F" iptables -E foo2 bar
# test rule adding
cmd 0 iptables -A INPUT -j ACCEPT
cmd 1 "$ENOENT" iptables -A noexist -j ACCEPT
+cmd 2 "" iptables -I INPUT -j foobar
+cmd 2 "" iptables -R INPUT 1 -j foobar
+cmd 2 "" iptables -D INPUT -j foobar
# test rulenum commands
cmd 1 "$E2BIG_I" iptables -I INPUT 23 -j ACCEPT
diff --git a/iptables/tests/shell/testcases/iptables/0006-46-args_0 b/iptables/tests/shell/testcases/iptables/0006-46-args_0
new file mode 100755
index 00000000..17a0a018
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0006-46-args_0
@@ -0,0 +1,88 @@
+#!/bin/bash
+
+RC=0
+
+$XT_MULTI iptables -6 -A FORWARD -j ACCEPT
+rc=$?
+if [[ $rc -ne 2 ]]; then
+ echo "'iptables -6' returned $rc instead of 2"
+ RC=1
+fi
+
+$XT_MULTI ip6tables -4 -A FORWARD -j ACCEPT
+rc=$?
+if [[ $rc -ne 2 ]]; then
+ echo "'ip6tables -4' returned $rc instead of 2"
+ RC=1
+fi
+
+RULESET='*filter
+-4 -A FORWARD -d 10.0.0.1 -j ACCEPT
+-6 -A FORWARD -d fec0:10::1 -j ACCEPT
+COMMIT
+'
+EXPECT4='-P FORWARD ACCEPT
+-A FORWARD -d 10.0.0.1/32 -j ACCEPT'
+EXPECT6='-P FORWARD ACCEPT
+-A FORWARD -d fec0:10::1/128 -j ACCEPT'
+EXPECT_EMPTY='-P FORWARD ACCEPT'
+
+echo "$RULESET" | $XT_MULTI iptables-restore || {
+ echo "iptables-restore failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT4") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected iptables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected non-empty ip6tables ruleset"
+ RC=1
+}
+
+$XT_MULTI iptables -F FORWARD
+
+echo "$RULESET" | $XT_MULTI ip6tables-restore || {
+ echo "ip6tables-restore failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT6") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected ip6tables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected non-empty iptables ruleset"
+ RC=1
+}
+
+$XT_MULTI ip6tables -F FORWARD
+
+$XT_MULTI iptables -4 -A FORWARD -d 10.0.0.1 -j ACCEPT || {
+ echo "iptables failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT4") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected iptables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected non-empty ip6tables ruleset"
+ RC=1
+}
+
+$XT_MULTI iptables -F FORWARD
+
+$XT_MULTI ip6tables -6 -A FORWARD -d fec0:10::1 -j ACCEPT || {
+ echo "ip6tables failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT6") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected ip6tables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected non-empty iptables ruleset"
+ RC=1
+}
+
+exit $RC
diff --git a/iptables/tests/shell/testcases/nft-only/0001compat_0 b/iptables/tests/shell/testcases/nft-only/0001compat_0
index 4319ea5a..a617c52f 100755
--- a/iptables/tests/shell/testcases/nft-only/0001compat_0
+++ b/iptables/tests/shell/testcases/nft-only/0001compat_0
@@ -5,17 +5,18 @@
# xtables: avoid bogus 'is incompatible' warning
case "$XT_MULTI" in
-*/xtables-nft-multi)
- nft -v >/dev/null || exit 0
- nft 'add table ip nft-test; add chain ip nft-test foobar { type filter hook forward priority 42; }' || exit 1
- nft 'add table ip6 nft-test; add chain ip6 nft-test foobar { type filter hook forward priority 42; }' || exit 1
-
- $XT_MULTI iptables -L -t filter || exit 1
- $XT_MULTI ip6tables -L -t filter || exit 1
+*xtables-nft-multi)
;;
*)
echo skip $XT_MULTI
+ exit 0
;;
esac
+nft -v >/dev/null || exit 0
+nft 'add table ip nft-test; add chain ip nft-test foobar { type filter hook forward priority 42; }' || exit 1
+nft 'add table ip6 nft-test; add chain ip6 nft-test foobar { type filter hook forward priority 42; }' || exit 1
+
+$XT_MULTI iptables -L -t filter || exit 1
+$XT_MULTI ip6tables -L -t filter || exit 1
exit 0
diff --git a/iptables/tests/shell/testcases/nft-only/0002invflags_0 b/iptables/tests/shell/testcases/nft-only/0002invflags_0
index 406b6081..fe33874d 100755
--- a/iptables/tests/shell/testcases/nft-only/0002invflags_0
+++ b/iptables/tests/shell/testcases/nft-only/0002invflags_0
@@ -2,7 +2,7 @@
set -e
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
$XT_MULTI iptables -A INPUT -p tcp --dport 53 ! -s 192.168.0.1 -j ACCEPT
$XT_MULTI ip6tables -A INPUT -p tcp --dport 53 ! -s feed:babe::1 -j ACCEPT
diff --git a/iptables/tests/shell/testcases/nft-only/0003delete-with-comment_0 b/iptables/tests/shell/testcases/nft-only/0003delete-with-comment_0
index 67af9fd8..ccb009e4 100755
--- a/iptables/tests/shell/testcases/nft-only/0003delete-with-comment_0
+++ b/iptables/tests/shell/testcases/nft-only/0003delete-with-comment_0
@@ -2,7 +2,7 @@
set -e
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
comment1="foo bar"
comment2="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
diff --git a/iptables/tests/shell/testcases/nft-only/0006-policy-override_0 b/iptables/tests/shell/testcases/nft-only/0006-policy-override_0
new file mode 100755
index 00000000..68e2019b
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0006-policy-override_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+
+# make sure none of the commands invoking nft_xt_builtin_init() override
+# non-default chain policies via needless chain add.
+
+RC=0
+
+do_test() {
+ $XT_MULTI $@
+ $XT_MULTI iptables -S | grep -q -- '-P FORWARD DROP' && return
+
+ echo "command '$@' kills chain policies"
+ $XT_MULTI iptables -P FORWARD DROP
+ RC=1
+}
+
+$XT_MULTI iptables -P FORWARD DROP
+
+do_test iptables -A OUTPUT -j ACCEPT
+do_test iptables -F
+do_test iptables -N foo
+do_test iptables -E foo foo2
+do_test iptables -I OUTPUT -j ACCEPT
+do_test iptables -nL
+do_test iptables -S
+
+exit $RC
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 16c58914..c1d1371a 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -495,7 +495,6 @@ void add_param_to_argv(struct argv_store *store, char *parsestart, int line)
continue;
} else if (*curchar == '"') {
quote_open = 0;
- *curchar = '"';
} else {
add_param(&param, curchar);
continue;
diff --git a/iptables/xshared.h b/iptables/xshared.h
index 490b19ad..c41bd054 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -6,6 +6,7 @@
#include <stdint.h>
#include <netinet/in.h>
#include <net/if.h>
+#include <sys/time.h>
#include <linux/netfilter_arp/arp_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c
index eca7bb97..04cf7dcc 100644
--- a/iptables/xtables-arp-standalone.c
+++ b/iptables/xtables-arp-standalone.c
@@ -56,6 +56,7 @@ int xtables_arp_main(int argc, char *argv[])
ret = nft_commit(&h);
nft_fini(&h);
+ xtables_fini();
if (!ret)
fprintf(stderr, "arptables: %s\n", nft_strerror(errno));
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 9cfad762..8632774d 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -235,7 +235,7 @@ exit_tryhelp(int status)
}
static void
-exit_printhelp(void)
+printhelp(void)
{
struct xtables_target *t = NULL;
int i;
@@ -325,7 +325,6 @@ exit_printhelp(void)
printf("\n");
t->help();
}
- exit(0);
}
static char
@@ -400,7 +399,7 @@ list_entries(struct nft_handle *h, const char *chain, const char *table,
if (linenumbers)
format |= FMT_LINENUMBERS;
- return nft_rule_list(h, chain, table, rulenum, format);
+ return nft_cmd_rule_list(h, chain, table, rulenum, format);
}
static int
@@ -427,10 +426,10 @@ append_entry(struct nft_handle *h,
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,
+ ret = nft_cmd_rule_append(h, chain, table, cs, NULL,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table, cs,
+ ret = nft_cmd_rule_insert(h, chain, table, cs,
rulenum, verbose);
}
}
@@ -455,7 +454,7 @@ replace_entry(const char *chain,
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);
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
}
static int
@@ -479,7 +478,7 @@ delete_entry(const char *chain,
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);
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
}
}
@@ -500,17 +499,10 @@ int nft_init_arp(struct nft_handle *h, const char *pname)
init_extensionsa();
#endif
- memset(h, 0, sizeof(*h));
- h->family = NFPROTO_ARP;
-
- if (nft_init(h, xtables_arp) < 0)
+ if (nft_init(h, NFPROTO_ARP, xtables_arp) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
- h->ops = nft_family_ops_lookup(h->family);
- if (h->ops == NULL)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
-
return 0;
}
@@ -673,7 +665,8 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
if (!optarg)
optarg = argv[optind];
- exit_printhelp();
+ printhelp();
+ command = CMD_NONE;
break;
case 's':
check_inverse(optarg, &invert, &optind, argc);
@@ -888,8 +881,6 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
if (optind < argc)
xtables_error(PARAMETER_PROBLEM,
"unknown arguments found on commandline");
- if (!command)
- xtables_error(PARAMETER_PROBLEM, "no command specified");
if (invert)
xtables_error(PARAMETER_PROBLEM,
"nothing appropriate following !");
@@ -962,7 +953,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
options&OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
- ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
+ ret = nft_cmd_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
break;
case CMD_REPLACE:
ret = replace_entry(chain, *table, &cs, rulenum - 1,
@@ -984,10 +975,10 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
options&OPT_LINENUMBERS);
break;
case CMD_FLUSH:
- ret = nft_rule_flush(h, chain, *table, options & OPT_VERBOSE);
+ ret = nft_cmd_rule_flush(h, chain, *table, options & OPT_VERBOSE);
break;
case CMD_ZERO:
- ret = nft_chain_zero_counters(h, chain, *table,
+ ret = nft_cmd_chain_zero_counters(h, chain, *table,
options & OPT_VERBOSE);
break;
case CMD_LIST|CMD_ZERO:
@@ -997,25 +988,27 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
/*options&OPT_EXPANDED*/0,
options&OPT_LINENUMBERS);
if (ret)
- ret = nft_chain_zero_counters(h, chain, *table,
+ ret = nft_cmd_chain_zero_counters(h, chain, *table,
options & OPT_VERBOSE);
break;
case CMD_NEW_CHAIN:
- ret = nft_chain_user_add(h, chain, *table);
+ ret = nft_cmd_chain_user_add(h, chain, *table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_chain_user_del(h, chain, *table,
+ ret = nft_cmd_chain_user_del(h, chain, *table,
options & OPT_VERBOSE);
break;
case CMD_RENAME_CHAIN:
- ret = nft_chain_user_rename(h, chain, *table, newname);
+ ret = nft_cmd_chain_user_rename(h, chain, *table, newname);
break;
case CMD_SET_POLICY:
- ret = nft_chain_set(h, *table, chain, policy, NULL);
+ ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
if (ret < 0)
xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
policy);
break;
+ case CMD_NONE:
+ break;
default:
/* We should never reach this... */
exit_tryhelp(2);
@@ -1026,9 +1019,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
free(daddrs);
free(dmasks);
- if (cs.target)
- free(cs.target->t);
-
+ nft_clear_iptables_command_state(&cs);
xtables_free_opts(1);
/* if (verbose > 1)
diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c
index a9081c78..181cf2d0 100644
--- a/iptables/xtables-eb-standalone.c
+++ b/iptables/xtables-eb-standalone.c
@@ -53,6 +53,8 @@ int xtables_eb_main(int argc, char *argv[])
if (ret)
ret = nft_bridge_commit(&h);
+ nft_fini_eb(&h);
+
if (!ret)
fprintf(stderr, "ebtables: %s\n", nft_strerror(errno));
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index fd7d601f..375a95d1 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -150,9 +150,9 @@ append_entry(struct nft_handle *h,
int ret = 1;
if (append)
- ret = nft_rule_append(h, chain, table, cs, NULL, verbose);
+ ret = nft_cmd_rule_append(h, chain, table, cs, NULL, verbose);
else
- ret = nft_rule_insert(h, chain, table, cs, rule_nr, verbose);
+ ret = nft_cmd_rule_insert(h, chain, table, cs, rule_nr, verbose);
return ret;
}
@@ -169,10 +169,10 @@ delete_entry(struct nft_handle *h,
int ret = 1;
if (rule_nr == -1)
- ret = nft_rule_delete(h, chain, table, cs, verbose);
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
else {
do {
- ret = nft_rule_delete_num(h, chain, table,
+ ret = nft_cmd_rule_delete_num(h, chain, table,
rule_nr, verbose);
rule_nr++;
} while (rule_nr < rule_nr_end);
@@ -427,7 +427,7 @@ static int list_rules(struct nft_handle *h, const char *chain, const char *table
if (!counters)
format |= FMT_NOCOUNTS;
- return nft_rule_list(h, chain, table, rule_nr, format);
+ return nft_cmd_rule_list(h, chain, table, rule_nr, format);
}
static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end)
@@ -594,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");
@@ -738,16 +739,9 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
init_extensionsb();
#endif
- memset(h, 0, sizeof(*h));
-
- h->family = NFPROTO_BRIDGE;
-
- if (nft_init(h, xtables_bridge) < 0)
+ if (nft_init(h, NFPROTO_BRIDGE, xtables_bridge) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
- h->ops = nft_family_ops_lookup(h->family);
- if (!h->ops)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
/* manually registering ebt matches, given the original ebtables parser
* don't use '-m matchname' and the match can't be loaded dynamically when
@@ -758,6 +752,24 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
return 0;
}
+void nft_fini_eb(struct nft_handle *h)
+{
+ struct xtables_match *match;
+ struct xtables_target *target;
+
+ for (match = xtables_matches; match; match = match->next) {
+ free(match->m);
+ }
+ for (target = xtables_targets; target; target = target->next) {
+ free(target->t);
+ }
+
+ free(opts);
+
+ nft_fini(h);
+ xtables_fini();
+}
+
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
bool restore)
{
@@ -819,7 +831,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
flags |= OPT_COMMAND;
if (c == 'N') {
- ret = nft_chain_user_add(h, chain, *table);
+ ret = nft_cmd_chain_user_add(h, chain, *table);
break;
} else if (c == 'X') {
/* X arg is optional, optarg is NULL */
@@ -827,7 +839,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
chain = argv[optind];
optind++;
}
- ret = nft_chain_user_del(h, chain, *table, 0);
+ ret = nft_cmd_chain_user_del(h, chain, *table, 0);
break;
}
@@ -841,7 +853,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
else if (strchr(argv[optind], ' ') != NULL)
xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names");
- ret = nft_chain_user_rename(h, chain, *table,
+ ret = nft_cmd_chain_user_rename(h, chain, *table,
argv[optind]);
if (ret != 0 && errno == ENOENT)
xtables_error(PARAMETER_PROBLEM, "Chain '%s' doesn't exists", chain);
@@ -1143,7 +1155,7 @@ print_zero:
/*case 7 :*/ /* atomic-init */
/*case 10:*/ /* atomic-save */
case 11: /* init-table */
- nft_table_flush(h, *table);
+ nft_cmd_table_flush(h, *table);
return 1;
/*
replace->command = c;
@@ -1206,7 +1218,7 @@ print_zero:
if (command == 'h' && !(flags & OPT_ZERO)) {
print_help(cs.target, cs.matches, *table);
- exit(0);
+ ret = 1;
}
/* Do the final checks */
@@ -1231,13 +1243,13 @@ print_zero:
if (command == 'P') {
if (selected_chain >= NF_BR_NUMHOOKS) {
- ret = ebt_set_user_chain_policy(h, *table, chain, policy);
+ ret = ebt_cmd_user_chain_policy(h, *table, chain, policy);
} else {
if (strcmp(policy, "RETURN") == 0) {
xtables_error(PARAMETER_PROBLEM,
"Policy RETURN only allowed for user defined chains");
}
- ret = nft_chain_set(h, *table, chain, policy, NULL);
+ ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
if (ret < 0)
xtables_error(PARAMETER_PROBLEM, "Wrong policy");
}
@@ -1250,9 +1262,9 @@ print_zero:
flags&LIST_C);
}
if (flags & OPT_ZERO) {
- ret = nft_chain_zero_counters(h, chain, *table, 0);
+ ret = nft_cmd_chain_zero_counters(h, chain, *table, 0);
} else if (command == 'F') {
- ret = nft_rule_flush(h, chain, *table, 0);
+ ret = nft_cmd_rule_flush(h, chain, *table, 0);
} else if (command == 'A') {
ret = append_entry(h, chain, *table, &cs, 0, 0, true);
} else if (command == 'I') {
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index eb80bac8..57def83e 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -11,6 +11,7 @@
#define _GNU_SOURCE
#include "config.h"
+#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
@@ -41,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)
@@ -106,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:
@@ -593,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";
@@ -610,6 +615,14 @@ int xtables_monitor_main(int argc, char *argv[])
init_extensions4();
#endif
+ if (nft_init(&h, AF_INET, 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) {
@@ -675,6 +688,8 @@ int xtables_monitor_main(int argc, char *argv[])
}
mnl_socket_close(nl);
+ xtables_fini();
+
return EXIT_SUCCESS;
}
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 2f0fe7d4..a3bb4f00 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -61,11 +61,11 @@ static void print_usage(const char *name, const char *version)
static const struct nft_xt_restore_cb restore_cb = {
.commit = nft_commit,
.abort = nft_abort,
- .table_new = nft_table_new,
- .table_flush = nft_table_flush,
+ .table_new = nft_cmd_table_new,
+ .table_flush = nft_cmd_table_flush,
.do_command = do_commandx,
- .chain_set = nft_chain_set,
- .chain_restore = nft_chain_restore,
+ .chain_set = nft_cmd_chain_set,
+ .chain_restore = nft_cmd_chain_restore,
};
struct nft_xt_restore_state {
@@ -85,8 +85,10 @@ static void xtables_restore_parse_line(struct nft_handle *h,
if (buffer[0] == '\n')
return;
else if (buffer[0] == '#') {
- if (verbose)
+ if (verbose) {
fputs(buffer, stdout);
+ fflush(stdout);
+ }
return;
} else if (state->in_table &&
(strncmp(buffer, "COMMIT", 6) == 0) &&
@@ -126,6 +128,10 @@ static void xtables_restore_parse_line(struct nft_handle *h,
if (p->tablename && (strcmp(p->tablename, table) != 0))
return;
+ /* implicit commit if no explicit COMMIT supported */
+ if (!p->commit)
+ cb->commit(h);
+
if (h->noflush == 0) {
DEBUGP("Cleaning all chains of table '%s'\n", table);
if (cb->table_flush)
@@ -189,7 +195,7 @@ static void xtables_restore_parse_line(struct nft_handle *h,
"cannot create chain '%s' (%s)\n",
chain, strerror(errno));
} else if (h->family == NFPROTO_BRIDGE &&
- !ebt_set_user_chain_policy(h, state->curtable->name,
+ !ebt_cmd_user_chain_policy(h, state->curtable->name,
chain, policy)) {
xtables_error(OTHER_PROBLEM,
"Can't set policy `%s' on `%s' line %u: %s\n",
@@ -248,95 +254,16 @@ static void xtables_restore_parse_line(struct nft_handle *h,
}
}
-/* 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;
- }
-
- return false;
-}
-
-#define PREBUFSIZ 65536
-
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;
+ char buffer[10240] = {};
- 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;
- }
-
- if (cmd_needs_full_cache(buffer)) {
- do_cache = true;
- break;
- }
-
- /* copy string including terminating nul-char */
- memcpy(ptr, buffer, blen);
- ptr += blen;
- buffer[0] = '\0';
- }
-
- if (do_cache)
- nft_build_cache(h, NULL);
- }
+ if (!h->noflush)
+ nft_cache_level_set(h, NFT_CL_FAKE, NULL);
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);
- }
while (fgets(buffer, sizeof(buffer), p->in)) {
h->error.lineno = ++line;
DEBUGP("%s: input line %d: '%s'\n", __func__, line, buffer);
@@ -356,15 +283,13 @@ static int
xtables_restore_main(int family, const char *progname, int argc, char *argv[])
{
const struct builtin_table *tables;
- struct nft_handle h = {
- .family = family,
- .restore = true,
- };
- int c;
struct nft_xt_restore_parse p = {
.commit = true,
.cb = &restore_cb,
};
+ bool noflush = false;
+ struct nft_handle h;
+ int c;
line = 0;
@@ -377,7 +302,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
exit(1);
}
- while ((c = getopt_long(argc, argv, "bcvVthnM:T:46wW", options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "bcvVthnM:T:wW", options, NULL)) != -1) {
switch (c) {
case 'b':
fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -398,7 +323,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
print_usage(prog_name, PACKAGE_VERSION);
exit(0);
case 'n':
- h.noflush = 1;
+ noflush = true;
break;
case 'M':
xtables_modprobe_program = optarg;
@@ -406,13 +331,6 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
case 'T':
p.tablename = optarg;
break;
- case '4':
- h.family = AF_INET;
- break;
- case '6':
- h.family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
- break;
case 'w': /* fallthrough. Ignored by xt-restore */
case 'W':
if (!optarg && xs_has_arg(argc, argv))
@@ -460,17 +378,20 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
return 1;
}
- if (nft_init(&h, tables) < 0) {
+ if (nft_init(&h, family, tables) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
strerror(errno));
exit(EXIT_FAILURE);
}
+ h.noflush = noflush;
+ h.restore = true;
xtables_restore_parse(&h, &p);
nft_fini(&h);
+ xtables_fini();
fclose(p.in);
return 0;
}
@@ -487,20 +408,13 @@ int xtables_ip6_restore_main(int argc, char *argv[])
argc, argv);
}
-static int ebt_table_flush(struct nft_handle *h, const char *table)
-{
- /* drop any pending policy rule add/removal jobs */
- nft_abort_policy_rule(h, table);
- return nft_table_flush(h, table);
-}
-
static const struct nft_xt_restore_cb ebt_restore_cb = {
.commit = nft_bridge_commit,
- .table_new = nft_table_new,
- .table_flush = ebt_table_flush,
+ .table_new = nft_cmd_table_new,
+ .table_flush = nft_cmd_table_flush,
.do_command = do_commandeb,
- .chain_set = nft_chain_set,
- .chain_restore = nft_chain_restore,
+ .chain_set = nft_cmd_chain_set,
+ .chain_restore = nft_cmd_chain_restore,
};
static const struct option ebt_restore_options[] = {
@@ -535,18 +449,18 @@ int xtables_eb_restore_main(int argc, char *argv[])
nft_init_eb(&h, "ebtables-restore");
h.noflush = noflush;
xtables_restore_parse(&h, &p);
- nft_fini(&h);
+ nft_fini_eb(&h);
return 0;
}
static const struct nft_xt_restore_cb arp_restore_cb = {
.commit = nft_commit,
- .table_new = nft_table_new,
- .table_flush = nft_table_flush,
+ .table_new = nft_cmd_table_new,
+ .table_flush = nft_cmd_table_flush,
.do_command = do_commandarp,
- .chain_set = nft_chain_set,
- .chain_restore = nft_chain_restore,
+ .chain_set = nft_cmd_chain_set,
+ .chain_restore = nft_cmd_chain_restore,
};
int xtables_arp_restore_main(int argc, char *argv[])
@@ -560,6 +474,7 @@ int xtables_arp_restore_main(int argc, char *argv[])
nft_init_arp(&h, "arptables-restore");
xtables_restore_parse(&h, &p);
nft_fini(&h);
+ xtables_fini();
return 0;
}
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 44687f99..bb3d8cd3 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -32,7 +32,7 @@
#define prog_name xtables_globals.program_name
#define prog_vers xtables_globals.program_version
-static const char *ipt_save_optstring = "bcdt:M:f:46V";
+static const char *ipt_save_optstring = "bcdt:M:f:V";
static const struct option ipt_save_options[] = {
{.name = "counters", .has_arg = false, .val = 'c'},
{.name = "version", .has_arg = false, .val = 'V'},
@@ -40,8 +40,6 @@ static const struct option ipt_save_options[] = {
{.name = "table", .has_arg = true, .val = 't'},
{.name = "modprobe", .has_arg = true, .val = 'M'},
{.name = "file", .has_arg = true, .val = 'f'},
- {.name = "ipv4", .has_arg = false, .val = '4'},
- {.name = "ipv6", .has_arg = false, .val = '6'},
{NULL},
};
@@ -139,10 +137,8 @@ xtables_save_main(int family, int argc, char *argv[],
struct do_output_data d = {
.format = FMT_NOCOUNTS,
};
+ struct nft_handle h;
bool dump = false;
- struct nft_handle h = {
- .family = family,
- };
FILE *file = NULL;
int ret, c;
@@ -189,13 +185,6 @@ xtables_save_main(int family, int argc, char *argv[],
case 'd':
dump = true;
break;
- case '4':
- h.family = AF_INET;
- break;
- case '6':
- h.family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
- break;
case 'V':
printf("%s v%s (nf_tables)\n", prog_name, prog_vers);
exit(0);
@@ -242,7 +231,7 @@ xtables_save_main(int family, int argc, char *argv[],
return 1;
}
- if (nft_init(&h, tables) < 0) {
+ if (nft_init(&h, family, tables) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -250,8 +239,12 @@ xtables_save_main(int family, int argc, char *argv[],
exit(EXIT_FAILURE);
}
+ nft_cache_level_set(&h, NFT_CL_RULES, NULL);
+ nft_cache_build(&h);
+
ret = do_output(&h, tablename, &d);
nft_fini(&h);
+ xtables_fini();
if (dump)
exit(0);
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index 1a28c548..dd6fb791 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -44,9 +44,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
{
int ret;
char *table = "filter";
- struct nft_handle h = {
- .family = family,
- };
+ struct nft_handle h;
xtables_globals.program_name = progname;
ret = xtables_init_all(&xtables_globals, family);
@@ -61,7 +59,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
init_extensions4();
#endif
- if (nft_init(&h, xtables_ipv4) < 0) {
+ if (nft_init(&h, family, xtables_ipv4) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -74,6 +72,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
ret = nft_commit(&h);
nft_fini(&h);
+ xtables_fini();
if (!ret) {
if (errno == EINVAL) {
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index a42c60a3..5aa42496 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -32,16 +32,38 @@
void xlate_ifname(struct xt_xlate *xl, const char *nftmeta, const char *ifname,
bool invert)
{
- char iface[IFNAMSIZ];
- int ifaclen;
+ int ifaclen = strlen(ifname), i, j;
+ char iface[IFNAMSIZ * 2];
- if (ifname[0] == '\0')
+ if (ifaclen < 1 || ifaclen >= IFNAMSIZ)
return;
- strcpy(iface, ifname);
- ifaclen = strlen(iface);
- if (iface[ifaclen - 1] == '+')
- iface[ifaclen - 1] = '*';
+ for (i = 0, j = 0; i < ifaclen + 1; i++, j++) {
+ switch (ifname[i]) {
+ case '*':
+ iface[j++] = '\\';
+ /* fall through */
+ default:
+ iface[j] = ifname[i];
+ break;
+ }
+ }
+
+ if (ifaclen == 1 && ifname[0] == '+') {
+ /* Nftables does not support wildcard only string. Workaround
+ * is easy, given that this will match always or never
+ * depending on 'invert' value. To match always, simply don't
+ * generate an expression. To match never, use an invalid
+ * interface name (kernel doesn't accept '/' in names) to match
+ * against. */
+ if (!invert)
+ return;
+ strcpy(iface, "INVAL/D");
+ invert = false;
+ }
+
+ if (iface[j - 2] == '+')
+ iface[j - 2] = '*';
xt_xlate_add(xl, "%s %s\"%s\" ", nftmeta, invert ? "!= " : "", iface);
}
@@ -458,7 +480,7 @@ static int xtables_xlate_main_common(struct nft_handle *h,
return 1;
}
- if (nft_init(h, tables) < 0) {
+ if (nft_init(h, family, tables) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -487,6 +509,7 @@ static int xtables_xlate_main(int family, const char *progname, int argc,
fprintf(stderr, "Translation not implemented\n");
nft_fini(&h);
+ xtables_fini();
exit(!ret);
}
@@ -541,6 +564,7 @@ static int xtables_restore_xlate_main(int family, const char *progname,
printf("# Completed on %s", ctime(&now));
nft_fini(&h);
+ xtables_fini();
fclose(p.in);
exit(0);
}
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 8f9dc628..9d2e441e 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -161,7 +161,7 @@ exit_tryhelp(int status)
}
static void
-exit_printhelp(const struct xtables_rule_match *matches)
+printhelp(const struct xtables_rule_match *matches)
{
printf("%s v%s\n\n"
"Usage: %s -[ACD] chain rule-specification [options]\n"
@@ -240,7 +240,6 @@ exit_printhelp(const struct xtables_rule_match *matches)
"[!] --version -V print package version.\n");
print_extension_helps(xtables_targets, matches);
- exit(0);
}
void
@@ -361,11 +360,11 @@ add_entry(const char *chain,
cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
if (append) {
- ret = nft_rule_append(h, chain, table,
+ ret = nft_cmd_rule_append(h, chain, table,
cs, NULL,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table,
+ ret = nft_cmd_rule_insert(h, chain, table,
cs, rulenum,
verbose);
}
@@ -381,11 +380,11 @@ add_entry(const char *chain,
memcpy(&cs->fw6.ipv6.dmsk,
&d.mask.v6[j], sizeof(struct in6_addr));
if (append) {
- ret = nft_rule_append(h, chain, table,
+ ret = nft_cmd_rule_append(h, chain, table,
cs, NULL,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table,
+ ret = nft_cmd_rule_insert(h, chain, table,
cs, rulenum,
verbose);
}
@@ -418,7 +417,7 @@ replace_entry(const char *chain, const char *table,
} else
return 1;
- return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
}
static int
@@ -440,7 +439,7 @@ delete_entry(const char *chain, const char *table,
for (j = 0; j < d.naddrs; j++) {
cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_rule_delete(h, chain,
+ ret = nft_cmd_rule_delete(h, chain,
table, cs, verbose);
}
} else if (family == AF_INET6) {
@@ -453,7 +452,7 @@ delete_entry(const char *chain, const char *table,
&d.addr.v6[j], sizeof(struct in6_addr));
memcpy(&cs->fw6.ipv6.dmsk,
&d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_rule_delete(h, chain,
+ ret = nft_cmd_rule_delete(h, chain,
table, cs, verbose);
}
}
@@ -480,7 +479,7 @@ check_entry(const char *chain, const char *table,
for (j = 0; j < d.naddrs; j++) {
cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_rule_check(h, chain,
+ ret = nft_cmd_rule_check(h, chain,
table, cs, verbose);
}
} else if (family == AF_INET6) {
@@ -493,7 +492,7 @@ check_entry(const char *chain, const char *table,
&d.addr.v6[j], sizeof(struct in6_addr));
memcpy(&cs->fw6.ipv6.dmsk,
&d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_rule_check(h, chain,
+ ret = nft_cmd_rule_check(h, chain,
table, cs, verbose);
}
}
@@ -524,7 +523,7 @@ list_entries(struct nft_handle *h, const char *chain, const char *table,
if (linenumbers)
format |= FMT_LINENUMBERS;
- return nft_rule_list(h, chain, table, rulenum, format);
+ return nft_cmd_rule_list(h, chain, table, rulenum, format);
}
static int
@@ -534,7 +533,7 @@ list_rules(struct nft_handle *h, const char *chain, const char *table,
if (counters)
counters = -1; /* iptables -c format */
- return nft_rule_list_save(h, chain, table, rulenum, counters);
+ return nft_cmd_rule_list_save(h, chain, table, rulenum, counters);
}
void do_parse(struct nft_handle *h, int argc, char *argv[],
@@ -571,10 +570,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
demand-load a protocol. */
opterr = 0;
- h->ops = nft_family_ops_lookup(h->family);
- if (h->ops == NULL)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
-
opts = xt_params->orig_opts;
while ((cs->c = getopt_long(argc, argv,
"-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
@@ -728,7 +723,9 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
xtables_find_match(cs->protocol,
XTF_TRY_LOAD, &cs->matches);
- exit_printhelp(cs->matches);
+ printhelp(cs->matches);
+ p->command = CMD_NONE;
+ return;
/*
* Option selection
@@ -917,27 +914,22 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
break;
case '4':
+ if (args->family == AF_INET)
+ break;
+
if (p->restore && args->family == AF_INET6)
return;
- if (args->family != AF_INET)
- exit_tryhelp(2);
-
- h->ops = nft_family_ops_lookup(args->family);
- break;
+ exit_tryhelp(2);
case '6':
+ if (args->family == AF_INET6)
+ break;
+
if (p->restore && args->family == AF_INET)
return;
- args->family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
-
- h->ops = nft_family_ops_lookup(args->family);
- if (h->ops == NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Unknown family");
- break;
+ exit_tryhelp(2);
case 1: /* non option */
if (optarg[0] == '!' && optarg[1] == '\0') {
@@ -1031,11 +1023,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
opt2char(OPT_VIANAMEIN),
p->chain);
}
-
- if (!p->xlate && !cs->target && strlen(cs->jumpto) > 0 &&
- !nft_chain_exists(h, p->table, cs->jumpto))
- xtables_error(PARAMETER_PROBLEM,
- "Chain '%s' does not exist", cs->jumpto);
}
}
@@ -1066,8 +1053,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
cs.options & OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
- ret = nft_rule_delete_num(h, p.chain, p.table,
- p.rulenum - 1, p.verbose);
+ ret = nft_cmd_rule_delete_num(h, p.chain, p.table,
+ p.rulenum - 1, p.verbose);
break;
case CMD_CHECK:
ret = check_entry(p.chain, p.table, &cs, h->family,
@@ -1085,15 +1072,15 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
cs.options&OPT_VERBOSE, h, false);
break;
case CMD_FLUSH:
- ret = nft_rule_flush(h, p.chain, p.table,
- cs.options & OPT_VERBOSE);
+ ret = nft_cmd_rule_flush(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
break;
case CMD_ZERO:
- ret = nft_chain_zero_counters(h, p.chain, p.table,
- cs.options & OPT_VERBOSE);
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
break;
case CMD_ZERO_NUM:
- ret = nft_rule_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
p.rulenum - 1);
break;
case CMD_LIST:
@@ -1105,11 +1092,11 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
cs.options & OPT_EXPANDED,
cs.options & OPT_LINENUMBERS);
if (ret && (p.command & CMD_ZERO)) {
- ret = nft_chain_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
cs.options & OPT_VERBOSE);
}
if (ret && (p.command & CMD_ZERO_NUM)) {
- ret = nft_rule_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
p.rulenum - 1);
}
nft_check_xt_legacy(h->family, false);
@@ -1120,27 +1107,27 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
ret = list_rules(h, p.chain, p.table, p.rulenum,
cs.options & OPT_VERBOSE);
if (ret && (p.command & CMD_ZERO)) {
- ret = nft_chain_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
cs.options & OPT_VERBOSE);
}
if (ret && (p.command & CMD_ZERO_NUM)) {
- ret = nft_rule_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
p.rulenum - 1);
}
nft_check_xt_legacy(h->family, false);
break;
case CMD_NEW_CHAIN:
- ret = nft_chain_user_add(h, p.chain, p.table);
+ ret = nft_cmd_chain_user_add(h, p.chain, p.table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_chain_user_del(h, p.chain, p.table,
+ ret = nft_cmd_chain_user_del(h, p.chain, p.table,
cs.options & OPT_VERBOSE);
break;
case CMD_RENAME_CHAIN:
- ret = nft_chain_user_rename(h, p.chain, p.table, p.newname);
+ ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
break;
case CMD_SET_POLICY:
- ret = nft_chain_set(h, p.table, p.chain, p.policy, NULL);
+ ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL);
break;
case CMD_NONE:
/* do_parse ignored the line (eg: -4 with ip6tables-restore) */
@@ -1152,11 +1139,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
*table = p.table;
- xtables_rule_matches_free(&cs.matches);
- if (cs.target) {
- free(cs.target->t);
- cs.target->t = NULL;
- }
+ nft_clear_iptables_command_state(&cs);
if (h->family == AF_INET) {
free(args.s.addr.v4);
diff --git a/libipq/ipq_set_verdict.3 b/libipq/ipq_set_verdict.3
index 7771ed6a..a6172b30 100644
--- a/libipq/ipq_set_verdict.3
+++ b/libipq/ipq_set_verdict.3
@@ -30,7 +30,7 @@ The
.B ipq_set_verdict
function issues a verdict on a packet previously obtained with
.BR ipq_read ,
-specifing the intended disposition of the packet, and optionally
+specifying the intended disposition of the packet, and optionally
supplying a modified version of the payload data.
.PP
The
diff --git a/libiptc/libip4tc.c b/libiptc/libip4tc.c
index 55540638..78a896f7 100644
--- a/libiptc/libip4tc.c
+++ b/libiptc/libip4tc.c
@@ -22,7 +22,7 @@
#define inline
#endif
-#if !defined(__GLIBC__) || (__GLIBC__ < 2)
+#if !defined(__BIONIC__) && (!defined(__GLIBC__) || (__GLIBC__ < 2))
typedef unsigned int socklen_t;
#endif
diff --git a/libiptc/libip6tc.c b/libiptc/libip6tc.c
index b7dd1e33..06cd6237 100644
--- a/libiptc/libip6tc.c
+++ b/libiptc/libip6tc.c
@@ -23,7 +23,7 @@
#define inline
#endif
-#if !defined(__GLIBC__) || (__GLIBC__ < 2)
+#if !defined(__BIONIC__) && (!defined(__GLIBC__) || (__GLIBC__ < 2))
typedef unsigned int socklen_t;
#endif
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 895f6988..7fe42580 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -206,6 +206,38 @@ struct xtables_target *xtables_targets;
static bool xtables_fully_register_pending_match(struct xtables_match *me);
static bool xtables_fully_register_pending_target(struct xtables_target *me);
+/* registry for loaded shared objects to close later */
+struct dlreg {
+ struct dlreg *next;
+ void *handle;
+};
+static struct dlreg *dlreg = NULL;
+
+static int dlreg_add(void *handle)
+{
+ struct dlreg *new = malloc(sizeof(*new));
+
+ if (!new)
+ return -1;
+
+ new->handle = handle;
+ new->next = dlreg;
+ dlreg = new;
+ return 0;
+}
+
+static void dlreg_free(void)
+{
+ struct dlreg *next;
+
+ while (dlreg) {
+ next = dlreg->next;
+ dlclose(dlreg->handle);
+ free(dlreg);
+ dlreg = next;
+ }
+}
+
void xtables_init(void)
{
xtables_libdir = getenv("XTABLES_LIBDIR");
@@ -233,6 +265,11 @@ void xtables_init(void)
xtables_libdir = XTABLES_LIBDIR;
}
+void xtables_fini(void)
+{
+ dlreg_free();
+}
+
void xtables_set_nfproto(uint8_t nfproto)
{
switch (nfproto) {
@@ -567,6 +604,8 @@ static void *load_extension(const char *search_path, const char *af_prefix,
next = dir + strlen(dir);
for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
+ void *handle;
+
snprintf(path, sizeof(path), "%.*s/%s%s.so",
(unsigned int)(next - dir), dir,
*prefix, name);
@@ -578,11 +617,14 @@ static void *load_extension(const char *search_path, const char *af_prefix,
strerror(errno));
return NULL;
}
- if (dlopen(path, RTLD_NOW) == NULL) {
+ handle = dlopen(path, RTLD_NOW);
+ if (handle == NULL) {
fprintf(stderr, "%s: %s\n", path, dlerror());
break;
}
+ dlreg_add(handle);
+
if (is_target)
ptr = xtables_find_target(name, XTF_DONT_LOAD);
else
@@ -856,7 +898,8 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
xtables_load_ko(xtables_modprobe_program, true);
- strcpy(rev.name, name);
+ strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
+ rev.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0';
rev.revision = revision;
max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
diff --git a/utils/nfnl_osf.c b/utils/nfnl_osf.c
index 15d53197..8008e83d 100644
--- a/utils/nfnl_osf.c
+++ b/utils/nfnl_osf.c
@@ -378,9 +378,11 @@ static int osf_load_line(char *buffer, int len, int del)
memset(buf, 0, sizeof(buf));
if (del)
- nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE, NLM_F_REQUEST);
+ nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE,
+ NLM_F_ACK | NLM_F_REQUEST);
else
- nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD, NLM_F_REQUEST | NLM_F_CREATE);
+ nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD,
+ NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE);
nfnl_addattr_l(nmh, sizeof(buf), OSF_ATTR_FINGER, &f, sizeof(struct xt_osf_user_finger));
@@ -390,7 +392,7 @@ static int osf_load_line(char *buffer, int len, int del)
static int osf_load_entries(char *path, int del)
{
FILE *inf;
- int err = 0;
+ int err = 0, lineno = 0;
char buf[1024];
inf = fopen(path, "r");
@@ -400,7 +402,9 @@ static int osf_load_entries(char *path, int del)
}
while(fgets(buf, sizeof(buf), inf)) {
- int len;
+ int len, rc;
+
+ lineno++;
if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
continue;
@@ -412,9 +416,11 @@ static int osf_load_entries(char *path, int del)
buf[len] = '\0';
- err = osf_load_line(buf, len, del);
- if (err)
- break;
+ rc = osf_load_line(buf, len, del);
+ if (rc && (!del || errno != ENOENT)) {
+ ulog_err("Failed to load line %d", lineno);
+ err = rc;
+ }
memset(buf, 0, sizeof(buf));
}
@@ -446,6 +452,7 @@ int main(int argc, char *argv[])
if (!fingerprints) {
err = -ENOENT;
+ ulog("Missing fingerprints file argument.\n");
goto err_out_exit;
}