1# 2# SPDX-License-Identifier: BSD-2-Clause 3# 4# Copyright (c) 2021 Modirum MDPay 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 29common_dir=$(atf_get_srcdir)/../common 30 31syncookie_state() 32{ 33 jail=$1 34 35 jexec $jail pfctl -si -v | grep -A 2 '^Syncookies' | grep active \ 36 | awk '{ print($2); }' 37} 38 39atf_test_case "basic" "cleanup" 40basic_head() 41{ 42 atf_set descr 'Basic syncookie test' 43 atf_set require.user root 44} 45 46basic_body() 47{ 48 pft_init 49 50 epair=$(vnet_mkepair) 51 52 vnet_mkjail alcatraz ${epair}b 53 jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up 54 jexec alcatraz /usr/sbin/inetd -p inetd-alcatraz.pid \ 55 $(atf_get_srcdir)/echo_inetd.conf 56 57 ifconfig ${epair}a 192.0.2.2/24 up 58 59 jexec alcatraz pfctl -e 60 pft_set_rules alcatraz \ 61 "set syncookies always" \ 62 "pass in" \ 63 "pass out" 64 65 # Sanity check 66 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1 67 68 reply=$(echo foo | nc -N -w 5 192.0.2.1 7) 69 if [ "${reply}" != "foo" ]; 70 then 71 atf_fail "Failed to connect to syncookie protected echo daemon" 72 fi 73 74 75 # Check that status shows syncookies as being active 76 active=$(syncookie_state alcatraz) 77 if [ "$active" != "active" ]; 78 then 79 atf_fail "syncookies not active" 80 fi 81} 82 83basic_cleanup() 84{ 85 rm -f inetd-alcatraz.pid 86 pft_cleanup 87} 88 89atf_test_case "forward" "cleanup" 90forward_head() 91{ 92 atf_set descr 'Syncookies for forwarded hosts' 93 atf_set require.user root 94} 95 96forward_body() 97{ 98 pft_init 99 100 epair_in=$(vnet_mkepair) 101 epair_out=$(vnet_mkepair) 102 103 vnet_mkjail fwd ${epair_in}b ${epair_out}a 104 vnet_mkjail srv ${epair_out}b 105 106 jexec fwd ifconfig ${epair_in}b 192.0.2.1/24 up 107 jexec fwd ifconfig ${epair_out}a 198.51.100.1/24 up 108 jexec fwd sysctl net.inet.ip.forwarding=1 109 110 jexec srv ifconfig ${epair_out}b 198.51.100.2/24 up 111 jexec srv route add default 198.51.100.1 112 jexec srv /usr/sbin/inetd -p inetd-alcatraz.pid \ 113 $(atf_get_srcdir)/echo_inetd.conf 114 115 ifconfig ${epair_in}a 192.0.2.2/24 up 116 route add -net 198.51.100.0/24 192.0.2.1 117 118 jexec fwd pfctl -e 119 pft_set_rules fwd \ 120 "set syncookies always" \ 121 "pass in" \ 122 "pass out" 123 124 # Sanity check 125 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 126 127 reply=$(echo foo | nc -N -w 5 198.51.100.2 7) 128 if [ "${reply}" != "foo" ]; 129 then 130 atf_fail "Failed to connect to syncookie protected echo daemon" 131 fi 132} 133 134forward_cleanup() 135{ 136 rm -f inetd-alcatraz.pid 137 pft_cleanup 138} 139 140atf_test_case "nostate" "cleanup" 141nostate_head() 142{ 143 atf_set descr 'Ensure that we do not create until SYN|ACK' 144 atf_set require.user root 145 atf_set require.progs scapy 146} 147 148nostate_body() 149{ 150 pft_init 151 152 epair=$(vnet_mkepair) 153 ifconfig ${epair}a 192.0.2.2/24 up 154 155 vnet_mkjail alcatraz ${epair}b 156 jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up 157 158 jexec alcatraz pfctl -e 159 pft_set_rules alcatraz \ 160 "set syncookies always" \ 161 "pass in" \ 162 "pass out" 163 164 # Sanity check 165 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1 166 167 # Now syn flood to create many states 168 ${common_dir}/pft_synflood.py \ 169 --sendif ${epair}a \ 170 --to 192.0.2.2 \ 171 --count 20 172 173 states=$(jexec alcatraz pfctl -ss | grep tcp) 174 if [ -n "$states" ]; 175 then 176 echo "$states" 177 atf_fail "Found unexpected state" 178 fi 179} 180 181nostate_cleanup() 182{ 183 pft_cleanup 184} 185 186atf_test_case "adaptive" "cleanup" 187adaptive_head() 188{ 189 atf_set descr 'Adaptive mode test' 190 atf_set require.user root 191 atf_set require.progs scapy 192} 193 194adaptive_body() 195{ 196 pft_init 197 198 epair=$(vnet_mkepair) 199 ifconfig ${epair}a 192.0.2.2/24 up 200 201 vnet_mkjail alcatraz ${epair}b 202 jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up 203 204 jexec alcatraz pfctl -e 205 pft_set_rules alcatraz \ 206 "set limit states 100" \ 207 "set syncookies adaptive (start 10%%, end 5%%)" \ 208 "pass in" \ 209 "pass out" 210 211 # Sanity check 212 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1 213 214 # Check that status shows syncookies as being inactive 215 active=$(syncookie_state alcatraz) 216 if [ "$active" != "inactive" ]; 217 then 218 atf_fail "syncookies active when they should not be" 219 fi 220 221 # Now syn flood to create many states 222 ${common_dir}/pft_synflood.py \ 223 --sendif ${epair}a \ 224 --to 192.0.2.2 \ 225 --count 100 226 227 # Check that status shows syncookies as being active 228 active=$(syncookie_state alcatraz) 229 if [ "$active" != "active" ]; 230 then 231 atf_fail "syncookies not active" 232 fi 233 234 # Adaptive mode should kick in and stop us from creating more than 235 # about 10 states 236 states=$(jexec alcatraz pfctl -ss | grep tcp | wc -l) 237 if [ "$states" -gt 20 ]; 238 then 239 echo "$states" 240 atf_fail "Found unexpected states" 241 fi 242} 243 244adaptive_cleanup() 245{ 246 pft_cleanup 247} 248 249atf_test_case "limits" "cleanup" 250limits_head() 251{ 252 atf_set descr 'Ensure limit calculation works for low or high state limits' 253 atf_set require.user root 254} 255 256limits_body() 257{ 258 pft_init 259 260 vnet_mkjail alcatraz 261 262 jexec alcatraz pfctl -e 263 pft_set_rules alcatraz \ 264 "set limit states 1" \ 265 "set syncookies adaptive (start 10%%, end 5%%)" \ 266 "pass in" \ 267 "pass out" 268 269 pft_set_rules alcatraz \ 270 "set limit states 326000000" \ 271 "set syncookies adaptive (start 10%%, end 5%%)" \ 272 "pass in" \ 273 "pass out" 274} 275 276limits_cleanup() 277{ 278 pft_cleanup 279} 280 281atf_test_case "port_reuse" "cleanup" 282port_reuse_head() 283{ 284 atf_set descr 'Test rapid port re-use' 285 atf_set require.user root 286} 287 288port_reuse_body() 289{ 290 pft_init 291 292 epair=$(vnet_mkepair) 293 294 vnet_mkjail alcatraz ${epair}b 295 vnet_mkjail singsing 296 jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up 297 jexec alcatraz /usr/sbin/inetd -p ${HOME}/inetd-alcatraz.pid \ 298 $(atf_get_srcdir)/echo_inetd.conf 299 300 ifconfig ${epair}a 192.0.2.2/24 up 301 302 jexec alcatraz pfctl -e 303 jexec alcatraz pfctl -x loud 304 pft_set_rules alcatraz \ 305 "set syncookies always" \ 306 "pass in" \ 307 "pass out" 308 309 # Sanity check 310 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1 311 312 reply=$(echo foo | nc -p 1234 -N -w 5 192.0.2.1 7) 313 if [ "${reply}" != "foo" ]; 314 then 315 atf_fail "Failed to connect to syncookie protected echo daemon" 316 fi 317 318 # We can't re-use the source IP/port combo quickly enough, so we're 319 # going to play a really dirty trick, and move our interface to a new 320 # jail, and do it from there. 321 ifconfig ${epair}a vnet singsing 322 jexec singsing ifconfig ${epair}a 192.0.2.2/24 up 323 atf_check -s exit:0 -o ignore jexec singsing ping -c 1 192.0.2.1 324 325 reply=$(echo bar | jexec singsing nc -p 1234 -N -w 5 192.0.2.1 7) 326 if [ "${reply}" != "bar" ]; 327 then 328 atf_fail "Failed to connect to syncookie protected echo daemon (2)" 329 fi 330} 331 332port_reuse_cleanup() 333{ 334 pft_cleanup 335} 336 337atf_init_test_cases() 338{ 339 atf_add_test_case "basic" 340 atf_add_test_case "forward" 341 atf_add_test_case "nostate" 342 atf_add_test_case "adaptive" 343 atf_add_test_case "limits" 344 atf_add_test_case "port_reuse" 345} 346