All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] tests: shell: Add a test case for FTP helper combined with NAT.
@ 2025-06-05 10:33 Yi Chen
  2025-06-05 10:49 ` [PATCH v2] " Yi Chen
  2025-06-09  8:14 ` Yi Chen
  0 siblings, 2 replies; 9+ messages in thread
From: Yi Chen @ 2025-06-05 10:33 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

This test verifies functionality of the FTP helper,
for both passive, active FTP modes,
and the functionality of the nf_nat_ftp module.

Signed-off-by: Yi Chen <yiche@redhat.com>
---
 tests/shell/features/curl.sh             |   4 +
 tests/shell/features/tcpdump.sh          |   4 +
 tests/shell/features/vsftpd.sh           |   4 +
 tests/shell/testcases/packetpath/ftp_nat | 164 +++++++++++++++++++++++
 tests/shell/testcases/packetpath/nat_ftp | 164 +++++++++++++++++++++++
 5 files changed, 340 insertions(+)
 create mode 100755 tests/shell/features/curl.sh
 create mode 100755 tests/shell/features/tcpdump.sh
 create mode 100755 tests/shell/features/vsftpd.sh
 create mode 100755 tests/shell/testcases/packetpath/ftp_nat
 create mode 100755 tests/shell/testcases/packetpath/nat_ftp

