xref: /freebsd/tests/sys/netpfil/pf/pflow.sh (revision 63a5fe834354dc9249388e0805e6ea68dc9f02c7)
1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2023 Rubicon Communications, LLC (Netgate)
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26
27. $(atf_get_srcdir)/utils.subr
28
29atf_test_case "basic" "cleanup"
30basic_head()
31{
32	atf_set descr 'Basic pflow test'
33	atf_set require.user root
34}
35
36basic_body()
37{
38	pflow_init
39
40	epair=$(vnet_mkepair)
41	ifconfig ${epair}a 192.0.2.2/24 up
42
43	vnet_mkjail alcatraz ${epair}b
44	jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
45
46	# Sanity check
47	atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
48
49	pflow=$(jexec alcatraz pflowctl -c)
50
51	# Reject invalid flow destinations
52	atf_check -s exit:1 -e ignore \
53	    jexec alcatraz pflowctl -s ${pflow} dst 256.0.0.1:4000
54	atf_check -s exit:1 -e ignore \
55	    jexec alcatraz pflowctl -s ${pflow} dst 192.0.0.2:400000
56
57	# A valid destination is accepted
58	atf_check -s exit:0 \
59	    jexec alcatraz pflowctl -s ${pflow} dst 192.0.2.2:4000
60
61	# Reject invalid version numbers
62	atf_check -s exit:1 -e ignore \
63	    jexec alcatraz pflowctl -s ${pflow} proto 9
64
65	# Valid version passes
66	atf_check -s exit:0 \
67	    jexec alcatraz pflowctl -s ${pflow} proto 5
68	atf_check -s exit:0 \
69	    jexec alcatraz pflowctl -s ${pflow} proto 10
70
71	# We can change the observation domain
72	atf_check -s exit:0 \
73	    jexec alcatraz pflowctl -s ${pflow} domain 13
74	atf_check -s exit:0 -o match:".*domain 13.*" \
75	    jexec alcatraz pflowctl -l
76}
77
78basic_cleanup()
79{
80	pft_cleanup
81}
82
83atf_test_case "state_defaults" "cleanup"
84state_defaults_head()
85{
86	atf_set descr 'Test set state-defaults pflow'
87	atf_set require.user root
88	atf_set require.progs scapy
89}
90
91state_defaults_body()
92{
93	pflow_init
94
95	epair=$(vnet_mkepair)
96	ifconfig ${epair}a 192.0.2.2/24 up
97
98	vnet_mkjail alcatraz ${epair}b
99	jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
100
101	# Sanity check
102	atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
103
104	jexec alcatraz pfctl -e
105	pft_set_rules alcatraz \
106		"pass"
107
108	pflow=$(jexec alcatraz pflowctl -c)
109	jexec alcatraz pflowctl -s ${pflow} dst 192.0.2.2:2055
110
111	# No flow data is generated because no states are marked for it.
112	ping -c 1 192.0.2.1
113	# Flush states to force pflow creation
114	jexec alcatraz pfctl -Fstates
115
116	atf_check -o match:"No data" \
117	    $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}a --port 2055
118
119	# Expect pflow output with state-defaults pflow
120	pft_set_rules alcatraz \
121		"set state-defaults pflow" \
122		"pass"
123
124	ping -c 1 192.0.2.1
125
126	# We default to version 5
127	atf_check -o match:".*v=5.*" \
128	    $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}a --port 2055
129
130	# Switch to version 10
131	jexec alcatraz pflowctl -s ${pflow} proto 10
132
133	ping -c 1 192.0.2.1
134
135	atf_check -o match:".*v=10.*" \
136	    $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}a --port 2055
137}
138
139state_defaults_cleanup()
140{
141	pft_cleanup
142}
143
144atf_test_case "v6" "cleanup"
145v6_head()
146{
147	atf_set descr 'Test pflow over IPv6'
148	atf_set require.user root
149	atf_set require.progs scapy
150}
151
152v6_body()
153{
154	pflow_init
155
156	epair=$(vnet_mkepair)
157	ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
158
159	vnet_mkjail alcatraz ${epair}b
160	jexec alcatraz ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
161
162	# Sanity check
163	atf_check -s exit:0 -o ignore \
164	    ping -6 -c 1 2001:db8::1
165
166	pflow=$(jexec alcatraz pflowctl -c )
167	# Note proto 10, because there's no IPv6 information in v5
168	jexec alcatraz pflowctl -s ${pflow} dst [2001:db8::2]:2055 proto 10
169
170	jexec alcatraz pfctl -e
171	pft_set_rules alcatraz \
172		"set state-defaults pflow" \
173		"pass"
174
175	ping -6 -c 1 2001:db8::1
176
177	atf_check -o match:".*v=10,IPv6,proto=58,src=2001:db8::2,dst=2001:db8::1.*" \
178	    $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}a --port 2055
179}
180
181v6_cleanup()
182{
183	pft_cleanup
184}
185
186atf_test_case "nat" "cleanup"
187nat_head()
188{
189	atf_set descr 'Test pflow export for NAT44'
190	atf_set require.user root
191	atf_set require.progs scapy
192}
193
194nat_body()
195{
196	pflow_init
197
198	epair=$(vnet_mkepair)
199	epair_srv=$(vnet_mkepair)
200
201	vnet_mkjail srv ${epair_srv}a
202	vnet_mkjail rtr ${epair_srv}b ${epair}a
203
204	ifconfig ${epair}b 192.0.2.2/24 up
205
206	jexec srv ifconfig ${epair_srv}a 198.51.100.2/24 up
207	jexec srv route add default 198.51.100.1
208
209	jexec rtr ifconfig ${epair_srv}b 198.51.100.1/24 up
210	jexec rtr ifconfig ${epair}a 192.0.2.1/24 up
211	jexec rtr sysctl net.inet.ip.forwarding=1
212
213	route add -net 198.51.100.0/24 192.0.2.1
214
215	jexec rtr pfctl -e
216	pft_set_rules rtr \
217		"set state-defaults pflow" \
218		"nat pass on ${epair_srv}b inet from 192.0.2.0/24 to any -> (${epair_srv}b)" \
219		"pass"
220
221	pflow=$(jexec rtr pflowctl -c)
222	jexec rtr pflowctl -s ${pflow} dst 192.0.2.2:2055 proto 10
223
224	# Sanity check
225	atf_check -s exit:0 -o ignore \
226	    ping -c 1 198.51.100.2
227
228	atf_check -o match:".*v=10,NAT=4,proto=1,src=192.0.2.2-198.51.100.1.*" \
229	    $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}b --port 2055
230}
231
232nat_cleanup()
233{
234	pft_cleanup
235}
236
237atf_test_case "rule" "cleanup"
238rule_head()
239{
240	atf_set descr 'Test per-rule pflow option'
241	atf_set require.user root
242	atf_set require.progs scapy
243}
244
245rule_body()
246{
247	pflow_init
248
249	epair=$(vnet_mkepair)
250	ifconfig ${epair}a 192.0.2.2/24 up
251	ifconfig ${epair}a alias 192.0.2.3/24 up
252
253	vnet_mkjail alcatraz ${epair}b
254	jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
255
256	# Sanity check
257	atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
258
259	jexec alcatraz pfctl -e
260	pft_set_rules alcatraz \
261		"pass in from 192.0.2.2 keep state (pflow)" \
262		"pass in from 192.0.2.3 keep state"
263
264	pflow=$(jexec alcatraz pflowctl -c)
265	jexec alcatraz pflowctl -s ${pflow} dst 192.0.2.2:2055
266
267	# No flow is generated if we ping from 192.0.2.3
268	ping -c 1 -S 192.0.2.3 192.0.2.1
269
270	atf_check -o match:"No data" \
271	    $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}a --port 2055
272
273	# But there is one if we ping from 192.0.2.2
274	ping -c 1 -S 192.0.2.2 192.0.2.1
275
276	atf_check -o match:".*v=5.*" \
277	    $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}a --port 2055
278}
279
280rule_cleanup()
281{
282	pft_cleanup
283}
284
285atf_test_case "max_entries" "cleanup"
286max_entries_head()
287{
288	atf_set descr 'Test that we can only create X pflow senders'
289	atf_set require.user root
290}
291
292max_entries_body()
293{
294	pflow_init
295
296	vnet_mkjail alcatraz
297
298	for i in `seq 1 128`
299	do
300		atf_check -s exit:0 -o ignore \
301		    jexec alcatraz pflowctl -c
302	done
303
304	# We cannot create the 129th pflow sender
305	atf_check -s exit:1 -o ignore -e ignore \
306	    jexec alcatraz pflowctl -c
307
308	jexec alcatraz pflowctl -l
309}
310
311max_entries_cleanup()
312{
313	pft_cleanup
314}
315
316atf_test_case "obs_dom" "cleanup"
317obs_dom_head()
318{
319	atf_set descr 'Test configuring observation domain values'
320	atf_set require.user root
321}
322
323obs_dom_body()
324{
325	pflow_init
326
327	vnet_mkjail alcatraz
328
329	pflow=$(jexec alcatraz pflowctl -c)
330	jexec alcatraz pflowctl -s ${pflow} domain 2300000000
331	atf_check -o match:".*domain 2300000000.*" -s exit:0 \
332	    jexec alcatraz pflowctl -l
333}
334
335obs_dom_cleanup()
336{
337	pft_cleanup
338}
339
340atf_init_test_cases()
341{
342	atf_add_test_case "basic"
343	atf_add_test_case "state_defaults"
344	atf_add_test_case "v6"
345	atf_add_test_case "nat"
346	atf_add_test_case "rule"
347	atf_add_test_case "max_entries"
348	atf_add_test_case "obs_dom"
349}
350