1. Add rate_limit test case. 2. Consolidate frequently used functions in helper/lib.sh 3. Introduce NFT_TEST_LIBRARY_FILE variable to source helper/lib.sh in tests. 4. Replace sleep with wait_local_port_listen(). 5. Other fixes: nft->$NFT; add dumps/*.nodump files Signed-off-by: Yi Chen <yiche@xxxxxxxxxx> --- tests/shell/helpers/lib.sh | 51 +++++++ tests/shell/helpers/test-wrapper.sh | 1 + .../testcases/packetpath/dumps/nat_ftp.nodump | 0 .../packetpath/dumps/rate_limit.nodump | 0 tests/shell/testcases/packetpath/flowtables | 32 +--- tests/shell/testcases/packetpath/nat_ftp | 32 ++-- tests/shell/testcases/packetpath/rate_limit | 137 ++++++++++++++++++ 7 files changed, 211 insertions(+), 42 deletions(-) create mode 100755 tests/shell/helpers/lib.sh create mode 100644 tests/shell/testcases/packetpath/dumps/nat_ftp.nodump create mode 100644 tests/shell/testcases/packetpath/dumps/rate_limit.nodump create mode 100755 tests/shell/testcases/packetpath/rate_limit diff --git a/tests/shell/helpers/lib.sh b/tests/shell/helpers/lib.sh new file mode 100755 index 00000000..4e01c957 --- /dev/null +++ b/tests/shell/helpers/lib.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Frequently used functions. + +wait_local_port_listen() +{ + local listener_ns="${1}" + local port="${2}" + local protocol="${3}" + local pattern + local i + + pattern=":$(printf "%04X" "${port}") " + + # for tcp protocol additionally check the socket state + [ ${protocol} = "tcp" ] && pattern="${pattern}0A" + for i in $(seq 10); do + if ip netns exec "${listener_ns}" awk '{print $2" "$4}' \ + /proc/net/"${protocol}"* | grep -q "${pattern}"; then + break + fi + sleep 0.1 + done +} + +assert_pass() +{ + local ret=$? + if [ $ret != 0 ]; then + echo "FAIL: ${@}" + if type -t failout; then + failout + fi + exit 1 + else + echo "PASS: ${@}" + fi +} +assert_fail() +{ + local ret=$? + if [ $ret == 0 ]; then + echo "FAIL: ${@}" + if type -t failout; then + failout + fi + exit 1 + else + echo "PASS: ${@}" + fi +} diff --git a/tests/shell/helpers/test-wrapper.sh b/tests/shell/helpers/test-wrapper.sh index 4a7e8b7b..6ec4e030 100755 --- a/tests/shell/helpers/test-wrapper.sh +++ b/tests/shell/helpers/test-wrapper.sh @@ -36,6 +36,7 @@ TESTDIR="$(dirname "$TEST")" START_TIME="$(cut -d ' ' -f1 /proc/uptime)" export TMPDIR="$NFT_TEST_TESTTMPDIR" +export NFT_TEST_LIBRARY_FILE="$NFT_TEST_BASEDIR/helpers/lib.sh" CLEANUP_UMOUNT_VAR_RUN=n diff --git a/tests/shell/testcases/packetpath/dumps/nat_ftp.nodump b/tests/shell/testcases/packetpath/dumps/nat_ftp.nodump new file mode 100644 index 00000000..e69de29b diff --git a/tests/shell/testcases/packetpath/dumps/rate_limit.nodump b/tests/shell/testcases/packetpath/dumps/rate_limit.nodump new file mode 100644 index 00000000..e69de29b diff --git a/tests/shell/testcases/packetpath/flowtables b/tests/shell/testcases/packetpath/flowtables index b68c5dd4..01a775a1 100755 --- a/tests/shell/testcases/packetpath/flowtables +++ b/tests/shell/testcases/packetpath/flowtables @@ -3,6 +3,8 @@ # NFT_TEST_REQUIRES(NFT_TEST_HAVE_socat) # NFT_TEST_SKIP(NFT_TEST_SKIP_slow) +. $NFT_TEST_LIBRARY_FILE + rnd=$(mktemp -u XXXXXXXX) R="flowtable-router-$rnd" C="flowtable-client-$rnd" @@ -17,29 +19,10 @@ cleanup() } trap cleanup EXIT -assert_pass() -{ - local ret=$? - if [ $ret != 0 ] - then - echo "FAIL: ${@}" - ip netns exec $R cat /proc/net/nf_conntrack - exit 1 - else - echo "PASS: ${@}" - fi -} -assert_fail() +# call back when assert failed +failout() { - local ret=$? - if [ $ret == 0 ] - then - echo "FAIL: ${@}" - ip netns exec $R cat /proc/net/nf_conntrack - exit 1 - else - echo "PASS: ${@}" - fi + ip netns exec $R cat /proc/net/nf_conntrack } ip netns add $R @@ -67,7 +50,7 @@ sleep 3 ip netns exec $C ping -q -6 2001:db8:ffff:22::1 -c1 assert_pass "topo initialization" -ip netns exec $R nft -f - <<EOF +ip netns exec $R $NFT -f - <<EOF table ip6 filter { flowtable f1 { hook ingress priority -100 @@ -100,7 +83,8 @@ assert_pass "set net.netfilter.nf_conntrack_tcp_timeout_established=86400" # A trick to control the timing to send a packet ip netns exec $S socat TCP6-LISTEN:10001 GOPEN:/tmp/socat-$rnd,ignoreeof & -sleep 1 +wait_local_port_listen $S 10001 tcp + ip netns exec $C socat -b 2048 PIPE:/tmp/pipefile-$rnd 'TCP:[2001:db8:ffff:22::1]:10001' & sleep 1 ip netns exec $C echo "send sth" >> /tmp/pipefile-$rnd ; assert_pass "send a packet" diff --git a/tests/shell/testcases/packetpath/nat_ftp b/tests/shell/testcases/packetpath/nat_ftp index 327047b8..4b9f6eb0 100755 --- a/tests/shell/testcases/packetpath/nat_ftp +++ b/tests/shell/testcases/packetpath/nat_ftp @@ -4,6 +4,7 @@ # NFT_TEST_REQUIRES(NFT_TEST_HAVE_curl) # NFT_TEST_REQUIRES(NFT_TEST_HAVE_vsftpd) +. $NFT_TEST_LIBRARY_FILE cleanup() { for i in $R $C $S;do @@ -14,22 +15,15 @@ cleanup() } trap cleanup EXIT -assert_pass() +# call back when assert failed +failout() { - local ret=$? - if [ $ret != 0 ] - then - echo "FAIL: ${@}" - ip netns exec $R nft list ruleset - tcpdump -nnr ${PCAP} - test -r /proc/net/nf_conntrack && ip netns exec $R cat /proc/net/nf_conntrack - ip netns exec $R conntrack -S - ip netns exec $R conntrack -L - ip netns exec $S ss -nitepal - exit 1 - else - echo "PASS: ${@}" - fi + ip netns exec $R $NFT list ruleset + tcpdump -nnr ${PCAP} + test -r /proc/net/nf_conntrack && ip netns exec $R cat /proc/net/nf_conntrack + ip netns exec $R conntrack -S + ip netns exec $R conntrack -L + ip netns exec $S ss -nitepal } rnd=$(mktemp -u XXXXXXXX) @@ -82,7 +76,7 @@ assert_pass "topo initialization" reload_ruleset() { ip netns exec $R conntrack -F 2> /dev/null - ip netns exec $R nft -f - <<-EOF + ip netns exec $R $NFT -f - <<-EOF flush ruleset table ip6 ftp_helper_nat_test { ct helper ftp-standard { @@ -138,7 +132,8 @@ pam_service_name=vsftpd background=YES EOF ip netns exec $S vsftpd ${FTPCONF} -sleep 1 +wait_local_port_listen $S 21 tcp + ip netns exec $S ss -6ltnp | grep -q '*:21' assert_pass "start vsftpd server" @@ -147,7 +142,7 @@ assert_pass "start vsftpd server" reload_ruleset ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null & pid=$! -sleep 1 +sleep 0.5 ip netns exec $C curl --no-progress-meter --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE assert_pass "curl ftp passive mode " @@ -164,6 +159,7 @@ reload_ruleset ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null & pid=$! +sleep 0.5 ip netns exec $C curl --no-progress-meter -P - --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE assert_pass "curl ftp active mode " diff --git a/tests/shell/testcases/packetpath/rate_limit b/tests/shell/testcases/packetpath/rate_limit new file mode 100755 index 00000000..84ee5621 --- /dev/null +++ b/tests/shell/testcases/packetpath/rate_limit @@ -0,0 +1,137 @@ +#!/bin/bash + +# NFT_TEST_REQUIRES(NFT_TEST_HAVE_socat) +# + +. $NFT_TEST_LIBRARY_FILE + +cleanup() +{ + for i in $C $S;do + kill $(ip netns pid $i) 2>/dev/null + ip netns del $i + done +} +trap cleanup EXIT + +rnd=$(mktemp -u XXXXXXXX) +C="ratelimit-client-$rnd" +S="ratelimit-server-$rnd" + +ip_sc=10.167.1.1 +ip_cs=10.167.1.2 +ip1_cs=10.167.1.3 + +ip netns add $S +ip netns add $C + +ip link add s_c netns $S type veth peer name c_s netns $C +ip -net $S link set s_c up +ip -net $C link set c_s up +ip -net $S link set lo up +ip -net $C link set lo up +ip -net $S addr add ${ip_sc}/24 dev s_c +ip -net $C addr add ${ip_cs}/24 dev c_s +ip -net $C addr add ${ip1_cs}/24 dev c_s +ip netns exec $C ping ${ip_sc} -c1 +assert_pass "topo initialization" + +ip netns exec $S $NFT -f - <<EOF +table ip filter { + set icmp1 { + type ipv4_addr + size 65535 + flags dynamic,timeout + } + + set http1 { + type inet_service . ipv4_addr + size 65535 + flags dynamic + } + + chain input { + type filter hook input priority filter; policy accept; + ip protocol icmp counter jump in_icmp + ip protocol tcp counter jump in_tcp + } + chain in_tcp { + iifname "s_c" tcp dport 80 ct state new add @http1 { tcp dport . ip saddr limit rate over 1/minute burst 5 packets } counter reject + iifname "s_c" tcp dport 80 counter accept + } + + chain in_icmp { + iifname "s_c" ip protocol icmp counter update @icmp1 { ip saddr timeout 3s limit rate 1/second burst 5 packets } counter accept + iifname "s_c" ip protocol icmp counter reject + } + +} +EOF +assert_pass "Apply ruleset" + +# icmp test +ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip_cs} | grep -q '5 received' +assert_pass "saddr1, burst 5 accept" + +ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip1_cs} | grep -q '5 received' +assert_pass "saddr2, burst 5 accept" + +ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip_cs} | grep -q '1 received' +assert_fail "saddr1, burst 5 up to limit, reject" + +sleep 3 +ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip_cs} | grep -q '5 received' +assert_pass "saddr1, element timeout,burst 5 pass again" + +ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip_cs} | grep -q '1 received' +assert_fail "saddr1, burst 5 up to limit" + +ip netns exec $C ping -W 1 ${ip_sc} -c 6 -i 1 -I ${ip1_cs} | grep -q '6 received' +assert_pass "saddr2, 6s test, limit rate 1/second accept" + +ip netns exec $C ping -W 1 ${ip_sc} -c 4 -f -I ${ip1_cs} | grep -q '4 received' +assert_pass "saddr2, burst 4 accept" + +sleep 2 +ip netns exec $C ping -W 1 ${ip_sc} -c 2 -f -I ${ip1_cs} | grep -q '2 received' +assert_pass "saddr2, burst 2 sleep 2, accept" + +sleep 2 +ip netns exec $C ping -W 1 ${ip_sc} -c 2 -f -I ${ip1_cs} | grep -q '2 received' +assert_pass "saddr2, burst 2 sleep 2, accept" + +ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip1_cs} | grep -q '1 received' +assert_fail "saddr2, limit rate 1/second up to limit, reject" + + +# tcp test +ip netns exec $S socat TCP-LISTEN:80,reuseaddr,fork - > /dev/null & +wait_local_port_listen $S 80 tcp + +for port in {1..5};do + ip netns exec $C socat -u - TCP:${ip_sc}:80,connect-timeout=1 <<< 'AAA' + assert_pass "tcp connection burst 5 accept" +done +ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA' +assert_fail "tcp connection burst 5 up to limit reject" + +ip netns exec $S $NFT flush chain filter in_tcp +assert_pass result "flush chain" + +ip netns exec $S $NFT flush set filter http1 +assert_pass result "flush set" + +ip netns exec $S $NFT add rule filter in_tcp iifname s_c tcp dport 80 ct state new add @http1 { tcp dport . ip saddr limit rate over 1/second burst 1 packets} counter reject +assert_pass result "add rule limit rate over 1/second burst 1" +ip netns exec $S $NFT add rule filter in_tcp iifname s_c tcp dport 80 counter accept + +sleep 1 +ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA' +assert_pass result "tcp connection limit rate 1/sec burst 1 accept" + +ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA' +assert_fail result "tcp connection limit rate 1/sec burst 1 reject" + +sleep 1 +ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA' +assert_pass result "tcp connection limit rate 1/sec burst 1 accept" -- 2.49.0