diff --git a/tests/shell/features/curl.sh b/tests/shell/features/curl.sh
new file mode 100755
index 00000000..fa0c43be
--- /dev/null
+++ b/tests/shell/features/curl.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether curl is installed
+curl -h >/dev/null 2>&1
diff --git a/tests/shell/features/tcpdump.sh b/tests/shell/features/tcpdump.sh
new file mode 100755
index 00000000..70df9f68
--- /dev/null
+++ b/tests/shell/features/tcpdump.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether tcpdump is installed
+tcpdump -h >/dev/null 2>&1
diff --git a/tests/shell/features/vsftpd.sh b/tests/shell/features/vsftpd.sh
new file mode 100755
index 00000000..d3500640
--- /dev/null
+++ b/tests/shell/features/vsftpd.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether vsftpd is installed
+which vsftpd >/dev/null 2>&1
diff --git a/tests/shell/testcases/packetpath/ftp_nat b/tests/shell/testcases/packetpath/ftp_nat
new file mode 100755
index 00000000..5c5a98f9
--- /dev/null
+++ b/tests/shell/testcases/packetpath/ftp_nat
@@ -0,0 +1,164 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_tcpdump)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_curl)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_vsftpd)
+
+rnd=$(mktemp -u XXXXXXXX)
+R="cthelper-router-$rnd"
+C="cthelper-client-$rnd"
+S="cthelper-server-$rnd"
+
+cleanup()
+{
+	for i in $R $C $S;do
+		kill $(ip netns pid $i) 2>/dev/null
+		ip netns del $i
+	done
+	rm -f $INFILE $OUTFILE
+}
+trap cleanup EXIT
+
+INFILE=$(mktemp -p /var/ftp/pub/)
+OUTFILE=$(mktemp)
+
+assert_pass()
+{
+	local ret=$?
+	if [ $ret != 0 ]
+	then
+		echo "FAIL: ${@}"
+		ip netns exec $R nft list ruleset
+		tcpdump -nnr ${0##*/}.pcap
+		ip netns exec $R cat /proc/net/nf_conntrack
+		exit 1
+	else
+		echo "PASS: ${@}"
+	fi
+}
+
+ip_sr=2001:db8:ffff:22::1
+ip_cr=2001:db8:ffff:21::2
+ip_rs=2001:db8:ffff:22::fffe
+ip_rc=2001:db8:ffff:21::fffe
+
+ip netns add $R
+ip netns add $S
+ip netns add $C
+ip -net $S link set lo up
+ip -net $R link set lo up
+ip -net $C link set lo up
+ip netns exec $R sysctl -wq net.ipv6.conf.all.forwarding=1
+
+ip link add s_r netns $S type veth peer name r_s netns $R
+ip link add c_r netns $C type veth peer name r_c netns $R
+ip -net $S link set s_r up
+ip -net $R link set r_s up
+ip -net $R link set r_c up
+ip -net $C link set c_r up
+
+ip -net $S addr add ${ip_sr}/64 dev s_r
+ip -net $C addr add ${ip_cr}/64 dev c_r
+ip -net $R addr add ${ip_rs}/64 dev r_s
+ip -net $R addr add ${ip_rc}/64 dev r_c
+ip -net $C route add ${ip_rs}/64 via ${ip_rc} dev c_r
+ip -net $S route add ${ip_rc}/64 via ${ip_rs} dev s_r
+
+sleep 3
+ip netns exec $C ping -q -6 ${ip_sr} -c1 > /dev/null
+assert_pass "topo initialization"
+
+reload_ruleset()
+{
+	ip netns exec $R conntrack -F 2> /dev/null
+	ip netns exec $R nft -f - <<-EOF
+	flush ruleset
+	table ip6 ftp_helper_nat_test {
+		ct helper ftp-standard {
+			type "ftp" protocol tcp;
+		}
+
+		chain PRE-dnat {
+			type nat hook prerouting priority dstnat; policy accept;
+			# Dnat the control connection, data connection will be automaticly NATed.
+			ip6 daddr ${ip_rc} ip6 nexthdr tcp tcp dport 2121 counter dnat ip6 to [${ip_sr}]:21
+		}
+
+		chain PRE-aftnat {
+			type filter hook prerouting priority 350; policy drop;
+			iifname r_c tcp dport 21 ct state new ct helper set "ftp-standard" counter accept
+
+			ip6 nexthdr tcp ct state related counter accept
+			ip6 nexthdr tcp ct state established counter accept
+
+			ip6 nexthdr icmpv6 counter accept
+
+			counter log
+		}
+
+		chain forward {
+			type filter hook forward priority filter; policy drop;
+			ip6 daddr ${ip_sr} tcp dport 21 ct state new counter accept
+			ip6 nexthdr tcp ct state established counter accept
+			ip6 nexthdr tcp ct state related     counter log accept
+		}
+
+		chain POST-srcnat {
+			type nat hook postrouting priority srcnat; policy accept;
+			ip6 daddr ${ip_sr} ip6 nexthdr tcp tcp dport 21 counter snat ip6 to [${ip_rs}]:16500
+		}
+	}
+	EOF
+	assert_pass "apply ftp helper ruleset"
+}
+
+dd if=/dev/urandom of="$INFILE" bs=4096 count=1 2>/dev/null
+chmod 755 $INFILE
+assert_pass "Prepare the file for FTP transmission"
+
+cat > ./vsftpd.conf <<-EOF
+anonymous_enable=YES
+local_enable=YES
+connect_from_port_20=YES
+listen=NO
+listen_ipv6=YES
+pam_service_name=vsftpd
+background=YES
+EOF
+ip netns exec $S vsftpd ./vsftpd.conf
+sleep 1
+ip netns exec $S ss -6ltnp | grep -q '*:21'
+assert_pass "start vsftpd server"
+
+# test passive mode
+reload_ruleset
+ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null & sleep 2
+ip netns exec $C curl -s --connect-timeout 5 ftp://[${ip_rc}]:2121${INFILE#/var/ftp} -o $OUTFILE
+assert_pass "curl ftp passive mode "
+
+pkill tcpdump
+tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
+assert_pass "assert FTP traffic NATed"
+
+cmp "$INFILE" "$OUTFILE"
+assert_pass "FTP Passive mode: The input and output files remain the same when traffic passes through NAT."
+
+
+# test active mode
+reload_ruleset
+modprobe nf_nat_ftp
+assert_pass "modprobe nf_nat_ftp. Active mode need it to modify the client ip in PORT command under SNAT"
+
+ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null & sleep 2
+ip netns exec $C curl -s -P - --connect-timeout 5 ftp://[${ip_rc}]:2121${INFILE#/var/ftp} -o $OUTFILE
+assert_pass "curl ftp active mode "
+
+pkill tcpdump
+tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
+assert_pass "assert FTP traffic NATed"
+
+cmp "$INFILE" "$OUTFILE"
+assert_pass "FTP Active mode: in and output files remain the same when FTP traffic passes through NAT."
+
+# trap calls cleanup
+exit 0
diff --git a/tests/shell/testcases/packetpath/nat_ftp b/tests/shell/testcases/packetpath/nat_ftp
new file mode 100755
index 00000000..24fbecaa
--- /dev/null
+++ b/tests/shell/testcases/packetpath/nat_ftp
@@ -0,0 +1,164 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_tcpdump)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_curl)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_vsftpd)
+
+rnd=$(mktemp -u XXXXXXXX)
+R="cthelper-router-$rnd"
+C="cthelper-client-$rnd"
+S="cthelper-server-$rnd"
+
+cleanup()
+{
+	for i in $R $C $S;do
+		kill $(ip netns pid $i) 2>/dev/null
+		ip netns del $i
+	done
+	rm -f $INFILE $OUTFILE
+}
+trap cleanup EXIT
+
+INFILE=$(mktemp -p /var/ftp/pub/)
+OUTFILE=$(mktemp)
+
+assert_pass()
+{
+	local ret=$?
+	if [ $ret != 0 ]
+	then
+		echo "FAIL: ${@}"
+		ip netns exec $R nft list ruleset
+		tcpdump -nnr ${0##*/}.pcap
+		ip netns exec $R cat /proc/net/nf_conntrack
+		exit 1
+	else
+		echo "PASS: ${@}"
+	fi
+}
+
+ip_sr=2001:db8:ffff:22::1
+ip_cr=2001:db8:ffff:21::2
+ip_rs=2001:db8:ffff:22::fffe
+ip_rc=2001:db8:ffff:21::fffe
+
+ip netns add $R
+ip netns add $S
+ip netns add $C
+ip -net $S link set lo up
+ip -net $R link set lo up
+ip -net $C link set lo up
+ip netns exec $R sysctl -wq net.ipv6.conf.all.forwarding=1
+
+ip link add s_r netns $S type veth peer name r_s netns $R
+ip link add c_r netns $C type veth peer name r_c netns $R
+ip -net $S link set s_r up
+ip -net $R link set r_s up
+ip -net $R link set r_c up
+ip -net $C link set c_r up
+
+ip -net $S addr add ${ip_sr}/64 dev s_r
+ip -net $C addr add ${ip_cr}/64 dev c_r
+ip -net $R addr add ${ip_rs}/64 dev r_s
+ip -net $R addr add ${ip_rc}/64 dev r_c
+ip -net $C route add ${ip_rs}/64 via ${ip_rc} dev c_r
+ip -net $S route add ${ip_rc}/64 via ${ip_rs} dev s_r
+
+sleep 3
+ip netns exec $C ping -q -6 ${ip_sr} -c1 > /dev/null
+assert_pass "topo initialization"
+
+reload_ruleset()
+{
+	ip netns exec $R conntrack -F 2> /dev/null
+	ip netns exec $R nft -f - <<-EOF
+	flush ruleset
+	table ip6 ftp_helper_nat_test {
+		ct helper ftp-standard {
+			type "ftp" protocol tcp;
+		}
+
+		chain PRE-dnat {
+			type nat hook prerouting priority dstnat; policy accept;
+			# Dnat the control connection, data connection will be automaticly NATed.
+			ip6 daddr ${ip_rc} ip6 nexthdr tcp tcp dport 2121 counter dnat ip6 to [${ip_sr}]:21
+		}
+
+		chain PRE-aftnat {
+			type filter hook prerouting priority 350; policy drop;
+			iifname r_c tcp dport 21 ct state new ct helper set "ftp-standard" counter accept
+
+			ip6 nexthdr tcp ct state related counter accept
+			ip6 nexthdr tcp ct state established counter accept
+
+			ip6 nexthdr icmpv6 counter accept
+
+			counter log
+		}
+
+		chain forward {
+			type filter hook forward priority filter; policy drop;
+			ip6 daddr ${ip_sr} tcp dport 21 ct state new counter accept
+			ct state established counter accept
+			ct state related     counter log accept
+		}
+
+		chain POST-srcnat {
+			type nat hook postrouting priority srcnat; policy accept;
+			ip6 daddr ${ip_sr} ip6 nexthdr tcp tcp dport 21 counter snat ip6 to [${ip_rs}]:16500
+		}
+	}
+	EOF
+	assert_pass "apply ftp helper ruleset"
+}
+
+dd if=/dev/urandom of="$INFILE" bs=4096 count=1 2>/dev/null
+chmod 755 $INFILE
+assert_pass "Prepare the file for FTP transmission"
+
+cat > ./vsftpd.conf <<-EOF
+anonymous_enable=YES
+local_enable=YES
+connect_from_port_20=YES
+listen=NO
+listen_ipv6=YES
+pam_service_name=vsftpd
+background=YES
+EOF
+ip netns exec $S vsftpd ./vsftpd.conf
+sleep 1
+ip netns exec $S ss -6ltnp | grep -q '*:21'
+assert_pass "start vsftpd server"
+
+# test passive mode
+reload_ruleset
+ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null & sleep 2
+ip netns exec $C curl -s --connect-timeout 5 ftp://[${ip_rc}]:2121${INFILE#/var/ftp} -o $OUTFILE
+assert_pass "curl ftp passive mode "
+
+pkill tcpdump
+tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
+assert_pass "assert FTP traffic NATed"
+
+cmp "$INFILE" "$OUTFILE"
+assert_pass "FTP Passive mode: The input and output files remain the same when traffic passes through NAT."
+
+
+# test active mode
+reload_ruleset
+modprobe nf_nat_ftp
+assert_pass "modprobe nf_nat_ftp. Active mode need it to modify the client ip in PORT command under SNAT"
+
+ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null & sleep 2
+ip netns exec $C curl -s -P - --connect-timeout 5 ftp://[${ip_rc}]:2121${INFILE#/var/ftp} -o $OUTFILE
+assert_pass "curl ftp active mode "
+
+pkill tcpdump
+tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
+assert_pass "assert FTP traffic NATed"
+
+cmp "$INFILE" "$OUTFILE"
+assert_pass "FTP Active mode: in and output files remain the same when FTP traffic passes through NAT."
+
+# trap calls cleanup
+exit 0
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2] tests: shell: Add a test case for FTP helper combined with NAT.
  2025-06-05 10:33 [PATCH] tests: shell: Add a test case for FTP helper combined with NAT Yi Chen
