1#!/bin/bash
2#
3# This tests connection tracking helper assignment:
4# 1. can attach ftp helper to a connection from nft ruleset.
5# 2. auto-assign still works.
6#
7# Kselftest framework requirement - SKIP code is 4.
8
9source lib.sh
10
11ret=0
12
13testipv6=1
14
15checktool "socat -h" "run test without socat"
16checktool "conntrack --version" "run test without conntrack"
17checktool "nft --version" "run test without nft"
18
19cleanup()
20{
21	ip netns pids "$ns1" | xargs kill 2>/dev/null
22
23	ip netns del "$ns1"
24	ip netns del "$ns2"
25}
26
27trap cleanup EXIT
28
29setup_ns ns1 ns2
30
31if ! ip link add veth0 netns "$ns1" type veth peer name veth0 netns "$ns2" > /dev/null 2>&1;then
32    echo "SKIP: No virtual ethernet pair device support in kernel"
33    exit $ksft_skip
34fi
35
36ip -net "$ns1" link set veth0 up
37ip -net "$ns2" link set veth0 up
38
39ip -net "$ns1" addr add 10.0.1.1/24 dev veth0
40ip -net "$ns1" addr add dead:1::1/64 dev veth0 nodad
41
42ip -net "$ns2" addr add 10.0.1.2/24 dev veth0
43ip -net "$ns2" addr add dead:1::2/64 dev veth0 nodad
44
45load_ruleset_family() {
46	local family=$1
47	local ns=$2
48
49ip netns exec "$ns" nft -f - <<EOF
50table $family raw {
51	ct helper ftp {
52             type "ftp" protocol tcp
53        }
54	chain pre {
55		type filter hook prerouting priority 0; policy accept;
56		tcp dport 2121 ct helper set "ftp"
57	}
58	chain output {
59		type filter hook output priority 0; policy accept;
60		tcp dport 2121 ct helper set "ftp"
61	}
62}
63EOF
64	return $?
65}
66
67check_for_helper()
68{
69	local netns=$1
70	local message=$2
71	local port=$3
72
73	if echo "$message" |grep -q 'ipv6';then
74		local family="ipv6"
75	else
76		local family="ipv4"
77	fi
78
79	if ! ip netns exec "$netns" conntrack -L -f $family -p tcp --dport "$port" 2> /dev/null |grep -q 'helper=ftp';then
80		if [ "$autoassign" -eq 0 ] ;then
81			echo "FAIL: ${netns} did not show attached helper $message" 1>&2
82			ret=1
83		else
84			echo "PASS: ${netns} did not show attached helper $message" 1>&2
85		fi
86	else
87		if [ "$autoassign" -eq 0 ] ;then
88			echo "PASS: ${netns} connection on port $port has ftp helper attached" 1>&2
89		else
90			echo "FAIL: ${netns} connection on port $port has ftp helper attached" 1>&2
91			ret=1
92		fi
93	fi
94
95	return 0
96}
97
98listener_ready()
99{
100	ns="$1"
101	port="$2"
102	proto="$3"
103	ss -N "$ns" -lnt -o "sport = :$port" | grep -q "$port"
104}
105
106test_helper()
107{
108	local port=$1
109	local autoassign=$2
110
111	if [ "$autoassign" -eq 0 ] ;then
112		msg="set via ruleset"
113	else
114		msg="auto-assign"
115	fi
116
117	ip netns exec "$ns2" socat -t 3 -u -4 TCP-LISTEN:"$port",reuseaddr STDOUT > /dev/null &
118	busywait "$BUSYWAIT_TIMEOUT" listener_ready "$ns2" "$port" "-4"
119
120	ip netns exec "$ns1" socat -u -4 STDIN TCP:10.0.1.2:"$port" < /dev/null > /dev/null
121
122	check_for_helper "$ns1" "ip $msg" "$port" "$autoassign"
123	check_for_helper "$ns2" "ip $msg" "$port" "$autoassign"
124
125	if [ $testipv6 -eq 0 ] ;then
126		return 0
127	fi
128
129	ip netns exec "$ns1" conntrack -F 2> /dev/null
130	ip netns exec "$ns2" conntrack -F 2> /dev/null
131
132	ip netns exec "$ns2" socat -t 3 -u -6 TCP-LISTEN:"$port",reuseaddr STDOUT > /dev/null &
133	busywait $BUSYWAIT_TIMEOUT listener_ready "$ns2" "$port" "-6"
134
135	ip netns exec "$ns1" socat -t 3 -u -6 STDIN TCP:"[dead:1::2]":"$port" < /dev/null > /dev/null
136
137	check_for_helper "$ns1" "ipv6 $msg" "$port"
138	check_for_helper "$ns2" "ipv6 $msg" "$port"
139}
140
141if ! load_ruleset_family ip "$ns1"; then
142	echo "FAIL: ${ns1} cannot load ip ruleset" 1>&2
143	exit 1
144fi
145
146if ! load_ruleset_family ip6 "$ns1"; then
147	echo "SKIP: ${ns1} cannot load ip6 ruleset" 1>&2
148	testipv6=0
149fi
150
151if ! load_ruleset_family inet "${ns2}"; then
152	echo "SKIP: ${ns1} cannot load inet ruleset" 1>&2
153	if ! load_ruleset_family ip "${ns2}"; then
154		echo "FAIL: ${ns2} cannot load ip ruleset" 1>&2
155		exit 1
156	fi
157
158	if [ "$testipv6" -eq 1 ] ;then
159		if ! load_ruleset_family ip6 "$ns2"; then
160			echo "FAIL: ${ns2} cannot load ip6 ruleset" 1>&2
161			exit 1
162		fi
163	fi
164fi
165
166test_helper 2121 0
167ip netns exec "$ns1" sysctl -qe 'net.netfilter.nf_conntrack_helper=1'
168ip netns exec "$ns2" sysctl -qe 'net.netfilter.nf_conntrack_helper=1'
169test_helper 21 1
170
171exit $ret
172