1# $FreeBSD$ 2# 3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4# 5# Copyright (c) 2017 Kristof Provost <kp@FreeBSD.org> 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 32atf_test_case "too_many_fragments" "cleanup" 33 34too_many_fragments_head() 35{ 36 atf_set descr 'IPv4 fragment limitation test' 37 atf_set require.user root 38} 39 40too_many_fragments_body() 41{ 42 pft_init 43 44 epair=$(vnet_mkepair) 45 vnet_mkjail alcatraz ${epair}a 46 47 ifconfig ${epair}b inet 192.0.2.1/24 up 48 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 49 50 ifconfig ${epair}b mtu 200 51 jexec alcatraz ifconfig ${epair}a mtu 200 52 53 jexec alcatraz pfctl -e 54 pft_set_rules alcatraz \ 55 "set reassemble yes" \ 56 "pass keep state" 57 58 # So we know pf is limiting things 59 jexec alcatraz sysctl net.inet.ip.maxfragsperpacket=1024 60 61 # Sanity check 62 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 63 64 # We can ping with < 64 fragments 65 atf_check -s exit:0 -o ignore ping -c 1 -s 800 192.0.2.2 66 67 # Too many fragments should fail 68 atf_check -s exit:2 -o ignore ping -c 1 -s 20000 192.0.2.2 69} 70 71too_many_fragments_cleanup() 72{ 73 pft_cleanup 74} 75 76atf_test_case "v6" "cleanup" 77v6_head() 78{ 79 atf_set descr 'IPv6 fragmentation test' 80 atf_set require.user root 81 atf_set require.progs scapy 82} 83 84v6_body() 85{ 86 pft_init 87 88 epair_send=$(vnet_mkepair) 89 epair_link=$(vnet_mkepair) 90 91 vnet_mkjail alcatraz ${epair_send}b ${epair_link}a 92 vnet_mkjail singsing ${epair_link}b 93 94 ifconfig ${epair_send}a inet6 2001:db8:42::1/64 no_dad up 95 96 jexec alcatraz ifconfig ${epair_send}b inet6 2001:db8:42::2/64 no_dad up 97 jexec alcatraz ifconfig ${epair_link}a inet6 2001:db8:43::2/64 no_dad up 98 jexec alcatraz sysctl net.inet6.ip6.forwarding=1 99 100 jexec singsing ifconfig ${epair_link}b inet6 2001:db8:43::3/64 no_dad up 101 jexec singsing route add -6 2001:db8:42::/64 2001:db8:43::2 102 route add -6 2001:db8:43::/64 2001:db8:42::2 103 104 jexec alcatraz ifconfig ${epair_send}b inet6 -ifdisabled 105 jexec alcatraz ifconfig ${epair_link}a inet6 -ifdisabled 106 jexec singsing ifconfig ${epair_link}b inet6 -ifdisabled 107 ifconfig ${epair_send}a inet6 -ifdisabled 108 109 ifconfig ${epair_send}a 110 jexec alcatraz ifconfig ${epair_send}b 111 lladdr=$(jexec alcatraz ifconfig ${epair_send}b | awk '/ scopeid / { print($2); }' | cut -f 1 -d %) 112 113 jexec alcatraz pfctl -e 114 pft_set_rules alcatraz \ 115 "set reassemble yes" \ 116 "pass keep state" \ 117 "block in" \ 118 "pass in inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ 119 "pass in inet6 proto icmp6 icmp6-type { echoreq, echorep }" 120 121 # Host test 122 atf_check -s exit:0 -o ignore \ 123 ping -6 -c 1 2001:db8:42::2 124 125 atf_check -s exit:0 -o ignore \ 126 ping -6 -c 1 -s 4500 2001:db8:42::2 127 128 atf_check -s exit:0 -o ignore\ 129 ping -6 -c 1 -b 70000 -s 65000 2001:db8:42::2 130 131 # Force an NDP lookup 132 ping -6 -c 1 ${lladdr}%${epair_send}a 133 134 atf_check -s exit:0 -o ignore\ 135 ping -6 -c 1 -b 70000 -s 65000 ${lladdr}%${epair_send}a 136 137 # Forwarding test 138 atf_check -s exit:0 -o ignore \ 139 ping -6 -c 1 2001:db8:43::3 140 141 atf_check -s exit:0 -o ignore \ 142 ping -6 -c 1 -s 4500 2001:db8:43::3 143 144 atf_check -s exit:0 -o ignore\ 145 ping -6 -c 1 -b 70000 -s 65000 2001:db8:43::3 146 147 $(atf_get_srcdir)/CVE-2019-5597.py \ 148 ${epair_send}a \ 149 2001:db8:42::1 \ 150 2001:db8:43::3 151} 152 153v6_cleanup() 154{ 155 pft_cleanup 156} 157 158atf_test_case "mtu_diff" "cleanup" 159mtu_diff_head() 160{ 161 atf_set descr 'Test reassembly across different MTUs, PR #255432' 162 atf_set require.user root 163} 164 165mtu_diff_body() 166{ 167 pft_init 168 169 epair_small=$(vnet_mkepair) 170 epair_large=$(vnet_mkepair) 171 172 vnet_mkjail first ${epair_small}b ${epair_large}a 173 vnet_mkjail second ${epair_large}b 174 175 ifconfig ${epair_small}a 192.0.2.1/25 up 176 jexec first ifconfig ${epair_small}b 192.0.2.2/25 up 177 178 jexec first sysctl net.inet.ip.forwarding=1 179 jexec first ifconfig ${epair_large}a 192.0.2.130/25 up 180 jexec first ifconfig ${epair_large}a mtu 9000 181 jexec second ifconfig ${epair_large}b 192.0.2.131/25 up 182 jexec second ifconfig ${epair_large}b mtu 9000 183 jexec second route add default 192.0.2.130 184 185 route add 192.0.2.128/25 192.0.2.2 186 187 jexec first pfctl -e 188 pft_set_rules first \ 189 "set reassemble yes" \ 190 "pass keep state" 191 192 # Sanity checks 193 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 194 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.130 195 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.131 196 197 # Large packet that'll get reassembled and sent out in one on the large 198 # epair 199 atf_check -s exit:0 -o ignore ping -c 1 -s 8000 192.0.2.131 200} 201 202mtu_diff_cleanup() 203{ 204 pft_cleanup 205} 206 207frag_common() 208{ 209 name=$1 210 211 pft_init 212 213 epair=$(vnet_mkepair) 214 vnet_mkjail alcatraz ${epair}a 215 216 ifconfig ${epair}b inet 192.0.2.1/24 up 217 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 218 219 jexec alcatraz pfctl -e 220 pft_set_rules alcatraz \ 221 "set reassemble yes" \ 222 "pass keep state" 223 224 # Sanity check 225 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 226 227 atf_check -s exit:0 -o ignore $(atf_get_srcdir)/frag-${1}.py \ 228 --to 192.0.2.2 \ 229 --fromaddr 192.0.2.1 \ 230 --sendif ${epair}b \ 231 --recvif ${epair}b 232} 233 234atf_test_case "overreplace" "cleanup" 235overreplace_head() 236{ 237 atf_set descr 'ping fragment that overlaps fragment at index boundary and replace it' 238 atf_set require.user root 239 atf_set require.progs scapy 240} 241 242overreplace_body() 243{ 244 frag_common overreplace 245} 246 247overreplace_cleanup() 248{ 249 pft_cleanup 250} 251 252atf_test_case "overindex" "cleanup" 253overindex_head() 254{ 255 atf_set descr 'ping fragment that overlaps the first fragment at index boundary' 256 atf_set require.user root 257 atf_set require.progs scapy 258} 259 260overindex_body() 261{ 262 frag_common overindex 263} 264 265overindex_cleanup() 266{ 267 pft_cleanup 268} 269 270atf_test_case "overlimit" "cleanup" 271overlimit_head() 272{ 273 atf_set descr 'ping fragment at index boundary that cannot be requeued' 274 atf_set require.user root 275 atf_set require.progs scapy 276} 277 278overlimit_body() 279{ 280 frag_common overlimit 281} 282 283overlimit_cleanup() 284{ 285 pft_cleanup 286} 287 288atf_test_case "reassemble" "cleanup" 289reassemble_head() 290{ 291 atf_set descr 'Test reassembly' 292 atf_set require.user root 293} 294 295reassemble_body() 296{ 297 pft_init 298 299 epair=$(vnet_mkepair) 300 vnet_mkjail alcatraz ${epair}a 301 302 ifconfig ${epair}b inet 192.0.2.1/24 up 303 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 304 305 # Sanity check 306 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 307 308 jexec alcatraz pfctl -e 309 pft_set_rules alcatraz \ 310 "pass out" \ 311 "block in" \ 312 "pass in inet proto icmp all icmp-type echoreq" 313 314 # Single fragment passes 315 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 316 317 # But a fragmented ping does not 318 atf_check -s exit:2 -o ignore ping -c 1 -s 2000 192.0.2.2 319 320 pft_set_rules alcatraz \ 321 "set reassemble yes" \ 322 "pass out" \ 323 "block in" \ 324 "pass in inet proto icmp all icmp-type echoreq" 325 326 # Both single packet & fragmented pass when we scrub 327 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 328 atf_check -s exit:0 -o ignore ping -c 1 -s 2000 192.0.2.2 329} 330 331reassemble_cleanup() 332{ 333 pft_cleanup 334} 335 336atf_test_case "no_df" "cleanup" 337no_df_head() 338{ 339 atf_set descr 'Test removing of DF flag' 340 atf_set require.user root 341} 342 343no_df_body() 344{ 345 setup_router_server_ipv4 346 347 ifconfig ${epair_tester}a mtu 9000 348 jexec router ifconfig ${epair_tester}b mtu 9000 349 jexec router ifconfig ${epair_server}a mtu 1500 350 jexec server ifconfig ${epair_server}b mtu 1500 351 352 # Sanity check. 353 ping_server_check_reply exit:0 --ping-type=icmp 354 355 pft_set_rules router \ 356 "set reassemble no" \ 357 "pass out" \ 358 "block in" \ 359 "pass in inet proto icmp all icmp-type echoreq" 360 361 # Ping with normal, fragmentable packets. 362 ping_server_check_reply exit:1 --ping-type=icmp --send-length=2000 363 364 pft_set_rules router \ 365 "set reassemble yes" \ 366 "pass out" \ 367 "block in" \ 368 "pass in inet proto icmp all icmp-type echoreq" 369 370 # Ping with normal, fragmentable packets. 371 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 372 373 # Ping with non-fragmentable packets. 374 ping_server_check_reply exit:1 --ping-type=icmp --send-length=2000 --send-flags DF 375 376 pft_set_rules router \ 377 "set reassemble yes no-df" \ 378 "pass out" \ 379 "block in" \ 380 "pass in inet proto icmp all icmp-type echoreq" 381 382 # Ping with non-fragmentable packets again. 383 # This time pf will strip the DF flag. 384 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 --send-flags DF 385} 386no_df_cleanup() 387{ 388 pft_cleanup 389} 390 391atf_test_case "no_df" "cleanup" 392no_df_head() 393{ 394 atf_set descr 'Test removing of DF flag' 395 atf_set require.user root 396} 397 398no_df_body() 399{ 400 setup_router_server_ipv4 401 402 # Tester can send long packets which will get fragmented by the router. 403 # Replies from server will come in fragments which might get 404 # reassembled resulting in a long reply packet sent back to tester. 405 ifconfig ${epair_tester}a mtu 9000 406 jexec router ifconfig ${epair_tester}b mtu 9000 407 jexec router ifconfig ${epair_server}a mtu 1500 408 jexec server ifconfig ${epair_server}b mtu 1500 409 410 # Sanity check. 411 ping_server_check_reply exit:0 --ping-type=icmp 412 413 # Enable packet reassembly with clearing of the no-df flag. 414 pft_set_rules router \ 415 "scrub all fragment reassemble no-df" \ 416 "block" \ 417 "pass inet proto icmp all icmp-type echoreq" 418 # Ping with non-fragmentable packets. 419 # pf will strip the DF flag resulting in fragmentation and packets 420 # getting properly forwarded. 421 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 --send-flags DF 422} 423no_df_cleanup() 424{ 425 pft_cleanup 426} 427 428atf_init_test_cases() 429{ 430 atf_add_test_case "too_many_fragments" 431 atf_add_test_case "v6" 432 atf_add_test_case "mtu_diff" 433 atf_add_test_case "overreplace" 434 atf_add_test_case "overindex" 435 atf_add_test_case "overlimit" 436 atf_add_test_case "reassemble" 437 atf_add_test_case "no_df" 438} 439