@ 2025-06-05 10:49 ` Yi Chen
  2025-06-06 13:49   ` Florian Westphal
  2025-06-09  8:14 ` Yi Chen
  1 sibling, 1 reply; 9+ messages in thread
From: Yi Chen @ 2025-06-05 10:49 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

This test verifies functionality of the FTP helper,
for both passive, active FTP modes,
and the functionality of the nf_nat_ftp module.

Signed-off-by: Yi Chen <yiche@redhat.com>
---
 tests/shell/features/curl.sh             |   4 +
 tests/shell/features/tcpdump.sh          |   4 +
 tests/shell/features/vsftpd.sh           |   4 +
 tests/shell/testcases/packetpath/nat_ftp | 164 +++++++++++++++++++++++
 4 files changed, 176 insertions(+)
 create mode 100755 tests/shell/features/curl.sh
 create mode 100755 tests/shell/features/tcpdump.sh
 create mode 100755 tests/shell/features/vsftpd.sh
 create mode 100755 tests/shell/testcases/packetpath/nat_ftp

diff --git a/tests/shell/features/curl.sh b/tests/shell/features/curl.sh
new file mode 100755
index 00000000..fa0c43be
--- /dev/null
+++ b/tests/shell/features/curl.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether curl is installed
+curl -h >/dev/null 2>&1
diff --git a/tests/shell/features/tcpdump.sh b/tests/shell/features/tcpdump.sh
new file mode 100755
index 00000000..70df9f68
--- /dev/null
+++ b/tests/shell/features/tcpdump.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether tcpdump is installed
+tcpdump -h >/dev/null 2>&1
diff --git a/tests/shell/features/vsftpd.sh b/tests/shell/features/vsftpd.sh
new file mode 100755
index 00000000..d3500640
--- /dev/null
+++ b/tests/shell/features/vsftpd.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether vsftpd is installed
+which vsftpd >/dev/null 2>&1
diff --git a/tests/shell/testcases/packetpath/nat_ftp b/tests/shell/testcases/packetpath/nat_ftp
new file mode 100755
index 00000000..24fbecaa
--- /dev/null
+++ b/tests/shell/testcases/packetpath/nat_ftp
@@ -0,0 +1,164 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_tcpdump)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_curl)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_vsftpd)
+
+rnd=$(mktemp -u XXXXXXXX)
+R="cthelper-router-$rnd"
+C="cthelper-client-$rnd"
+S="cthelper-server-$rnd"
+
+cleanup()
+{
+	for i in $R $C $S;do
+		kill $(ip netns pid $i) 2>/dev/null
+		ip netns del $i
+	done
+	rm -f $INFILE $OUTFILE
+}
+trap cleanup EXIT
+
+INFILE=$(mktemp -p /var/ftp/pub/)
+OUTFILE=$(mktemp)
+
+assert_pass()
+{
+	local ret=$?
+	if [ $ret != 0 ]
+	then
+		echo "FAIL: ${@}"
+		ip netns exec $R nft list ruleset
+		tcpdump -nnr ${0##*/}.pcap
+		ip netns exec $R cat /proc/net/nf_conntrack
+		exit 1
+	else
+		echo "PASS: ${@}"
+	fi
+}
+
+ip_sr=2001:db8:ffff:22::1
+ip_cr=2001:db8:ffff:21::2
+ip_rs=2001:db8:ffff:22::fffe
+ip_rc=2001:db8:ffff:21::fffe
+
+ip netns add $R
+ip netns add $S
+ip netns add $C
+ip -net $S link set lo up
+ip -net $R link set lo up
+ip -net $C link set lo up
+ip netns exec $R sysctl -wq net.ipv6.conf.all.forwarding=1
+
+ip link add s_r netns $S type veth peer name r_s netns $R
+ip link add c_r netns $C type veth peer name r_c netns $R
+ip -net $S link set s_r up
+ip -net $R link set r_s up
+ip -net $R link set r_c up
+ip -net $C link set c_r up
+
+ip -net $S addr add ${ip_sr}/64 dev s_r
+ip -net $C addr add ${ip_cr}/64 dev c_r
+ip -net $R addr add ${ip_rs}/64 dev r_s
+ip -net $R addr add ${ip_rc}/64 dev r_c
+ip -net $C route add ${ip_rs}/64 via ${ip_rc} dev c_r
+ip -net $S route add ${ip_rc}/64 via ${ip_rs} dev s_r
+
+sleep 3
+ip netns exec $C ping -q -6 ${ip_sr} -c1 > /dev/null
+assert_pass "topo initialization"
+
+reload_ruleset()
+{
+	ip netns exec $R conntrack -F 2> /dev/null
+	ip netns exec $R nft -f - <<-EOF
+	flush ruleset
+	table ip6 ftp_helper_nat_test {
+		ct helper ftp-standard {
+			type "ftp" protocol tcp;
+		}
+
+		chain PRE-dnat {
+			type nat hook prerouting priority dstnat; policy accept;
+			# Dnat the control connection, data connection will be automaticly NATed.
+			ip6 daddr ${ip_rc} ip6 nexthdr tcp tcp dport 2121 counter dnat ip6 to [${ip_sr}]:21
+		}
+
+		chain PRE-aftnat {
+			type filter hook prerouting priority 350; policy drop;
+			iifname r_c tcp dport 21 ct state new ct helper set "ftp-standard" counter accept
+
+			ip6 nexthdr tcp ct state related counter accept
+			ip6 nexthdr tcp ct state established counter accept
+
+			ip6 nexthdr icmpv6 counter accept
+
+			counter log
+		}
+
+		chain forward {
+			type filter hook forward priority filter; policy drop;
+			ip6 daddr ${ip_sr} tcp dport 21 ct state new counter accept
+			ct state established counter accept
+			ct state related     counter log accept
+		}
+
+		chain POST-srcnat {
+			type nat hook postrouting priority srcnat; policy accept;
+			ip6 daddr ${ip_sr} ip6 nexthdr tcp tcp dport 21 counter snat ip6 to [${ip_rs}]:16500
+		}
+	}
+	EOF
+	assert_pass "apply ftp helper ruleset"
+}
+
+dd if=/dev/urandom of="$INFILE" bs=4096 count=1 2>/dev/null
+chmod 755 $INFILE
+assert_pass "Prepare the file for FTP transmission"
+
+cat > ./vsftpd.conf <<-EOF
+anonymous_enable=YES
+local_enable=YES
+connect_from_port_20=YES
+listen=NO
+listen_ipv6=YES
+pam_service_name=vsftpd
+background=YES
+EOF
+ip netns exec $S vsftpd ./vsftpd.conf
+sleep 1
+ip netns exec $S ss -6ltnp | grep -q '*:21'
+assert_pass "start vsftpd server"
+
+# test passive mode
+reload_ruleset
+ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null & sleep 2
+ip netns exec $C curl -s --connect-timeout 5 ftp://[${ip_rc}]:2121${INFILE#/var/ftp} -o $OUTFILE
+assert_pass "curl ftp passive mode "
+
+pkill tcpdump
+tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
+assert_pass "assert FTP traffic NATed"
+
+cmp "$INFILE" "$OUTFILE"
+assert_pass "FTP Passive mode: The input and output files remain the same when traffic passes through NAT."
+
+
+# test active mode
+reload_ruleset
+modprobe nf_nat_ftp
+assert_pass "modprobe nf_nat_ftp. Active mode need it to modify the client ip in PORT command under SNAT"
+
+ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null & sleep 2
+ip netns exec $C curl -s -P - --connect-timeout 5 ftp://[${ip_rc}]:2121${INFILE#/var/ftp} -o $OUTFILE
+assert_pass "curl ftp active mode "
+
+pkill tcpdump
+tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
+assert_pass "assert FTP traffic NATed"
+
+cmp "$INFILE" "$OUTFILE"
+assert_pass "FTP Active mode: in and output files remain the same when FTP traffic passes through NAT."
+
+# trap calls cleanup
+exit 0
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] tests: shell: Add a test case for FTP helper combined with NAT.
  2025-06-05 10:49 ` [PATCH v2] " Yi Chen
