xref: /freebsd/tests/sys/netpfil/pf/pflog.sh (revision 40faf87894ff67ffdf8126fce9bb438ddf61a26f)
1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2023 Rubicon Communications, LLC (Netgate)
5# Copyright (c) 2024 Deciso B.V.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27
28. $(atf_get_srcdir)/utils.subr
29
30common_dir=$(atf_get_srcdir)/../common
31
32atf_test_case "malformed" "cleanup"
33malformed_head()
34{
35	atf_set descr 'Test that we do not log malformed packets as passing'
36	atf_set require.user root
37	atf_set require.progs scapy
38}
39
40malformed_body()
41{
42	pflog_init
43
44	epair=$(vnet_mkepair)
45
46	vnet_mkjail srv ${epair}b
47	jexec srv ifconfig ${epair}b 192.0.2.1/24 up
48
49	vnet_mkjail cl ${epair}a
50	jexec cl ifconfig ${epair}a 192.0.2.2/24 up
51
52	jexec cl pfctl -e
53	jexec cl ifconfig pflog0 up
54	pft_set_rules cl \
55		"pass log keep state"
56
57	# Not required, but the 'pf: dropping packet with ip options' kernel log can
58	# help when debugging the test.
59	jexec cl pfctl -x loud
60
61	jexec cl tcpdump -n -e -ttt --immediate-mode -l -U -i pflog0 >> pflog.txt &
62	sleep 1 # Wait for tcpdump to start
63
64	# Sanity check
65	atf_check -s exit:0 -o ignore \
66	    jexec srv ping -c 1 192.0.2.2
67
68	jexec srv ${common_dir}/pft_ping.py  \
69	    --sendif ${epair}b \
70	    --to 192.0.2.2 \
71	    --send-nop \
72	    --recvif ${epair}b
73
74	atf_check -o match:".*rule 0/8\(ip-option\): block in on ${epair}a: 192.0.2.1 > 192.0.2.2: ICMP echo request.*" \
75	    cat pflog.txt
76}
77
78malformed_cleanup()
79{
80	pft_cleanup
81}
82
83atf_test_case "matches" "cleanup"
84matches_head()
85{
86	atf_set descr 'Test the pflog matches keyword'
87	atf_set require.user root
88}
89
90matches_body()
91{
92	pflog_init
93
94	epair=$(vnet_mkepair)
95
96	vnet_mkjail alcatraz ${epair}a
97	jexec alcatraz ifconfig ${epair}a 192.0.2.1/24 up
98
99	ifconfig ${epair}b 192.0.2.2/24 up
100
101	# Sanity check
102	atf_check -s exit:0 -o ignore \
103	    ping -c 1 192.0.2.1
104
105	jexec alcatraz pfctl -e
106	jexec alcatraz ifconfig pflog0 up
107	pft_set_rules alcatraz \
108		"match log(matches) inet proto icmp" \
109		"match log(matches) inet from 192.0.2.2" \
110		"pass"
111
112	jexec alcatraz tcpdump -n -e -ttt --immediate-mode -l -U -i pflog0 >> ${PWD}/pflog.txt &
113	sleep 1 # Wait for tcpdump to start
114
115	atf_check -s exit:0 -o ignore \
116	    ping -c 1 192.0.2.1
117
118	echo "Rules"
119	jexec alcatraz pfctl -sr -vv
120	echo "States"
121	jexec alcatraz pfctl -ss -vv
122	echo "Log"
123	cat ${PWD}/pflog.txt
124
125	atf_check -o match:".*rule 0/0\(match\): match in on ${epair}a: 192.0.2.2 > 192.0.2.1: ICMP echo request.*" \
126	    cat pflog.txt
127	atf_check -o match:".*rule 1/0\(match\): match in on ${epair}a: 192.0.2.2 > 192.0.2.1: ICMP echo request.*" \
128	    cat pflog.txt
129}
130
131matches_cleanup()
132{
133	pft_cleanup
134}
135
136atf_test_case "state_max" "cleanup"
137state_max_head()
138{
139	atf_set descr 'Ensure that drops due to state limits are logged'
140	atf_set require.user root
141}
142
143state_max_body()
144{
145	pflog_init
146
147	epair=$(vnet_mkepair)
148
149	vnet_mkjail alcatraz ${epair}a
150	jexec alcatraz ifconfig ${epair}a 192.0.2.1/24 up
151
152	ifconfig ${epair}b 192.0.2.2/24 up
153
154	# Sanity check
155	atf_check -s exit:0 -o ignore \
156	    ping -c 1 192.0.2.1
157
158	jexec alcatraz pfctl -e
159	jexec alcatraz ifconfig pflog0 up
160	pft_set_rules alcatraz "pass log inet keep state (max 1)"
161
162	jexec alcatraz tcpdump -n -e -ttt --immediate-mode -l -U -i pflog0 >> ${PWD}/pflog.txt &
163	sleep 1 # Wait for tcpdump to start
164
165	atf_check -s exit:0 -o ignore \
166	    ping -c 1 192.0.2.1
167
168	atf_check -s exit:2 -o ignore \
169	    ping -c 1 192.0.2.1
170
171	echo "Rules"
172	jexec alcatraz pfctl -sr -vv
173	echo "States"
174	jexec alcatraz pfctl -ss -vv
175	echo "Log"
176	cat ${PWD}/pflog.txt
177
178	# First ping passes.
179	atf_check -o match:".*rule 0/0\(match\): pass in on ${epair}a: 192.0.2.2 > 192.0.2.1: ICMP echo request.*" \
180	    cat pflog.txt
181
182	# Second ping is blocked due to the state limit.
183	atf_check -o match:".*rule 0/0\(match\): block in on ${epair}a: 192.0.2.2 > 192.0.2.1: ICMP echo request.*" \
184	    cat pflog.txt
185
186	# At most three lines should be written: one for the first ping, and
187	# two for the second: one for the initial pass through the ruleset, and
188	# then a drop because of the state limit.  Ideally only the drop would
189	# be logged; if this is fixed, the count will be 2 instead of 3.
190	atf_check -o match:3 grep -c . pflog.txt
191}
192
193state_max_cleanup()
194{
195	pft_cleanup
196}
197
198atf_test_case "unspecified_v4" "cleanup"
199unspecified_v4_head()
200{
201	atf_set descr 'Ensure that packets to the unspecified address are visible to pfil hooks'
202	atf_set require.user root
203}
204
205unspecified_v4_body()
206{
207	pflog_init
208
209	vnet_mkjail alcatraz
210	jexec alcatraz ifconfig lo0 inet 127.0.0.1
211	jexec alcatraz route add default 127.0.0.1
212
213	jexec alcatraz pfctl -e
214	jexec alcatraz ifconfig pflog0 up
215	pft_set_rules alcatraz "block log on lo0 to 0.0.0.0"
216
217	jexec alcatraz tcpdump -n -e -ttt --immediate-mode -l -U -i pflog0 >> pflog.txt &
218	sleep 1 # Wait for tcpdump to start
219
220	atf_check -s not-exit:0 -o ignore -e ignore \
221	    jexec alcatraz ping -S 127.0.0.1 -c 1 0.0.0.0
222
223	atf_check -o match:".*: block out on lo0: 127.0.0.1 > 0.0.0.0: ICMP echo request,.*" \
224	    cat pflog.txt
225}
226
227unspecified_v4_cleanup()
228{
229	pft_cleanup
230}
231
232atf_test_case "unspecified_v6" "cleanup"
233unspecified_v6_head()
234{
235	atf_set descr 'Ensure that packets to the unspecified address are visible to pfil hooks'
236	atf_set require.user root
237}
238
239unspecified_v6_body()
240{
241	pflog_init
242
243	vnet_mkjail alcatraz
244	jexec alcatraz ifconfig lo0 up
245	jexec alcatraz route -6 add ::0 ::1
246
247	jexec alcatraz pfctl -e
248	jexec alcatraz ifconfig pflog0 up
249	pft_set_rules alcatraz "block log on lo0 to ::0"
250
251	jexec alcatraz tcpdump -n -e -ttt --immediate-mode -l -U -i pflog0 >> pflog.txt &
252	sleep 1 # Wait for tcpdump to start
253
254	atf_check -s not-exit:0 -o ignore -e ignore \
255	    jexec alcatraz ping -6 -S ::1 -c 1 ::0
256
257	cat pflog.txt
258	atf_check -o match:".*: block out on lo0: ::1 > ::: ICMP6, echo request,.*" \
259	    cat pflog.txt
260}
261
262unspecified_v6_cleanup()
263{
264	pft_cleanup
265}
266
267atf_init_test_cases()
268{
269	atf_add_test_case "malformed"
270	atf_add_test_case "matches"
271	atf_add_test_case "state_max"
272	atf_add_test_case "unspecified_v4"
273	atf_add_test_case "unspecified_v6"
274}
275