1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# return code to signal skipped test
5ksft_skip=4
6rc=0
7
8source lib.sh
9
10checktool "socat -h" "run test without socat"
11checktool "iptables --version" "test needs iptables"
12
13infile=$(mktemp)
14
15cleanup()
16{
17	ip netns del "$netns"
18	rm -f "$infile"
19}
20
21trap cleanup EXIT
22
23setup_ns netns
24
25ip -net "$netns" link add d0 type dummy
26ip -net "$netns" link set d0 up
27ip -net "$netns" addr add 10.1.2.1/24 dev d0
28
29pattern="foo bar baz"
30patlen=11
31hdrlen=$((20 + 8)) # IPv4 + UDP
32
33#ip netns exec "$netns" tcpdump -npXi d0 &
34#tcpdump_pid=$!
35#trap 'kill $tcpdump_pid; ip netns del $netns' EXIT
36
37add_rule() { # (alg, from, to)
38	ip netns exec "$netns" \
39		iptables -A OUTPUT -o d0 -m string \
40			--string "$pattern" --algo "$1" --from "$2" --to "$3"
41}
42showrules() { # ()
43	ip netns exec "$netns" iptables -v -S OUTPUT | grep '^-A'
44}
45zerorules() {
46	ip netns exec "$netns" iptables -Z OUTPUT
47}
48countrule() { # (pattern)
49	showrules | grep -c -- "$*"
50}
51send() { # (offset)
52	( for ((i = 0; i < $1 - hdrlen; i++)); do
53		echo -n " "
54	  done
55	  echo -n "$pattern"
56	) > "$infile"
57
58	ip netns exec "$netns" socat -t 1 -u STDIN UDP-SENDTO:10.1.2.2:27374 < "$infile"
59}
60
61add_rule bm 1000 1500
62add_rule bm 1400 1600
63add_rule kmp 1000 1500
64add_rule kmp 1400 1600
65
66zerorules
67send 0
68send $((1000 - patlen))
69if [ "$(countrule -c 0 0)" -ne 4 ]; then
70	echo "FAIL: rules match data before --from"
71	showrules
72	((rc--))
73fi
74
75zerorules
76send 1000
77send $((1400 - patlen))
78if [ "$(countrule -c 2)" -ne 2 ]; then
79	echo "FAIL: only two rules should match at low offset"
80	showrules
81	((rc--))
82fi
83
84zerorules
85send $((1500 - patlen))
86if [ "$(countrule -c 1)" -ne 4 ]; then
87	echo "FAIL: all rules should match at end of packet"
88	showrules
89	((rc--))
90fi
91
92zerorules
93send 1495
94if [ "$(countrule -c 1)" -ne 1 ]; then
95	echo "FAIL: only kmp with proper --to should match pattern spanning fragments"
96	showrules
97	((rc--))
98fi
99
100zerorules
101send 1500
102if [ "$(countrule -c 1)" -ne 2 ]; then
103	echo "FAIL: two rules should match pattern at start of second fragment"
104	showrules
105	((rc--))
106fi
107
108zerorules
109send $((1600 - patlen))
110if [ "$(countrule -c 1)" -ne 2 ]; then
111	echo "FAIL: two rules should match pattern at end of largest --to"
112	showrules
113	((rc--))
114fi
115
116zerorules
117send $((1600 - patlen + 1))
118if [ "$(countrule -c 1)" -ne 0 ]; then
119	echo "FAIL: no rules should match pattern extending largest --to"
120	showrules
121	((rc--))
122fi
123
124zerorules
125send 1600
126if [ "$(countrule -c 1)" -ne 0 ]; then
127	echo "FAIL: no rule should match pattern past largest --to"
128	showrules
129	((rc--))
130fi
131
132[ $rc -eq 0 ] && echo "PASS: string match tests"
133exit $rc
134