@ 2025-06-06 13:49   ` Florian Westphal
  2025-06-06 16:47     ` Yi Chen
  0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2025-06-06 13:49 UTC (permalink / raw)
  To: Yi Chen; +Cc: netfilter-devel

Yi Chen <yiche@redhat.com> wrote:
> This test verifies functionality of the FTP helper,
> for both passive, active FTP modes,
> and the functionality of the nf_nat_ftp module.

Thanks for this test case.

Some minor comments below.

> diff --git a/tests/shell/features/tcpdump.sh b/tests/shell/features/tcpdump.sh
> new file mode 100755
> index 00000000..70df9f68
> --- /dev/null
> +++ b/tests/shell/features/tcpdump.sh
> @@ -0,0 +1,4 @@
> +#!/bin/sh
> +
> +# check whether tcpdump is installed
> +tcpdump -h >/dev/null 2>&1

Is tcpdump a requirement? AFAICS the dumps are only used
as a debug aid when something goes wrong?

> +INFILE=$(mktemp -p /var/ftp/pub/)

This directory might not be writeable.

Can you use a /tmp/ directory?

I suggest to do:

WORKDIR=$(mktemp -d)
mkdir "$WORKDIR/pub"

... and then place all files there.

> +dd if=/dev/urandom of="$INFILE" bs=4096 count=1 2>/dev/null
> +chmod 755 $INFILE
> +assert_pass "Prepare the file for FTP transmission"

Including this one

... and this config:

> +cat > ./vsftpd.conf <<-EOF
> +anonymous_enable=YES
> +local_enable=YES
> +connect_from_port_20=YES
> +listen=NO
> +listen_ipv6=YES
> +pam_service_name=vsftpd
> +background=YES
> +EOF
> +ip netns exec $S vsftpd ./vsftpd.conf
> +sleep 1
> +ip netns exec $S ss -6ltnp | grep -q '*:21'
> +assert_pass "start vsftpd server"

So no files are created outside of /tmp.

> +# test passive mode
> +reload_ruleset
> +ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null & sleep 2
> +ip netns exec $C curl -s --connect-timeout 5 ftp://[${ip_rc}]:2121${INFILE#/var/ftp} -o $OUTFILE
> +assert_pass "curl ftp passive mode "
> +
> +pkill tcpdump

Can you do this instead?:
> +ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null &

tcpdump_pid=$!
sleep 2
...
kill "$tcpdump_pid"

?

pkill will zap all tcpdump instances.
Since tests are executed in parallel, it might zap other tcpdump
instances as well and not just the one spawned by this script.

> +tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP

