diff options
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; } |