xref: /freebsd/tests/sys/netpfil/pf/mbuf.sh (revision 8829d4cb09d39801d3b6bcf8ab8c6b72dd757636)
1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
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
29dummymbuf_init()
30{
31	if ! kldstat -q -m dummymbuf; then
32		atf_skip "This test requires dummymbuf"
33	fi
34}
35
36atf_test_case "inet_in_mbuf_len" "cleanup"
37inet_in_mbuf_len_head()
38{
39	atf_set descr 'Test that pf can handle inbound with the first mbuf with m_len < sizeof(struct ip)'
40	atf_set require.user root
41}
42inet_in_mbuf_len_body()
43{
44	pft_init
45	dummymbuf_init
46
47	epair=$(vnet_mkepair)
48	ifconfig ${epair}a 192.0.2.1/24 up
49
50	# Set up a simple jail with one interface
51	vnet_mkjail alcatraz ${epair}b
52	jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
53
54	# Sanity check
55	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
56
57	# Should be denied
58	jexec alcatraz pfctl -e
59	pft_set_rules alcatraz \
60		"block"
61	atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2
62
63	# Should be allowed by from/to addresses
64	pft_set_rules alcatraz \
65		"block" \
66		"pass in from 192.0.2.1 to 192.0.2.2"
67	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
68
69	# Should still work for m_len=0
70	jexec alcatraz pfilctl link -i dummymbuf:inet inet
71	jexec alcatraz sysctl net.dummymbuf.rules="inet in ${epair}b pull-head 0;"
72	atf_check_equal "0" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
73	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
74	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
75
76	# m_len=1
77	jexec alcatraz sysctl net.dummymbuf.rules="inet in ${epair}b pull-head 1;"
78	jexec alcatraz sysctl net.dummymbuf.hits=0
79	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
80	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
81
82	# m_len=19
83	# provided IPv4 basic header is 20 bytes long, it should impact the dst addr
84	jexec alcatraz sysctl net.dummymbuf.rules="inet in ${epair}b pull-head 19;"
85	jexec alcatraz sysctl net.dummymbuf.hits=0
86	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
87	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
88}
89inet_in_mbuf_len_cleanup()
90{
91	pft_cleanup
92}
93
94atf_test_case "inet6_in_mbuf_len" "cleanup"
95inet6_in_mbuf_len_head()
96{
97	atf_set descr 'Test that pf can handle inbound with the first mbuf with m_len < sizeof(struct ip6_hdr)'
98	atf_set require.user root
99}
100inet6_in_mbuf_len_body()
101{
102	pft_init
103	dummymbuf_init
104
105	epair=$(vnet_mkepair)
106	ifconfig ${epair}a inet6 2001:db8::1/64 up no_dad
107
108	# Set up a simple jail with one interface
109	vnet_mkjail alcatraz ${epair}b
110	jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 up no_dad
111
112	# Sanity check
113	atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
114
115	# Should be denied
116	jexec alcatraz pfctl -e
117	pft_set_rules alcatraz \
118		"block" \
119		"pass quick inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }"
120	atf_check -s not-exit:0 -o ignore ping -c1 -t1 2001:db8::2
121
122	# Avoid redundant ICMPv6 packets to avoid false positives during
123	# counting of net.dummymbuf.hits.
124	ndp -i ${epair}a -- -nud
125	jexec alcatraz ndp -i ${epair}b -- -nud
126
127	# Should be allowed by from/to addresses
128	pft_set_rules alcatraz \
129		"block" \
130		"pass quick inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
131		"pass in inet6 from 2001:db8::1 to 2001:db8::2"
132	atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
133
134	# Should still work for m_len=0
135	jexec alcatraz pfilctl link -i dummymbuf:inet6 inet6
136	jexec alcatraz sysctl net.dummymbuf.rules="inet6 in ${epair}b pull-head 0;"
137	atf_check_equal "0" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
138	atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
139	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
140
141	# m_len=1
142	jexec alcatraz sysctl net.dummymbuf.rules="inet6 in ${epair}b pull-head 1;"
143	jexec alcatraz sysctl net.dummymbuf.hits=0
144	atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
145	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
146
147	# m_len=39
148	# provided IPv6 basic header is 40 bytes long, it should impact the dst addr
149	jexec alcatraz sysctl net.dummymbuf.rules="inet6 in ${epair}b pull-head 39;"
150	jexec alcatraz sysctl net.dummymbuf.hits=0
151	atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
152	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
153}
154inet6_in_mbuf_len_cleanup()
155{
156	pft_cleanup
157}
158
159atf_test_case "ethernet_in_mbuf_len" "cleanup"
160ethernet_in_mbuf_len_head()
161{
162	atf_set descr 'Test that pf can handle inbound with the first mbuf with m_len < sizeof(struct ether_header)'
163	atf_set require.user root
164}
165ethernet_in_mbuf_len_body()
166{
167	pft_init
168	dummymbuf_init
169
170	epair=$(vnet_mkepair)
171	epair_a_mac=$(ifconfig ${epair}a ether | awk '/ether/ { print $2; }')
172	ifconfig ${epair}a 192.0.2.1/24 up
173
174	# Set up a simple jail with one interface
175	vnet_mkjail alcatraz ${epair}b
176	jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
177	epair_b_mac=$(jexec alcatraz ifconfig ${epair}b ether | awk '/ether/ { print $2; }')
178
179	# Sanity check
180	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
181
182	# Should be denied
183	jexec alcatraz pfctl -e
184	pft_set_rules alcatraz \
185		"ether block" \
186		"pass"
187	atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2
188
189	# Should be allowed by from/to addresses
190	echo $epair_a_mac
191	echo $epair_b_mac
192	pft_set_rules alcatraz \
193		"ether block" \
194		"ether pass in  from ${epair_a_mac} to ${epair_b_mac}" \
195		"ether pass out from ${epair_b_mac} to ${epair_a_mac}" \
196		"pass"
197	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
198
199	# Should still work for m_len=0
200	jexec alcatraz pfilctl link -i dummymbuf:ethernet ethernet
201	jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 0;"
202	atf_check_equal "0" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
203	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
204	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
205
206	# m_len=1
207	jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 1;"
208	jexec alcatraz sysctl net.dummymbuf.hits=0
209	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
210	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
211
212	# m_len=11
213	# for the simplest L2 Ethernet frame it should impact src field
214	jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 11;"
215	jexec alcatraz sysctl net.dummymbuf.hits=0
216	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
217	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
218
219	# m_len=13
220	# provided L2 Ethernet simplest header is 14 bytes long, it should impact ethertype field
221	jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 13;"
222	jexec alcatraz sysctl net.dummymbuf.hits=0
223	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
224	atf_check_equal "1" "$(jexec alcatraz sysctl -n net.dummymbuf.hits)"
225}
226ethernet_in_mbuf_len_cleanup()
227{
228	pft_cleanup
229}
230
231atf_init_test_cases()
232{
233	atf_add_test_case "inet_in_mbuf_len"
234	atf_add_test_case "inet6_in_mbuf_len"
235	atf_add_test_case "ethernet_in_mbuf_len"
236}
237