Not sure why the above is needed.  Isn't the 'cmp' enough to see
if the ftp xfer worked?

> +assert_pass "assert FTP traffic NATed"
> +
> +cmp "$INFILE" "$OUTFILE"

... because if there is a problem with the helper, then the cmp
ought to fail?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] tests: shell: Add a test case for FTP helper combined with NAT.
  2025-06-06 13:49   ` Florian Westphal
@ 2025-06-06 16:47     ` Yi Chen
  2025-06-09  8:37       ` Florian Westphal
  0 siblings, 1 reply; 9+ messages in thread
From: Yi Chen @ 2025-06-06 16:47 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

> +tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
Why tcpdump check is needed:
If the snat rule doesn't work, does this test still pass?  "cmp file"
pass doesn't mean the snat really happened.
Add tcpdump check to make sure NAT really happened.


> tcpdump_pid=$!
> sleep 2
> ...
> kill "$tcpdump_pid"
Sure, will do.

> So no files are created outside of /tmp.
Sure, got this principal

> +INFILE=$(mktemp -p /var/ftp/pub/)
> This directory might not be writeable.
Sure, vsftpd must support a custom file path. I will find the configuration.

> Is tcpdump a requirement? AFAICS the dumps are only used
> as a debug aid when something goes wrong?
tcpdump is widely used in our LNST test cases. for example check if
one packet got modified.
Is it bad to use in upstream tests? If you still feel strange, I can
remove the tcpdump check.

What I care about most is whether the ruleset in the test is
configured correctly.
One only needs to NAT the control connection — the data connection
will be NATed automatically.

Of course, if there's a better ruleset that can exercise more kernel
code, that would be even better.
Will send out the next version.


On Fri, Jun 6, 2025 at 9:49 PM Florian Westphal <fw@strlen.de> wrote:
>
> Yi Chen <yiche@redhat.com> wrote:
> > This test verifies functionality of the FTP helper,
> > for both passive, active FTP modes,
> > and the functionality of the nf_nat_ftp module.
>
> Thanks for this test case.
>
> Some minor comments below.
>
> > diff --git a/tests/shell/features/tcpdump.sh b/tests/shell/features/tcpdump.sh
> > new file mode 100755
> > index 00000000..70df9f68
> > --- /dev/null
> > +++ b/tests/shell/features/tcpdump.sh
> > @@ -0,0 +1,4 @@
> > +#!/bin/sh
> > +
> > +# check whether tcpdump is installed
> > +tcpdump -h >/dev/null 2>&1
>
> Is tcpdump a requirement? AFAICS the dumps are only used
> as a debug aid when something goes wrong?
>
> > +INFILE=$(mktemp -p /var/ftp/pub/)
>
> This directory might not be writeable.
>
> Can you use a /tmp/ directory?
>
> I suggest to do:
>
> WORKDIR=$(mktemp -d)
> mkdir "$WORKDIR/pub"
>
> ... and then place all files there.
>
> > +dd if=/dev/urandom of="$INFILE" bs=4096 count=1 2>/dev/null
> > +chmod 755 $INFILE
> > +assert_pass "Prepare the file for FTP transmission"
>
> Including this one
>
> ... and this config:
>
> > +cat > ./vsftpd.conf <<-EOF
> > +anonymous_enable=YES
> > +local_enable=YES
> > +connect_from_port_20=YES
> > +listen=NO
> > +listen_ipv6=YES
> > +pam_service_name=vsftpd
> > +background=YES
> > +EOF
> > +ip netns exec $S vsftpd ./vsftpd.conf
> > +sleep 1
> > +ip netns exec $S ss -6ltnp | grep -q '*:21'
> > +assert_pass "start vsftpd server"
>
> So no files are created outside of /tmp.
>
> > +# test passive mode
> > +reload_ruleset
> > +ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null & sleep 2
> > +ip netns exec $C curl -s --connect-timeout 5 ftp://[${ip_rc}]:2121${INFILE#/var/ftp} -o $OUTFILE
> > +assert_pass "curl ftp passive mode "
> > +
> > +pkill tcpdump
>
> Can you do this instead?:
> > +ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null &
>
> tcpdump_pid=$!
> sleep 2
> ...
> kill "$tcpdump_pid"
>
> ?
>
> pkill will zap all tcpdump instances.
> Since tests are executed in parallel, it might zap other tcpdump
> instances as well and not just the one spawned by this script.
>
> > +tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
>
> Not sure why the above is needed.  Isn't the 'cmp' enough to see
> if the ftp xfer worked?
>
> > +assert_pass "assert FTP traffic NATed"
> > +
> > +cmp "$INFILE" "$OUTFILE"
>
> ... because if there is a problem with the helper, then the cmp
> ought to fail?
>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2] tests: shell: Add a test case for FTP helper combined with NAT.
  2025-06-05 10:33 [PATCH] tests: shell: Add a test case for FTP helper combined with NAT Yi Chen
  2025-06-05 10:49 ` [PATCH v2] " Yi Chen
@ 2025-06-09  8:14 ` Yi Chen
  2025-06-09 21:35   ` Florian Westphal
  1 sibling, 1 reply; 9+ messages in thread
From: Yi Chen @ 2025-06-09  8:14 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

This test verifies functionality of the FTP helper,
for both passive, active FTP modes,
and the functionality of the nf_nat_ftp module.

Signed-off-by: Yi Chen <yiche@redhat.com>
---
 tests/shell/features/curl.sh             |   4 +
 tests/shell/features/tcpdump.sh          |   4 +
 tests/shell/features/vsftpd.sh           |   4 +
 tests/shell/testcases/packetpath/nat_ftp | 174 +++++++++++++++++++++++
 4 files changed, 186 insertions(+)
 create mode 100755 tests/shell/features/curl.sh
 create mode 100755 tests/shell/features/tcpdump.sh
 create mode 100755 tests/shell/features/vsftpd.sh
 create mode 100755 tests/shell/testcases/packetpath/nat_ftp

