1# 2# SPDX-License-Identifier: BSD-2-Clause 3# 4# Copyright (c) 2017 Kristof Provost <kp@FreeBSD.org> 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 31atf_test_case "too_many_fragments" "cleanup" 32 33too_many_fragments_head() 34{ 35 atf_set descr 'IPv4 fragment limitation test' 36 atf_set require.user root 37} 38 39too_many_fragments_body() 40{ 41 pft_init 42 43 epair=$(vnet_mkepair) 44 vnet_mkjail alcatraz ${epair}a 45 46 ifconfig ${epair}b inet 192.0.2.1/24 up 47 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 48 49 ifconfig ${epair}b mtu 200 50 jexec alcatraz ifconfig ${epair}a mtu 200 51 52 jexec alcatraz pfctl -e 53 pft_set_rules alcatraz \ 54 "set reassemble yes" \ 55 "pass keep state" 56 57 # So we know pf is limiting things 58 jexec alcatraz sysctl net.inet.ip.maxfragsperpacket=1024 59 60 # Sanity check 61 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 62 63 # We can ping with < 64 fragments 64 atf_check -s exit:0 -o ignore ping -c 1 -s 800 192.0.2.2 65 66 # Too many fragments should fail 67 atf_check -s exit:2 -o ignore ping -c 1 -s 20000 192.0.2.2 68} 69 70too_many_fragments_cleanup() 71{ 72 pft_cleanup 73} 74 75atf_test_case "v6" "cleanup" 76v6_head() 77{ 78 atf_set descr 'IPv6 fragmentation test' 79 atf_set require.user root 80 atf_set require.progs scapy 81} 82 83v6_body() 84{ 85 pft_init 86 87 epair_send=$(vnet_mkepair) 88 epair_link=$(vnet_mkepair) 89 90 vnet_mkjail alcatraz ${epair_send}b ${epair_link}a 91 vnet_mkjail singsing ${epair_link}b 92 93 ifconfig ${epair_send}a inet6 2001:db8:42::1/64 no_dad up 94 95 jexec alcatraz ifconfig ${epair_send}b inet6 2001:db8:42::2/64 no_dad up 96 jexec alcatraz ifconfig ${epair_link}a inet6 2001:db8:43::2/64 no_dad up 97 jexec alcatraz sysctl net.inet6.ip6.forwarding=1 98 99 jexec singsing ifconfig ${epair_link}b inet6 2001:db8:43::3/64 no_dad up 100 jexec singsing route add -6 2001:db8:42::/64 2001:db8:43::2 101 route add -6 2001:db8:43::/64 2001:db8:42::2 102 103 jexec alcatraz ifconfig ${epair_send}b inet6 -ifdisabled 104 jexec alcatraz ifconfig ${epair_link}a inet6 -ifdisabled 105 jexec singsing ifconfig ${epair_link}b inet6 -ifdisabled 106 ifconfig ${epair_send}a inet6 -ifdisabled 107 108 ifconfig ${epair_send}a 109 jexec alcatraz ifconfig ${epair_send}b 110 lladdr=$(jexec alcatraz ifconfig ${epair_send}b | awk '/ scopeid / { print($2); }' | cut -f 1 -d %) 111 112 jexec alcatraz pfctl -e 113 pft_set_rules alcatraz \ 114 "set reassemble yes" \ 115 "pass keep state" \ 116 "block in" \ 117 "pass in inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ 118 "pass in inet6 proto icmp6 icmp6-type { echoreq, echorep }" \ 119 "set skip on lo" 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_test_case "reassemble_slowpath" "cleanup" 429reassemble_slowpath_head() 430{ 431 atf_set descr 'Test reassembly on the slow path' 432 atf_set require.user root 433} 434 435reassemble_slowpath_body() 436{ 437 if ! sysctl -q kern.features.ipsec >/dev/null ; then 438 atf_skip "This test requires ipsec" 439 fi 440 441 setup_router_server_ipv4 442 443 # Now define an ipsec policy so we end up taking the slow path. 444 # We don't actually need the traffic to go through ipsec, we just don't 445 # want to go through ip_tryforward(). 446 echo "flush; 447 spdflush; 448 spdadd 203.0.113.1/32 203.0.113.2/32 any -P out ipsec esp/transport//require; 449 add 203.0.113.1 203.0.113.2 esp 0x1001 -E aes-gcm-16 \"12345678901234567890\";" \ 450 | jexec router setkey -c 451 452 # Sanity check. 453 ping_server_check_reply exit:0 --ping-type=icmp 454 455 # Enable packet reassembly with clearing of the no-df flag. 456 pft_set_rules router \ 457 "scrub in on ${epair_tester}b fragment no reassemble" \ 458 "scrub on ${epair_server}a fragment reassemble" \ 459 "pass" 460 461 # Ensure that the packet makes it through the slow path 462 atf_check -s exit:0 -o ignore \ 463 ping -c 1 -s 2000 198.51.100.2 464} 465 466reassemble_slowpath_cleanup() 467{ 468 pft_cleanup 469} 470 471atf_test_case "dummynet" "cleanup" 472dummynet_head() 473{ 474 atf_set descr 'dummynet + reassembly test' 475 atf_set require.user root 476} 477 478dummynet_body() 479{ 480 pft_init 481 dummynet_init 482 483 epair=$(vnet_mkepair) 484 vnet_mkjail alcatraz ${epair}a 485 486 ifconfig ${epair}b inet 192.0.2.1/24 up 487 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 488 489 # Sanity check 490 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 491 492 jexec alcatraz dnctl pipe 1 config bw 600Byte/s 493 jexec alcatraz dnctl pipe 2 config bw 700Byte/s 494 495 jexec alcatraz pfctl -e 496 pft_set_rules alcatraz \ 497 "set reassemble yes" \ 498 "block" \ 499 "pass inet proto icmp all icmp-type echoreq dnpipe (1, 2)" 500 501 atf_check -s exit:0 -o ignore ping -s 2000 -c 1 192.0.2.2 502} 503 504dummynet_cleanup() 505{ 506 pft_cleanup 507} 508 509atf_test_case "dummynet_nat" "cleanup" 510dummynet_nat_head() 511{ 512 atf_set descr 'Test dummynet on NATed fragmented traffic' 513 atf_set require.user root 514} 515 516dummynet_nat_body() 517{ 518 pft_init 519 dummynet_init 520 521 epair_one=$(vnet_mkepair) 522 ifconfig ${epair_one}a 192.0.2.1/24 up 523 524 epair_two=$(vnet_mkepair) 525 526 vnet_mkjail alcatraz ${epair_one}b ${epair_two}a 527 jexec alcatraz ifconfig ${epair_one}b 192.0.2.2/24 up 528 jexec alcatraz ifconfig ${epair_two}a 198.51.100.1/24 up 529 jexec alcatraz sysctl net.inet.ip.forwarding=1 530 531 vnet_mkjail singsing ${epair_two}b 532 jexec singsing ifconfig ${epair_two}b 198.51.100.2/24 up 533 jexec singsing route add default 198.51.100.1 534 535 route add 198.51.100.0/24 192.0.2.2 536 537 jexec alcatraz dnctl pipe 1 config bw 1600Byte/s 538 jexec alcatraz dnctl pipe 2 config bw 1700Byte/s 539 540 jexec alcatraz pfctl -e 541 pft_set_rules alcatraz \ 542 "set reassemble yes" \ 543 "nat on ${epair_two}a from 192.0.2.0/24 -> (${epair_two}a)" \ 544 "block in" \ 545 "pass in inet proto icmp all icmp-type echoreq dnpipe (1, 2)" 546 547 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 548 atf_check -s exit:0 -o ignore ping -c 1 -s 2000 198.51.100.2 549} 550 551dummynet_nat_cleanup() 552{ 553 pft_cleanup 554} 555 556atf_test_case "dummynet_fragmented" "cleanup" 557dummynet_fragmented_head() 558{ 559 atf_set descr 'Test dummynet on NATed fragmented traffic' 560 atf_set require.user root 561} 562 563dummynet_fragmented_body() 564{ 565 pft_init 566 dummynet_init 567 568 # No test for IPv6. IPv6 fragment reassembly can't be disabled. 569 setup_router_dummy_ipv4 570 571 jexec router dnctl pipe 1 config delay 1 572 573 pft_set_rules router \ 574 "set reassemble no" \ 575 "block" \ 576 "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ 577 "pass in on ${epair_tester}b inet proto udp dnpipe (1, 1)" \ 578 "pass out on ${epair_server}a inet proto udp" \ 579 580 ping_dummy_check_request exit:0 --ping-type=udp --send-length=10000 --send-frag-length=1280 581 582 rules=$(mktemp) || exit 1 583 jexec router pfctl -qvsr > $rules 584 585 # Count that fragmented packets have hit the rule only once and that 586 # they have not created states. There is no stateful firewall support 587 # for fragmented packets. 588 grep -A2 'pass in on epair0b inet proto udp all keep state dnpipe(1, 1)' $rules | 589 grep -qE 'Packets: 8\s+Bytes: 10168\s+States: 0\s+' || 590 atf_fail "Fragmented packets not counted correctly" 591} 592 593dummynet_fragmented_cleanup() 594{ 595 pft_cleanup 596} 597 598atf_init_test_cases() 599{ 600 atf_add_test_case "too_many_fragments" 601 atf_add_test_case "v6" 602 atf_add_test_case "mtu_diff" 603 atf_add_test_case "overreplace" 604 atf_add_test_case "overindex" 605 atf_add_test_case "overlimit" 606 atf_add_test_case "reassemble" 607 atf_add_test_case "no_df" 608 atf_add_test_case "reassemble_slowpath" 609 atf_add_test_case "dummynet" 610 atf_add_test_case "dummynet_nat" 611 atf_add_test_case "dummynet_fragmented" 612} 613