1# $FreeBSD$ 2# 3# SPDX-License-Identifier: BSD-2-Clause 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 "set skip on lo" 121 122 # Host test 123 atf_check -s exit:0 -o ignore \ 124 ping -6 -c 1 2001:db8:42::2 125 126 atf_check -s exit:0 -o ignore \ 127 ping -6 -c 1 -s 4500 2001:db8:42::2 128 129 atf_check -s exit:0 -o ignore\ 130 ping -6 -c 1 -b 70000 -s 65000 2001:db8:42::2 131 132 # Force an NDP lookup 133 ping -6 -c 1 ${lladdr}%${epair_send}a 134 135 atf_check -s exit:0 -o ignore\ 136 ping -6 -c 1 -b 70000 -s 65000 ${lladdr}%${epair_send}a 137 138 # Forwarding test 139 atf_check -s exit:0 -o ignore \ 140 ping -6 -c 1 2001:db8:43::3 141 142 atf_check -s exit:0 -o ignore \ 143 ping -6 -c 1 -s 4500 2001:db8:43::3 144 145 atf_check -s exit:0 -o ignore\ 146 ping -6 -c 1 -b 70000 -s 65000 2001:db8:43::3 147 148 $(atf_get_srcdir)/CVE-2019-5597.py \ 149 ${epair_send}a \ 150 2001:db8:42::1 \ 151 2001:db8:43::3 152} 153 154v6_cleanup() 155{ 156 pft_cleanup 157} 158 159atf_test_case "mtu_diff" "cleanup" 160mtu_diff_head() 161{ 162 atf_set descr 'Test reassembly across different MTUs, PR #255432' 163 atf_set require.user root 164} 165 166mtu_diff_body() 167{ 168 pft_init 169 170 epair_small=$(vnet_mkepair) 171 epair_large=$(vnet_mkepair) 172 173 vnet_mkjail first ${epair_small}b ${epair_large}a 174 vnet_mkjail second ${epair_large}b 175 176 ifconfig ${epair_small}a 192.0.2.1/25 up 177 jexec first ifconfig ${epair_small}b 192.0.2.2/25 up 178 179 jexec first sysctl net.inet.ip.forwarding=1 180 jexec first ifconfig ${epair_large}a 192.0.2.130/25 up 181 jexec first ifconfig ${epair_large}a mtu 9000 182 jexec second ifconfig ${epair_large}b 192.0.2.131/25 up 183 jexec second ifconfig ${epair_large}b mtu 9000 184 jexec second route add default 192.0.2.130 185 186 route add 192.0.2.128/25 192.0.2.2 187 188 jexec first pfctl -e 189 pft_set_rules first \ 190 "set reassemble yes" \ 191 "pass keep state" 192 193 # Sanity checks 194 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 195 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.130 196 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.131 197 198 # Large packet that'll get reassembled and sent out in one on the large 199 # epair 200 atf_check -s exit:0 -o ignore ping -c 1 -s 8000 192.0.2.131 201} 202 203mtu_diff_cleanup() 204{ 205 pft_cleanup 206} 207 208frag_common() 209{ 210 name=$1 211 212 pft_init 213 214 epair=$(vnet_mkepair) 215 vnet_mkjail alcatraz ${epair}a 216 217 ifconfig ${epair}b inet 192.0.2.1/24 up 218 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 219 220 jexec alcatraz pfctl -e 221 pft_set_rules alcatraz \ 222 "set reassemble yes" \ 223 "pass keep state" 224 225 # Sanity check 226 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 227 228 atf_check -s exit:0 -o ignore $(atf_get_srcdir)/frag-${1}.py \ 229 --to 192.0.2.2 \ 230 --fromaddr 192.0.2.1 \ 231 --sendif ${epair}b \ 232 --recvif ${epair}b 233} 234 235atf_test_case "overreplace" "cleanup" 236overreplace_head() 237{ 238 atf_set descr 'ping fragment that overlaps fragment at index boundary and replace it' 239 atf_set require.user root 240 atf_set require.progs scapy 241} 242 243overreplace_body() 244{ 245 frag_common overreplace 246} 247 248overreplace_cleanup() 249{ 250 pft_cleanup 251} 252 253atf_test_case "overindex" "cleanup" 254overindex_head() 255{ 256 atf_set descr 'ping fragment that overlaps the first fragment at index boundary' 257 atf_set require.user root 258 atf_set require.progs scapy 259} 260 261overindex_body() 262{ 263 frag_common overindex 264} 265 266overindex_cleanup() 267{ 268 pft_cleanup 269} 270 271atf_test_case "overlimit" "cleanup" 272overlimit_head() 273{ 274 atf_set descr 'ping fragment at index boundary that cannot be requeued' 275 atf_set require.user root 276 atf_set require.progs scapy 277} 278 279overlimit_body() 280{ 281 frag_common overlimit 282} 283 284overlimit_cleanup() 285{ 286 pft_cleanup 287} 288 289atf_test_case "reassemble" "cleanup" 290reassemble_head() 291{ 292 atf_set descr 'Test reassembly' 293 atf_set require.user root 294} 295 296reassemble_body() 297{ 298 pft_init 299 300 epair=$(vnet_mkepair) 301 vnet_mkjail alcatraz ${epair}a 302 303 ifconfig ${epair}b inet 192.0.2.1/24 up 304 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 305 306 # Sanity check 307 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 308 309 jexec alcatraz pfctl -e 310 pft_set_rules alcatraz \ 311 "pass out" \ 312 "block in" \ 313 "pass in inet proto icmp all icmp-type echoreq" 314 315 # Single fragment passes 316 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 317 318 # But a fragmented ping does not 319 atf_check -s exit:2 -o ignore ping -c 1 -s 2000 192.0.2.2 320 321 pft_set_rules alcatraz \ 322 "set reassemble yes" \ 323 "pass out" \ 324 "block in" \ 325 "pass in inet proto icmp all icmp-type echoreq" 326 327 # Both single packet & fragmented pass when we scrub 328 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 329 atf_check -s exit:0 -o ignore ping -c 1 -s 2000 192.0.2.2 330} 331 332reassemble_cleanup() 333{ 334 pft_cleanup 335} 336 337atf_test_case "no_df" "cleanup" 338no_df_head() 339{ 340 atf_set descr 'Test removing of DF flag' 341 atf_set require.user root 342} 343 344no_df_body() 345{ 346 setup_router_server_ipv4 347 348 ifconfig ${epair_tester}a mtu 9000 349 jexec router ifconfig ${epair_tester}b mtu 9000 350 jexec router ifconfig ${epair_server}a mtu 1500 351 jexec server ifconfig ${epair_server}b mtu 1500 352 353 # Sanity check. 354 ping_server_check_reply exit:0 --ping-type=icmp 355 356 pft_set_rules router \ 357 "set reassemble no" \ 358 "pass out" \ 359 "block in" \ 360 "pass in inet proto icmp all icmp-type echoreq" 361 362 # Ping with normal, fragmentable packets. 363 ping_server_check_reply exit:1 --ping-type=icmp --send-length=2000 364 365 pft_set_rules router \ 366 "set reassemble yes" \ 367 "pass out" \ 368 "block in" \ 369 "pass in inet proto icmp all icmp-type echoreq" 370 371 # Ping with normal, fragmentable packets. 372 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 373 374 # Ping with non-fragmentable packets. 375 ping_server_check_reply exit:1 --ping-type=icmp --send-length=2000 --send-flags DF 376 377 pft_set_rules router \ 378 "set reassemble yes no-df" \ 379 "pass out" \ 380 "block in" \ 381 "pass in inet proto icmp all icmp-type echoreq" 382 383 # Ping with non-fragmentable packets again. 384 # This time pf will strip the DF flag. 385 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 --send-flags DF 386} 387no_df_cleanup() 388{ 389 pft_cleanup 390} 391 392atf_test_case "no_df" "cleanup" 393no_df_head() 394{ 395 atf_set descr 'Test removing of DF flag' 396 atf_set require.user root 397} 398 399no_df_body() 400{ 401 setup_router_server_ipv4 402 403 # Tester can send long packets which will get fragmented by the router. 404 # Replies from server will come in fragments which might get 405 # reassembled resulting in a long reply packet sent back to tester. 406 ifconfig ${epair_tester}a mtu 9000 407 jexec router ifconfig ${epair_tester}b mtu 9000 408 jexec router ifconfig ${epair_server}a mtu 1500 409 jexec server ifconfig ${epair_server}b mtu 1500 410 411 # Sanity check. 412 ping_server_check_reply exit:0 --ping-type=icmp 413 414 # Enable packet reassembly with clearing of the no-df flag. 415 pft_set_rules router \ 416 "scrub all fragment reassemble no-df" \ 417 "block" \ 418 "pass inet proto icmp all icmp-type echoreq" 419 # Ping with non-fragmentable packets. 420 # pf will strip the DF flag resulting in fragmentation and packets 421 # getting properly forwarded. 422 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 --send-flags DF 423} 424no_df_cleanup() 425{ 426 pft_cleanup 427} 428 429atf_test_case "reassemble_slowpath" "cleanup" 430reassemble_slowpath_head() 431{ 432 atf_set descr 'Test reassembly on the slow path' 433 atf_set require.user root 434} 435 436reassemble_slowpath_body() 437{ 438 if ! sysctl -q kern.features.ipsec >/dev/null ; then 439 atf_skip "This test requires ipsec" 440 fi 441 442 setup_router_server_ipv4 443 444 # Now define an ipsec policy so we end up taking the slow path. 445 # We don't actually need the traffic to go through ipsec, we just don't 446 # want to go through ip_tryforward(). 447 echo "flush; 448 spdflush; 449 spdadd 203.0.113.1/32 203.0.113.2/32 any -P out ipsec esp/transport//require; 450 add 203.0.113.1 203.0.113.2 esp 0x1001 -E aes-gcm-16 \"12345678901234567890\";" \ 451 | jexec router setkey -c 452 453 # Sanity check. 454 ping_server_check_reply exit:0 --ping-type=icmp 455 456 # Enable packet reassembly with clearing of the no-df flag. 457 pft_set_rules router \ 458 "scrub in on ${epair_tester}b fragment no reassemble" \ 459 "scrub on ${epair_server}a fragment reassemble" \ 460 "pass" 461 462 # Ensure that the packet makes it through the slow path 463 atf_check -s exit:0 -o ignore \ 464 ping -c 1 -s 2000 198.51.100.2 465} 466 467reassemble_slowpath_cleanup() 468{ 469 pft_cleanup 470} 471 472atf_init_test_cases() 473{ 474 atf_add_test_case "too_many_fragments" 475 atf_add_test_case "v6" 476 atf_add_test_case "mtu_diff" 477 atf_add_test_case "overreplace" 478 atf_add_test_case "overindex" 479 atf_add_test_case "overlimit" 480 atf_add_test_case "reassemble" 481 atf_add_test_case "no_df" 482 atf_add_test_case "reassemble_slowpath" 483} 484