diff --git a/tests/shell/features/curl.sh b/tests/shell/features/curl.sh
new file mode 100755
index 00000000..fa0c43be
--- /dev/null
+++ b/tests/shell/features/curl.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether curl is installed
+curl -h >/dev/null 2>&1
diff --git a/tests/shell/features/tcpdump.sh b/tests/shell/features/tcpdump.sh
new file mode 100755
index 00000000..70df9f68
--- /dev/null
+++ b/tests/shell/features/tcpdump.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether tcpdump is installed
+tcpdump -h >/dev/null 2>&1
diff --git a/tests/shell/features/vsftpd.sh b/tests/shell/features/vsftpd.sh
new file mode 100755
index 00000000..d3500640
--- /dev/null
+++ b/tests/shell/features/vsftpd.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether vsftpd is installed
+which vsftpd >/dev/null 2>&1
diff --git a/tests/shell/testcases/packetpath/nat_ftp b/tests/shell/testcases/packetpath/nat_ftp
new file mode 100755
index 00000000..8d0ce24b
--- /dev/null
+++ b/tests/shell/testcases/packetpath/nat_ftp
@@ -0,0 +1,174 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_tcpdump)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_curl)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_vsftpd)
+
+cleanup()
+{
+	for i in $R $C $S;do
+		kill $(ip netns pid $i) 2>/dev/null
+		ip netns del $i
+	done
+	rm -rf $WORKDIR
+}
+trap cleanup EXIT
+
+assert_pass()
+{
+	local ret=$?
+	if [ $ret != 0 ]
+	then
+		echo "FAIL: ${@}"
+		ip netns exec $R nft list ruleset
+		tcpdump -nnr ${PCAP}
+		ip netns exec $R cat /proc/net/nf_conntrack
+		exit 1
+	else
+		echo "PASS: ${@}"
+	fi
+}
+
+rnd=$(mktemp -u XXXXXXXX)
+R="natftp-router-$rnd"
+C="natftp-client-$rnd"
+S="natftp-server-$rnd"
+
+WORKDIR="/tmp/nat_ftp_test-$rnd"
+FTPCONF="$WORKDIR/ftp-conf"
+INFILE="$WORKDIR/infile"
+OUTFILE="$WORKDIR/outfile"
+PCAP="$WORKDIR/tcpdump.pcap"
+
+mkdir -p $WORKDIR
+assert_pass "mkdir $WORKDIR"
+
+ip_sr=2001:db8:ffff:22::1
+ip_cr=2001:db8:ffff:21::2
+ip_rs=2001:db8:ffff:22::fffe
+ip_rc=2001:db8:ffff:21::fffe
+
+ip netns add $R
+ip netns add $S
+ip netns add $C
+ip -net $S link set lo up
+ip -net $R link set lo up
+ip -net $C link set lo up
+ip netns exec $R sysctl -wq net.ipv6.conf.all.forwarding=1
+
+ip link add s_r netns $S type veth peer name r_s netns $R
+ip link add c_r netns $C type veth peer name r_c netns $R
+ip -net $S link set s_r up
+ip -net $R link set r_s up
+ip -net $R link set r_c up
+ip -net $C link set c_r up
+
+ip -net $S addr add ${ip_sr}/64 dev s_r nodad
+ip -net $C addr add ${ip_cr}/64 dev c_r nodad
+ip -net $R addr add ${ip_rs}/64 dev r_s nodad
+ip -net $R addr add ${ip_rc}/64 dev r_c nodad
+ip -net $C route add ${ip_rs}/64 via ${ip_rc} dev c_r
+ip -net $S route add ${ip_rc}/64 via ${ip_rs} dev s_r
+
+ip netns exec $C ping -q -6 ${ip_sr} -c1 > /dev/null
+assert_pass "topo initialization"
+
+reload_ruleset()
+{
+	ip netns exec $R conntrack -F 2> /dev/null
+	ip netns exec $R nft -f - <<-EOF
+	flush ruleset
+	table ip6 ftp_helper_nat_test {
+		ct helper ftp-standard {
+			type "ftp" protocol tcp;
+		}
+
+		chain PRE-dnat {
+			type nat hook prerouting priority dstnat; policy accept;
+			# Dnat the control connection, data connection will be automaticly NATed.
+			ip6 daddr ${ip_rc} ip6 nexthdr tcp tcp dport 2121 counter dnat ip6 to [${ip_sr}]:21
+		}
+
+		chain PRE-aftnat {
+			type filter hook prerouting priority 350; policy drop;
+			iifname r_c tcp dport 21 ct state new ct helper set "ftp-standard" counter accept
+
+			ip6 nexthdr tcp ct state related counter accept
+			ip6 nexthdr tcp ct state established counter accept
+
+			ip6 nexthdr icmpv6 counter accept
+
+			counter log
+		}
+
+		chain forward {
+			type filter hook forward priority filter; policy drop;
+			ip6 daddr ${ip_sr} tcp dport 21 ct state new counter accept
+			ip6 nexthdr tcp ct state established counter accept
+			ip6 nexthdr tcp ct state related     counter log accept
+		}
+
+		chain POST-srcnat {
+			type nat hook postrouting priority srcnat; policy accept;
+			ip6 daddr ${ip_sr} ip6 nexthdr tcp tcp dport 21 counter snat ip6 to [${ip_rs}]:16500
+		}
+	}
+	EOF
+	assert_pass "apply ftp helper ruleset"
+}
+
+dd if=/dev/urandom of="$INFILE" bs=4096 count=1 2>/dev/null
+chmod 755 $INFILE
+assert_pass "Prepare the file for FTP transmission"
+
+cat > ${FTPCONF} <<-EOF
+anonymous_enable=YES
+anon_root=${WORKDIR}
+local_enable=YES
+connect_from_port_20=YES
+listen=NO
+listen_ipv6=YES
+pam_service_name=vsftpd
+background=YES
+EOF
+ip netns exec $S vsftpd ${FTPCONF}
+sleep 1
+ip netns exec $S ss -6ltnp | grep -q '*:21'
+assert_pass "start vsftpd server"
+
+
+# test passive mode
+reload_ruleset
+ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null &
+pid=$!
+sleep 1
+ip netns exec $C curl -s --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
+assert_pass "curl ftp passive mode "
+
+cmp "$INFILE" "$OUTFILE"
+assert_pass "FTP Passive mode: The input and output files remain the same when traffic passes through NAT."
+
+kill $pid; sync
+tcpdump -nnr ${PCAP} src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
+assert_pass "assert FTP traffic NATed"
+
+
+# test active mode
+reload_ruleset
+modprobe nf_nat_ftp
+assert_pass "modprobe nf_nat_ftp. Active mode need it to modify the client ip in PORT command under SNAT"
+
+ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null &
+pid=$!
+ip netns exec $C curl -s -P - --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
+assert_pass "curl ftp active mode "
+
+cmp "$INFILE" "$OUTFILE"
+assert_pass "FTP Active mode: in and output files remain the same when FTP traffic passes through NAT."
+
+kill $pid; sync
+tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
+assert_pass "assert FTP traffic NATed"
+
+# trap calls cleanup
+exit 0
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] tests: shell: Add a test case for FTP helper combined with NAT.
  2025-06-06 16:47     ` Yi Chen
@ 2025-06-09  8:37       ` Florian Westphal
  0 siblings, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2025-06-09  8:37 UTC (permalink / raw)
  To: Yi Chen; +Cc: netfilter-devel

