1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
. $(atf_get_srcdir)/utils.subr
dummymbuf_init()
{
if ! kldstat -q -m dummymbuf; then
atf_skip "This test requires dummymbuf"
fi
}
atf_test_case "inet_in_mbuf_len" "cleanup"
inet_in_mbuf_len_head()
{
atf_set descr 'Test that pf can handle inbound with the first mbuf with m_len < sizeof(struct ip)'
atf_set require.user root
}
inet_in_mbuf_len_body()
{
pft_init
dummymbuf_init
epair=$(vnet_mkepair)
ifconfig ${epair}a 192.0.2.1/24 up
# Set up a simple jail with one interface
vnet_mkjail alcatraz ${epair}b
jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
# Sanity check
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
# Should be denied
jexec alcatraz pfctl -e
pft_set_rules alcatraz \
"block"
atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2
# Should be allowed by from/to addresses
pft_set_rules alcatraz \
"block" \
"pass in from 192.0.2.1 to 192.0.2.2"
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
# Should still work for m_len=0
jexec alcatraz pfilctl link -i dummymbuf:inet inet
jexec alcatraz sysctl net.dummymbuf.rules="inet in ${epair}b pull-head 0;"
atf_check_equal '0' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
# m_len=1
jexec alcatraz sysctl net.dummymbuf.rules="inet in ${epair}b pull-head 1;"
jexec alcatraz sysctl net.dummymbuf.hits=0
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
# m_len=19
# provided IPv4 basic header is 20 bytes long, it should impact the dst addr
jexec alcatraz sysctl net.dummymbuf.rules="inet in ${epair}b pull-head 19;"
jexec alcatraz sysctl net.dummymbuf.hits=0
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
}
inet_in_mbuf_len_cleanup()
{
pft_cleanup
}
atf_test_case "inet6_in_mbuf_len" "cleanup"
inet6_in_mbuf_len_head()
{
atf_set descr 'Test that pf can handle inbound with the first mbuf with m_len < sizeof(struct ip6_hdr)'
atf_set require.user root
}
inet6_in_mbuf_len_body()
{
pft_init
dummymbuf_init
epair=$(vnet_mkepair)
ifconfig ${epair}a inet6 2001:db8::1/64 up no_dad
# Ensure we don't unintentionally send MLD packets to alcatraz
pfctl -e
echo "block
pass out inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv, echoreq, echorep }
" | pfctl -g -f -
# Set up a simple jail with one interface
vnet_mkjail alcatraz ${epair}b
jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 up no_dad
# Sanity check
atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
# Should be denied
jexec alcatraz pfctl -e
pft_set_rules alcatraz \
"block" \
"pass quick inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }"
atf_check -s not-exit:0 -o ignore ping -c1 -t1 2001:db8::2
# Avoid redundant ICMPv6 packets to avoid false positives during
# counting of net.dummymbuf.hits.
ndp -i ${epair}a -- -nud
jexec alcatraz ndp -i ${epair}b -- -nud
# Should be allowed by from/to addresses
pft_set_rules alcatraz \
"block" \
"pass quick inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
"pass in inet6 from 2001:db8::1 to 2001:db8::2"
atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
# Should still work for m_len=0
jexec alcatraz pfilctl link -i dummymbuf:inet6 inet6
jexec alcatraz sysctl net.dummymbuf.rules="inet6 in ${epair}b pull-head 0;"
atf_check_equal '0' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
# m_len=1
jexec alcatraz sysctl net.dummymbuf.rules="inet6 in ${epair}b pull-head 1;"
jexec alcatraz sysctl net.dummymbuf.hits=0
atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
# m_len=39
# provided IPv6 basic header is 40 bytes long, it should impact the dst addr
jexec alcatraz sysctl net.dummymbuf.rules="inet6 in ${epair}b pull-head 39;"
jexec alcatraz sysctl net.dummymbuf.hits=0
atf_check -s exit:0 -o ignore ping -c1 2001:db8::2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
}
inet6_in_mbuf_len_cleanup()
{
pft_cleanup
}
atf_test_case "ethernet_in_mbuf_len" "cleanup"
ethernet_in_mbuf_len_head()
{
atf_set descr 'Test that pf can handle inbound with the first mbuf with m_len < sizeof(struct ether_header)'
atf_set require.user root
}
ethernet_in_mbuf_len_body()
{
pft_init
dummymbuf_init
epair=$(vnet_mkepair)
epair_a_mac=$(ifconfig ${epair}a ether | awk '/ether/ { print $2; }')
ifconfig ${epair}a 192.0.2.1/24 up
# Set up a simple jail with one interface
vnet_mkjail alcatraz ${epair}b
jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
epair_b_mac=$(jexec alcatraz ifconfig ${epair}b ether | awk '/ether/ { print $2; }')
# Sanity check
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
# Should be denied
jexec alcatraz pfctl -e
pft_set_rules alcatraz \
"ether block" \
"pass"
atf_check -s not-exit:0 -o ignore ping -c1 -t1 192.0.2.2
# Should be allowed by from/to addresses
echo $epair_a_mac
echo $epair_b_mac
pft_set_rules alcatraz \
"ether block" \
"ether pass in from ${epair_a_mac} to ${epair_b_mac}" \
"ether pass out from ${epair_b_mac} to ${epair_a_mac}" \
"pass"
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
# Should still work for m_len=0
jexec alcatraz pfilctl link -i dummymbuf:ethernet ethernet
jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 0;"
atf_check_equal '0' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
# m_len=1
jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 1;"
jexec alcatraz sysctl net.dummymbuf.hits=0
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
# m_len=11
# for the simplest L2 Ethernet frame it should impact src field
jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 11;"
jexec alcatraz sysctl net.dummymbuf.hits=0
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
# m_len=13
# provided L2 Ethernet simplest header is 14 bytes long, it should impact ethertype field
jexec alcatraz sysctl net.dummymbuf.rules="ethernet in ${epair}b pull-head 13;"
jexec alcatraz sysctl net.dummymbuf.hits=0
atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
atf_check_equal '1' '$(jexec alcatraz sysctl -n net.dummymbuf.hits)'
}
ethernet_in_mbuf_len_cleanup()
{
pft_cleanup
}
atf_init_test_cases()
{
atf_add_test_case "inet_in_mbuf_len"
atf_add_test_case "inet6_in_mbuf_len"
atf_add_test_case "ethernet_in_mbuf_len"
}
|