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