Yi Chen <yiche@redhat.com> wrote:
> > Is tcpdump a requirement? AFAICS the dumps are only used
> > as a debug aid when something goes wrong?
> tcpdump is widely used in our LNST test cases. for example check if
> one packet got modified.
> Is it bad to use in upstream tests? If you still feel strange, I can
> remove the tcpdump check.

No need, you can keep tcpdump around.

> What I care about most is whether the ruleset in the test is
> configured correctly.
> One only needs to NAT the control connection — the data connection
> will be NATed automatically.

I'd have expected that the ftp connection would fail in case
there is a problem with NAT.

But if you prefer to also validate via tcpdump thats fine.

Thanks for v2, I will have a look.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] tests: shell: Add a test case for FTP helper combined with NAT.
  2025-06-09  8:14 ` Yi Chen
@ 2025-06-09 21:35   ` Florian Westphal
  2025-06-10  4:05     ` Yi Chen
  0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2025-06-09 21:35 UTC (permalink / raw)
  To: Yi Chen; +Cc: netfilter-devel

Yi Chen <yiche@redhat.com> wrote:
> This test verifies functionality of the FTP helper,
> for both passive, active FTP modes,
> and the functionality of the nf_nat_ftp module.

Thanks, I had to apply this delta to make this work for me, can
you check that it still passes on your end?

I guess nf_nat_ftp module is already loaded on
your system, its needed for all tests as the FTP server
is on a different address than what the client connectects to.

The important changes are:
 - load nf_nat_ftp early
 - use ${PCAP} for last tcpdump too, local dir isn't writeable
   in my virtme-ng setup.

Rest is debugging aid/cosmetic.  The curl feature check gets extended
to skip in case curl exists but was built with no ftp support.

I removed -s flag from curl, this also removes the error messages,
if any, which makes it harder to debug.  Its fine to have more
information available in case something goes wrong.

I now get:
  I: [OK]         1/1 tests/shell/testcases/packetpath/nat_ftp

No need to resend unless you want to make further enhancements.

diff --git a/tests/shell/features/curl.sh b/tests/shell/features/curl.sh
--- a/tests/shell/features/curl.sh
+++ b/tests/shell/features/curl.sh
@@ -1,4 +1,4 @@
 #!/bin/sh
 
-# check whether curl is installed
-curl -h >/dev/null 2>&1
+# check whether curl is installed and supports ftp
+curl --version | grep "^Protocols: "| grep -q " ftp"
diff --git a/tests/shell/testcases/packetpath/nat_ftp b/tests/shell/testcases/packetpath/nat_ftp
--- a/tests/shell/testcases/packetpath/nat_ftp
+++ b/tests/shell/testcases/packetpath/nat_ftp
@@ -22,7 +22,10 @@ assert_pass()
 		echo "FAIL: ${@}"
 		ip netns exec $R nft list ruleset
 		tcpdump -nnr ${PCAP}
-		ip netns exec $R cat /proc/net/nf_conntrack
+		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: ${@}"
@@ -43,6 +46,9 @@ PCAP="$WORKDIR/tcpdump.pcap"
 mkdir -p $WORKDIR
 assert_pass "mkdir $WORKDIR"
 
+modprobe nf_nat_ftp
+assert_pass "modprobe nf_nat_ftp. Needed for DNAT of data connection and active mode PORT change with SNAT"
+
 ip_sr=2001:db8:ffff:22::1
 ip_cr=2001:db8:ffff:21::2
 ip_rs=2001:db8:ffff:22::fffe
@@ -86,7 +92,7 @@ reload_ruleset()
 		chain PRE-dnat {
 			type nat hook prerouting priority dstnat; policy accept;
 			# Dnat the control connection, data connection will be automaticly NATed.
-			ip6 daddr ${ip_rc} ip6 nexthdr tcp tcp dport 2121 counter dnat ip6 to [${ip_sr}]:21
+			ip6 daddr ${ip_rc} counter ip6 nexthdr tcp tcp dport 2121 counter dnat ip6 to [${ip_sr}]:21
 		}
 
 		chain PRE-aftnat {
@@ -103,7 +109,7 @@ reload_ruleset()
 
 		chain forward {
 			type filter hook forward priority filter; policy drop;
-			ip6 daddr ${ip_sr} tcp dport 21 ct state new counter accept
+			ip6 daddr ${ip_sr} counter tcp dport 21 ct state new counter accept
 			ip6 nexthdr tcp ct state established counter accept
 			ip6 nexthdr tcp ct state related     counter log accept
 		}
@@ -142,7 +148,7 @@ reload_ruleset
 ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null &
 pid=$!
 sleep 1
-ip netns exec $C curl -s --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
+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 "
 
 cmp "$INFILE" "$OUTFILE"
@@ -155,19 +161,17 @@ assert_pass "assert FTP traffic NATed"
 
 # test active mode
 reload_ruleset
-modprobe nf_nat_ftp
-assert_pass "modprobe nf_nat_ftp. Active mode need it to modify the client ip in PORT command under SNAT"
 
-ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null &
+ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null &
 pid=$!
-ip netns exec $C curl -s -P - --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
+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 "
 
 cmp "$INFILE" "$OUTFILE"
 assert_pass "FTP Active mode: in and output files remain the same when FTP traffic passes through NAT."
 
 kill $pid; sync
-tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
+tcpdump -nnr ${PCAP} src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
 assert_pass "assert FTP traffic NATed"
 
 # trap calls cleanup

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] tests: shell: Add a test case for FTP helper combined with NAT.
  2025-06-09 21:35   ` Florian Westphal
