xref: /freebsd/tests/sys/netpfil/pf/mbuf.sh (revision 24e4dcf4ba5e9dedcf89efd358ea3e1fe5867020)
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	# Ensure we don't unintentionally send MLD packets to alcatraz
109	pfctl -e
110	echo "block
111	pass out inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv, echoreq, echorep }
112	" | pfctl -g -f -
113
114	# Set up a simple jail with one interface
115	vnet_mkjail alcatraz ${epair}b
116	jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 up no_dad
117
118	# Sanity check
119	atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
120
121	# Should be denied
122	jexec alcatraz pfctl -e
123	pft_set_rules alcatraz \
124		"block" \
125		"pass quick inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }"
126	atf_check -s not-exit:0 -o ignore ping -c1 -t1 2001:db8::2
127
128	# Avoid redundant ICMPv6 packets to avoid false positives during
129	# counting of net.dummymbuf.hits.
130	ndp -i ${epair}a -- -nud
131	jexec alcatraz ndp -i ${epair}b -- -nud
132
133	# Should be allowed by from/to addresses
134	pft_set_rules alcatraz \
135		"block" \
136		"pass quick inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
137		"pass in inet6 from 2001:db8::1 to 2001:db8::2"
138	atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
139
140	# Should still work for m_len=0
141	jexec alcatraz pfilctl link -i dummymbuf:inet6 inet6
142	jexec alcatraz sysctl net.dummymbuf.rules="inet6 in ${epair}b pull-head 0;"
143	atf_check_equal '0' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
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=1
148	jexec alcatraz sysctl net.dummymbuf.rules="inet6 in ${epair}b pull-head 1;"
149	jexec alcatraz sysctl net.dummymbuf.hits=0
150	atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
151	atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
152
153	# m_len=39
154	# provided IPv6 basic header is 40 bytes long, it should impact the dst addr
155	jexec alcatraz sysctl net.dummymbuf.rules="inet6 in ${epair}b pull-head 39;"
156	jexec alcatraz sysctl net.dummymbuf.hits=0
157	atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
158	atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
159}
160inet6_in_mbuf_len_cleanup()
161{
162	pft_cleanup
163}
164
165atf_test_case "ethernet_in_mbuf_len" "cleanup"
166ethernet_in_mbuf_len_head()
167{
168	atf_set descr 'Test that pf can handle inbound with the first mbuf with m_len < sizeof(struct ether_header)'
169	atf_set require.user root
170}
171ethernet_in_mbuf_len_body()
172{
173	pft_init
174	dummymbuf_init
175
176	epair=$(vnet_mkepair)
177	epair_a_mac=$(ifconfig ${epair}a ether | awk '/ether/ { print $2; }')
178	ifconfig ${epair}a 192.0.2.1/24 up
179
180	# Set up a simple jail with one interface
181	vnet_mkjail alcatraz ${epair}b
182	jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
183	epair_b_mac=$(jexec alcatraz ifconfig ${epair}b ether | awk '/ether/ { print $2; }')
184
185	# Sanity check
186	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
187
188	# Should be denied
189	jexec alcatraz pfctl -e
190	pft_set_rules alcatraz \
191		"ether block" \
192		"pass"
193	atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2
194
195	# Should be allowed by from/to addresses
196	echo $epair_a_mac
197	echo $epair_b_mac
198	pft_set_rules alcatraz \
199		"ether block" \
200		"ether pass in  from ${epair_a_mac} to ${epair_b_mac}" \
201		"ether pass out from ${epair_b_mac} to ${epair_a_mac}" \
202		"pass"
203	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
204
205	# Should still work for m_len=0
206	jexec alcatraz pfilctl link -i dummymbuf:ethernet ethernet
207	jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 0;"
208	atf_check_equal '0' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
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=1
213	jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 1;"
214	jexec alcatraz sysctl net.dummymbuf.hits=0
215	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
216	atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
217
218	# m_len=11
219	# for the simplest L2 Ethernet frame it should impact src field
220	jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 11;"
221	jexec alcatraz sysctl net.dummymbuf.hits=0
222	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
223	atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
224
225	# m_len=13
226	# provided L2 Ethernet simplest header is 14 bytes long, it should impact ethertype field
227	jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 13;"
228	jexec alcatraz sysctl net.dummymbuf.hits=0
229	atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
230	atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
231}
232ethernet_in_mbuf_len_cleanup()
233{
234	pft_cleanup
235}
236
237atf_init_test_cases()
238{
239	atf_add_test_case "inet_in_mbuf_len"
240	atf_add_test_case "inet6_in_mbuf_len"
241	atf_add_test_case "ethernet_in_mbuf_len"
242}
243