summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--extensions/libip6t_LOG.t12
-rw-r--r--extensions/libip6t_REJECT.t9
-rw-r--r--extensions/libip6t_ah.t14
-rw-r--r--extensions/libip6t_eui64.t8
-rw-r--r--extensions/libipt_DNAT.t8
-rw-r--r--extensions/libipt_ECN.t5
-rw-r--r--extensions/libipt_LOG.t12
-rw-r--r--extensions/libipt_MASQUERADE.t8
-rw-r--r--extensions/libipt_REJECT.t9
-rw-r--r--extensions/libipt_SNAT.t8
-rw-r--r--extensions/libipt_ULOG.t19
-rw-r--r--extensions/libipt_ah.t12
-rw-r--r--extensions/libipt_icmp.t15
-rw-r--r--extensions/libipt_ttl.t15
-rw-r--r--extensions/libxt_AUDIT.t6
-rw-r--r--extensions/libxt_CHECKSUM.t4
-rw-r--r--extensions/libxt_CLASSIFY.t9
-rw-r--r--extensions/libxt_CONNMARK.t7
-rw-r--r--extensions/libxt_CT.t20
-rw-r--r--extensions/libxt_DSCP.t11
-rw-r--r--extensions/libxt_MARK.t7
-rw-r--r--extensions/libxt_NFLOG.t19
-rw-r--r--extensions/libxt_NFQUEUE.t12
-rw-r--r--extensions/libxt_NOTRACK.t4
-rw-r--r--extensions/libxt_TEE.t4
-rw-r--r--extensions/libxt_TOS.t16
-rw-r--r--extensions/libxt_TRACE.t3
-rw-r--r--extensions/libxt_addrtype.t17
-rw-r--r--extensions/libxt_cluster.t10
-rw-r--r--extensions/libxt_comment.t12
-rw-r--r--extensions/libxt_connbytes.t21
-rw-r--r--extensions/libxt_connlabel.c27
-rw-r--r--extensions/libxt_connlimit.t16
-rw-r--r--extensions/libxt_connmark.t9
-rw-r--r--extensions/libxt_conntrack.t27
-rw-r--r--extensions/libxt_cpu.t6
-rw-r--r--extensions/libxt_dccp.t30
-rw-r--r--extensions/libxt_devgroup.c6
-rw-r--r--extensions/libxt_dscp.t10
-rw-r--r--extensions/libxt_esp.t9
-rw-r--r--extensions/libxt_hashlimit.t26
-rw-r--r--extensions/libxt_helper.t6
-rw-r--r--extensions/libxt_iprange.t11
-rw-r--r--extensions/libxt_length.t10
-rw-r--r--extensions/libxt_limit.t6
-rw-r--r--extensions/libxt_mark.t7
-rw-r--r--extensions/libxt_multiport.t23
-rw-r--r--extensions/libxt_nfacct.t10
-rw-r--r--extensions/libxt_owner.t12
-rw-r--r--extensions/libxt_physdev.t14
-rw-r--r--extensions/libxt_pkttype.t6
-rw-r--r--extensions/libxt_quota.t10
-rw-r--r--extensions/libxt_rateest.t16
-rw-r--r--extensions/libxt_sctp.t32
-rw-r--r--extensions/libxt_standard.t4
-rw-r--r--extensions/libxt_state.t6
-rw-r--r--extensions/libxt_string.t18
-rw-r--r--extensions/libxt_tcp.t26
-rw-r--r--extensions/libxt_time.t4
-rw-r--r--extensions/libxt_tos.t13
-rw-r--r--extensions/libxt_udp.t22
-rw-r--r--include/linux/netfilter/nf_tables.h77
-rwxr-xr-xiptables-test.py311
-rw-r--r--iptables/nft-arp.c259
-rw-r--r--iptables/nft-arp.h16
-rw-r--r--iptables/nft-ipv4.c85
-rw-r--r--iptables/nft-ipv6.c56
-rw-r--r--iptables/nft-shared.c136
-rw-r--r--iptables/nft-shared.h61
-rw-r--r--iptables/nft.c357
-rw-r--r--iptables/nft.h5
-rw-r--r--iptables/xtables-arp-standalone.c5
-rw-r--r--iptables/xtables-arp.c181
-rw-r--r--iptables/xtables-config-parser.y10
-rw-r--r--iptables/xtables-events.c37
-rw-r--r--libxtables/xtables.c21
77 files changed, 1757 insertions, 620 deletions
diff --git a/Makefile.am b/Makefile.am
index c38d3600..275ebc35 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -21,7 +21,7 @@ tarball:
rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION};
pushd ${top_srcdir} && git archive --prefix=${PACKAGE_TARNAME}-${PACKAGE_VERSION}/ HEAD | tar -C /tmp -x && popd;
pushd /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION} && ./autogen.sh && popd;
- tar -C /tmp -cjf ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.bz2 --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/;
+ tar --exclude=*.t --exclude=iptables-test.py -C /tmp -cjf ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.bz2 --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/;
rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION};
config.status: extensions/GNUmakefile.in \
diff --git a/extensions/libip6t_LOG.t b/extensions/libip6t_LOG.t
new file mode 100644
index 00000000..fbf5118b
--- /dev/null
+++ b/extensions/libip6t_LOG.t
@@ -0,0 +1,12 @@
+:INPUT,FORWARD,OUTPUT
+-j LOG;-j LOG;OK
+-j LOG --log-prefix "test: ";=;OK
+-j LOG --log-prefix "test: " --log-level 1;=;OK
+# iptables displays the log-level output using the number; not the string
+-j LOG --log-prefix "test: " --log-level alert;-j LOG --log-prefix "test: " --log-level 1;OK
+-j LOG --log-prefix "test: " --log-tcp-sequence;=;OK
+-j LOG --log-prefix "test: " --log-tcp-options;=;OK
+-j LOG --log-prefix "test: " --log-ip-options;=;OK
+-j LOG --log-prefix "test: " --log-uid;=;OK
+-j LOG --log-prefix "test: " --log-level bad;;FAIL
+-j LOG --log-prefix;;FAIL
diff --git a/extensions/libip6t_REJECT.t b/extensions/libip6t_REJECT.t
new file mode 100644
index 00000000..5a389420
--- /dev/null
+++ b/extensions/libip6t_REJECT.t
@@ -0,0 +1,9 @@
+:INPUT,FORWARD,OUTPUT
+-j REJECT;=;OK
+# manpage for IPv6 variant of REJECT does not show up for some reason?
+-j REJECT --reject-with icmp6-no-route;=;OK
+-j REJECT --reject-with icmp6-adm-prohibited;=;OK
+-j REJECT --reject-with icmp6-addr-unreachable;=;OK
+-j REJECT --reject-with icmp6-port-unreachable;=;OK
+-p tcp -j REJECT --reject-with tcp-reset;=;OK
+-j REJECT --reject-with tcp-reset;;FAIL
diff --git a/extensions/libip6t_ah.t b/extensions/libip6t_ah.t
new file mode 100644
index 00000000..459e9ecd
--- /dev/null
+++ b/extensions/libip6t_ah.t
@@ -0,0 +1,14 @@
+:INPUT,FORWARD,OUTPUT
+-m ah --ahspi 0;=;OK
+-m ah --ahspi 4294967295;=;OK
+-m ah --ahspi 0:4294967295;-m ah;OK
+-m ah ! --ahspi 0;=;OK
+# ERROR: should fail: iptables -A FORWARD -t mangle -j CLASSIFY --set-class 1:-1
+# -m ah --ahres;=;OK
+# ERROR: line 7 (cannot find: ip6tables -I INPUT -m ah --ahlen 32
+# -m ah --ahlen 32;=;OK
+-m ah --ahspi -1;;FAIL
+-m ah --ahspi 4294967296;;FAIL
+-m ah --ahspi invalid;;FAIL
+-m ah --ahspi 0:invalid;;FAIL
+-m ah --ahspi;;FAIL
diff --git a/extensions/libip6t_eui64.t b/extensions/libip6t_eui64.t
new file mode 100644
index 00000000..e5aaaace
--- /dev/null
+++ b/extensions/libip6t_eui64.t
@@ -0,0 +1,8 @@
+:PREROUTING
+*raw
+-m eui64;=;OK
+:INPUT,FORWARD
+*filter
+-m eui64;=;OK
+:OUTPUT
+-m eui64;;FAIL
diff --git a/extensions/libipt_DNAT.t b/extensions/libipt_DNAT.t
new file mode 100644
index 00000000..e3fd5632
--- /dev/null
+++ b/extensions/libipt_DNAT.t
@@ -0,0 +1,8 @@
+:PREROUTING
+*nat
+-j DNAT --to-destination 1.1.1.1;=;OK
+-j DNAT --to-destination 1.1.1.1-1.1.1.10;=;OK
+-p tcp -j DNAT --to-destination 1.1.1.1:1025-65535;=;OK
+-p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65535;=;OK
+-p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65536;;FAIL
+-j DNAT;;FAIL
diff --git a/extensions/libipt_ECN.t b/extensions/libipt_ECN.t
new file mode 100644
index 00000000..2e092052
--- /dev/null
+++ b/extensions/libipt_ECN.t
@@ -0,0 +1,5 @@
+:PREROUTING,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j ECN;;FAIL
+-p tcp -j ECN;;FAIL
+-p tcp -j ECN --ecn-tcp-remove;=;OK
diff --git a/extensions/libipt_LOG.t b/extensions/libipt_LOG.t
new file mode 100644
index 00000000..fbf5118b
--- /dev/null
+++ b/extensions/libipt_LOG.t
@@ -0,0 +1,12 @@
+:INPUT,FORWARD,OUTPUT
+-j LOG;-j LOG;OK
+-j LOG --log-prefix "test: ";=;OK
+-j LOG --log-prefix "test: " --log-level 1;=;OK
+# iptables displays the log-level output using the number; not the string
+-j LOG --log-prefix "test: " --log-level alert;-j LOG --log-prefix "test: " --log-level 1;OK
+-j LOG --log-prefix "test: " --log-tcp-sequence;=;OK
+-j LOG --log-prefix "test: " --log-tcp-options;=;OK
+-j LOG --log-prefix "test: " --log-ip-options;=;OK
+-j LOG --log-prefix "test: " --log-uid;=;OK
+-j LOG --log-prefix "test: " --log-level bad;;FAIL
+-j LOG --log-prefix;;FAIL
diff --git a/extensions/libipt_MASQUERADE.t b/extensions/libipt_MASQUERADE.t
new file mode 100644
index 00000000..46502040
--- /dev/null
+++ b/extensions/libipt_MASQUERADE.t
@@ -0,0 +1,8 @@
+:POSTROUTING
+*nat
+-j MASQUERADE;=;OK
+-j MASQUERADE --random;=;OK
+-p tcp -j MASQUERADE --to-ports 1024;=;OK
+-p udp -j MASQUERADE --to-ports 1024-65535;=;OK
+-p udp -j MASQUERADE --to-ports 1024-65536;;FAIL
+-p udp -j MASQUERADE --to-ports -1;;FAIL
diff --git a/extensions/libipt_REJECT.t b/extensions/libipt_REJECT.t
new file mode 100644
index 00000000..5b26b107
--- /dev/null
+++ b/extensions/libipt_REJECT.t
@@ -0,0 +1,9 @@
+:INPUT,FORWARD,OUTPUT
+-j REJECT;=;OK
+-j REJECT --reject-with icmp-net-unreachable;=;OK
+-j REJECT --reject-with icmp-host-unreachable;=;OK
+-j REJECT --reject-with icmp-port-unreachable;=;OK
+-j REJECT --reject-with icmp-proto-unreachable;=;OK
+-j REJECT --reject-with icmp-net-prohibited;=;OK
+-j REJECT --reject-with icmp-host-prohibited;=;OK
+-j REJECT --reject-with icmp-admin-prohibited;=;OK
diff --git a/extensions/libipt_SNAT.t b/extensions/libipt_SNAT.t
new file mode 100644
index 00000000..73071bb0
--- /dev/null
+++ b/extensions/libipt_SNAT.t
@@ -0,0 +1,8 @@
+:POSTROUTING
+*nat
+-j SNAT --to-source 1.1.1.1;=;OK
+-j SNAT --to-source 1.1.1.1-1.1.1.10;=;OK
+-p tcp -j SNAT --to-source 1.1.1.1:1025-65535;=;OK
+-p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65535;=;OK
+-p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65536;;FAIL
+-j SNAT;;FAIL
diff --git a/extensions/libipt_ULOG.t b/extensions/libipt_ULOG.t
new file mode 100644
index 00000000..97500b00
--- /dev/null
+++ b/extensions/libipt_ULOG.t
@@ -0,0 +1,19 @@
+:INPUT,FORWARD,OUTPUT
+-j ULOG --ulog-nlgroup 1;-j ULOG;OK
+-j ULOG --ulog-nlgroup 32;=;OK
+-j ULOG --ulog-nlgroup 33;;FAIL
+-j ULOG --ulog-nlgroup 0;;FAIL
+-j ULOG --ulog-cprange 1;=;OK
+-j ULOG --ulog-cprange 4294967295;=;OK
+# This below outputs 0 in iptables-save
+# ERROR: should fail: iptables -A INPUT -j ULOG --ulog-cprange 4294967296
+#-j ULOG --ulog-cprange 4294967296;;FAIL
+# supports up to 31 characters
+-j ULOG --ulog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
+# ERROR: should fail: iptables -A INPUT -j ULOG --ulog-prefix xxxxxx [...]
+#-j ULOG --ulog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
+-j ULOG --ulog-qthreshold 1;-j ULOG;OK
+-j ULOG --ulog-qthreshold 0;;FAIL
+-j ULOG --ulog-qthreshold 50;=;OK
+-j ULOG --ulog-qthreshold 51;;FAIL
+-j ULOG;=;OK
diff --git a/extensions/libipt_ah.t b/extensions/libipt_ah.t
new file mode 100644
index 00000000..a0ce3b06
--- /dev/null
+++ b/extensions/libipt_ah.t
@@ -0,0 +1,12 @@
+:INPUT,FORWARD,OUTPUT
+-p ah -m ah --ahspi 0;=;OK
+-p ah -m ah --ahspi 4294967295;=;OK
+-p ah -m ah --ahspi 0:4294967295;-p ah -m ah;OK
+-p ah -m ah ! --ahspi 0;=;OK
+-p ah -m ah --ahspi -1;;FAIL
+-p ah -m ah --ahspi 4294967296;;FAIL
+-p ah -m ah --ahspi invalid;;FAIL
+-p ah -m ah --ahspi 0:invalid;;FAIL
+-m ah --ahspi 0;;FAIL
+-m ah --ahspi;;FAIL
+-m ah;;FAIL
diff --git a/extensions/libipt_icmp.t b/extensions/libipt_icmp.t
new file mode 100644
index 00000000..f4ba65c2
--- /dev/null
+++ b/extensions/libipt_icmp.t
@@ -0,0 +1,15 @@
+:INPUT,FORWARD,OUTPUT
+-p icmp -m icmp --icmp-type any;=;OK
+# output uses the number, better use the name?
+# ERROR: cannot find: iptables -I INPUT -p icmp -m icmp --icmp-type echo-reply
+# -p icmp -m icmp --icmp-type echo-reply;=;OK
+# output uses the number, better use the name?
+# ERROR: annot find: iptables -I INPUT -p icmp -m icmp --icmp-type destination-unreachable
+# -p icmp -m icmp --icmp-type destination-unreachable;=;OK
+# it does not acccept name/name, should we accept this?
+# ERROR: cannot load: iptables -A INPUT -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable
+# -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable;=;OK
+-m icmp;;FAIL
+# we accept "iptables -I INPUT -p tcp -m tcp", why not this below?
+# ERROR: cannot load: iptables -A INPUT -p icmp -m icmp
+# -p icmp -m icmp;=;OK
diff --git a/extensions/libipt_ttl.t b/extensions/libipt_ttl.t
new file mode 100644
index 00000000..ebe5b3a2
--- /dev/null
+++ b/extensions/libipt_ttl.t
@@ -0,0 +1,15 @@
+:INPUT,FORWARD,OUTPUT
+-m ttl --ttl-eq 0;=;OK
+-m ttl --ttl-eq 255;=;OK
+-m ttl ! --ttl-eq 0;=;OK
+-m ttl ! --ttl-eq 255;=;OK
+-m ttl --ttl-gt 0;=;OK
+# not possible have anything greater than 255, TTL is 8-bit long
+# ERROR: should fail: iptables -A INPUT -m ttl --ttl-gt 255
+## -m ttl --ttl-gt 255;;FAIL
+# not possible have anything below 0
+# ERROR: should fail: iptables -A INPUT -m ttl --ttl-lt 0
+## -m ttl --ttl-lt 0;;FAIL
+-m ttl --ttl-eq 256;;FAIL
+-m ttl --ttl-eq -1;;FAIL
+-m ttl;;FAIL
diff --git a/extensions/libxt_AUDIT.t b/extensions/libxt_AUDIT.t
new file mode 100644
index 00000000..97575b0e
--- /dev/null
+++ b/extensions/libxt_AUDIT.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-j AUDIT --type accept;=;OK
+-j AUDIT --type drop;=;OK
+-j AUDIT --type reject;=;OK
+-j AUDIT;;FAIL
+-j AUDIT --type wrong;;FAIL
diff --git a/extensions/libxt_CHECKSUM.t b/extensions/libxt_CHECKSUM.t
new file mode 100644
index 00000000..9451ad86
--- /dev/null
+++ b/extensions/libxt_CHECKSUM.t
@@ -0,0 +1,4 @@
+:PREROUTING,FORWARD,POSTROUTING
+*mangle
+-j CHECKSUM --checksum-fill;=;OK
+-j CHECKSUM;;FAIL
diff --git a/extensions/libxt_CLASSIFY.t b/extensions/libxt_CLASSIFY.t
new file mode 100644
index 00000000..7b3ddbf7
--- /dev/null
+++ b/extensions/libxt_CLASSIFY.t
@@ -0,0 +1,9 @@
+:FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j CLASSIFY --set-class 0000:ffff;=;OK
+# maximum handle accepted by tc is 0xffff
+# ERROR : should fail: iptables -A FORWARD -t mangle -j CLASSIFY --set-class 0000:ffffffff
+# -j CLASSIFY --set-class 0000:ffffffff;;FAIL
+# ERROR: should fail: iptables -A FORWARD -t mangle -j CLASSIFY --set-class 1:-1
+# -j CLASSIFY --set-class 1:-1;;FAIL
+-j CLASSIFY;;FAIL
diff --git a/extensions/libxt_CONNMARK.t b/extensions/libxt_CONNMARK.t
new file mode 100644
index 00000000..79a838fe
--- /dev/null
+++ b/extensions/libxt_CONNMARK.t
@@ -0,0 +1,7 @@
+:PREROUTING,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j CONNMARK --restore-mark;=;OK
+-j CONNMARK --save-mark;=;OK
+-j CONNMARK --save-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --save-mark;OK
+-j CONNMARK --restore-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --restore-mark;OK
+-j CONNMARK;;FAIL
diff --git a/extensions/libxt_CT.t b/extensions/libxt_CT.t
new file mode 100644
index 00000000..3c28534e
--- /dev/null
+++ b/extensions/libxt_CT.t
@@ -0,0 +1,20 @@
+:PREROUTING,OUTPUT
+*raw
+-j CT --notrack;=;OK
+-j CT --ctevents new,related,destroy,reply,assured,protoinfo,helper,mark;=;OK
+-j CT --expevents new;=;OK
+# ERROR: cannot find: iptables -I PREROUTING -t raw -j CT --zone 0
+# -j CT --zone 0;=;OK
+-j CT --zone 65535;=;OK
+-j CT --zone 65536;;FAIL
+-j CT --zone -1;;FAIL
+# ERROR: should fail: iptables -A PREROUTING -t raw -j CT
+# -j CT;;FAIL
+@nfct timeout add test inet tcp ESTABLISHED 100
+# cannot load: iptables -A PREROUTING -t raw -j CT --timeout test
+# -j CT --timeout test;=;OK
+@nfct timeout del test
+@nfct helper add rpc inet tcp
+# cannot load: iptables -A PREROUTING -t raw -j CT --helper rpc
+# -j CT --helper rpc;=;OK
+@nfct helper del rpc
diff --git a/extensions/libxt_DSCP.t b/extensions/libxt_DSCP.t
new file mode 100644
index 00000000..fcc55986
--- /dev/null
+++ b/extensions/libxt_DSCP.t
@@ -0,0 +1,11 @@
+:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j DSCP --set-dscp 0;=;OK
+-j DSCP --set-dscp 0x3f;=;OK
+-j DSCP --set-dscp -1;;FAIL
+-j DSCP --set-dscp 0x40;;FAIL
+-j DSCP --set-dscp 0x3f --set-dscp-class CS0;;FAIL
+-j DSCP --set-dscp-class CS0;-j DSCP --set-dscp 0x00;OK
+-j DSCP --set-dscp-class BE;-j DSCP --set-dscp 0x00;OK
+-j DSCP --set-dscp-class EF;-j DSCP --set-dscp 0x2e;OK
+-j DSCP;;FAIL
diff --git a/extensions/libxt_MARK.t b/extensions/libxt_MARK.t
new file mode 100644
index 00000000..9d1aa7d7
--- /dev/null
+++ b/extensions/libxt_MARK.t
@@ -0,0 +1,7 @@
+:INPUT,FORWARD,OUTPUT
+-j MARK --set-xmark 0xfeedcafe/0xfeedcafe;=;OK
+-j MARK --set-xmark 0;=;OK
+-j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff;OK
+-j MARK --set-xmark 4294967296;;FAIL
+-j MARK --set-xmark -1;;FAIL
+-j MARK;;FAIL
diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t
new file mode 100644
index 00000000..f9768aae
--- /dev/null
+++ b/extensions/libxt_NFLOG.t
@@ -0,0 +1,19 @@
+:INPUT,FORWARD,OUTPUT
+-j NFLOG --nflog-group 1;=;OK
+-j NFLOG --nflog-group 65535;=;OK
+-j NFLOG --nflog-group 65536;;FAIL
+-j NFLOG --nflog-group 0;-j NFLOG;OK
+-j NFLOG --nflog-range 1;=;OK
+-j NFLOG --nflog-range 4294967295;=;OK
+-j NFLOG --nflog-range 4294967296;;FAIL
+-j NFLOG --nflog-range -1;;FAIL
+# ERROR: cannot find: iptables -I INPUT -j NFLOG --nflog-prefix xxxxxx [...]
+# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
+# ERROR: should fail: iptables -A INPUT -j NFLOG --nflog-prefix xxxxxxx [...]
+# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
+-j NFLOG --nflog-threshold 1;=;OK
+# ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0
+# -j NFLOG --nflog-threshold 0;;FAIL
+-j NFLOG --nflog-threshold 65535;=;OK
+-j NFLOG --nflog-threshold 65536;;FAIL
+-j NFLOG;=;OK
diff --git a/extensions/libxt_NFQUEUE.t b/extensions/libxt_NFQUEUE.t
new file mode 100644
index 00000000..d4e4274b
--- /dev/null
+++ b/extensions/libxt_NFQUEUE.t
@@ -0,0 +1,12 @@
+:INPUT,FORWARD,OUTPUT
+-j NFQUEUE;=;OK
+-j NFQUEUE --queue-num 0;=;OK
+-j NFQUEUE --queue-num 65535;=;OK
+-j NFQUEUE --queue-num 65536;;FAIL
+-j NFQUEUE --queue-num -1;;FAIL
+# it says "NFQUEUE: number of total queues is 0", overflow in NFQUEUE_parse_v1?
+# ERROR: cannot load: iptables -A INPUT -j NFQUEUE --queue-balance 0:65535
+# -j NFQUEUE --queue-balance 0:65535;=;OK
+-j NFQUEUE --queue-balance 0:65536;;FAIL
+-j NFQUEUE --queue-balance -1:65535;;FAIL
+-j NFQUEUE --queue-num 10 --queue-bypass;=;OK
diff --git a/extensions/libxt_NOTRACK.t b/extensions/libxt_NOTRACK.t
new file mode 100644
index 00000000..585be82d
--- /dev/null
+++ b/extensions/libxt_NOTRACK.t
@@ -0,0 +1,4 @@
+:PREROUTING,OUTPUT
+*raw
+# ERROR: cannot find: iptables -I PREROUTING -t raw -j NOTRACK
+#-j NOTRACK;=;OK
diff --git a/extensions/libxt_TEE.t b/extensions/libxt_TEE.t
new file mode 100644
index 00000000..ce8b103e
--- /dev/null
+++ b/extensions/libxt_TEE.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-j TEE --gateway 1.1.1.1;=;OK
+-j TEE ! --gateway 1.1.1.1;;FAIL
+-j TEE;;FAIL
diff --git a/extensions/libxt_TOS.t b/extensions/libxt_TOS.t
new file mode 100644
index 00000000..ae8531cc
--- /dev/null
+++ b/extensions/libxt_TOS.t
@@ -0,0 +1,16 @@
+:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j TOS --set-tos 0x1f;=;OK
+-j TOS --set-tos 0x1f/0x1f;=;OK
+# maximum TOS is 0x1f (5 bits)
+# ERROR: should fail: iptables -A PREROUTING -t mangle -j TOS --set-tos 0xff
+# -j TOS --set-tos 0xff;;FAIL
+-j TOS --set-tos Minimize-Delay;-j TOS --set-tos 0x10;OK
+-j TOS --set-tos Maximize-Throughput;-j TOS --set-tos 0x08;OK
+-j TOS --set-tos Maximize-Reliability;-j TOS --set-tos 0x04;OK
+-j TOS --set-tos Minimize-Cost;-j TOS --set-tos 0x02;OK
+-j TOS --set-tos Normal-Service;-j TOS --set-tos 0x00;OK
+-j TOS --and-tos 0x12;-j TOS --set-tos 0x00/0xed;OK
+-j TOS --or-tos 0x12;-j TOS --set-tos 0x12/0x12;OK
+-j TOS --xor-tos 0x12;-j TOS --set-tos 0x12/0x00;OK
+-j TOS;;FAIL
diff --git a/extensions/libxt_TRACE.t b/extensions/libxt_TRACE.t
new file mode 100644
index 00000000..cadb7330
--- /dev/null
+++ b/extensions/libxt_TRACE.t
@@ -0,0 +1,3 @@
+:PREROUTING,OUTPUT
+*raw
+-j TRACE;=;OK
diff --git a/extensions/libxt_addrtype.t b/extensions/libxt_addrtype.t
new file mode 100644
index 00000000..390a63f0
--- /dev/null
+++ b/extensions/libxt_addrtype.t
@@ -0,0 +1,17 @@
+:INPUT,FORWARD,OUTPUT
+-m addrtype;;FAIL
+-m addrtype --src-type wrong;;FAIL
+-m addrtype --src-type UNSPEC;=;OK
+-m addrtype --dst-type UNSPEC;=;OK
+-m addrtype --src-type LOCAL --dst-type LOCAL;=;OK
+-m addrtype --dst-type UNSPEC;=;OK
+-m addrtype --limit-iface-in;;FAIL
+-m addrtype --limit-iface-out;;FAIL
+-m addrtype --limit-iface-in --limit-iface-out;;FAIL
+-m addrtype --src-type LOCAL --limit-iface-in --limit-iface-out;;FAIL
+:INPUT
+-m addrtype --src-type LOCAL --limit-iface-in;=;OK
+-m addrtype --dst-type LOCAL --limit-iface-in;=;OK
+:OUTPUT
+-m addrtype --src-type LOCAL --limit-iface-out;=;OK
+-m addrtype --dst-type LOCAL --limit-iface-out;=;OK
diff --git a/extensions/libxt_cluster.t b/extensions/libxt_cluster.t
new file mode 100644
index 00000000..ac608244
--- /dev/null
+++ b/extensions/libxt_cluster.t
@@ -0,0 +1,10 @@
+:PREROUTING,FORWARD,POSTROUTING
+*mangle
+-m cluster;;FAIL
+-m cluster --cluster-total-nodes 3;;FAIL
+-m cluster --cluster-total-nodes 2 --cluster-local-node 2;;FAIL
+-m cluster --cluster-total-nodes 2 --cluster-local-node 3 --cluster-hash-seed;;FAIL
+#
+# outputs --cluster-local-nodemask instead of --cluster-local-node
+#
+-m cluster --cluster-total-nodes 2 --cluster-local-node 2 --cluster-hash-seed 0xfeedcafe;-m cluster --cluster-local-nodemask 0x00000002 --cluster-total-nodes 2 --cluster-hash-seed 0xfeedcafe;OK
diff --git a/extensions/libxt_comment.t b/extensions/libxt_comment.t
new file mode 100644
index 00000000..f12cd668
--- /dev/null
+++ b/extensions/libxt_comment.t
@@ -0,0 +1,12 @@
+:INPUT,FORWARD,OUTPUT
+-m comment;;FAIL
+-m comment --comment;;FAIL
+#
+# it fails with 256 characters
+#
+# should fail: iptables -A INPUT -m comment --comment xxxxxxxxxxxxxxxxx [....]
+# -m comment --comment xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
+#
+# success with 255 characters
+#
+-m comment --comment xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
diff --git a/extensions/libxt_connbytes.t b/extensions/libxt_connbytes.t
new file mode 100644
index 00000000..6b24e266
--- /dev/null
+++ b/extensions/libxt_connbytes.t
@@ -0,0 +1,21 @@
+:INPUT,FORWARD,OUTPUT
+-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir original;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir reply;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir both;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode bytes --connbytes-dir original;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode bytes --connbytes-dir reply;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode bytes --connbytes-dir both;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir original;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir reply;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir both;=;OK
+-m connbytes --connbytes -1:0 --connbytes-mode packets --connbytes-dir original;;FAIL
+-m connbytes --connbytes 0:-1 --connbytes-mode packets --connbytes-dir original;;FAIL
+# ERROR: cannot find: iptables -I INPUT -m connbytes --connbytes 0:18446744073709551615 --connbytes-mode avgpkt --connbytes-dir both
+# -m connbytes --connbytes 0:18446744073709551615 --connbytes-mode avgpkt --connbytes-dir both;=;OK
+-m connbytes --connbytes 0:18446744073709551616 --connbytes-mode avgpkt --connbytes-dir both;;FAIL
+-m connbytes --connbytes 0:1000 --connbytes-mode wrong --connbytes-dir both;;FAIL
+-m connbytes --connbytes 0:1000 --connbytes-dir original;;FAIL
+-m connbytes --connbytes 0:1000 --connbytes-mode packets;;FAIL
+-m connbytes --connbytes-dir original;;FAIL
+-m connbytes --connbytes 0:1000;;FAIL
+-m connbytes;;FAIL
diff --git a/extensions/libxt_connlabel.c b/extensions/libxt_connlabel.c
index c84a1671..1f830954 100644
--- a/extensions/libxt_connlabel.c
+++ b/extensions/libxt_connlabel.c
@@ -29,11 +29,26 @@ static const struct xt_option_entry connlabel_mt_opts[] = {
XTOPT_TABLEEND,
};
+/* cannot do this via _init, else static builds might spew error message
+ * for every iptables invocation.
+ */
+static void connlabel_open(void)
+{
+ if (map)
+ return;
+
+ map = nfct_labelmap_new(NULL);
+ if (!map && errno)
+ xtables_error(RESOURCE_PROBLEM, "cannot open connlabel.conf: %s\n",
+ strerror(errno));
+}
+
static void connlabel_mt_parse(struct xt_option_call *cb)
{
struct xt_connlabel_mtinfo *info = cb->data;
int tmp;
+ connlabel_open();
xtables_option_parse(cb);
switch (cb->entry->id) {
@@ -54,7 +69,11 @@ static void connlabel_mt_parse(struct xt_option_call *cb)
static const char *connlabel_get_name(int b)
{
- const char *name = nfct_labelmap_get_name(map, b);
+ const char *name;
+
+ connlabel_open();
+
+ name = nfct_labelmap_get_name(map, b);
if (name && strcmp(name, ""))
return name;
return NULL;
@@ -114,11 +133,5 @@ static struct xtables_match connlabel_mt_reg = {
void _init(void)
{
- map = nfct_labelmap_new(NULL);
- if (!map) {
- fprintf(stderr, "cannot open connlabel.conf, not registering '%s' match: %s\n",
- connlabel_mt_reg.name, strerror(errno));
- return;
- }
xtables_register_match(&connlabel_mt_reg);
}
diff --git a/extensions/libxt_connlimit.t b/extensions/libxt_connlimit.t
new file mode 100644
index 00000000..c7ea61e9
--- /dev/null
+++ b/extensions/libxt_connlimit.t
@@ -0,0 +1,16 @@
+:INPUT,FORWARD,OUTPUT
+-m connlimit --connlimit-upto 0;=;OK
+-m connlimit --connlimit-upto 4294967295;=;OK
+-m connlimit --connlimit-upto 4294967296;;FAIL
+-m connlimit --connlimit-upto -1;;FAIL
+-m connlimit --connlimit-above 0;=;OK
+-m connlimit --connlimit-above 4294967295;=;OK
+-m connlimit --connlimit-above 4294967296;;FAIL
+-m connlimit --connlimit-above -1;;FAIL
+-m connlimit --connlimit-upto 1 --conlimit-above 1;;FAIL
+-m connlimit --connlimit-above 10 --connlimit-saddr;-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-saddr;OK
+-m connlimit --connlimit-above 10 --connlimit-daddr;-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-daddr;OK
+-m connlimit --connlimit-above 10 --connlimit-saddr --connlimit-daddr;;FAIL
+-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-saddr;=;OK
+-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-daddr;=;OK
+-m connlimit;;FAIL
diff --git a/extensions/libxt_connmark.t b/extensions/libxt_connmark.t
new file mode 100644
index 00000000..4dd7d9af
--- /dev/null
+++ b/extensions/libxt_connmark.t
@@ -0,0 +1,9 @@
+:PREROUTING,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-m connmark --mark 0xffffffff;=;OK
+-m connmark --mark 0xffffffff/0xffffffff;-m connmark --mark 0xffffffff;OK
+-m connmark --mark 0xffffffff/0;=;OK
+-m connmark --mark 0/0xffffffff;-m connmark --mark 0;OK
+-m connmark --mark -1;;FAIL
+-m connmark --mark 0xfffffffff;;FAIL
+-m connmark;;FAIL
diff --git a/extensions/libxt_conntrack.t b/extensions/libxt_conntrack.t
new file mode 100644
index 00000000..db531475
--- /dev/null
+++ b/extensions/libxt_conntrack.t
@@ -0,0 +1,27 @@
+:INPUT,FORWARD,OUTPUT
+-m conntrack --ctstate NEW;=;OK
+-m conntrack --ctstate NEW,ESTABLISHED;=;OK
+-m conntrack --ctstate NEW,RELATED,ESTABLISHED;=;OK
+-m conntrack --ctstate INVALID;=;OK
+-m conntrack --ctstate UNTRACKED;=;OK
+-m conntrack --ctstate SNAT,DNAT;=;OK
+-m conntrack --ctstate wrong;;FAIL
+# should we convert this to output "tcp" instead of 6?
+-m conntrack --ctproto tcp;-m conntrack --ctproto 6;OK
+-m conntrack --ctorigsrc 1.1.1.1;=;OK
+-m conntrack --ctorigdst 1.1.1.1;=;OK
+-m conntrack --ctreplsrc 1.1.1.1;=;OK
+-m conntrack --ctrepldst 1.1.1.1;=;OK
+-m conntrack --ctexpire 0;=;OK
+-m conntrack --ctexpire 4294967295;=;OK
+-m conntrack --ctexpire 0:4294967295;=;OK
+-m conntrack --ctexpire 42949672956;;FAIL
+-m conntrack --ctexpire -1;;FAIL
+-m conntrack --ctdir ORIGINAL;=;OK
+-m conntrack --ctdir REPLY;=;OK
+-m conntrack --ctstatus NONE;=;OK
+-m conntrack --ctstatus CONFIRMED;=;OK
+-m conntrack --ctstatus ASSURED;=;OK
+-m conntrack --ctstatus EXPECTED;=;OK
+-m conntrack --ctstatus SEEN_REPLY;=;OK
+-m conntrack;;FAIL
diff --git a/extensions/libxt_cpu.t b/extensions/libxt_cpu.t
new file mode 100644
index 00000000..f5adb45d
--- /dev/null
+++ b/extensions/libxt_cpu.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m cpu --cpu 0;=;OK
+-m cpu ! --cpu 0;=;OK
+-m cpu --cpu 4294967295;=;OK
+-m cpu --cpu 4294967296;;FAIL
+-m cpu;;FAIL
diff --git a/extensions/libxt_dccp.t b/extensions/libxt_dccp.t
new file mode 100644
index 00000000..f60b480f
--- /dev/null
+++ b/extensions/libxt_dccp.t
@@ -0,0 +1,30 @@
+:INPUT,FORWARD,OUTPUT
+-p dccp -m dccp --sport 1;=;OK
+-p dccp -m dccp --sport 65535;=;OK
+-p dccp -m dccp --dport 1;=;OK
+-p dccp -m dccp --dport 65535;=;OK
+-p dccp -m dccp --sport 1:1023;=;OK
+-p dccp -m dccp --sport 1024:65535;=;OK
+-p dccp -m dccp --sport 1024:;-p dccp -m dccp --sport 1024:65535;OK
+-p dccp -m dccp ! --sport 1;=;OK
+-p dccp -m dccp ! --sport 65535;=;OK
+-p dccp -m dccp ! --dport 1;=;OK
+-p dccp -m dccp ! --dport 65535;=;OK
+-p dccp -m dccp --sport 1 --dport 65535;=;OK
+-p dccp -m dccp --sport 65535 --dport 1;=;OK
+-p dccp -m dccp ! --sport 1 --dport 65535;=;OK
+-p dccp -m dccp ! --sport 65535 --dport 1;=;OK
+# ERROR: should fail: iptables -A INPUT -p dccp -m dccp --sport 65536
+# -p dccp -m dccp --sport 65536;;FAIL
+-p dccp -m dccp --sport -1;;FAIL
+-p dccp -m dccp --dport -1;;FAIL
+-p dccp -m dccp --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,RESET,SYNC,SYNCACK,INVALID;=;OK
+-p dccp -m dccp ! --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,RESET,SYNC,SYNCACK,INVALID;=;OK
+# DCCP option 0 is valid, see http://tools.ietf.org/html/rfc4340#page-29
+# ERROR: cannot load: iptables -A INPUT -p dccp -m dccp --dccp-option 0
+#-p dccp -m dccp --dccp-option 0;=;OK
+-p dccp -m dccp --dccp-option 255;=;OK
+-p dccp -m dccp --dccp-option 256;;FAIL
+-p dccp -m dccp --dccp-option -1;;FAIL
+# should we accept this below?
+-p dccp -m dccp;=;OK
diff --git a/extensions/libxt_devgroup.c b/extensions/libxt_devgroup.c
index 4a69c822..1a526273 100644
--- a/extensions/libxt_devgroup.c
+++ b/extensions/libxt_devgroup.c
@@ -31,12 +31,12 @@ static const struct xt_option_entry devgroup_opts[] = {
XTOPT_TABLEEND,
};
-/* array of devgroups from /etc/iproute2/group_map */
+/* array of devgroups from /etc/iproute2/group */
static struct xtables_lmap *devgroups;
static void devgroup_init(struct xt_entry_match *match)
{
- const char file[] = "/etc/iproute2/group_map";
+ const char file[] = "/etc/iproute2/group";
devgroups = xtables_lmap_init(file);
if (devgroups == NULL && errno != ENOENT)
fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno));
@@ -124,7 +124,7 @@ static void devgroup_show(const char *pfx, const struct xt_devgroup_info *info,
if (info->flags & XT_DEVGROUP_INVERT_DST)
printf(" !");
printf(" %sdst-group ", pfx);
- print_devgroup(info->src_group, info->src_mask, numeric);
+ print_devgroup(info->dst_group, info->dst_mask, numeric);
}
}
diff --git a/extensions/libxt_dscp.t b/extensions/libxt_dscp.t
new file mode 100644
index 00000000..38d7f04e
--- /dev/null
+++ b/extensions/libxt_dscp.t
@@ -0,0 +1,10 @@
+:INPUT,FORWARD,OUTPUT
+-m dscp --dscp 0;=;OK
+-m dscp --dscp 0x3f;=;OK
+-m dscp --dscp -1;;FAIL
+-m dscp --dscp 0x40;;FAIL
+-m dscp --dscp 0x3f --dscp-class CS0;;FAIL
+-m dscp --dscp-class CS0;-m dscp --dscp 0x00;OK
+-m dscp --dscp-class BE;-m dscp --dscp 0x00;OK
+-m dscp --dscp-class EF;-m dscp --dscp 0x2e;OK
+-m dscp;;FAIL
diff --git a/extensions/libxt_esp.t b/extensions/libxt_esp.t
new file mode 100644
index 00000000..008013b9
--- /dev/null
+++ b/extensions/libxt_esp.t
@@ -0,0 +1,9 @@
+:INPUT,FORWARD,OUTPUT
+-p esp -m esp --espspi 0;=;OK
+-p esp -m esp --espspi :32;-p esp -m esp --espspi 0:32;OK
+-p esp -m esp --espspi 0:4294967295;-p esp -m esp;OK
+-p esp -m esp ! --espspi 0:4294967294;=;OK
+-p esp -m esp --espspi -1;;FAIL
+# should fail?
+-p esp -m esp;=;OK
+-m esp;;FAIL
diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t
new file mode 100644
index 00000000..59d66135
--- /dev/null
+++ b/extensions/libxt_hashlimit.t
@@ -0,0 +1,26 @@
+:INPUT,FORWARD,OUTPUT
+-m hashlimit --hashlimit-above 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
+-m hashlimit --hashlimit-above 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
+-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode srcip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-max 2000 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-max 2000 --hashlimit-htable-gcinterval 60000 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-name mini1;-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;OK
+-m hashlimit --hashlimit-upto 4kb/s --hashlimit-burst 400kb --hashlimit-name mini5;=;OK
+-m hashlimit --hashlimit-upto 10mb/s --hashlimit-name mini6;=;OK
+-m hashlimit --hashlimit-upto 123456b/s --hashlimit-burst 1mb --hashlimit-name mini7;=;OK
+# should work, it says "iptables v1.4.15: burst cannot be smaller than 96b"
+# ERROR: cannot load: iptables -A INPUT -m hashlimit --hashlimit-upto 96b/s --hashlimit-burst 5 --hashlimit-name mini1
+# -m hashlimit --hashlimit-upto 96b/s --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-upto 1/sec;;FAIL
+-m hashlimit;;FAIL
diff --git a/extensions/libxt_helper.t b/extensions/libxt_helper.t
new file mode 100644
index 00000000..8c8420ac
--- /dev/null
+++ b/extensions/libxt_helper.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m helper --helper ftp;=;OK
+# should be OK?
+# ERROR: should fail: iptables -A INPUT -m helper --helper wrong
+# -m helper --helper wrong;;FAIL
+-m helper;;FAIL
diff --git a/extensions/libxt_iprange.t b/extensions/libxt_iprange.t
new file mode 100644
index 00000000..6fd98be6
--- /dev/null
+++ b/extensions/libxt_iprange.t
@@ -0,0 +1,11 @@
+:INPUT,FORWARD,OUTPUT
+-m iprange --src-range 1.1.1.1-1.1.1.10;=;OK
+-m iprange ! --src-range 1.1.1.1-1.1.1.10;=;OK
+-m iprange --dst-range 1.1.1.1-1.1.1.10;=;OK
+-m iprange ! --dst-range 1.1.1.1-1.1.1.10;=;OK
+# it shows -A INPUT -m iprange --src-range 1.1.1.1-1.1.1.1, should we support this?
+# ERROR: should fail: iptables -A INPUT -m iprange --src-range 1.1.1.1
+# -m iprange --src-range 1.1.1.1;;FAIL
+# ERROR: should fail: iptables -A INPUT -m iprange --dst-range 1.1.1.1
+#-m iprange --dst-range 1.1.1.1;;FAIL
+-m iprange;;FAIL
diff --git a/extensions/libxt_length.t b/extensions/libxt_length.t
new file mode 100644
index 00000000..0b6624ee
--- /dev/null
+++ b/extensions/libxt_length.t
@@ -0,0 +1,10 @@
+:INPUT,FORWARD,OUTPUT
+-m length --length 1;=;OK
+-m length --length :2;-m length --length 0:2;OK
+-m length --length 0:3;=;OK
+-m length --length 4:;=;OK
+-m length --length 0:65535;=;OK
+-m length ! --length 0:65535;=;OK
+-m length --length 0:65536;;FAIL
+-m length --length -1:65535;;FAIL
+-m length;;FAIL
diff --git a/extensions/libxt_limit.t b/extensions/libxt_limit.t
new file mode 100644
index 00000000..b0af6538
--- /dev/null
+++ b/extensions/libxt_limit.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m limit --limit 1/sec;=;OK
+-m limit --limit 1/min;=;OK
+-m limit --limit 1000/hour;=;OK
+-m limit --limit 1000/day;=;OK
+-m limit --limit 1/sec --limit-burst 1;=;OK
diff --git a/extensions/libxt_mark.t b/extensions/libxt_mark.t
new file mode 100644
index 00000000..7c005379
--- /dev/null
+++ b/extensions/libxt_mark.t
@@ -0,0 +1,7 @@
+:INPUT,FORWARD,OUTPUT
+-m mark --mark 0xfeedcafe/0xfeedcafe;=;OK
+-m mark --mark 0;=;OK
+-m mark --mark 4294967295;-m mark --mark 0xffffffff;OK
+-m mark --mark 4294967296;;FAIL
+-m mark --mark -1;;FAIL
+-m mark;;FAIL
diff --git a/extensions/libxt_multiport.t b/extensions/libxt_multiport.t
new file mode 100644
index 00000000..e9b80a4e
--- /dev/null
+++ b/extensions/libxt_multiport.t
@@ -0,0 +1,23 @@
+:INPUT,FORWARD,OUTPUT
+-p tcp -m multiport --sports 53,1024:65535;=;OK
+-p tcp -m multiport --dports 53,1024:65535;=;OK
+-p udp -m multiport --sports 53,1024:65535;=;OK
+-p udp -m multiport --dports 53,1024:65535;=;OK
+-p udp -m multiport --ports 53,1024:65535;=;OK
+-p udp -m multiport --ports 53,1024:65535;=;OK
+-p sctp -m multiport --sports 53,1024:65535;=;OK
+-p sctp -m multiport --dports 53,1024:65535;=;OK
+-p dccp -m multiport --sports 53,1024:65535;=;OK
+-p dccp -m multiport --dports 53,1024:65535;=;OK
+-p udplite -m multiport --sports 53,1024:65535;=;OK
+-p udplite -m multiport --dports 53,1024:65535;=;OK
+-p tcp -m multiport --sports 1024:65536;;FAIL
+-p udp -m multiport --sports 1024:65536;;FAIL
+-p tcp -m multiport --ports 1024:65536;;FAIL
+-p udp -m multiport --ports 1024:65536;;FAIL
+-p tcp -m multiport --ports 1,2,3,4,6,7,8,9,10,11,12,13,14,15;=;OK
+# fix manpage, it says "up to 15 ports supported"
+# ERROR: should fail: iptables -A INPUT -p tcp -m multiport --ports 1,2,3,4,6,7,8,9,10,11,12,13,14,15,16
+# -p tcp -m multiport --ports 1,2,3,4,6,7,8,9,10,11,12,13,14,15,16;;FAIL
+-p tcp --multiport;;FAIL
+-m multiport;;FAIL
diff --git a/extensions/libxt_nfacct.t b/extensions/libxt_nfacct.t
new file mode 100644
index 00000000..3419b4ce
--- /dev/null
+++ b/extensions/libxt_nfacct.t
@@ -0,0 +1,10 @@
+:INPUT,FORWARD,OUTPUT
+@nfacct add test
+#
+# extra space in iptables-save output, fix it
+#
+# ERROR: cannot load: iptables -A INPUT -m nfacct --nfacct-name test
+#-m nfacct --nfacct-name test;=;OK
+-m nfacct --nfacct-name wrong;;FAIL
+-m nfacct;;FAIL
+@nfacct del test
diff --git a/extensions/libxt_owner.t b/extensions/libxt_owner.t
new file mode 100644
index 00000000..aec30b65
--- /dev/null
+++ b/extensions/libxt_owner.t
@@ -0,0 +1,12 @@
+:OUTPUT,POSTROUTING
+*mangle
+-m owner --uid-owner root;-m owner --uid-owner 0;OK
+-m owner --uid-owner 0-10;=;OK
+-m owner --gid-owner root;-m owner --gid-owner 0;OK
+-m owner --gid-owner 0-10;=;OK
+-m owner --uid-owner root --gid-owner root;-m owner --uid-owner 0 --gid-owner 0;OK
+-m owner --uid-owner 0-10 --gid-owner 0-10;=;OK
+-m owner ! --uid-owner root;-m owner ! --uid-owner 0;OK
+-m owner --socket-exists;=;OK
+:INPUT
+-m owner --uid-owner root;;FAIL
diff --git a/extensions/libxt_physdev.t b/extensions/libxt_physdev.t
new file mode 100644
index 00000000..1fab7e19
--- /dev/null
+++ b/extensions/libxt_physdev.t
@@ -0,0 +1,14 @@
+:INPUT,FORWARD
+-m physdev --physdev-in lo;=;OK
+-m physdev --physdev-is-in --physdev-in lo;=;OK
+:OUTPUT,FORWARD
+# xt_physdev: using --physdev-out in the OUTPUT, FORWARD and POSTROUTING chains for non-bridged traffic is not supported anymore.
+# ERROR: should fail: iptables -A FORWARD -m physdev --physdev-out lo
+#-m physdev --physdev-out lo;;FAIL
+# ERROR: cannot load: iptables -A OUTPUT -m physdev --physdev-is-out --physdev-out lo
+#-m physdev --physdev-is-out --physdev-out lo;=;OK
+:FORWARD
+-m physdev --physdev-in lo --physdev-is-bridged;=;OK
+:POSTROUTING
+*mangle
+-m physdev --physdev-out lo --physdev-is-bridged;=;OK
diff --git a/extensions/libxt_pkttype.t b/extensions/libxt_pkttype.t
new file mode 100644
index 00000000..d93baeaf
--- /dev/null
+++ b/extensions/libxt_pkttype.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m pkttype --pkt-type unicast;=;OK
+-m pkttype --pkt-type broadcast;=;OK
+-m pkttype --pkt-type multicast;=;OK
+-m pkttype --pkt-type wrong;;FAIL
+-m pkttype;;FAIL
diff --git a/extensions/libxt_quota.t b/extensions/libxt_quota.t
new file mode 100644
index 00000000..76f0ee95
--- /dev/null
+++ b/extensions/libxt_quota.t
@@ -0,0 +1,10 @@
+:INPUT,FORWARD,OUTPUT
+-m quota --quota 0;=;OK
+# iptables-save shows wrong output
+# ERROR: cannot find: iptables -I INPUT -m quota ! --quota 0)
+#-m quota ! --quota 0;=;OK
+-m quota --quota 18446744073709551615;=;OK
+# ERROR: cannot find: iptables -I INPUT -m quota ! --quota 18446744073709551615
+#-m quota ! --quota 18446744073709551615;=;OK
+-m quota --quota 18446744073709551616;;FAIL
+-m quota;;FAIL
diff --git a/extensions/libxt_rateest.t b/extensions/libxt_rateest.t
new file mode 100644
index 00000000..c53b4b62
--- /dev/null
+++ b/extensions/libxt_rateest.t
@@ -0,0 +1,16 @@
+:INPUT,FORWARD,OUTPUT
+@iptables -I INPUT -j RATEEST --rateest-name RE1 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms
+-m rateest --rateest RE1 --rateest-lt --rateest-bps 8bit;=;OK
+-m rateest --rateest RE1 --rateest-eq --rateest-pps 5;=;OK
+-m rateest --rateest RE1 --rateest-gt --rateest-bps 5kbit;-m rateest --rateest RE1 --rateest-gt --rateest-bps 5000bit;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-bps1 8bit --rateest-lt --rateest-bps2 16bit;=;OK
+@iptables -I INPUT -j RATEEST --rateest-name RE2 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms
+-m rateest --rateest1 RE1 --rateest-lt --rateest-bps --rateest2 RE2;=;OK
+-m rateest --rateest-delta --rateest1 RE1 --rateest-pps1 0 --rateest-lt --rateest-pps2 42 --rateest2 RE2;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-bps1 8bit --rateest-eq --rateest-bps2 16bit;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-bps1 8bit --rateest-gt --rateest-bps2 16bit;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-pps1 8 --rateest-lt --rateest-pps2 9;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-pps1 8 --rateest-eq --rateest-pps2 9;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-pps1 8 --rateest-gt --rateest-pps2 9;=;OK
+@iptables -D INPUT -j RATEEST --rateest-name RE1 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms
+@iptables -D INPUT -j RATEEST --rateest-name RE2 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms
diff --git a/extensions/libxt_sctp.t b/extensions/libxt_sctp.t
new file mode 100644
index 00000000..2f75e2a6
--- /dev/null
+++ b/extensions/libxt_sctp.t
@@ -0,0 +1,32 @@
+:INPUT,FORWARD,OUTPUT
+-p sctp -m sctp --sport 1;=;OK
+-p sctp -m sctp --sport 65535;=;OK
+-p sctp -m sctp --sport 1:65535;=;OK
+-p sctp -m sctp --sport -1;;FAIL
+-p sctp -m sctp --sport 65536;;FAIL
+-p sctp -m sctp --dport 1;=;OK
+-p sctp -m sctp --dport 1:65535;=;OK
+-p sctp -m sctp --dport 65535;=;OK
+-p sctp -m sctp --dport -1;;FAIL
+-p sctp -m sctp --dport 65536;;FAIL
+-p sctp -m sctp --chunk-types all DATA;=;OK
+-p sctp -m sctp --chunk-types all INIT;=;OK
+-p sctp -m sctp --chunk-types all INIT_ACK;=;OK
+-p sctp -m sctp --chunk-types all SACK;=;OK
+-p sctp -m sctp --chunk-types all HEARTBEAT;=;OK
+-p sctp -m sctp --chunk-types all HEARTBEAT_ACK;=;OK
+-p sctp -m sctp --chunk-types all ABORT;=;OK
+-p sctp -m sctp --chunk-types all SHUTDOWN;=;OK
+-p sctp -m sctp --chunk-types all SHUTDOWN_ACK;=;OK
+-p sctp -m sctp --chunk-types all ERROR;=;OK
+-p sctp -m sctp --chunk-types all COOKIE_ECHO;=;OK
+-p sctp -m sctp --chunk-types all COOKIE_ACK;=;OK
+-p sctp -m sctp --chunk-types all ECN_ECNE;=;OK
+-p sctp -m sctp --chunk-types all ECN_CWR;=;OK
+# ERROR: iptables-save segfaults: iptables -A INPUT -p sctp -m sctp --chunk-types all ASCONF
+# -p sctp -m sctp --chunk-types all ASCONF;=;OK
+# ERROR: iptables-save segfaults: iptables -A INPUT -p sctp -m sctp --chunk-types all ASCONF_ACK
+# -p sctp -m sctp --chunk-types all ASCONF_ACK;=;OK
+# ERROR: iptables-save segfaults: iptables -A INPUT -p sctp -m sctp --chunk-types all FORWARD_TSN
+# -p sctp -m sctp --chunk-types all FORWARD_TSN;=;OK
+-p sctp -m sctp --chunk-types all SHUTDOWN_COMPLETE;=;OK
diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t
new file mode 100644
index 00000000..923569c3
--- /dev/null
+++ b/extensions/libxt_standard.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-j DROP;=;OK
+-j ACCEPT;=;OK
+-j RETURN;=;OK
diff --git a/extensions/libxt_state.t b/extensions/libxt_state.t
new file mode 100644
index 00000000..8e4bce3f
--- /dev/null
+++ b/extensions/libxt_state.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m state --state INVALID;=;OK
+-m state --state NEW,RELATED;=;OK
+-m state --state UNTRACKED;=;OK
+-m state wrong;;FAIL
+-m state;;FAIL
diff --git a/extensions/libxt_string.t b/extensions/libxt_string.t
new file mode 100644
index 00000000..d68f099d
--- /dev/null
+++ b/extensions/libxt_string.t
@@ -0,0 +1,18 @@
+:INPUT,FORWARD,OUTPUT
+# ERROR: cannot find: iptables -I INPUT -m string --algo bm --string "test"
+# -m string --algo bm --string "test";=;OK
+# ERROR: cannot find: iptables -I INPUT -m string --algo kmp --string "test")
+# -m string --algo kmp --string "test";=;OK
+# ERROR: cannot find: iptables -I INPUT -m string --algo kmp ! --string "test"
+# -m string --algo kmp ! --string "test";=;OK
+# cannot find: iptables -I INPUT -m string --algo bm --string "xxxxxxxxxxx" ....]
+# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK
+# ERROR: cannot load: iptables -A INPUT -m string --algo bm --string "xxxx"
+# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK
+# ERROR: cannot load: iptables -A INPUT -m string --algo bm --hexstring "|0a0a0a0a|"
+# -m string --algo bm --hexstring "|0a0a0a0a|";=;OK
+# ERROR: cannot find: iptables -I INPUT -m string --algo bm --from 0 --to 65535 --string "test"
+# -m string --algo bm --from 0 --to 65535 --string "test";=;OK
+-m string --algo wrong;;FAIL
+-m string --algo bm;;FAIL
+-m string;;FAIL
diff --git a/extensions/libxt_tcp.t b/extensions/libxt_tcp.t
new file mode 100644
index 00000000..b0e8006e
--- /dev/null
+++ b/extensions/libxt_tcp.t
@@ -0,0 +1,26 @@
+:INPUT,FORWARD,OUTPUT
+-p tcp -m tcp --sport 1;=;OK
+-p tcp -m tcp --sport 65535;=;OK
+-p tcp -m tcp --dport 1;=;OK
+-p tcp -m tcp --dport 65535;=;OK
+-p tcp -m tcp --sport 1:1023;=;OK
+-p tcp -m tcp --sport 1024:65535;=;OK
+-p tcp -m tcp --sport 1024:;-p tcp -m tcp --sport 1024:65535;OK
+-p tcp -m tcp ! --sport 1;=;OK
+-p tcp -m tcp ! --sport 65535;=;OK
+-p tcp -m tcp ! --dport 1;=;OK
+-p tcp -m tcp ! --dport 65535;=;OK
+-p tcp -m tcp --sport 1 --dport 65535;=;OK
+-p tcp -m tcp --sport 65535 --dport 1;=;OK
+-p tcp -m tcp ! --sport 1 --dport 65535;=;OK
+-p tcp -m tcp ! --sport 65535 --dport 1;=;OK
+-p tcp -m tcp --sport 65536;;FAIL
+-p tcp -m tcp --sport -1;;FAIL
+-p tcp -m tcp --dport -1;;FAIL
+-p tcp -m tcp --syn;-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN;OK
+-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN;=;OK
+-p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK
+-p tcp -m tcp ! --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK
+-p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG RST;=;OK
+# should we accept this below?
+-p tcp -m tcp;=;OK
diff --git a/extensions/libxt_time.t b/extensions/libxt_time.t
new file mode 100644
index 00000000..673af09b
--- /dev/null
+++ b/extensions/libxt_time.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-m time --timestart 01:02:03 --timestop 04:05:06 --monthdays 1,2,3,4,5 --weekdays Mon,Fri,Sun --datestart 2001-02-03T04:05:06 --datestop 2012-09-08T09:06:05 --kerneltz;=;OK
+-m time --timestart 01:02:03 --timestop 04:05:06 --monthdays 1,2,3,4,5 --weekdays Mon,Fri,Sun --datestart 2001-02-03T04:05:06 --datestop 2012-09-08T09:06:05;=;OK
+-m time --timestart 02:00:00 --timestop 03:00:00 --datestart 1970-01-01T02:00:00 --datestop 1970-01-01T03:00:00;=;OK
diff --git a/extensions/libxt_tos.t b/extensions/libxt_tos.t
new file mode 100644
index 00000000..ccbe8009
--- /dev/null
+++ b/extensions/libxt_tos.t
@@ -0,0 +1,13 @@
+:INPUT,FORWARD,OUTPUT
+-m tos --tos Minimize-Delay;-m tos --tos 0x10/0x3f;OK
+-m tos --tos Maximize-Throughput;-m tos --tos 0x08/0x3f;OK
+-m tos --tos Maximize-Reliability;-m tos --tos 0x04/0x3f;OK
+-m tos --tos Minimize-Cost;-m tos --tos 0x02/0x3f;OK
+-m tos --tos Normal-Service;-m tos --tos 0x00/0x3f;OK
+-m tos --tos 0xff;=;OK
+-m tos ! --tos 0xff;=;OK
+-m tos --tos 0x00;=;OK
+-m tos --tos 0x0f;=;OK
+-m tos --tos 0x0f/0x0f;=;OK
+-m tos --tos wrong;;FAIL
+-m tos;;FAIL
diff --git a/extensions/libxt_udp.t b/extensions/libxt_udp.t
new file mode 100644
index 00000000..1b4d3dd6
--- /dev/null
+++ b/extensions/libxt_udp.t
@@ -0,0 +1,22 @@
+:INPUT,OUTPUT,FORWARD
+-p udp -m udp --sport 1;=;OK
+-p udp -m udp --sport 65535;=;OK
+-p udp -m udp --dport 1;=;OK
+-p udp -m udp --dport 65535;=;OK
+-p udp -m udp --sport 1:1023;=;OK
+-p udp -m udp --sport 1024:65535;=;OK
+-p udp -m udp --sport 1024:;-p udp -m udp --sport 1024:65535;OK
+-p udp -m udp ! --sport 1;=;OK
+-p udp -m udp ! --sport 65535;=;OK
+-p udp -m udp ! --dport 1;=;OK
+-p udp -m udp ! --dport 65535;=;OK
+-p udp -m udp --sport 1 --dport 65535;=;OK
+-p udp -m udp --sport 65535 --dport 1;=;OK
+-p udp -m udp ! --sport 1 --dport 65535;=;OK
+-p udp -m udp ! --sport 65535 --dport 1;=;OK
+# ERRROR: should fail: iptables -A INPUT -p udp -m udp --sport 65536
+# -p udp -m udp --sport 65536;;FAIL
+-p udp -m udp --sport -1;;FAIL
+-p udp -m udp --dport -1;;FAIL
+# should we accept this below?
+-p udp -m udp;=;OK
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index fbfd229a..801bdd1e 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1,7 +1,8 @@
#ifndef _LINUX_NF_TABLES_H
#define _LINUX_NF_TABLES_H
-#define NFT_CHAIN_MAXNAMELEN 32
+#define NFT_CHAIN_MAXNAMELEN 32
+#define NFT_USERDATA_MAXLEN 256
enum nft_registers {
NFT_REG_VERDICT,
@@ -110,11 +111,13 @@ enum nft_table_flags {
*
* @NFTA_TABLE_NAME: name of the table (NLA_STRING)
* @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
+ * @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
*/
enum nft_table_attributes {
NFTA_TABLE_UNSPEC,
NFTA_TABLE_NAME,
NFTA_TABLE_FLAGS,
+ NFTA_TABLE_USE,
__NFTA_TABLE_MAX
};
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
@@ -154,6 +157,7 @@ enum nft_chain_attributes {
* @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
* @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes)
* @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
+ * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
*/
enum nft_rule_attributes {
NFTA_RULE_UNSPEC,
@@ -163,6 +167,7 @@ enum nft_rule_attributes {
NFTA_RULE_EXPRESSIONS,
NFTA_RULE_COMPAT,
NFTA_RULE_POSITION,
+ NFTA_RULE_USERDATA,
__NFTA_RULE_MAX
};
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
@@ -207,6 +212,29 @@ enum nft_set_flags {
};
/**
+ * enum nft_set_policies - set selection policy
+ *
+ * @NFT_SET_POL_PERFORMANCE: prefer high performance over low memory use
+ * @NFT_SET_POL_MEMORY: prefer low memory use over high performance
+ */
+enum nft_set_policies {
+ NFT_SET_POL_PERFORMANCE,
+ NFT_SET_POL_MEMORY,
+};
+
+/**
+ * enum nft_set_desc_attributes - set element description
+ *
+ * @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32)
+ */
+enum nft_set_desc_attributes {
+ NFTA_SET_DESC_UNSPEC,
+ NFTA_SET_DESC_SIZE,
+ __NFTA_SET_DESC_MAX
+};
+#define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1)
+
+/**
* enum nft_set_attributes - nf_tables set netlink attributes
*
* @NFTA_SET_TABLE: table name (NLA_STRING)
@@ -216,6 +244,9 @@ enum nft_set_flags {
* @NFTA_SET_KEY_LEN: key data length (NLA_U32)
* @NFTA_SET_DATA_TYPE: mapping data type (NLA_U32)
* @NFTA_SET_DATA_LEN: mapping data length (NLA_U32)
+ * @NFTA_SET_POLICY: selection policy (NLA_U32)
+ * @NFTA_SET_DESC: set description (NLA_NESTED)
+ * @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
*/
enum nft_set_attributes {
NFTA_SET_UNSPEC,
@@ -226,6 +257,9 @@ enum nft_set_attributes {
NFTA_SET_KEY_LEN,
NFTA_SET_DATA_TYPE,
NFTA_SET_DATA_LEN,
+ NFTA_SET_POLICY,
+ NFTA_SET_DESC,
+ NFTA_SET_ID,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
@@ -261,12 +295,14 @@ enum nft_set_elem_attributes {
* @NFTA_SET_ELEM_LIST_TABLE: table of the set to be changed (NLA_STRING)
* @NFTA_SET_ELEM_LIST_SET: name of the set to be changed (NLA_STRING)
* @NFTA_SET_ELEM_LIST_ELEMENTS: list of set elements (NLA_NESTED: nft_set_elem_attributes)
+ * @NFTA_SET_ELEM_LIST_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
*/
enum nft_set_elem_list_attributes {
NFTA_SET_ELEM_LIST_UNSPEC,
NFTA_SET_ELEM_LIST_TABLE,
NFTA_SET_ELEM_LIST_SET,
NFTA_SET_ELEM_LIST_ELEMENTS,
+ NFTA_SET_ELEM_LIST_SET_ID,
__NFTA_SET_ELEM_LIST_MAX
};
#define NFTA_SET_ELEM_LIST_MAX (__NFTA_SET_ELEM_LIST_MAX - 1)
@@ -452,12 +488,14 @@ enum nft_cmp_attributes {
* @NFTA_LOOKUP_SET: name of the set where to look for (NLA_STRING)
* @NFTA_LOOKUP_SREG: source register of the data to look for (NLA_U32: nft_registers)
* @NFTA_LOOKUP_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_LOOKUP_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
*/
enum nft_lookup_attributes {
NFTA_LOOKUP_UNSPEC,
NFTA_LOOKUP_SET,
NFTA_LOOKUP_SREG,
NFTA_LOOKUP_DREG,
+ NFTA_LOOKUP_SET_ID,
__NFTA_LOOKUP_MAX
};
#define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1)
@@ -529,6 +567,10 @@ enum nft_exthdr_attributes {
* @NFT_META_NFTRACE: packet nftrace bit
* @NFT_META_RTCLASSID: realm value of packet's route (skb->dst->tclassid)
* @NFT_META_SECMARK: packet secmark (skb->secmark)
+ * @NFT_META_NFPROTO: netfilter protocol
+ * @NFT_META_L4PROTO: layer 4 protocol number
+ * @NFT_META_BRI_IIFNAME: packet input bridge interface name
+ * @NFT_META_BRI_OIFNAME: packet output bridge interface name
*/
enum nft_meta_keys {
NFT_META_LEN,
@@ -546,6 +588,10 @@ enum nft_meta_keys {
NFT_META_NFTRACE,
NFT_META_RTCLASSID,
NFT_META_SECMARK,
+ NFT_META_NFPROTO,
+ NFT_META_L4PROTO,
+ NFT_META_BRI_IIFNAME,
+ NFT_META_BRI_OIFNAME,
};
/**
@@ -553,11 +599,13 @@ enum nft_meta_keys {
*
* @NFTA_META_DREG: destination register (NLA_U32)
* @NFTA_META_KEY: meta data item to load (NLA_U32: nft_meta_keys)
+ * @NFTA_META_SREG: source register (NLA_U32)
*/
enum nft_meta_attributes {
NFTA_META_UNSPEC,
NFTA_META_DREG,
NFTA_META_KEY,
+ NFTA_META_SREG,
__NFTA_META_MAX
};
#define NFTA_META_MAX (__NFTA_META_MAX - 1)
@@ -593,6 +641,7 @@ enum nft_ct_keys {
NFT_CT_PROTOCOL,
NFT_CT_PROTO_SRC,
NFT_CT_PROTO_DST,
+ NFT_CT_LABELS,
};
/**
@@ -601,12 +650,14 @@ enum nft_ct_keys {
* @NFTA_CT_DREG: destination register (NLA_U32)
* @NFTA_CT_KEY: conntrack data item to load (NLA_U32: nft_ct_keys)
* @NFTA_CT_DIRECTION: direction in case of directional keys (NLA_U8)
+ * @NFTA_CT_SREG: source register (NLA_U32)
*/
enum nft_ct_attributes {
NFTA_CT_UNSPEC,
NFTA_CT_DREG,
NFTA_CT_KEY,
NFTA_CT_DIRECTION,
+ NFTA_CT_SREG,
__NFTA_CT_MAX
};
#define NFTA_CT_MAX (__NFTA_CT_MAX - 1)
@@ -646,6 +697,8 @@ enum nft_counter_attributes {
* @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING)
* @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32)
* @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32)
+ * @NFTA_LOG_LEVEL: log level (NLA_U32)
+ * @NFTA_LOG_FLAGS: logging flags (NLA_U32)
*/
enum nft_log_attributes {
NFTA_LOG_UNSPEC,
@@ -653,11 +706,33 @@ enum nft_log_attributes {
NFTA_LOG_PREFIX,
NFTA_LOG_SNAPLEN,
NFTA_LOG_QTHRESHOLD,
+ NFTA_LOG_LEVEL,
+ NFTA_LOG_FLAGS,
__NFTA_LOG_MAX
};
#define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1)
/**
+ * enum nft_queue_attributes - nf_tables queue expression netlink attributes
+ *
+ * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16)
+ * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16)
+ * @NFTA_QUEUE_FLAGS: various flags (NLA_U16)
+ */
+enum nft_queue_attributes {
+ NFTA_QUEUE_UNSPEC,
+ NFTA_QUEUE_NUM,
+ NFTA_QUEUE_TOTAL,
+ NFTA_QUEUE_FLAGS,
+ __NFTA_QUEUE_MAX
+};
+#define NFTA_QUEUE_MAX (__NFTA_QUEUE_MAX - 1)
+
+#define NFT_QUEUE_FLAG_BYPASS 0x01 /* for compatibility with v2 */
+#define NFT_QUEUE_FLAG_CPU_FANOUT 0x02 /* use current CPU (no hashing) */
+#define NFT_QUEUE_FLAG_MASK 0x03
+
+/**
* enum nft_reject_types - nf_tables reject expression reject types
*
* @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
diff --git a/iptables-test.py b/iptables-test.py
new file mode 100755
index 00000000..9e137f8c
--- /dev/null
+++ b/iptables-test.py
@@ -0,0 +1,311 @@
+#!/usr/bin/python
+#
+# (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This software has been sponsored by Sophos Astaro <http://www.sophos.com>
+#
+
+import sys
+import os
+import subprocess
+import argparse
+
+IPTABLES = "iptables"
+IP6TABLES = "ip6tables"
+#IPTABLES = "xtables -4"
+#IP6TABLES = "xtables -6"
+
+IPTABLES_SAVE = "iptables-save"
+IP6TABLES_SAVE = "ip6tables-save"
+#IPTABLES_SAVE = ['xtables-save','-4']
+#IP6TABLES_SAVE = ['xtables-save','-6']
+
+EXTENSIONS_PATH = "extensions"
+LOGFILE="/tmp/iptables-test.log"
+log_file = None
+
+
+class Colors:
+ HEADER = '\033[95m'
+ BLUE = '\033[94m'
+ GREEN = '\033[92m'
+ YELLOW = '\033[93m'
+ RED = '\033[91m'
+ ENDC = '\033[0m'
+
+
+def print_error(reason, filename=None, lineno=None):
+ '''
+ Prints an error with nice colors, indicating file and line number.
+ '''
+ print (filename + ": " + Colors.RED + "ERROR" +
+ Colors.ENDC + ": line %d (%s)" % (lineno, reason))
+
+
+def delete_rule(iptables, rule, filename, lineno):
+ '''
+ Removes an iptables rule
+ '''
+ cmd = iptables + " -D " + rule
+ ret = execute_cmd(cmd, filename, lineno)
+ if ret == 1:
+ reason = "cannot delete: " + iptables + " -I " + rule
+ print_error(reason, filename, lineno)
+ return -1
+
+ return 0
+
+
+def run_test(iptables, rule, rule_save, res, filename, lineno):
+ '''
+ Executes an unit test. Returns the output of delete_rule().
+
+ Parameters:
+ :param iptables: string with the iptables command to execute
+ :param rule: string with iptables arguments for the rule to test
+ :param rule_save: string to find the rule in the output of iptables -save
+ :param res: expected result of the rule. Valid values: "OK", "FAIL"
+ :param filename: name of the file tested (used for print_error purposes)
+ :param lineno: line number being tested (used for print_error purposes)
+ '''
+ ret = 0
+
+ cmd = iptables + " -A " + rule
+ ret = execute_cmd(cmd, filename, lineno)
+
+ #
+ # report failed test
+ #
+ if ret:
+ if res == "OK":
+ reason = "cannot load: " + cmd
+ print_error(reason, filename, lineno)
+ return -1
+ else:
+ # do not report this error
+ return 0
+ else:
+ if res == "FAIL":
+ reason = "should fail: " + cmd
+ print_error(reason, filename, lineno)
+ delete_rule(iptables, rule, filename, lineno)
+ return -1
+
+ matching = 0
+ splitted = iptables.split(" ")
+ if len(splitted) == 2:
+ if splitted[1] == '-4':
+ command = IPTABLES_SAVE
+ elif splitted[1] == '-6':
+ command = IP6TABLES_SAVE
+ elif len(splitted) == 1:
+ if splitted[0] == IPTABLES:
+ command = IPTABLES_SAVE
+ elif splitted[0] == IP6TABLES:
+ command = IP6TABLES_SAVE
+ args = splitted[1:]
+ proc = subprocess.Popen(command, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = proc.communicate()
+
+ #
+ # check for segfaults
+ #
+ if proc.returncode == -11:
+ reason = "iptables-save segfaults: " + cmd
+ print_error(reason, filename, lineno)
+ delete_rule(iptables, rule, filename, lineno)
+ return -1
+
+ # find the rule
+ matching = out.find(rule_save)
+ if matching < 0:
+ reason = "cannot find: " + iptables + " -I " + rule
+ print_error(reason, filename, lineno)
+ delete_rule(iptables, rule, filename, lineno)
+ return -1
+
+ return delete_rule(iptables, rule, filename, lineno)
+
+
+def execute_cmd(cmd, filename, lineno):
+ '''
+ Executes a command, checking for segfaults and returning the command exit
+ code.
+
+ :param cmd: string with the command to be executed
+ :param filename: name of the file tested (used for print_error purposes)
+ :param lineno: line number being tested (used for print_error purposes)
+ '''
+ global log_file
+ print >> log_file, "command: %s" % cmd
+ ret = subprocess.call(cmd, shell=True, universal_newlines=True,
+ stderr=subprocess.STDOUT, stdout=log_file)
+ log_file.flush()
+
+ # generic check for segfaults
+ if ret == -11:
+ reason = "command segfaults: " + cmd
+ print_error(reason, filename, lineno)
+ return ret
+
+
+def run_test_file(filename):
+ '''
+ Runs a test file
+
+ :param filename: name of the file with the test rules
+ '''
+ #
+ # if this is not a test file, skip.
+ #
+ if not filename.endswith(".t"):
+ return 0, 0
+
+ if "libipt_" in filename:
+ iptables = IPTABLES
+ elif "libip6t_" in filename:
+ iptables = IP6TABLES
+ elif "libxt_" in filename:
+ iptables = IPTABLES
+ else:
+ # default to iptables if not known prefix
+ iptables = IPTABLES
+
+ f = open(filename)
+
+ tests = 0
+ passed = 0
+ table = ""
+ total_test_passed = True
+
+ for lineno, line in enumerate(f):
+ if line[0] == "#":
+ continue
+
+ if line[0] == ":":
+ chain_array = line.rstrip()[1:].split(",")
+ continue
+
+ # external non-iptables invocation, executed as is.
+ if line[0] == "@":
+ external_cmd = line.rstrip()[1:]
+ execute_cmd(external_cmd, filename, lineno)
+ continue
+
+ if line[0] == "*":
+ table = line.rstrip()[1:]
+ continue
+
+ if len(chain_array) == 0:
+ print "broken test, missing chain, leaving"
+ sys.exit()
+
+ test_passed = True
+ tests += 1
+
+ for chain in chain_array:
+ item = line.split(";")
+ if table == "":
+ rule = chain + " " + item[0]
+ else:
+ rule = chain + " -t " + table + " " + item[0]
+
+ if item[1] == "=":
+ rule_save = chain + " " + item[0]
+ else:
+ rule_save = chain + " " + item[1]
+
+ res = item[2].rstrip()
+
+ ret = run_test(iptables, rule, rule_save,
+ res, filename, lineno + 1)
+ if ret < 0:
+ test_passed = False
+ total_test_passed = False
+ break
+
+ if test_passed:
+ passed += 1
+
+ if total_test_passed:
+ print filename + ": " + Colors.GREEN + "OK" + Colors.ENDC
+
+ f.close()
+ return tests, passed
+
+
+def show_missing():
+ '''
+ Show the list of missing test files
+ '''
+ file_list = os.listdir(EXTENSIONS_PATH)
+ testfiles = [i for i in file_list if i.endswith('.t')]
+ libfiles = [i for i in file_list
+ if i.startswith('lib') and i.endswith('.c')]
+
+ def test_name(x):
+ return x[0:-2] + '.t'
+ missing = [test_name(i) for i in libfiles
+ if not test_name(i) in testfiles]
+
+ print '\n'.join(missing)
+
+
+#
+# main
+#
+def main():
+ parser = argparse.ArgumentParser(description='Run iptables tests')
+ parser.add_argument('filename', nargs='?',
+ metavar='path/to/file.t',
+ help='Run only this test')
+ parser.add_argument('-m', '--missing', action='store_true',
+ help='Check for missing tests')
+ args = parser.parse_args()
+
+ #
+ # show list of missing test files
+ #
+ if args.missing:
+ show_missing()
+ return
+
+ if os.getuid() != 0:
+ print "You need to be root to run this, sorry"
+ return
+
+ test_files = 0
+ tests = 0
+ passed = 0
+
+ # setup global var log file
+ global log_file
+ try:
+ log_file = open(LOGFILE, 'w')
+ except IOError:
+ print "Couldn't open log file %s" % LOGFILE
+ return
+
+ file_list = [os.path.join(EXTENSIONS_PATH, i)
+ for i in os.listdir(EXTENSIONS_PATH)]
+ if args.filename:
+ file_list = [args.filename]
+ for filename in file_list:
+ file_tests, file_passed = run_test_file(filename)
+ if file_tests:
+ tests += file_tests
+ passed += file_passed
+ test_files += 1
+
+ print ("%d test files, %d unit tests, %d passed" %
+ (test_files, tests, passed))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 902d1d2b..f45ad0f7 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -25,6 +25,7 @@
#include <linux/netfilter/nf_tables.h>
#include "nft-shared.h"
+#include "nft-arp.h"
#include "nft.h"
/* a few names */
@@ -160,11 +161,10 @@ static uint8_t arpt_to_ipt_flags(uint16_t invflags)
static int nft_arp_add(struct nft_rule *r, void *data)
{
- struct arpt_entry *fw = data;
+ struct arptables_command_state *cs = data;
+ struct arpt_entry *fw = &cs->fw;
uint8_t flags = arpt_to_ipt_flags(fw->arp.invflags);
- struct xt_entry_target *t;
- char *targname;
- int ret;
+ int ret = 0;
if (fw->arp.iniface[0] != '\0')
add_iniface(r, fw->arp.iniface, flags);
@@ -198,18 +198,22 @@ static int nft_arp_add(struct nft_rule *r, void *data)
add_cmp_ptr(r, NFT_CMP_EQ, fw->arp.src_devaddr.addr, fw->arp.arhln);
}
- if (fw->arp.src.s_addr != 0)
+ if (fw->arp.src.s_addr != 0) {
add_addr(r, sizeof(struct arphdr) + fw->arp.arhln,
- &fw->arp.src.s_addr, 4, flags);
+ &fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
+ sizeof(struct in_addr), flags);
+ }
if (fw->arp.tgt_devaddr.addr[0] != '\0') {
add_payload(r, sizeof(struct arphdr) + fw->arp.arhln + 4, fw->arp.arhln);
add_cmp_ptr(r, NFT_CMP_EQ, fw->arp.tgt_devaddr.addr, fw->arp.arhln);
}
- if (fw->arp.tgt.s_addr != 0)
+ if (fw->arp.tgt.s_addr != 0) {
add_addr(r, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
- &fw->arp.tgt.s_addr, 4, flags);
+ &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
+ sizeof(struct in_addr), flags);
+ }
/* Counters need to me added before the target, otherwise they are
* increased for each rule because of the way nf_tables works.
@@ -217,20 +221,20 @@ static int nft_arp_add(struct nft_rule *r, void *data)
if (add_counters(r, fw->counters.pcnt, fw->counters.bcnt) < 0)
return -1;
- t = nft_arp_get_target(fw);
- targname = t->u.user.name;
-
- /* Standard target? */
- if (strcmp(targname, XTC_LABEL_ACCEPT) == 0)
- ret = add_verdict(r, NF_ACCEPT);
- else if (strcmp(targname, XTC_LABEL_DROP) == 0)
- ret = add_verdict(r, NF_DROP);
- else if (strcmp(targname, XTC_LABEL_RETURN) == 0)
- ret = add_verdict(r, NFT_RETURN);
- else if (xtables_find_target(targname, XTF_TRY_LOAD) != NULL)
- ret = add_target(r, t);
- else
- ret = add_jumpto(r, targname, NFT_JUMP);
+ if (cs->target != NULL) {
+ /* Standard target? */
+ if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
+ ret = add_verdict(r, NF_ACCEPT);
+ else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
+ ret = add_verdict(r, NF_DROP);
+ else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
+ ret = add_verdict(r, NFT_RETURN);
+ else
+ ret = add_target(r, cs->target->t);
+ } else if (strlen(cs->jumpto) > 0) {
+ /* No goto in arptables */
+ ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
+ }
return ret;
}
@@ -257,13 +261,14 @@ static uint16_t ipt_to_arpt_flags(uint8_t invflags)
return result;
}
-static void nft_arp_parse_meta(struct nft_rule_expr *e, uint8_t key,
+static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e,
void *data)
{
- struct arpt_entry *fw = data;
+ struct arptables_command_state *cs = data;
+ struct arpt_entry *fw = &cs->fw;
uint8_t flags = 0;
- parse_meta(e, key, fw->arp.iniface, fw->arp.iniface_mask,
+ parse_meta(e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask,
fw->arp.outiface, fw->arp.outiface_mask,
&flags);
@@ -272,67 +277,57 @@ static void nft_arp_parse_meta(struct nft_rule_expr *e, uint8_t key,
static void nft_arp_parse_target(struct xtables_target *target, void *data)
{
- struct arpt_entry *fw = data;
- struct xt_entry_target **t;
+ struct arptables_command_state *cs = data;
- fw->target_offset = offsetof(struct arpt_entry, elems);
- fw->next_offset = fw->target_offset + target->t->u.target_size;
-
- t = (void *) &fw->elems;
- *t = target->t;
+ cs->target = target;
}
static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
void *data)
{
- struct xtables_target *target;
- size_t size;
-
- target = xtables_find_target(XT_STANDARD_TARGET,
- XTF_LOAD_MUST_SUCCEED);
-
- size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size;
+ struct arptables_command_state *cs = data;
- target->t = xtables_calloc(1, size);
- target->t->u.target_size = size;
- strcpy(target->t->u.user.name, jumpto);
- target->t->u.user.revision = target->revision;
+ cs->jumpto = jumpto;
+}
- nft_arp_parse_target(target, data);
+static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
+{
+ mask->s_addr = ctx->bitwise.mask[0];
}
-static void nft_arp_parse_payload(struct nft_rule_expr_iter *iter,
- uint32_t offset, void *data)
+static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
+ struct nft_rule_expr *e, void *data)
{
- struct arpt_entry *fw = data;
+ struct arptables_command_state *cs = data;
+ struct arpt_entry *fw = &cs->fw;
struct in_addr addr;
unsigned short int ar_hrd, ar_pro, ar_op, ar_hln;
bool inv;
- switch (offset) {
+ switch (ctx->payload.offset) {
case offsetof(struct arphdr, ar_hrd):
- get_cmp_data(iter, &ar_hrd, sizeof(ar_hrd), &inv);
+ get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv);
fw->arp.arhrd = ar_hrd;
fw->arp.arhrd_mask = 0xffff;
if (inv)
fw->arp.invflags |= ARPT_INV_ARPHRD;
break;
case offsetof(struct arphdr, ar_pro):
- get_cmp_data(iter, &ar_pro, sizeof(ar_pro), &inv);
+ get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv);
fw->arp.arpro = ar_pro;
fw->arp.arpro_mask = 0xffff;
if (inv)
fw->arp.invflags |= ARPT_INV_ARPPRO;
break;
case offsetof(struct arphdr, ar_op):
- get_cmp_data(iter, &ar_op, sizeof(ar_op), &inv);
+ get_cmp_data(e, &ar_op, sizeof(ar_op), &inv);
fw->arp.arpop = ar_op;
fw->arp.arpop_mask = 0xffff;
if (inv)
fw->arp.invflags |= ARPT_INV_ARPOP;
break;
case offsetof(struct arphdr, ar_hln):
- get_cmp_data(iter, &ar_hln, sizeof(ar_op), &inv);
+ get_cmp_data(e, &ar_hln, sizeof(ar_op), &inv);
fw->arp.arhln = ar_hln;
fw->arp.arhln_mask = 0xff;
if (inv)
@@ -342,16 +337,27 @@ static void nft_arp_parse_payload(struct nft_rule_expr_iter *iter,
if (fw->arp.arhln < 0)
break;
- if (offset == sizeof(struct arphdr) + fw->arp.arhln) {
- get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ if (ctx->payload.offset == sizeof(struct arphdr) +
+ fw->arp.arhln) {
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
fw->arp.src.s_addr = addr.s_addr;
- fw->arp.smsk.s_addr = 0xffffffff;
+ if (ctx->flags & NFT_XT_CTX_BITWISE)
+ parse_mask_ipv4(ctx, &fw->arp.smsk);
+ else
+ fw->arp.smsk.s_addr = 0xffffffff;
+
if (inv)
fw->arp.invflags |= ARPT_INV_SRCIP;
- } else if (offset == sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr)) {
- get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ } else if (ctx->payload.offset == sizeof(struct arphdr) +
+ fw->arp.arhln +
+ sizeof(struct in_addr)) {
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
fw->arp.tgt.s_addr = addr.s_addr;
- fw->arp.tmsk.s_addr = 0xffffffff;
+ if (ctx->flags & NFT_XT_CTX_BITWISE)
+ parse_mask_ipv4(ctx, &fw->arp.tmsk);
+ else
+ fw->arp.tmsk.s_addr = 0xffffffff;
+
if (inv)
fw->arp.invflags |= ARPT_INV_TGTIP;
}
@@ -359,13 +365,14 @@ static void nft_arp_parse_payload(struct nft_rule_expr_iter *iter,
}
}
-void nft_rule_to_arpt_entry(struct nft_rule *r, struct arpt_entry *fw)
+void nft_rule_to_arptables_command_state(struct nft_rule *r,
+ struct arptables_command_state *cs)
{
struct nft_rule_expr_iter *iter;
struct nft_rule_expr *expr;
int family = nft_rule_attr_get_u32(r, NFT_RULE_ATTR_FAMILY);
struct nft_xt_ctx ctx = {
- .state.fw = fw,
+ .state.cs_arp = cs,
.family = family,
};
@@ -380,11 +387,15 @@ void nft_rule_to_arpt_entry(struct nft_rule *r, struct arpt_entry *fw)
nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME);
if (strcmp(name, "counter") == 0)
- nft_parse_counter(expr, &ctx.state.fw->counters);
+ nft_parse_counter(expr, &ctx.state.cs_arp->fw.counters);
else if (strcmp(name, "payload") == 0)
nft_parse_payload(&ctx, expr);
else if (strcmp(name, "meta") == 0)
nft_parse_meta(&ctx, expr);
+ else if (strcmp(name, "bitwise") == 0)
+ nft_parse_bitwise(&ctx, expr);
+ else if (strcmp(name, "cmp") == 0)
+ nft_parse_cmp(&ctx, expr);
else if (strcmp(name, "immediate") == 0)
nft_parse_immediate(&ctx, expr);
else if (strcmp(name, "target") == 0)
@@ -394,25 +405,34 @@ void nft_rule_to_arpt_entry(struct nft_rule *r, struct arpt_entry *fw)
}
nft_rule_expr_iter_destroy(iter);
+
+ if (cs->target != NULL)
+ cs->jumpto = cs->target->name;
+ else if (cs->jumpto != NULL)
+ cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
+ else
+ cs->jumpto = "";
}
-static struct xtables_target
-*get_target(struct arpt_entry *fw, unsigned int format)
+static void nft_arp_print_header(unsigned int format, const char *chain,
+ const char *pol,
+ const struct xt_counters *counters,
+ bool basechain, uint32_t refs)
{
- const char *targname;
- struct xtables_target *target = NULL;
- const struct xt_entry_target *t;
-
- if (!fw->target_offset)
- return NULL;
-
- t = nft_arp_get_target(fw);
- targname = t->u.user.name;
- target = xtables_find_target(targname, XTF_TRY_LOAD);
- if (!(format & FMT_NOTARGET))
- printf("-j %s ", targname);
-
- return target;
+ printf("Chain %s", chain);
+ if (pol) {
+ printf(" (policy %s", pol);
+ if (!(format & FMT_NOCOUNTS)) {
+ fputc(' ', stdout);
+ xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
+ fputs("packets, ", stdout);
+ xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
+ fputs("bytes", stdout);
+ }
+ printf(")\n");
+ } else {
+ printf(" (%u references)\n", refs);
+ }
}
static void print_fw_details(struct arpt_entry *fw, unsigned int format)
@@ -560,54 +580,35 @@ static void
nft_arp_print_firewall(struct nft_rule *r, unsigned int num,
unsigned int format)
{
- struct arpt_entry fw = {};
- struct xtables_target *target = NULL;
- const struct xt_entry_target *t = NULL;
+ struct arptables_command_state cs = {};
- nft_rule_to_arpt_entry(r, &fw);
+ nft_rule_to_arptables_command_state(r, &cs);
if (format & FMT_LINENUMBERS)
printf("%u ", num);
- target = get_target(&fw, format);
- print_fw_details(&fw, format);
+ print_fw_details(&cs.fw, format);
- if (target) {
- if (target->print)
+ if (strlen(cs.jumpto) > 0) {
+ printf("-j %s\n", cs.jumpto);
+ } else if (cs.target) {
+ if (cs.target->print)
/* Print the target information. */
- target->print(&fw.arp, t, format & FMT_NUMERIC);
+ cs.target->print(&cs.fw, cs.target->t,
+ format & FMT_NUMERIC);
}
if (!(format & FMT_NOCOUNTS)) {
printf(", pcnt=");
- xtables_print_num(fw.counters.pcnt, format);
+ xtables_print_num(cs.fw.counters.pcnt, format);
printf("-- bcnt=");
- xtables_print_num(fw.counters.bcnt, format);
+ xtables_print_num(cs.fw.counters.bcnt, format);
}
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
}
-static void nft_arp_save_firewall(const void *data,
- unsigned int format)
-{
- const struct arpt_entry *fw = data;
- struct xtables_target *target = NULL;
- const struct xt_entry_target *t = NULL;
-
- print_fw_details((struct arpt_entry *)fw, format);
-
- target = get_target((struct arpt_entry *)fw, format);
-
- if (target) {
- if (target->print)
- /* Print the target information. */
- target->print(&fw->arp, t, format & FMT_NUMERIC);
- }
- printf("\n");
-}
-
static bool nft_arp_is_same(const void *data_a,
const void *data_b)
{
@@ -637,49 +638,24 @@ static bool nft_arp_is_same(const void *data_a,
static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nft_rule *r,
void *data)
{
- struct arpt_entry *fw = data;
- struct xt_entry_target *t_fw, *t_this;
- char *targname_fw, *targname_this;
- struct arpt_entry this = {};
+ const struct arptables_command_state *cs = data;
+ struct arptables_command_state this = {};
/* Delete by matching rule case */
- nft_rule_to_arpt_entry(r, &this);
+ nft_rule_to_arptables_command_state(r, &this);
- if (!ops->is_same(fw, &this))
+ if (!nft_arp_is_same(cs, &this))
return false;
- t_fw = nft_arp_get_target(fw);
- t_this = nft_arp_get_target(&this);
-
- targname_fw = t_fw->u.user.name;
- targname_this = t_this->u.user.name;
-
- if (!strcmp(targname_fw, targname_this) &&
- (!strcmp(targname_fw, "mangle") ||
- !strcmp(targname_fw, "CLASSIFY"))) {
- if (memcmp(t_fw->data, t_this->data,
- t_fw->u.user.target_size - sizeof(*t_fw)) != 0) {
- DEBUGP("Different target\n");
- return false;
- }
- return true;
- }
+ if (!compare_targets(cs->target, this.target))
+ return false;
- if (strcmp(targname_fw, targname_this) != 0) {
- DEBUGP("Different verdict\n");
+ if (strcmp(cs->jumpto, this.jumpto) != 0)
return false;
- }
return true;
}
-static void nft_arp_save_counters(const void *data)
-{
- const struct arpt_entry *fw = data;
-
- save_counters(fw->counters.pcnt, fw->counters.bcnt);
-}
-
struct nft_family_ops nft_family_ops_arp = {
.add = nft_arp_add,
.is_same = nft_arp_is_same,
@@ -687,9 +663,10 @@ struct nft_family_ops nft_family_ops_arp = {
.parse_meta = nft_arp_parse_meta,
.parse_payload = nft_arp_parse_payload,
.parse_immediate = nft_arp_parse_immediate,
+ .print_header = nft_arp_print_header,
.print_firewall = nft_arp_print_firewall,
- .save_firewall = nft_arp_save_firewall,
- .save_counters = nft_arp_save_counters,
+ .save_firewall = NULL,
+ .save_counters = NULL,
.post_parse = NULL,
.rule_find = nft_arp_rule_find,
.parse_target = nft_arp_parse_target,
diff --git a/iptables/nft-arp.h b/iptables/nft-arp.h
new file mode 100644
index 00000000..930dae5c
--- /dev/null
+++ b/iptables/nft-arp.h
@@ -0,0 +1,16 @@
+#ifndef _NFT_ARP_H_
+#define _NFT_ARP_H_
+
+extern char *opcodes[];
+#define NUMOPCODES 9
+
+struct arptables_command_state {
+ struct arpt_entry fw;
+ struct xtables_target *target;
+ const char *jumpto;
+};
+
+void nft_rule_to_arptables_command_state(struct nft_rule *r,
+ struct arptables_command_state *cs);
+
+#endif
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 70050ba5..a2c58060 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -41,14 +41,16 @@ static int nft_ipv4_add(struct nft_rule *r, void *data)
add_proto(r, offsetof(struct iphdr, protocol), 1,
cs->fw.ip.proto, cs->fw.ip.invflags);
- if (cs->fw.ip.src.s_addr != 0)
+ if (cs->fw.ip.src.s_addr != 0) {
add_addr(r, offsetof(struct iphdr, saddr),
- &cs->fw.ip.src.s_addr, 4, cs->fw.ip.invflags);
-
- if (cs->fw.ip.dst.s_addr != 0)
+ &cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr,
+ sizeof(struct in_addr), cs->fw.ip.invflags);
+ }
+ if (cs->fw.ip.dst.s_addr != 0) {
add_addr(r, offsetof(struct iphdr, daddr),
- &cs->fw.ip.dst.s_addr, 4, cs->fw.ip.invflags);
-
+ &cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr,
+ sizeof(struct in_addr), cs->fw.ip.invflags);
+ }
if (cs->fw.ip.flags & IPT_F_FRAG) {
add_payload(r, offsetof(struct iphdr, frag_off), 2);
/* get the 13 bits that contain the fragment offset */
@@ -102,35 +104,15 @@ static bool nft_ipv4_is_same(const void *data_a,
b->fw.ip.iniface_mask, b->fw.ip.outiface_mask);
}
-static void get_frag(struct nft_rule_expr_iter *iter, bool *inv)
+static void get_frag(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, bool *inv)
{
- struct nft_rule_expr *e;
- const char *name;
uint8_t op;
- e = nft_rule_expr_iter_next(iter);
- if (e == NULL)
- return;
-
/* we assume correct mask and xor */
- name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME);
- if (strcmp(name, "bitwise") != 0) {
- DEBUGP("skipping no bitwise after payload\n");
- return;
- }
-
- /* Now check for cmp */
- e = nft_rule_expr_iter_next(iter);
- if (e == NULL)
+ if (!(ctx->flags & NFT_XT_CTX_BITWISE))
return;
/* we assume correct data */
- name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME);
- if (strcmp(name, "cmp") != 0) {
- DEBUGP("skipping no cmp after payload\n");
- return;
- }
-
op = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_OP);
if (op == NFT_CMP_EQ)
*inv = true;
@@ -164,54 +146,66 @@ static const char *mask_to_str(uint32_t mask)
return mask_str;
}
-static void nft_ipv4_parse_meta(struct nft_rule_expr *e, uint8_t key,
+static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e,
void *data)
{
struct iptables_command_state *cs = data;
- parse_meta(e, key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
+ parse_meta(e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
cs->fw.ip.outiface, cs->fw.ip.outiface_mask,
&cs->fw.ip.invflags);
}
-static void nft_ipv4_parse_payload(struct nft_rule_expr_iter *iter,
- uint32_t offset, void *data)
+static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
{
- struct iptables_command_state *cs = data;
+ mask->s_addr = ctx->bitwise.mask[0];
+}
- switch(offset) {
+static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
+ struct nft_rule_expr *e, void *data)
+{
+ struct iptables_command_state *cs = data;
struct in_addr addr;
uint8_t proto;
bool inv;
+ switch(ctx->payload.offset) {
case offsetof(struct iphdr, saddr):
- get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
cs->fw.ip.src.s_addr = addr.s_addr;
- cs->fw.ip.smsk.s_addr = 0xffffffff;
+ if (ctx->flags & NFT_XT_CTX_BITWISE)
+ parse_mask_ipv4(ctx, &cs->fw.ip.smsk);
+ else
+ cs->fw.ip.smsk.s_addr = 0xffffffff;
+
if (inv)
cs->fw.ip.invflags |= IPT_INV_SRCIP;
break;
case offsetof(struct iphdr, daddr):
- get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
cs->fw.ip.dst.s_addr = addr.s_addr;
- cs->fw.ip.dmsk.s_addr = 0xffffffff;
+ if (ctx->flags & NFT_XT_CTX_BITWISE)
+ parse_mask_ipv4(ctx, &cs->fw.ip.dmsk);
+ else
+ cs->fw.ip.dmsk.s_addr = 0xffffffff;
+
if (inv)
cs->fw.ip.invflags |= IPT_INV_DSTIP;
break;
case offsetof(struct iphdr, protocol):
- get_cmp_data(iter, &proto, sizeof(proto), &inv);
+ get_cmp_data(e, &proto, sizeof(proto), &inv);
cs->fw.ip.proto = proto;
if (inv)
cs->fw.ip.invflags |= IPT_INV_PROTO;
break;
case offsetof(struct iphdr, frag_off):
cs->fw.ip.flags |= IPT_F_FRAG;
- get_frag(iter, &inv);
+ get_frag(ctx, e, &inv);
if (inv)
cs->fw.ip.invflags |= IPT_INV_FRAG;
break;
default:
- DEBUGP("unknown payload offset %d\n", offset);
+ DEBUGP("unknown payload offset %d\n", ctx->payload.offset);
break;
}
}
@@ -227,6 +221,14 @@ static void nft_ipv4_parse_immediate(const char *jumpto, bool nft_goto,
cs->fw.ip.flags |= IPT_F_GOTO;
}
+static void nft_ipv4_print_header(unsigned int format, const char *chain,
+ const char *pol,
+ const struct xt_counters *counters,
+ bool basechain, uint32_t refs)
+{
+ print_header(format, chain, pol, counters, basechain, refs);
+}
+
static void print_ipv4_addr(const struct iptables_command_state *cs,
unsigned int format)
{
@@ -421,6 +423,7 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.parse_meta = nft_ipv4_parse_meta,
.parse_payload = nft_ipv4_parse_payload,
.parse_immediate = nft_ipv4_parse_immediate,
+ .print_header = nft_ipv4_print_header,
.print_firewall = nft_ipv4_print_firewall,
.save_firewall = nft_ipv4_save_firewall,
.save_counters = nft_ipv4_save_counters,
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index 52de5b69..5489398a 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -38,14 +38,16 @@ static int nft_ipv6_add(struct nft_rule *r, void *data)
add_proto(r, offsetof(struct ip6_hdr, ip6_nxt), 1,
cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags);
- if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src))
+ if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src)) {
add_addr(r, offsetof(struct ip6_hdr, ip6_src),
- &cs->fw6.ipv6.src, 16, cs->fw6.ipv6.invflags);
-
- if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst))
+ &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
+ sizeof(struct in6_addr), cs->fw6.ipv6.invflags);
+ }
+ if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst)) {
add_addr(r, offsetof(struct ip6_hdr, ip6_dst),
- &cs->fw6.ipv6.dst, 16, cs->fw6.ipv6.invflags);
-
+ &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk,
+ sizeof(struct in6_addr), cs->fw6.ipv6.invflags);
+ }
add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags);
for (matchp = cs->matches; matchp; matchp = matchp->next) {
@@ -87,45 +89,60 @@ static bool nft_ipv6_is_same(const void *data_a,
b->fw6.ipv6.outiface_mask);
}
-static void nft_ipv6_parse_meta(struct nft_rule_expr *e, uint8_t key,
+static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e,
void *data)
{
struct iptables_command_state *cs = data;
- parse_meta(e, key, cs->fw6.ipv6.iniface,
+ parse_meta(e, ctx->meta.key, cs->fw6.ipv6.iniface,
cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface,
cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags);
}
-static void nft_ipv6_parse_payload(struct nft_rule_expr_iter *iter,
- uint32_t offset, void *data)
+static void parse_mask_ipv6(struct nft_xt_ctx *ctx, struct in6_addr *mask)
+{
+ memcpy(mask, ctx->bitwise.mask, sizeof(struct in6_addr));
+}
+
+static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
+ struct nft_rule_expr *e, void *data)
{
struct iptables_command_state *cs = data;
- switch (offset) {
struct in6_addr addr;
uint8_t proto;
bool inv;
+ switch (ctx->payload.offset) {
case offsetof(struct ip6_hdr, ip6_src):
- get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr));
+ if (ctx->flags & NFT_XT_CTX_BITWISE)
+ parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk);
+ else
+ memset(&cs->fw.ip.smsk, 0xff, sizeof(struct in6_addr));
+
if (inv)
cs->fw6.ipv6.invflags |= IPT_INV_SRCIP;
break;
case offsetof(struct ip6_hdr, ip6_dst):
- get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr));
+ if (ctx->flags & NFT_XT_CTX_BITWISE)
+ parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk);
+ else
+ memset(&cs->fw.ip.dmsk, 0xff, sizeof(struct in6_addr));
+
if (inv)
cs->fw6.ipv6.invflags |= IPT_INV_DSTIP;
break;
case offsetof(struct ip6_hdr, ip6_nxt):
- get_cmp_data(iter, &proto, sizeof(proto), &inv);
+ get_cmp_data(e, &proto, sizeof(proto), &inv);
cs->fw6.ipv6.flags |= IP6T_F_PROTO;
cs->fw6.ipv6.proto = proto;
if (inv)
cs->fw6.ipv6.invflags |= IPT_INV_PROTO;
default:
- DEBUGP("unknown payload offset %d\n", offset);
+ DEBUGP("unknown payload offset %d\n", ctx->payload.offset);
break;
}
}
@@ -141,6 +158,14 @@ static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto,
cs->fw6.ipv6.flags |= IP6T_F_GOTO;
}
+static void nft_ipv6_print_header(unsigned int format, const char *chain,
+ const char *pol,
+ const struct xt_counters *counters,
+ bool basechain, uint32_t refs)
+{
+ print_header(format, chain, pol, counters, basechain, refs);
+}
+
static void print_ipv6_addr(const struct iptables_command_state *cs,
unsigned int format)
{
@@ -343,6 +368,7 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.parse_meta = nft_ipv6_parse_meta,
.parse_payload = nft_ipv6_parse_payload,
.parse_immediate = nft_ipv6_parse_immediate,
+ .print_header = nft_ipv6_print_header,
.print_firewall = nft_ipv6_print_firewall,
.save_firewall = nft_ipv6_save_firewall,
.save_counters = nft_ipv6_save_counters,
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 0a4b85a3..00310a37 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -82,6 +82,24 @@ void add_bitwise_u16(struct nft_rule *r, int mask, int xor)
nft_rule_add_expr(r, expr);
}
+static void add_bitwise(struct nft_rule *r, uint8_t *mask, size_t len)
+{
+ struct nft_rule_expr *expr;
+ uint32_t xor[4] = { 0 };
+
+ expr = nft_rule_expr_alloc("bitwise");
+ if (expr == NULL)
+ return;
+
+ nft_rule_expr_set_u32(expr, NFT_EXPR_BITWISE_SREG, NFT_REG_1);
+ nft_rule_expr_set_u32(expr, NFT_EXPR_BITWISE_DREG, NFT_REG_1);
+ nft_rule_expr_set_u32(expr, NFT_EXPR_BITWISE_LEN, len);
+ nft_rule_expr_set(expr, NFT_EXPR_BITWISE_MASK, mask, len);
+ nft_rule_expr_set(expr, NFT_EXPR_BITWISE_XOR, &xor, len);
+
+ nft_rule_add_expr(r, expr);
+}
+
void add_cmp_ptr(struct nft_rule *r, uint32_t op, void *data, size_t len)
{
struct nft_rule_expr *expr;
@@ -151,11 +169,12 @@ void add_outiface(struct nft_rule *r, char *iface, int invflags)
}
void add_addr(struct nft_rule *r, int offset,
- void *data, size_t len, int invflags)
+ void *data, void *mask, size_t len, int invflags)
{
uint32_t op;
add_payload(r, offset, len);
+ add_bitwise(r, mask, len);
if (invflags & IPT_INV_SRCIP || invflags & IPT_INV_DSTIP)
op = NFT_CMP_NEQ;
@@ -284,7 +303,7 @@ static void *nft_get_data(struct nft_xt_ctx *ctx)
case NFPROTO_IPV6:
return ctx->state.cs;
case NFPROTO_ARP:
- return ctx->state.fw;
+ return ctx->state.cs_arp;
default:
/* Should not happen */
return NULL;
@@ -298,8 +317,8 @@ void nft_parse_target(struct nft_xt_ctx *ctx, struct nft_rule_expr *e)
const void *targinfo = nft_rule_expr_get(e, NFT_EXPR_TG_INFO, &tg_len);
struct xtables_target *target;
struct xt_entry_target *t;
- struct nft_family_ops *ops;
size_t size;
+ struct nft_family_ops *ops;
void *data = nft_get_data(ctx);
target = xtables_find_target(targname, XTF_TRY_LOAD);
@@ -365,24 +384,11 @@ void print_proto(uint16_t proto, int invert)
printf("-p %u ", proto);
}
-void get_cmp_data(struct nft_rule_expr_iter *iter,
- void *data, size_t dlen, bool *inv)
+void get_cmp_data(struct nft_rule_expr *e, void *data, size_t dlen, bool *inv)
{
- struct nft_rule_expr *e;
- const char *name;
uint32_t len;
uint8_t op;
- e = nft_rule_expr_iter_next(iter);
- if (e == NULL)
- return;
-
- name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME);
- if (strcmp(name, "cmp") != 0) {
- DEBUGP("skipping no cmp after meta\n");
- return;
- }
-
memcpy(data, nft_rule_expr_get(e, NFT_EXPR_CMP_DATA, &len), dlen);
op = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_OP);
if (op == NFT_CMP_NEQ)
@@ -393,33 +399,49 @@ void get_cmp_data(struct nft_rule_expr_iter *iter,
void nft_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e)
{
- uint8_t key = nft_rule_expr_get_u32(e, NFT_EXPR_META_KEY);
- struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family);
- const char *name;
- void *data = nft_get_data(ctx);
+ ctx->reg = nft_rule_expr_get_u32(e, NFT_EXPR_META_DREG);
+ ctx->meta.key = nft_rule_expr_get_u32(e, NFT_EXPR_META_KEY);
+ ctx->flags |= NFT_XT_CTX_META;
+}
- e = nft_rule_expr_iter_next(ctx->iter);
- if (e == NULL)
- return;
+void nft_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e)
+{
+ ctx->reg = nft_rule_expr_get_u32(e, NFT_EXPR_META_DREG);
+ ctx->payload.offset = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_OFFSET);
+ ctx->flags |= NFT_XT_CTX_PAYLOAD;
+}
- name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME);
- if (strcmp(name, "cmp") != 0) {
- DEBUGP("skipping no cmp after meta\n");
+void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nft_rule_expr *e)
+{
+ uint32_t reg, len;
+ const void *data;
+
+ reg = nft_rule_expr_get_u32(e, NFT_EXPR_BITWISE_SREG);
+ if (ctx->reg && reg != ctx->reg)
return;
- }
- ops->parse_meta(e, key, data);
+ data = nft_rule_expr_get(e, NFT_EXPR_BITWISE_XOR, &len);
+ memcpy(ctx->bitwise.xor, data, len);
+ data = nft_rule_expr_get(e, NFT_EXPR_BITWISE_MASK, &len);
+ memcpy(ctx->bitwise.mask, data, len);
+ ctx->flags |= NFT_XT_CTX_BITWISE;
}
-void nft_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e)
+void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nft_rule_expr *e)
{
struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family);
- uint32_t offset;
void *data = nft_get_data(ctx);
+ uint32_t reg;
- offset = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_OFFSET);
+ reg = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_SREG);
+ if (ctx->reg && reg != ctx->reg)
+ return;
- ops->parse_payload(ctx->iter, offset, data);
+ if (ctx->flags & NFT_XT_CTX_META)
+ ops->parse_meta(ctx, e, data);
+ /* bitwise context is interpreted from payload */
+ if (ctx->flags & NFT_XT_CTX_PAYLOAD)
+ ops->parse_payload(ctx, e, data);
}
void nft_parse_counter(struct nft_rule_expr *e, struct xt_counters *counters)
@@ -486,6 +508,10 @@ void nft_rule_to_iptables_command_state(struct nft_rule *r,
nft_parse_payload(&ctx, expr);
else if (strcmp(name, "meta") == 0)
nft_parse_meta(&ctx, expr);
+ else if (strcmp(name, "bitwise") == 0)
+ nft_parse_bitwise(&ctx, expr);
+ else if (strcmp(name, "cmp") == 0)
+ nft_parse_cmp(&ctx, expr);
else if (strcmp(name, "immediate") == 0)
nft_parse_immediate(&ctx, expr);
else if (strcmp(name, "match") == 0)
@@ -506,6 +532,50 @@ void nft_rule_to_iptables_command_state(struct nft_rule *r,
cs->jumpto = "";
}
+void print_header(unsigned int format, const char *chain, const char *pol,
+ const struct xt_counters *counters, bool basechain,
+ uint32_t refs)
+{
+ printf("Chain %s", chain);
+ if (basechain) {
+ printf(" (policy %s", pol);
+ if (!(format & FMT_NOCOUNTS)) {
+ fputc(' ', stdout);
+ xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
+ fputs("packets, ", stdout);
+ xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
+ fputs("bytes", stdout);
+ }
+ printf(")\n");
+ } else {
+ printf(" (%u references)\n", refs);
+ }
+
+ if (format & FMT_LINENUMBERS)
+ printf(FMT("%-4s ", "%s "), "num");
+ if (!(format & FMT_NOCOUNTS)) {
+ if (format & FMT_KILOMEGAGIGA) {
+ printf(FMT("%5s ","%s "), "pkts");
+ printf(FMT("%5s ","%s "), "bytes");
+ } else {
+ printf(FMT("%8s ","%s "), "pkts");
+ printf(FMT("%10s ","%s "), "bytes");
+ }
+ }
+ if (!(format & FMT_NOTARGET))
+ printf(FMT("%-9s ","%s "), "target");
+ fputs(" prot ", stdout);
+ if (format & FMT_OPTIONS)
+ fputs("opt", stdout);
+ if (format & FMT_VIA) {
+ printf(FMT(" %-6s ","%s "), "in");
+ printf(FMT("%-6s ","%s "), "out");
+ }
+ printf(FMT(" %-19s ","%s "), "source");
+ printf(FMT(" %-19s "," %s "), "destination");
+ printf("\n");
+}
+
void print_firewall_details(const struct iptables_command_state *cs,
const char *targname, uint8_t flags,
uint8_t invflags, uint8_t proto,
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index c4936dde..468da5c9 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -38,14 +38,33 @@
struct xtables_args;
+enum {
+ NFT_XT_CTX_PAYLOAD = (1 << 0),
+ NFT_XT_CTX_META = (1 << 1),
+ NFT_XT_CTX_BITWISE = (1 << 2),
+};
+
struct nft_xt_ctx {
union {
struct iptables_command_state *cs;
- struct arpt_entry *fw;
+ struct arptables_command_state *cs_arp;
} state;
struct nft_rule_expr_iter *iter;
int family;
uint32_t flags;
+
+ uint32_t reg;
+ struct {
+ uint32_t offset;
+ uint32_t len;
+ } payload;
+ struct {
+ uint32_t key;
+ } meta;
+ struct {
+ uint32_t mask[4];
+ uint32_t xor[4];
+ } bitwise;
};
struct nft_family_ops {
@@ -54,11 +73,20 @@ struct nft_family_ops {
const void *data_b);
void (*print_payload)(struct nft_rule_expr *e,
struct nft_rule_expr_iter *iter);
- void (*parse_meta)(struct nft_rule_expr *e, uint8_t key,
+ void (*parse_meta)(struct nft_xt_ctx *ctx, struct nft_rule_expr *e,
void *data);
- void (*parse_payload)(struct nft_rule_expr_iter *iter,
- uint32_t offset, void *data);
+ void (*parse_payload)(struct nft_xt_ctx *ctx, struct nft_rule_expr *e,
+ void *data);
+ void (*parse_bitwise)(struct nft_xt_ctx *ctx, struct nft_rule_expr *e,
+ void *data);
+ void (*parse_cmp)(struct nft_xt_ctx *ctx, struct nft_rule_expr *e,
+ void *data);
void (*parse_immediate)(const char *jumpto, bool nft_goto, void *data);
+
+ void (*print_header)(unsigned int format, const char *chain,
+ const char *pol,
+ const struct xt_counters *counters, bool basechain,
+ uint32_t refs);
void (*print_firewall)(struct nft_rule *r, unsigned int num,
unsigned int format);
void (*save_firewall)(const void *data, unsigned int format);
@@ -82,7 +110,7 @@ void add_cmp_u32(struct nft_rule *r, uint32_t val, uint32_t op);
void add_iniface(struct nft_rule *r, char *iface, int invflags);
void add_outiface(struct nft_rule *r, char *iface, int invflags);
void add_addr(struct nft_rule *r, int offset,
- void *data, size_t len, int invflags);
+ void *data, void *mask, size_t len, int invflags);
void add_proto(struct nft_rule *r, int offset, size_t len,
uint8_t proto, int invflags);
void add_compat(struct nft_rule *r, uint32_t proto, bool inv);
@@ -98,8 +126,9 @@ void parse_meta(struct nft_rule_expr *e, uint8_t key, char *iniface,
unsigned char *iniface_mask, char *outiface,
unsigned char *outiface_mask, uint8_t *invflags);
void print_proto(uint16_t proto, int invert);
-void get_cmp_data(struct nft_rule_expr_iter *iter,
- void *data, size_t dlen, bool *inv);
+void get_cmp_data(struct nft_rule_expr *e, void *data, size_t dlen, bool *inv);
+void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nft_rule_expr *e);
+void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nft_rule_expr *e);
void nft_parse_target(struct nft_xt_ctx *ctx, struct nft_rule_expr *e);
void nft_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e);
void nft_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e);
@@ -107,6 +136,9 @@ void nft_parse_counter(struct nft_rule_expr *e, struct xt_counters *counters);
void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nft_rule_expr *e);
void nft_rule_to_iptables_command_state(struct nft_rule *r,
struct iptables_command_state *cs);
+void print_header(unsigned int format, const char *chain, const char *pol,
+ const struct xt_counters *counters, bool basechain,
+ uint32_t refs);
void print_firewall_details(const struct iptables_command_state *cs,
const char *targname, uint8_t flags,
uint8_t invflags, uint8_t proto,
@@ -180,19 +212,4 @@ struct xtables_args {
#define CMD_ZERO_NUM 0x2000U
#define CMD_CHECK 0x4000U
-/*
- * ARP
- */
-extern char *opcodes[];
-#define NUMOPCODES 9
-
-static inline struct xt_entry_target *nft_arp_get_target(struct arpt_entry *fw)
-{
- struct xt_entry_target **target;
-
- target = (void *) &fw->elems;
-
- return *target;
-}
-
#endif
diff --git a/iptables/nft.c b/iptables/nft.c
index e3b07e03..6cb03a0d 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -61,10 +61,8 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
int ret;
char buf[MNL_SOCKET_BUFFER_SIZE];
- if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0) {
- perror("mnl_socket_send");
+ if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
return -1;
- }
ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
while (ret > 0) {
@@ -142,6 +140,18 @@ static void mnl_nft_set_sndbuffer(const struct mnl_socket *nl)
nlbuffsiz = newbuffsiz;
}
+static void mnl_nft_batch_reset(void)
+{
+ struct batch_page *batch_page, *next;
+
+ list_for_each_entry_safe(batch_page, next, &batch_page_list, head) {
+ list_del(&batch_page->head);
+ free(batch_page->batch);
+ free(batch_page);
+ batch_num_pages--;
+ }
+}
+
static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl)
{
static const struct sockaddr_nl snl = {
@@ -154,12 +164,12 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl)
.msg_iov = iov,
.msg_iovlen = batch_num_pages,
};
- struct batch_page *batch_page, *next;
- int i = 0;
+ struct batch_page *batch_page;
+ int i = 0, ret;
mnl_nft_set_sndbuffer(nl);
- list_for_each_entry_safe(batch_page, next, &batch_page_list, head) {
+ list_for_each_entry(batch_page, &batch_page_list, head) {
iov[i].iov_base = mnl_nlmsg_batch_head(batch_page->batch);
iov[i].iov_len = mnl_nlmsg_batch_size(batch_page->batch);
i++;
@@ -169,26 +179,14 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl)
mnl_nlmsg_batch_size(batch_page->batch),
sizeof(struct nfgenmsg));
#endif
- list_del(&batch_page->head);
- free(batch_page->batch);
- free(batch_page);
- batch_num_pages--;
}
- return sendmsg(mnl_socket_get_fd(nl), &msg, 0);
-}
+ ret = sendmsg(mnl_socket_get_fd(nl), &msg, 0);
+ mnl_nft_batch_reset();
-static int cb_err(const struct nlmsghdr *nlh, void *data)
-{
- /* We can provide better error reporting than iptables-restore */
- errno = EINVAL;
- return MNL_CB_ERROR;
+ return ret;
}
-static mnl_cb_t cb_ctl_array[NLMSG_MIN_TYPE] = {
- [NLMSG_ERROR] = cb_err,
-};
-
static int mnl_nft_batch_talk(struct nft_handle *h)
{
int ret, fd = mnl_socket_get_fd(h->nl);
@@ -201,78 +199,59 @@ static int mnl_nft_batch_talk(struct nft_handle *h)
int err = 0;
ret = mnl_nft_socket_sendmsg(h->nl);
- if (ret == -1) {
- perror("mnl_socket_sendmsg");
+ if (ret == -1)
return -1;
- }
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
/* receive and digest all the acknowledgments from the kernel. */
ret = select(fd+1, &readfds, NULL, NULL, &tv);
- if (ret == -1) {
- perror("select");
+ if (ret == -1)
return -1;
- }
+
while (ret > 0 && FD_ISSET(fd, &readfds)) {
ret = mnl_socket_recvfrom(h->nl, rcv_buf, sizeof(rcv_buf));
- if (ret == -1) {
- perror("mnl_socket_recvfrom");
+ if (ret == -1)
return -1;
- }
- ret = mnl_cb_run2(rcv_buf, ret, 0, h->portid,
- NULL, NULL, cb_ctl_array,
- MNL_ARRAY_SIZE(cb_ctl_array));
- /* Continue on error, make sure we get all acknoledgments */
- if (ret == -1)
+ ret = mnl_cb_run(rcv_buf, ret, 0, h->portid, NULL, NULL);
+ /* Annotate first error and continue, make sure we get all
+ * acknoledgments.
+ */
+ if (!err && ret == -1)
err = errno;
ret = select(fd+1, &readfds, NULL, NULL, &tv);
- if (ret == -1) {
- perror("select");
+ if (ret == -1)
return -1;
- }
+
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
}
+ errno = err;
return err ? -1 : 0;
}
-static void mnl_nft_batch_put(struct mnl_nlmsg_batch *batch, int type,
- uint32_t seq)
+static void mnl_nft_batch_begin(struct mnl_nlmsg_batch *batch, uint32_t seq)
{
- struct nlmsghdr *nlh;
- struct nfgenmsg *nfg;
-
- nlh = mnl_nlmsg_put_header(mnl_nlmsg_batch_current(batch));
- nlh->nlmsg_type = type;
- nlh->nlmsg_flags = NLM_F_REQUEST;
- nlh->nlmsg_seq = seq;
-
- nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
- nfg->nfgen_family = AF_INET;
- nfg->version = NFNETLINK_V0;
- nfg->res_id = NFNL_SUBSYS_NFTABLES;
-
+ nft_batch_begin(mnl_nlmsg_batch_current(batch), seq);
if (!mnl_nlmsg_batch_next(batch))
mnl_nft_batch_page_add(batch);
}
-static void mnl_nft_batch_begin(struct mnl_nlmsg_batch *batch, uint32_t seq)
-{
- mnl_nft_batch_put(batch, NFNL_MSG_BATCH_BEGIN, seq);
-}
-
static void mnl_nft_batch_end(struct mnl_nlmsg_batch *batch, uint32_t seq)
{
- mnl_nft_batch_put(batch, NFNL_MSG_BATCH_END, seq);
+ nft_batch_end(mnl_nlmsg_batch_current(batch), seq);
+ if (!mnl_nlmsg_batch_next(batch))
+ mnl_nft_batch_page_add(batch);
}
enum obj_update_type {
NFT_COMPAT_TABLE_ADD,
NFT_COMPAT_CHAIN_ADD,
+ NFT_COMPAT_CHAIN_USER_ADD,
+ NFT_COMPAT_CHAIN_USER_DEL,
NFT_COMPAT_CHAIN_UPDATE,
NFT_COMPAT_RULE_APPEND,
NFT_COMPAT_RULE_INSERT,
@@ -539,7 +518,7 @@ static int nft_table_builtin_add(struct nft_handle *h,
return ret;
}
-struct nft_chain *
+static struct nft_chain *
nft_chain_builtin_alloc(struct builtin_table *table,
struct builtin_chain *chain, int policy)
{
@@ -582,12 +561,13 @@ int nft_chain_add(struct nft_handle *h, struct nft_chain *c, uint16_t flags)
return mnl_talk(h, nlh, NULL, NULL);
}
-void nft_chain_builtin_add(struct nft_handle *h, struct builtin_table *table,
- struct builtin_chain *chain, int policy)
+static void nft_chain_builtin_add(struct nft_handle *h,
+ struct builtin_table *table,
+ struct builtin_chain *chain)
{
struct nft_chain *c;
- c = nft_chain_builtin_alloc(table, chain, policy);
+ c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT);
if (c == NULL)
return;
@@ -598,7 +578,7 @@ void nft_chain_builtin_add(struct nft_handle *h, struct builtin_table *table,
}
/* find if built-in table already exists */
-struct builtin_table *
+static struct builtin_table *
nft_table_builtin_find(struct nft_handle *h, const char *table)
{
int i;
@@ -619,7 +599,7 @@ nft_table_builtin_find(struct nft_handle *h, const char *table)
}
/* find if built-in chain already exists */
-struct builtin_chain *
+static struct builtin_chain *
nft_chain_builtin_find(struct builtin_table *t, const char *chain)
{
int i;
@@ -635,30 +615,28 @@ nft_chain_builtin_find(struct builtin_table *t, const char *chain)
return found ? &t->chains[i] : NULL;
}
-static void
-__nft_chain_builtin_init(struct nft_handle *h,
- struct builtin_table *table, const char *chain,
- int policy)
+static void nft_chain_builtin_init(struct nft_handle *h,
+ struct builtin_table *table)
{
- int i, default_policy;
+ int i;
+ struct nft_chain_list *list = nft_chain_dump(h);
+ struct nft_chain *c;
- /* Initialize all built-in chains. Exception, for e one received as
- * parameter, set the default policy as requested.
- */
+ /* Initialize built-in chains if they don't exist yet */
for (i=0; i<NF_IP_NUMHOOKS && table->chains[i].name != NULL; i++) {
- if (chain && strcmp(table->chains[i].name, chain) == 0)
- default_policy = policy;
- else
- default_policy = NF_ACCEPT;
- nft_chain_builtin_add(h, table, &table->chains[i],
- default_policy);
+ c = nft_chain_list_find(list, table->name,
+ table->chains[i].name);
+ if (c != NULL)
+ continue;
+
+ nft_chain_builtin_add(h, table, &table->chains[i]);
}
+
+ nft_chain_list_free(list);
}
-int
-nft_chain_builtin_init(struct nft_handle *h, const char *table,
- const char *chain, int policy)
+static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
{
int ret = 0;
struct builtin_table *t;
@@ -673,7 +651,7 @@ nft_chain_builtin_init(struct nft_handle *h, const char *table,
if (errno == EEXIST)
goto out;
}
- __nft_chain_builtin_init(h, t, chain, policy);
+ nft_chain_builtin_init(h, t);
out:
return ret;
}
@@ -732,15 +710,12 @@ err:
int nft_init(struct nft_handle *h, struct builtin_table *t)
{
h->nl = mnl_socket_open(NETLINK_NETFILTER);
- if (h->nl == NULL) {
- perror("mnl_socket_open");
+ if (h->nl == NULL)
return -1;
- }
- if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0) {
- perror("mnl_socket_bind");
+ if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0)
return -1;
- }
+
h->portid = mnl_socket_get_portid(h->nl);
h->tables = t;
@@ -1019,7 +994,7 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_chain_builtin_init(h, table, chain, NF_ACCEPT);
+ nft_xt_builtin_init(h, table);
nft_fn = nft_rule_append;
@@ -1074,15 +1049,11 @@ static int nft_chain_list_cb(const struct nlmsghdr *nlh, void *data)
struct nft_chain_list *list = data;
c = nft_chain_alloc();
- if (c == NULL) {
- perror("OOM");
+ if (c == NULL)
goto err;
- }
- if (nft_chain_nlmsg_parse(nlh, c) < 0) {
- perror("nft_rule_nlmsg_parse");
+ if (nft_chain_nlmsg_parse(nlh, c) < 0)
goto out;
- }
nft_chain_list_add_tail(c, list);
@@ -1180,15 +1151,11 @@ static int nft_rule_list_cb(const struct nlmsghdr *nlh, void *data)
struct nft_rule_list *list = data;
r = nft_rule_alloc();
- if (r == NULL) {
- perror("OOM");
+ if (r == NULL)
goto err;
- }
- if (nft_rule_nlmsg_parse(nlh, r) < 0) {
- perror("nft_rule_nlmsg_parse");
+ if (nft_rule_nlmsg_parse(nlh, r) < 0)
goto out;
- }
nft_rule_list_add_tail(r, list);
@@ -1328,14 +1295,14 @@ err:
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
{
- char buf[MNL_SOCKET_BUFFER_SIZE];
- struct nlmsghdr *nlh;
struct nft_chain *c;
int ret;
+ nft_fn = nft_chain_user_add;
+
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_chain_builtin_init(h, table, NULL, NF_ACCEPT);
+ nft_xt_builtin_init(h, table);
c = nft_chain_alloc();
if (c == NULL)
@@ -1344,12 +1311,19 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
nft_chain_attr_set(c, NFT_CHAIN_ATTR_TABLE, (char *)table);
nft_chain_attr_set(c, NFT_CHAIN_ATTR_NAME, (char *)chain);
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family,
- NLM_F_ACK|NLM_F_EXCL, h->seq);
- nft_chain_nlmsg_build_payload(nlh, c);
- nft_chain_free(c);
+ if (h->batch_support) {
+ ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ } else {
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
- ret = mnl_talk(h, nlh, NULL, NULL);
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN,
+ h->family,
+ NLM_F_ACK|NLM_F_EXCL, h->seq);
+ nft_chain_nlmsg_build_payload(nlh, c);
+ nft_chain_free(c);
+ ret = mnl_talk(h, nlh, NULL, NULL);
+ }
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1400,7 +1374,11 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *tabl
if (chain != NULL && strcmp(chain, chain_name) != 0)
goto next;
- ret = __nft_chain_del(h, c);
+ if (h->batch_support)
+ ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c);
+ else
+ ret = __nft_chain_del(h, c);
+
if (ret < 0)
break;
@@ -1414,11 +1392,14 @@ next:
nft_chain_list_iter_destroy(iter);
err:
- nft_chain_list_free(list);
+ if (!h->batch_support)
+ nft_chain_list_free(list);
/* chain not found */
- if (ret < 0 && deleted_ctr == 0)
+ if (deleted_ctr == 0) {
+ ret = -1;
errno = ENOENT;
+ }
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1472,15 +1453,13 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
int nft_chain_user_rename(struct nft_handle *h,const char *chain,
const char *table, const char *newname)
{
- char buf[MNL_SOCKET_BUFFER_SIZE];
- struct nlmsghdr *nlh;
struct nft_chain *c;
uint64_t handle;
int ret;
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_chain_builtin_init(h, table, NULL, NF_ACCEPT);
+ nft_xt_builtin_init(h, table);
/* Find the old chain to be renamed */
c = nft_chain_find(h, table, chain);
@@ -1499,12 +1478,19 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
nft_chain_attr_set(c, NFT_CHAIN_ATTR_NAME, (char *)newname);
nft_chain_attr_set_u64(c, NFT_CHAIN_ATTR_HANDLE, handle);
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family,
- NLM_F_ACK, h->seq);
- nft_chain_nlmsg_build_payload(nlh, c);
- nft_chain_free(c);
+ if (h->batch_support) {
+ ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ } else {
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
- ret = mnl_talk(h, nlh, NULL, NULL);
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN,
+ h->family, NLM_F_ACK, h->seq);
+ nft_chain_nlmsg_build_payload(nlh, c);
+ nft_chain_free(c);
+
+ ret = mnl_talk(h, nlh, NULL, NULL);
+ }
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1516,15 +1502,11 @@ static int nft_table_list_cb(const struct nlmsghdr *nlh, void *data)
struct nft_table_list *list = data;
t = nft_table_alloc();
- if (t == NULL) {
- perror("OOM");
+ if (t == NULL)
goto err;
- }
- if (nft_table_nlmsg_parse(nlh, t) < 0) {
- perror("nft_rule_nlmsg_parse");
+ if (nft_table_nlmsg_parse(nlh, t) < 0)
goto out;
- }
nft_table_list_add_tail(t, list);
@@ -1804,7 +1786,7 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
/* If built-in chains don't exist for this table, create them */
if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_chain_builtin_init(h, table, chain, NF_ACCEPT);
+ nft_xt_builtin_init(h, table);
nft_fn = nft_rule_insert;
@@ -1890,50 +1872,6 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
return ret;
}
-static void
-print_header(unsigned int format, const char *chain, const char *pol,
- const struct xt_counters *counters, bool basechain, uint32_t refs)
-{
- printf("Chain %s", chain);
- if (basechain) {
- printf(" (policy %s", pol);
- if (!(format & FMT_NOCOUNTS)) {
- fputc(' ', stdout);
- xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
- fputs("packets, ", stdout);
- xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
- fputs("bytes", stdout);
- }
- printf(")\n");
- } else {
- printf(" (%u references)\n", refs);
- }
-
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4s ", "%s "), "num");
- if (!(format & FMT_NOCOUNTS)) {
- if (format & FMT_KILOMEGAGIGA) {
- printf(FMT("%5s ","%s "), "pkts");
- printf(FMT("%5s ","%s "), "bytes");
- } else {
- printf(FMT("%8s ","%s "), "pkts");
- printf(FMT("%10s ","%s "), "bytes");
- }
- }
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ","%s "), "target");
- fputs(" prot ", stdout);
- if (format & FMT_OPTIONS)
- fputs("opt", stdout);
- if (format & FMT_VIA) {
- printf(FMT(" %-6s ","%s "), "in");
- printf(FMT("%-6s ","%s "), "out");
- }
- printf(FMT(" %-19s ","%s "), "source");
- printf(FMT(" %-19s "," %s "), "destination");
- printf("\n");
-}
-
static int
__nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
int rulenum, unsigned int format,
@@ -2001,8 +1939,14 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
bool found = false;
/* If built-in chains don't exist for this table, create them */
- if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
- nft_chain_builtin_init(h, table, NULL, NF_ACCEPT);
+ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) {
+ nft_xt_builtin_init(h, table);
+ /* Force table and chain creation, otherwise first iptables -L
+ * lists no table/chains.
+ */
+ if (!list_empty(&h->obj_list))
+ nft_commit(h);
+ }
ops = nft_family_ops_lookup(h->family);
@@ -2045,8 +1989,8 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if (found)
printf("\n");
- print_header(format, chain_name, policy_name[policy],
- &ctrs, basechain, refs);
+ ops->print_header(format, chain_name, policy_name[policy],
+ &ctrs, basechain, refs);
__nft_rule_list(h, chain_name, table,
rulenum, format, ops->print_firewall);
@@ -2266,6 +2210,15 @@ static int nft_action(struct nft_handle *h, int action)
NLM_F_CREATE, seq++,
n->chain);
break;
+ case NFT_COMPAT_CHAIN_USER_ADD:
+ nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
+ NLM_F_EXCL, seq++,
+ n->chain);
+ break;
+ case NFT_COMPAT_CHAIN_USER_DEL:
+ nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
+ 0, seq++, n->chain);
+ break;
case NFT_COMPAT_CHAIN_UPDATE:
nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
h->restore ?
@@ -2314,8 +2267,6 @@ static int nft_action(struct nft_handle *h, int action)
h->batch = mnl_nft_batch_page_add(h->batch);
ret = mnl_nft_batch_talk(h);
- if (ret < 0)
- perror("mnl_nft_batch_talk:");
mnl_nlmsg_batch_reset(h->batch);
@@ -2364,33 +2315,24 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt)
name, rev, type);
nl = mnl_socket_open(NETLINK_NETFILTER);
- if (nl == NULL) {
- perror("mnl_socket_open");
+ if (nl == NULL)
return 0;
- }
- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
- perror("mnl_socket_bind");
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
goto err;
- }
+
portid = mnl_socket_get_portid(nl);
- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
- perror("mnl_socket_send");
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
goto err;
- }
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
- if (ret == -1) {
- perror("mnl_socket_recvfrom");
+ if (ret == -1)
goto err;
- }
ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
- if (ret == -1) {
- perror("mnl_cb_run");
+ if (ret == -1)
goto err;
- }
err:
mnl_socket_close(nl);
@@ -2410,10 +2352,12 @@ const char *nft_strerror(int err)
{
{ nft_chain_user_del, ENOTEMPTY, "Chain is not empty" },
{ nft_chain_user_del, EINVAL, "Can't delete built-in chain" },
+ { nft_chain_user_del, EBUSY, "Directory not empty" },
{ nft_chain_user_del, EMLINK,
"Can't delete chain with references left" },
{ nft_chain_user_add, EEXIST, "Chain already exists" },
{ nft_rule_add, E2BIG, "Index of insertion too big" },
+ { nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" },
{ nft_rule_replace, E2BIG, "Index of replacement too big" },
{ nft_rule_delete_num, E2BIG, "Index of deletion too big" },
/* { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
@@ -2567,8 +2511,6 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
struct nft_chain_list *list;
struct nft_chain_list_iter *iter;
struct nft_chain *c;
- struct nlmsghdr *nlh;
- char buf[MNL_SOCKET_BUFFER_SIZE];
int ret = 0;
list = nft_chain_list_get(h);
@@ -2597,14 +2539,18 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
nft_chain_attr_unset(c, NFT_CHAIN_ATTR_HANDLE);
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN,
- h->family, NLM_F_ACK, h->seq);
-
- nft_chain_nlmsg_build_payload(nlh, c);
-
- ret = mnl_talk(h, nlh, NULL, NULL);
- if (ret < 0)
- perror("mnl_talk:nft_chain_zero_counters");
+ if (h->batch_support) {
+ ret = batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
+ } else {
+ struct nlmsghdr *nlh;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN,
+ h->family, NLM_F_ACK,
+ h->seq);
+ nft_chain_nlmsg_build_payload(nlh, c);
+ ret = mnl_talk(h, nlh, NULL, NULL);
+ }
if (chain != NULL)
break;
@@ -2612,11 +2558,12 @@ next:
c = nft_chain_list_iter_next(iter);
}
+ if (!h->batch_support)
+ nft_chain_list_free(list);
+
nft_chain_list_iter_destroy(iter);
err:
- nft_chain_list_free(list);
-
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
}
diff --git a/iptables/nft.h b/iptables/nft.h
index 339d7bcd..0db2ed6c 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -54,7 +54,6 @@ void nft_fini(struct nft_handle *h);
struct nft_table;
struct nft_chain_list;
-struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table);
int nft_table_add(struct nft_handle *h, struct nft_table *t, uint16_t flags);
int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, const char *tablename, bool counters), bool counters);
bool nft_table_find(struct nft_handle *h, const char *tablename);
@@ -65,10 +64,6 @@ int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nft_c
*/
struct nft_chain;
-struct nft_chain *nft_chain_builtin_alloc(struct builtin_table *table, struct builtin_chain *chain, int policy);
-void nft_chain_builtin_add(struct nft_handle *h, struct builtin_table *table, struct builtin_chain *chain, int policy);
-struct builtin_chain *nft_chain_builtin_find(struct builtin_table *t, const char *chain);
-int nft_chain_builtin_init(struct nft_handle *h, const char *table, const char *chain, int policy);
int nft_chain_add(struct nft_handle *h, struct nft_chain *c, uint16_t flags);
int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters);
struct nft_chain_list *nft_chain_dump(struct nft_handle *h);
diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c
index 23b6bcb4..182dd9f3 100644
--- a/iptables/xtables-arp-standalone.c
+++ b/iptables/xtables-arp-standalone.c
@@ -84,5 +84,10 @@ int xtables_arp_main(int argc, char *argv[])
if (ret)
ret = nft_commit(&h);
+ nft_fini(&h);
+
+ if (!ret)
+ fprintf(stderr, "arptables: %s\n", nft_strerror(errno));
+
exit(!ret);
}
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 0c79a387..c92b9e75 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -49,6 +49,7 @@
#include "xshared.h"
#include "nft.h"
+#include "nft-arp.h"
#include <linux/netfilter_arp/arp_tables.h>
typedef char arpt_chainlabel[32];
@@ -808,28 +809,6 @@ list_entries(struct nft_handle *h, const char *chain, const char *table,
return nft_rule_list(h, chain, table, rulenum, format);
}
-static struct arpt_entry *
-generate_entry(const struct arpt_entry *fw,
- struct arpt_entry_target *target)
-{
- struct arpt_entry_target **t;
- struct arpt_entry *e;
- unsigned int size;
-
-
- size = sizeof(struct arpt_entry);
-
- e = xtables_malloc(size);
- *e = *fw;
- e->target_offset = offsetof(struct arpt_entry, elems);
- e->next_offset = e->target_offset + target->u.target_size;
-
- t = (void *) &e->elems;
- *t = target;
-
- return e;
-}
-
static struct xtables_target *command_jump(struct arpt_entry *fw,
const char *jumpto)
{
@@ -869,7 +848,7 @@ static int
append_entry(struct nft_handle *h,
const char *chain,
const char *table,
- struct arpt_entry *fw,
+ struct arptables_command_state *cs,
int rulenum,
unsigned int nsaddrs,
const struct in_addr saddrs[],
@@ -881,14 +860,14 @@ append_entry(struct nft_handle *h,
int ret = 1;
for (i = 0; i < nsaddrs; i++) {
- fw->arp.src.s_addr = saddrs[i].s_addr;
+ cs->fw.arp.src.s_addr = saddrs[i].s_addr;
for (j = 0; j < ndaddrs; j++) {
- fw->arp.tgt.s_addr = daddrs[j].s_addr;
+ cs->fw.arp.tgt.s_addr = daddrs[j].s_addr;
if (append) {
- ret = nft_rule_append(h, chain, table, fw, 0,
+ ret = nft_rule_append(h, chain, table, cs, 0,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table, fw,
+ ret = nft_rule_insert(h, chain, table, cs,
rulenum, verbose);
}
}
@@ -900,22 +879,22 @@ append_entry(struct nft_handle *h,
static int
replace_entry(const char *chain,
const char *table,
- struct arpt_entry *fw,
+ struct arptables_command_state *cs,
unsigned int rulenum,
const struct in_addr *saddr,
const struct in_addr *daddr,
bool verbose, struct nft_handle *h)
{
- fw->arp.src.s_addr = saddr->s_addr;
- fw->arp.tgt.s_addr = daddr->s_addr;
+ cs->fw.arp.src.s_addr = saddr->s_addr;
+ cs->fw.arp.tgt.s_addr = daddr->s_addr;
- return nft_rule_replace(h, chain, table, fw, rulenum, verbose);
+ return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
}
static int
delete_entry(const char *chain,
const char *table,
- struct arpt_entry *fw,
+ struct arptables_command_state *cs,
unsigned int nsaddrs,
const struct in_addr saddrs[],
unsigned int ndaddrs,
@@ -926,10 +905,10 @@ delete_entry(const char *chain,
int ret = 1;
for (i = 0; i < nsaddrs; i++) {
- fw->arp.src.s_addr = saddrs[i].s_addr;
+ cs->fw.arp.src.s_addr = saddrs[i].s_addr;
for (j = 0; j < ndaddrs; j++) {
- fw->arp.tgt.s_addr = daddrs[j].s_addr;
- ret = nft_rule_delete(h, chain, table, fw, verbose);
+ cs->fw.arp.tgt.s_addr = daddrs[j].s_addr;
+ ret = nft_rule_delete(h, chain, table, cs, verbose);
}
}
@@ -938,7 +917,7 @@ delete_entry(const char *chain,
int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
{
- struct arpt_entry fw, *e = NULL;
+ struct arptables_command_state cs;
int invert = 0;
unsigned int nsaddrs = 0, ndaddrs = 0;
struct in_addr *saddrs = NULL, *daddrs = NULL;
@@ -950,12 +929,11 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
unsigned int rulenum = 0, options = 0, command = 0;
const char *pcnt = NULL, *bcnt = NULL;
int ret = 1;
- struct xtables_target *target = NULL;
struct xtables_target *t;
- const char *jumpto = "";
+ memset(&cs, 0, sizeof(cs));
+ cs.jumpto = "";
- memset(&fw, 0, sizeof(fw));
opts = original_opts;
global_option_offset = 0;
@@ -1106,47 +1084,47 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
break;
case 's':
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_S_IP, &fw.arp.invflags,
+ set_option(&options, OPT_S_IP, &cs.fw.arp.invflags,
invert);
shostnetworkmask = argv[optind-1];
break;
case 'd':
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_D_IP, &fw.arp.invflags,
+ set_option(&options, OPT_D_IP, &cs.fw.arp.invflags,
invert);
dhostnetworkmask = argv[optind-1];
break;
case 2:/* src-mac */
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_S_MAC, &fw.arp.invflags,
+ set_option(&options, OPT_S_MAC, &cs.fw.arp.invflags,
invert);
if (getmac_and_mask(argv[optind - 1],
- fw.arp.src_devaddr.addr, fw.arp.src_devaddr.mask))
+ cs.fw.arp.src_devaddr.addr, cs.fw.arp.src_devaddr.mask))
xtables_error(PARAMETER_PROBLEM, "Problem with specified "
"source mac");
break;
case 3:/* dst-mac */
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_D_MAC, &fw.arp.invflags,
+ set_option(&options, OPT_D_MAC, &cs.fw.arp.invflags,
invert);
if (getmac_and_mask(argv[optind - 1],
- fw.arp.tgt_devaddr.addr, fw.arp.tgt_devaddr.mask))
+ cs.fw.arp.tgt_devaddr.addr, cs.fw.arp.tgt_devaddr.mask))
xtables_error(PARAMETER_PROBLEM, "Problem with specified "
"destination mac");
break;
case 'l':/* hardware length */
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_H_LENGTH, &fw.arp.invflags,
+ set_option(&options, OPT_H_LENGTH, &cs.fw.arp.invflags,
invert);
- getlength_and_mask(argv[optind - 1], &fw.arp.arhln,
- &fw.arp.arhln_mask);
+ getlength_and_mask(argv[optind - 1], &cs.fw.arp.arhln,
+ &cs.fw.arp.arhln_mask);
- if (fw.arp.arhln != 6) {
+ if (cs.fw.arp.arhln != 6) {
xtables_error(PARAMETER_PROBLEM,
"Only harware address length of"
" 6 is supported currently.");
@@ -1158,19 +1136,20 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
xtables_error(PARAMETER_PROBLEM, "not supported");
/*
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_P_LENGTH, &fw.arp.invflags,
+ set_option(&options, OPT_P_LENGTH, &cs.fw.arp.invflags,
invert);
- getlength_and_mask(argv[optind - 1], &fw.arp.arpln,
- &fw.arp.arpln_mask);
+ getlength_and_mask(argv[optind - 1], &cs.fw.arp.arpln,
+ &cs.fw.arp.arpln_mask);
break;
*/
case 4:/* opcode */
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_OPCODE, &fw.arp.invflags,
+ set_option(&options, OPT_OPCODE, &cs.fw.arp.invflags,
invert);
- if (get16_and_mask(argv[optind - 1], &fw.arp.arpop, &fw.arp.arpop_mask, 10)) {
+ if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpop,
+ &cs.fw.arp.arpop_mask, 10)) {
int i;
for (i = 0; i < NUMOPCODES; i++)
@@ -1178,63 +1157,65 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
break;
if (i == NUMOPCODES)
xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode");
- fw.arp.arpop = htons(i+1);
+ cs.fw.arp.arpop = htons(i+1);
}
break;
case 5:/* h-type */
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_H_TYPE, &fw.arp.invflags,
+ set_option(&options, OPT_H_TYPE, &cs.fw.arp.invflags,
invert);
- if (get16_and_mask(argv[optind - 1], &fw.arp.arhrd, &fw.arp.arhrd_mask, 16)) {
+ if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arhrd,
+ &cs.fw.arp.arhrd_mask, 16)) {
if (strcasecmp(argv[optind-1], "Ethernet"))
xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type");
- fw.arp.arhrd = htons(1);
+ cs.fw.arp.arhrd = htons(1);
}
break;
case 6:/* proto-type */
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_P_TYPE, &fw.arp.invflags,
+ set_option(&options, OPT_P_TYPE, &cs.fw.arp.invflags,
invert);
- if (get16_and_mask(argv[optind - 1], &fw.arp.arpro, &fw.arp.arpro_mask, 0)) {
+ if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpro,
+ &cs.fw.arp.arpro_mask, 0)) {
if (strcasecmp(argv[optind-1], "ipv4"))
xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type");
- fw.arp.arpro = htons(0x800);
+ cs.fw.arp.arpro = htons(0x800);
}
break;
case 'j':
- set_option(&options, OPT_JUMP, &fw.arp.invflags,
+ set_option(&options, OPT_JUMP, &cs.fw.arp.invflags,
invert);
- jumpto = parse_target(optarg);
- target = command_jump(&fw, jumpto);
+ cs.jumpto = parse_target(optarg);
+ cs.target = command_jump(&cs.fw, cs.jumpto);
break;
case 'i':
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_VIANAMEIN, &fw.arp.invflags,
+ set_option(&options, OPT_VIANAMEIN, &cs.fw.arp.invflags,
invert);
parse_interface(argv[optind-1],
- fw.arp.iniface,
- fw.arp.iniface_mask);
-/* fw.nfcache |= NFC_IP_IF_IN; */
+ cs.fw.arp.iniface,
+ cs.fw.arp.iniface_mask);
+/* cs.fw.nfcache |= NFC_IP_IF_IN; */
break;
case 'o':
check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_VIANAMEOUT, &fw.arp.invflags,
+ set_option(&options, OPT_VIANAMEOUT, &cs.fw.arp.invflags,
invert);
parse_interface(argv[optind-1],
- fw.arp.outiface,
- fw.arp.outiface_mask);
- /* fw.nfcache |= NFC_IP_IF_OUT; */
+ cs.fw.arp.outiface,
+ cs.fw.arp.outiface_mask);
+ /* cs.fw.nfcache |= NFC_IP_IF_OUT; */
break;
case 'v':
if (!verbose)
set_option(&options, OPT_VERBOSE,
- &fw.arp.invflags, invert);
+ &cs.fw.arp.invflags, invert);
verbose++;
break;
@@ -1257,7 +1238,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
break;
case 'n':
- set_option(&options, OPT_NUMERIC, &fw.arp.invflags,
+ set_option(&options, OPT_NUMERIC, &cs.fw.arp.invflags,
invert);
break;
@@ -1277,7 +1258,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
exit(0);
case '0':
- set_option(&options, OPT_LINENUMBERS, &fw.arp.invflags,
+ set_option(&options, OPT_LINENUMBERS, &cs.fw.arp.invflags,
invert);
break;
@@ -1287,7 +1268,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
case 'c':
- set_option(&options, OPT_COUNTERS, &fw.arp.invflags,
+ set_option(&options, OPT_COUNTERS, &cs.fw.arp.invflags,
invert);
pcnt = optarg;
if (optind < argc && argv[optind][0] != '-'
@@ -1298,12 +1279,12 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
"-%c requires packet and byte counter",
opt2char(OPT_COUNTERS));
- if (sscanf(pcnt, "%llu", &fw.counters.pcnt) != 1)
+ if (sscanf(pcnt, "%llu", &cs.fw.counters.pcnt) != 1)
xtables_error(PARAMETER_PROBLEM,
"-%c packet counter not numeric",
opt2char(OPT_COUNTERS));
- if (sscanf(bcnt, "%llu", &fw.counters.bcnt) != 1)
+ if (sscanf(bcnt, "%llu", &cs.fw.counters.bcnt) != 1)
xtables_error(PARAMETER_PROBLEM,
"-%c byte counter not numeric",
opt2char(OPT_COUNTERS));
@@ -1325,17 +1306,17 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
exit_tryhelp(2);
default:
- if (target) {
+ if (cs.target) {
xtables_option_tpcall(c, argv,
- invert, target, &fw);
+ invert, cs.target, &cs.fw);
}
break;
}
invert = FALSE;
}
- if (target)
- xtables_option_tfcall(target);
+ if (cs.target)
+ xtables_option_tfcall(cs.target);
if (optind < argc)
xtables_error(PARAMETER_PROBLEM,
@@ -1355,14 +1336,14 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
if (shostnetworkmask)
parse_hostnetworkmask(shostnetworkmask, &saddrs,
- &(fw.arp.smsk), &nsaddrs);
+ &(cs.fw.arp.smsk), &nsaddrs);
if (dhostnetworkmask)
parse_hostnetworkmask(dhostnetworkmask, &daddrs,
- &(fw.arp.tmsk), &ndaddrs);
+ &(cs.fw.arp.tmsk), &ndaddrs);
if ((nsaddrs > 1 || ndaddrs > 1) &&
- (fw.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
+ (cs.fw.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
" source or destination IP addresses");
@@ -1409,34 +1390,26 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
chain);
}
- if (!target && strlen(jumpto) != 0) {
+ if (!cs.target && strlen(cs.jumpto) != 0) {
size_t size;
- target = xtables_find_target(XT_STANDARD_TARGET,
- XTF_LOAD_MUST_SUCCEED);
- size = sizeof(struct arpt_entry_target) + target->size;
- target->t = xtables_calloc(1, size);
- target->t->u.target_size = size;
- strcpy(target->t->u.user.name, jumpto);
- }
-
- if (!target) {
- xtables_error(PARAMETER_PROBLEM,
- "No target provided or"
- " initalization failed");
+ cs.target = xtables_find_target(XT_STANDARD_TARGET,
+ XTF_LOAD_MUST_SUCCEED);
+ size = sizeof(struct arpt_entry_target) + cs.target->size;
+ cs.target->t = xtables_calloc(1, size);
+ cs.target->t->u.target_size = size;
+ strcpy(cs.target->t->u.user.name, cs.jumpto);
}
-
- e = generate_entry(&fw, target->t);
}
switch (command) {
case CMD_APPEND:
- ret = append_entry(h, chain, *table, e, 0,
+ ret = append_entry(h, chain, *table, &cs, 0,
nsaddrs, saddrs, ndaddrs, daddrs,
options&OPT_VERBOSE, true);
break;
case CMD_DELETE:
- ret = delete_entry(chain, *table, e,
+ ret = delete_entry(chain, *table, &cs,
nsaddrs, saddrs, ndaddrs, daddrs,
options&OPT_VERBOSE, h);
break;
@@ -1444,11 +1417,11 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
break;
case CMD_REPLACE:
- ret = replace_entry(chain, *table, e, rulenum - 1,
+ ret = replace_entry(chain, *table, &cs, rulenum - 1,
saddrs, daddrs, options&OPT_VERBOSE, h);
break;
case CMD_INSERT:
- ret = append_entry(h, chain, *table, e, rulenum - 1,
+ ret = append_entry(h, chain, *table, &cs, rulenum - 1,
nsaddrs, saddrs, ndaddrs, daddrs,
options&OPT_VERBOSE, false);
break;
diff --git a/iptables/xtables-config-parser.y b/iptables/xtables-config-parser.y
index 2770a1b9..c8116c3e 100644
--- a/iptables/xtables-config-parser.y
+++ b/iptables/xtables-config-parser.y
@@ -204,10 +204,9 @@ int xtables_config_parse(char *filename, struct nft_table_list *table_list,
break;
case T_TABLE:
table = nft_table_alloc();
- if (table == NULL) {
- perror("nft_table_alloc");
+ if (table == NULL)
return -1;
- }
+
nft_table_attr_set_u32(table, NFT_TABLE_ATTR_FAMILY, family);
nft_table_attr_set(table, NFT_TABLE_ATTR_NAME, e->data);
/* This is intentionally prepending, instead of
@@ -222,10 +221,9 @@ int xtables_config_parse(char *filename, struct nft_table_list *table_list,
break;
case T_CHAIN:
chain = nft_chain_alloc();
- if (chain == NULL) {
- perror("nft_chain_alloc");
+ if (chain == NULL)
return -1;
- }
+
nft_chain_attr_set(chain, NFT_CHAIN_ATTR_TABLE,
(char *)nft_table_attr_get(table, NFT_TABLE_ATTR_NAME));
nft_chain_attr_set_u32(chain, NFT_CHAIN_ATTR_FAMILY,
diff --git a/iptables/xtables-events.c b/iptables/xtables-events.c
index 4746825e..5aa7c6f0 100644
--- a/iptables/xtables-events.c
+++ b/iptables/xtables-events.c
@@ -27,6 +27,7 @@
#include "iptables.h" /* for xtables_globals */
#include "xtables-multi.h"
#include "nft.h"
+#include "nft-arp.h"
static int table_cb(const struct nlmsghdr *nlh, int type)
{
@@ -34,15 +35,11 @@ static int table_cb(const struct nlmsghdr *nlh, int type)
char buf[4096];
t = nft_table_alloc();
- if (t == NULL) {
- perror("OOM");
+ if (t == NULL)
goto err;
- }
- if (nft_table_nlmsg_parse(nlh, t) < 0) {
- perror("nft_table_nlmsg_parse");
+ if (nft_table_nlmsg_parse(nlh, t) < 0)
goto err_free;
- }
nft_table_snprintf(buf, sizeof(buf), t, NFT_OUTPUT_DEFAULT, 0);
/* FIXME: define syntax to represent table events */
@@ -59,21 +56,17 @@ static bool counters;
static int rule_cb(const struct nlmsghdr *nlh, int type)
{
struct iptables_command_state cs = {};
- struct arpt_entry fw_arp = {};
+ struct arptables_command_state cs_arp = {};
struct nft_rule *r;
void *fw = NULL;
uint8_t family;
r = nft_rule_alloc();
- if (r == NULL) {
- perror("OOM");
+ if (r == NULL)
goto err;
- }
- if (nft_rule_nlmsg_parse(nlh, r) < 0) {
- perror("nft_rule_nlmsg_parse");
+ if (nft_rule_nlmsg_parse(nlh, r) < 0)
goto err_free;
- }
family = nft_rule_attr_get_u32(r, NFT_RULE_ATTR_FAMILY);
switch (family) {
@@ -85,8 +78,8 @@ static int rule_cb(const struct nlmsghdr *nlh, int type)
break;
case NFPROTO_ARP:
printf("-0 ");
- nft_rule_to_arpt_entry(r, &fw_arp);
- fw = &fw_arp;
+ nft_rule_to_arptables_command_state(r, &cs_arp);
+ fw = &cs_arp;
break;
default:
goto err_free;
@@ -109,15 +102,11 @@ static int chain_cb(const struct nlmsghdr *nlh, int type)
char buf[4096];
t = nft_chain_alloc();
- if (t == NULL) {
- perror("OOM");
+ if (t == NULL)
goto err;
- }
- if (nft_chain_nlmsg_parse(nlh, t) < 0) {
- perror("nft_chain_nlmsg_parse");
+ if (nft_chain_nlmsg_parse(nlh, t) < 0)
goto err_free;
- }
nft_chain_snprintf(buf, sizeof(buf), t, NFT_OUTPUT_DEFAULT, 0);
/* FIXME: define syntax to represent chain events */
@@ -198,12 +187,12 @@ int xtables_events_main(int argc, char *argv[])
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
- perror("mnl_socket_open");
+ perror("cannot open nfnetlink socket");
exit(EXIT_FAILURE);
}
if (mnl_socket_bind(nl, (1 << (NFNLGRP_NFTABLES-1)), MNL_SOCKET_AUTOPID) < 0) {
- perror("mnl_socket_bind");
+ perror("cannot bind to nfnetlink socket");
exit(EXIT_FAILURE);
}
@@ -215,7 +204,7 @@ int xtables_events_main(int argc, char *argv[])
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
}
if (ret == -1) {
- perror("error");
+ perror("cannot receive from nfnetlink socket");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 1ab86d5a..68411248 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -348,6 +348,11 @@ int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
modprobe = buf;
}
+ argv[0] = (char *)modprobe;
+ argv[1] = (char *)modname;
+ argv[2] = quiet ? "-q" : NULL;
+ argv[3] = NULL;
+
/*
* Need to flush the buffer, or the child may output it again
* when switching the program thru execv.
@@ -356,19 +361,10 @@ int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
switch (vfork()) {
case 0:
- argv[0] = (char *)modprobe;
- argv[1] = (char *)modname;
- if (quiet) {
- argv[2] = "-q";
- argv[3] = NULL;
- } else {
- argv[2] = NULL;
- argv[3] = NULL;
- }
execv(argv[0], argv);
/* not usually reached */
- exit(1);
+ _exit(1);
case -1:
free(buf);
return -1;
@@ -1702,8 +1698,9 @@ static struct in6_addr *parse_ip6mask(char *mask)
if (bits != 0) {
char *p = (void *)&maskaddr;
memset(p, 0xff, bits / 8);
- memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
- p[bits/8] = 0xff << (8 - (bits & 7));
+ memset(p + ((bits + 7) / 8), 0, (128 - bits) / 8);
+ if (bits < 128)
+ p[bits/8] = 0xff << (8 - (bits & 7));
return &maskaddr;
}