@ 2025-06-10  4:05     ` Yi Chen
  2025-06-10  6:02       ` Florian Westphal
  0 siblings, 1 reply; 9+ messages in thread
From: Yi Chen @ 2025-06-10  4:05 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

Indeed, both passive and active mode need to preload the nf_nat_ftp module.
The patched script passed on my side too.
Thanks for fixing mistakes in the script!

On Tue, Jun 10, 2025 at 5:35 AM Florian Westphal <fw@strlen.de> wrote:
>
> Yi Chen <yiche@redhat.com> wrote:
> > This test verifies functionality of the FTP helper,
> > for both passive, active FTP modes,
> > and the functionality of the nf_nat_ftp module.
>
> Thanks, I had to apply this delta to make this work for me, can
> you check that it still passes on your end?
>
> I guess nf_nat_ftp module is already loaded on
> your system, its needed for all tests as the FTP server
> is on a different address than what the client connectects to.
>
> The important changes are:
>  - load nf_nat_ftp early
>  - use ${PCAP} for last tcpdump too, local dir isn't writeable
>    in my virtme-ng setup.
>
> Rest is debugging aid/cosmetic.  The curl feature check gets extended
> to skip in case curl exists but was built with no ftp support.
>
> I removed -s flag from curl, this also removes the error messages,
> if any, which makes it harder to debug.  Its fine to have more
> information available in case something goes wrong.
>
> I now get:
>   I: [OK]         1/1 tests/shell/testcases/packetpath/nat_ftp
>
> No need to resend unless you want to make further enhancements.
>
> diff --git a/tests/shell/features/curl.sh b/tests/shell/features/curl.sh
> --- a/tests/shell/features/curl.sh
> +++ b/tests/shell/features/curl.sh
> @@ -1,4 +1,4 @@
>  #!/bin/sh
>
> -# check whether curl is installed
> -curl -h >/dev/null 2>&1
> +# check whether curl is installed and supports ftp
> +curl --version | grep "^Protocols: "| grep -q " ftp"
> diff --git a/tests/shell/testcases/packetpath/nat_ftp b/tests/shell/testcases/packetpath/nat_ftp
> --- a/tests/shell/testcases/packetpath/nat_ftp
> +++ b/tests/shell/testcases/packetpath/nat_ftp
> @@ -22,7 +22,10 @@ assert_pass()
>                 echo "FAIL: ${@}"
>                 ip netns exec $R nft list ruleset
>                 tcpdump -nnr ${PCAP}
> -               ip netns exec $R cat /proc/net/nf_conntrack
> +               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: ${@}"
> @@ -43,6 +46,9 @@ PCAP="$WORKDIR/tcpdump.pcap"
>  mkdir -p $WORKDIR
>  assert_pass "mkdir $WORKDIR"
>
> +modprobe nf_nat_ftp
> +assert_pass "modprobe nf_nat_ftp. Needed for DNAT of data connection and active mode PORT change with SNAT"
> +
>  ip_sr=2001:db8:ffff:22::1
>  ip_cr=2001:db8:ffff:21::2
>  ip_rs=2001:db8:ffff:22::fffe
> @@ -86,7 +92,7 @@ reload_ruleset()
>                 chain PRE-dnat {
>                         type nat hook prerouting priority dstnat; policy accept;
>                         # Dnat the control connection, data connection will be automaticly NATed.
> -                       ip6 daddr ${ip_rc} ip6 nexthdr tcp tcp dport 2121 counter dnat ip6 to [${ip_sr}]:21
> +                       ip6 daddr ${ip_rc} counter ip6 nexthdr tcp tcp dport 2121 counter dnat ip6 to [${ip_sr}]:21
>                 }
>
>                 chain PRE-aftnat {
> @@ -103,7 +109,7 @@ reload_ruleset()
>
>                 chain forward {
>                         type filter hook forward priority filter; policy drop;
> -                       ip6 daddr ${ip_sr} tcp dport 21 ct state new counter accept
> +                       ip6 daddr ${ip_sr} counter tcp dport 21 ct state new counter accept
>                         ip6 nexthdr tcp ct state established counter accept
>                         ip6 nexthdr tcp ct state related     counter log accept
>                 }
> @@ -142,7 +148,7 @@ reload_ruleset
>  ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null &
>  pid=$!
>  sleep 1
> -ip netns exec $C curl -s --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
> +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 "
>
>  cmp "$INFILE" "$OUTFILE"
> @@ -155,19 +161,17 @@ assert_pass "assert FTP traffic NATed"
>
>  # test active mode
>  reload_ruleset
> -modprobe nf_nat_ftp
> -assert_pass "modprobe nf_nat_ftp. Active mode need it to modify the client ip in PORT command under SNAT"
>
> -ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${0##*/}.pcap 2> /dev/null &
> +ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null &
>  pid=$!
> -ip netns exec $C curl -s -P - --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
> +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 "
>
>  cmp "$INFILE" "$OUTFILE"
>  assert_pass "FTP Active mode: in and output files remain the same when FTP traffic passes through NAT."
>
>  kill $pid; sync
> -tcpdump -nnr ${0##*/}.pcap src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
> +tcpdump -nnr ${PCAP} src ${ip_rs} and dst ${ip_sr} 2>&1 |grep -q FTP
>  assert_pass "assert FTP traffic NATed"
>
>  # trap calls cleanup
>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] tests: shell: Add a test case for FTP helper combined with NAT.
  2025-06-10  4:05     ` Yi Chen
@ 2025-06-10  6:02       ` Florian Westphal
  0 siblings, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2025-06-10  6:02 UTC (permalink / raw)
  To: Yi Chen; +Cc: netfilter-devel

Yi Chen <yiche@redhat.com> wrote:
> Indeed, both passive and active mode need to preload the nf_nat_ftp module.
> The patched script passed on my side too.

Thanks for double-checking, I've pushed the updated script out.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-06-10  6:02 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-05 10:33 [PATCH] tests: shell: Add a test case for FTP helper combined with NAT Yi Chen
2025-06-05 10:49 ` [PATCH v2] " Yi Chen
2025-06-06 13:49   ` Florian Westphal
2025-06-06 16:47     ` Yi Chen
2025-06-09  8:37       ` Florian Westphal
2025-06-09  8:14 ` Yi Chen
2025-06-09 21:35   ` Florian Westphal
2025-06-10  4:05     ` Yi Chen
2025-06-10  6:02       ` Florian Westphal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.