1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Check that UNREPLIED tcp conntrack will eventually timeout.
5#
6
7# Kselftest framework requirement - SKIP code is 4.
8ksft_skip=4
9ret=0
10
11waittime=20
12sfx=$(mktemp -u "XXXXXXXX")
13ns1="ns1-$sfx"
14ns2="ns2-$sfx"
15
16nft --version > /dev/null 2>&1
17if [ $? -ne 0 ];then
18	echo "SKIP: Could not run test without nft tool"
19	exit $ksft_skip
20fi
21
22ip -Version > /dev/null 2>&1
23if [ $? -ne 0 ];then
24	echo "SKIP: Could not run test without ip tool"
25	exit $ksft_skip
26fi
27
28cleanup() {
29	ip netns pids $ns1 | xargs kill 2>/dev/null
30	ip netns pids $ns2 | xargs kill 2>/dev/null
31
32	ip netns del $ns1
33	ip netns del $ns2
34}
35
36ipv4() {
37    echo -n 192.168.$1.2
38}
39
40check_counter()
41{
42	ns=$1
43	name=$2
44	expect=$3
45	local lret=0
46
47	cnt=$(ip netns exec $ns2 nft list counter inet filter "$name" | grep -q "$expect")
48	if [ $? -ne 0 ]; then
49		echo "ERROR: counter $name in $ns2 has unexpected value (expected $expect)" 1>&2
50		ip netns exec $ns2 nft list counter inet filter "$name" 1>&2
51		lret=1
52	fi
53
54	return $lret
55}
56
57# Create test namespaces
58ip netns add $ns1 || exit 1
59
60trap cleanup EXIT
61
62ip netns add $ns2 || exit 1
63
64# Connect the namespace to the host using a veth pair
65ip -net $ns1 link add name veth1 type veth peer name veth2
66ip -net $ns1 link set netns $ns2 dev veth2
67
68ip -net $ns1 link set up dev lo
69ip -net $ns2 link set up dev lo
70ip -net $ns1 link set up dev veth1
71ip -net $ns2 link set up dev veth2
72
73ip -net $ns2 addr add 10.11.11.2/24 dev veth2
74ip -net $ns2 route add default via 10.11.11.1
75
76ip netns exec $ns2 sysctl -q net.ipv4.conf.veth2.forwarding=1
77
78# add a rule inside NS so we enable conntrack
79ip netns exec $ns1 iptables -A INPUT -m state --state established,related -j ACCEPT
80
81ip -net $ns1 addr add 10.11.11.1/24 dev veth1
82ip -net $ns1 route add 10.99.99.99 via 10.11.11.2
83
84# Check connectivity works
85ip netns exec $ns1 ping -q -c 2 10.11.11.2 >/dev/null || exit 1
86
87ip netns exec $ns2 nc -l -p 8080 < /dev/null &
88
89# however, conntrack entries are there
90
91ip netns exec $ns2 nft -f - <<EOF
92table inet filter {
93	counter connreq { }
94	counter redir { }
95	chain input {
96		type filter hook input priority 0; policy accept;
97		ct state new tcp flags syn ip daddr 10.99.99.99 tcp dport 80 counter name "connreq" accept
98		ct state new ct status dnat tcp dport 8080 counter name "redir" accept
99	}
100}
101EOF
102if [ $? -ne 0 ]; then
103	echo "ERROR: Could not load nft rules"
104	exit 1
105fi
106
107ip netns exec $ns2 sysctl -q net.netfilter.nf_conntrack_tcp_timeout_syn_sent=10
108
109echo "INFO: connect $ns1 -> $ns2 to the virtual ip"
110ip netns exec $ns1 bash -c 'while true ; do
111	nc -p 60000 10.99.99.99 80
112	sleep 1
113	done' &
114
115sleep 1
116
117ip netns exec $ns2 nft -f - <<EOF
118table inet nat {
119	chain prerouting {
120		type nat hook prerouting priority 0; policy accept;
121		ip daddr 10.99.99.99 tcp dport 80 redirect to :8080
122	}
123}
124EOF
125if [ $? -ne 0 ]; then
126	echo "ERROR: Could not load nat redirect"
127	exit 1
128fi
129
130count=$(ip netns exec $ns2 conntrack -L -p tcp --dport 80 2>/dev/null | wc -l)
131if [ $count -eq 0 ]; then
132	echo "ERROR: $ns2 did not pick up tcp connection from peer"
133	exit 1
134fi
135
136echo "INFO: NAT redirect added in ns $ns2, waiting for $waittime seconds for nat to take effect"
137for i in $(seq 1 $waittime); do
138	echo -n "."
139
140	sleep 1
141
142	count=$(ip netns exec $ns2 conntrack -L -p tcp --reply-port-src 8080 2>/dev/null | wc -l)
143	if [ $count -gt 0 ]; then
144		echo
145		echo "PASS: redirection took effect after $i seconds"
146		break
147	fi
148
149	m=$((i%20))
150	if [ $m -eq 0 ]; then
151		echo " waited for $i seconds"
152	fi
153done
154
155expect="packets 1 bytes 60"
156check_counter "$ns2" "redir" "$expect"
157if [ $? -ne 0 ]; then
158	ret=1
159fi
160
161if [ $ret -eq 0 ];then
162	echo "PASS: redirection counter has expected values"
163else
164	echo "ERROR: no tcp connection was redirected"
165fi
166
167exit $ret
168