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 "v6_route_to" "cleanup" 159v6_route_to_head() 160{ 161 atf_set descr 'Test IPv6 reassembly combined with route-to' 162 atf_set require.user root 163} 164 165v6_route_to_body() 166{ 167 pft_init 168} 169 170v6_route_to_cleanup() 171{ 172 pft_cleanup 173 174 epair_send=$(vnet_mkepair) 175 epair_link=$(vnet_mkepair) 176 177 vnet_mkjail alcatraz ${epair_send}b ${epair_link}a 178 vnet_mkjail singsing ${epair_link}b 179 180 ifconfig ${epair_send}a inet6 2001:db8:42::1/64 no_dad up 181 182 jexec alcatraz ifconfig ${epair_send}b inet6 2001:db8:42::2/64 no_dad up 183 jexec alcatraz ifconfig ${epair_link}a inet6 2001:db8:43::2/64 no_dad up 184 jexec alcatraz sysctl net.inet6.ip6.forwarding=1 185 186 jexec singsing ifconfig ${epair_link}b inet6 2001:db8:43::3/64 no_dad up 187 jexec singsing route add -6 2001:db8:42::/64 2001:db8:43::2 188 route add -6 2001:db8:43::/64 2001:db8:42::2 189 190 jexec alcatraz ifconfig ${epair_send}b inet6 -ifdisabled 191 jexec alcatraz ifconfig ${epair_link}a inet6 -ifdisabled 192 jexec singsing ifconfig ${epair_link}b inet6 -ifdisabled 193 ifconfig ${epair_send}a inet6 -ifdisabled 194 195 jexec alcatraz pfctl -e 196 pft_set_rules alcatraz \ 197 "set reassemble yes" \ 198 "pass" \ 199 "pass in route-to (${epair_link}a 2001:db8:43::3) inet6 proto icmp6 from any to 2001:db8:43::3 keep state" 200 201 # Forwarding test 202 atf_check -s exit:0 -o ignore \ 203 ping -6 -c 1 2001:db8:43::3 204 205 atf_check -s exit:0 -o ignore \ 206 ping -6 -c 1 -s 4500 2001:db8:43::3 207 208 atf_check -s exit:0 -o ignore\ 209 ping -6 -c 1 -b 70000 -s 65000 2001:db8:43::3 210 211 # Now test this without fragmentation 212 pft_set_rules alcatraz \ 213 "set reassemble no" \ 214 "pass" \ 215 "pass in route-to (${epair_link}a 2001:db8:43::3) inet6 proto icmp6 from any to 2001:db8:43::3 keep state" 216 217 atf_check -s exit:0 -o ignore \ 218 ping -6 -c 1 2001:db8:43::3 219 220 atf_check -s exit:0 -o ignore \ 221 ping -6 -c 1 -s 4500 2001:db8:43::3 222 223 atf_check -s exit:0 -o ignore\ 224 ping -6 -c 1 -b 70000 -s 65000 2001:db8:43::3 225} 226 227atf_test_case "mtu_diff" "cleanup" 228mtu_diff_head() 229{ 230 atf_set descr 'Test reassembly across different MTUs, PR #255432' 231 atf_set require.user root 232} 233 234mtu_diff_body() 235{ 236 pft_init 237 238 epair_small=$(vnet_mkepair) 239 epair_large=$(vnet_mkepair) 240 241 vnet_mkjail first ${epair_small}b ${epair_large}a 242 vnet_mkjail second ${epair_large}b 243 244 ifconfig ${epair_small}a 192.0.2.1/25 up 245 jexec first ifconfig ${epair_small}b 192.0.2.2/25 up 246 247 jexec first sysctl net.inet.ip.forwarding=1 248 jexec first ifconfig ${epair_large}a 192.0.2.130/25 up 249 jexec first ifconfig ${epair_large}a mtu 9000 250 jexec second ifconfig ${epair_large}b 192.0.2.131/25 up 251 jexec second ifconfig ${epair_large}b mtu 9000 252 jexec second route add default 192.0.2.130 253 254 route add 192.0.2.128/25 192.0.2.2 255 256 jexec first pfctl -e 257 pft_set_rules first \ 258 "set reassemble yes" \ 259 "pass keep state" 260 261 # Sanity checks 262 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 263 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.130 264 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.131 265 266 # Large packet that'll get reassembled and sent out in one on the large 267 # epair 268 atf_check -s exit:0 -o ignore ping -c 1 -s 8000 192.0.2.131 269} 270 271mtu_diff_cleanup() 272{ 273 pft_cleanup 274} 275 276frag_common() 277{ 278 name=$1 279 280 pft_init 281 282 epair=$(vnet_mkepair) 283 vnet_mkjail alcatraz ${epair}a 284 285 ifconfig ${epair}b inet 192.0.2.1/24 up 286 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 287 288 jexec alcatraz pfctl -e 289 pft_set_rules alcatraz \ 290 "set reassemble yes" \ 291 "pass keep state" 292 293 # Sanity check 294 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 295 296 atf_check -s exit:0 -o ignore $(atf_get_srcdir)/frag-${1}.py \ 297 --to 192.0.2.2 \ 298 --fromaddr 192.0.2.1 \ 299 --sendif ${epair}b \ 300 --recvif ${epair}b 301} 302 303atf_test_case "overreplace" "cleanup" 304overreplace_head() 305{ 306 atf_set descr 'ping fragment that overlaps fragment at index boundary and replace it' 307 atf_set require.user root 308 atf_set require.progs scapy 309} 310 311overreplace_body() 312{ 313 frag_common overreplace 314} 315 316overreplace_cleanup() 317{ 318 pft_cleanup 319} 320 321atf_test_case "overindex" "cleanup" 322overindex_head() 323{ 324 atf_set descr 'ping fragment that overlaps the first fragment at index boundary' 325 atf_set require.user root 326 atf_set require.progs scapy 327} 328 329overindex_body() 330{ 331 frag_common overindex 332} 333 334overindex_cleanup() 335{ 336 pft_cleanup 337} 338 339atf_test_case "overlimit" "cleanup" 340overlimit_head() 341{ 342 atf_set descr 'ping fragment at index boundary that cannot be requeued' 343 atf_set require.user root 344 atf_set require.progs scapy 345} 346 347overlimit_body() 348{ 349 frag_common overlimit 350} 351 352overlimit_cleanup() 353{ 354 pft_cleanup 355} 356 357atf_test_case "reassemble" "cleanup" 358reassemble_head() 359{ 360 atf_set descr 'Test reassembly' 361 atf_set require.user root 362} 363 364reassemble_body() 365{ 366 pft_init 367 368 epair=$(vnet_mkepair) 369 vnet_mkjail alcatraz ${epair}a 370 371 ifconfig ${epair}b inet 192.0.2.1/24 up 372 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 373 374 # Sanity check 375 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 376 377 jexec alcatraz pfctl -e 378 pft_set_rules alcatraz \ 379 "pass out" \ 380 "block in" \ 381 "pass in inet proto icmp all icmp-type echoreq" 382 383 # Single fragment passes 384 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 385 386 # But a fragmented ping does not 387 atf_check -s exit:2 -o ignore ping -c 1 -s 2000 192.0.2.2 388 389 pft_set_rules alcatraz \ 390 "set reassemble yes" \ 391 "pass out" \ 392 "block in" \ 393 "pass in inet proto icmp all icmp-type echoreq" 394 395 # Both single packet & fragmented pass when we scrub 396 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 397 atf_check -s exit:0 -o ignore ping -c 1 -s 2000 192.0.2.2 398} 399 400reassemble_cleanup() 401{ 402 pft_cleanup 403} 404 405atf_test_case "no_df" "cleanup" 406no_df_head() 407{ 408 atf_set descr 'Test removing of DF flag' 409 atf_set require.user root 410} 411 412no_df_body() 413{ 414 setup_router_server_ipv4 415 416 # Tester can send long packets which will get fragmented by the router. 417 # Replies from server will come in fragments which might get 418 # reassembled resulting in a long reply packet sent back to tester. 419 ifconfig ${epair_tester}a mtu 9000 420 jexec router ifconfig ${epair_tester}b mtu 9000 421 jexec router ifconfig ${epair_server}a mtu 1500 422 jexec server ifconfig ${epair_server}b mtu 1500 423 424 # Sanity check. 425 ping_server_check_reply exit:0 --ping-type=icmp 426 427 # Enable packet reassembly with clearing of the no-df flag. 428 pft_set_rules router \ 429 "scrub all fragment reassemble no-df" \ 430 "block" \ 431 "pass inet proto icmp all icmp-type echoreq" 432 # Ping with non-fragmentable packets. 433 # pf will strip the DF flag resulting in fragmentation and packets 434 # getting properly forwarded. 435 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 --send-flags DF 436} 437 438no_df_cleanup() 439{ 440 pft_cleanup 441} 442 443atf_test_case "reassemble_slowpath" "cleanup" 444reassemble_slowpath_head() 445{ 446 atf_set descr 'Test reassembly on the slow path' 447 atf_set require.user root 448} 449 450reassemble_slowpath_body() 451{ 452 if ! sysctl -q kern.features.ipsec >/dev/null ; then 453 atf_skip "This test requires ipsec" 454 fi 455 456 setup_router_server_ipv4 457 458 # Now define an ipsec policy so we end up taking the slow path. 459 # We don't actually need the traffic to go through ipsec, we just don't 460 # want to go through ip_tryforward(). 461 echo "flush; 462 spdflush; 463 spdadd 203.0.113.1/32 203.0.113.2/32 any -P out ipsec esp/transport//require; 464 add 203.0.113.1 203.0.113.2 esp 0x1001 -E aes-gcm-16 \"12345678901234567890\";" \ 465 | jexec router setkey -c 466 467 # Sanity check. 468 ping_server_check_reply exit:0 --ping-type=icmp 469 470 # Enable packet reassembly with clearing of the no-df flag. 471 pft_set_rules router \ 472 "scrub in on ${epair_tester}b fragment no reassemble" \ 473 "scrub on ${epair_server}a fragment reassemble" \ 474 "pass" 475 476 # Ensure that the packet makes it through the slow path 477 atf_check -s exit:0 -o ignore \ 478 ping -c 1 -s 2000 198.51.100.2 479} 480 481reassemble_slowpath_cleanup() 482{ 483 pft_cleanup 484} 485 486atf_test_case "dummynet" "cleanup" 487dummynet_head() 488{ 489 atf_set descr 'dummynet + reassembly test' 490 atf_set require.user root 491} 492 493dummynet_body() 494{ 495 pft_init 496 dummynet_init 497 498 epair=$(vnet_mkepair) 499 vnet_mkjail alcatraz ${epair}a 500 501 ifconfig ${epair}b inet 192.0.2.1/24 up 502 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 503 504 # Sanity check 505 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 506 507 jexec alcatraz dnctl pipe 1 config bw 600Byte/s 508 jexec alcatraz dnctl pipe 2 config bw 700Byte/s 509 510 jexec alcatraz pfctl -e 511 pft_set_rules alcatraz \ 512 "set reassemble yes" \ 513 "block" \ 514 "pass inet proto icmp all icmp-type echoreq dnpipe (1, 2)" 515 516 atf_check -s exit:0 -o ignore ping -s 2000 -c 1 192.0.2.2 517} 518 519dummynet_cleanup() 520{ 521 pft_cleanup 522} 523 524atf_test_case "dummynet_nat" "cleanup" 525dummynet_nat_head() 526{ 527 atf_set descr 'Test dummynet on NATed fragmented traffic' 528 atf_set require.user root 529} 530 531dummynet_nat_body() 532{ 533 pft_init 534 dummynet_init 535 536 epair_one=$(vnet_mkepair) 537 ifconfig ${epair_one}a 192.0.2.1/24 up 538 539 epair_two=$(vnet_mkepair) 540 541 vnet_mkjail alcatraz ${epair_one}b ${epair_two}a 542 jexec alcatraz ifconfig ${epair_one}b 192.0.2.2/24 up 543 jexec alcatraz ifconfig ${epair_two}a 198.51.100.1/24 up 544 jexec alcatraz sysctl net.inet.ip.forwarding=1 545 546 vnet_mkjail singsing ${epair_two}b 547 jexec singsing ifconfig ${epair_two}b 198.51.100.2/24 up 548 jexec singsing route add default 198.51.100.1 549 550 route add 198.51.100.0/24 192.0.2.2 551 552 jexec alcatraz dnctl pipe 1 config bw 1600Byte/s 553 jexec alcatraz dnctl pipe 2 config bw 1700Byte/s 554 555 jexec alcatraz pfctl -e 556 pft_set_rules alcatraz \ 557 "set reassemble yes" \ 558 "nat on ${epair_two}a from 192.0.2.0/24 -> (${epair_two}a)" \ 559 "block in" \ 560 "pass in inet proto icmp all icmp-type echoreq dnpipe (1, 2)" 561 562 atf_check -s exit:0 -o ignore ping -c 1 198.51.100.2 563 atf_check -s exit:0 -o ignore ping -c 1 -s 2000 198.51.100.2 564} 565 566dummynet_nat_cleanup() 567{ 568 pft_cleanup 569} 570 571atf_test_case "dummynet_fragmented" "cleanup" 572dummynet_fragmented_head() 573{ 574 atf_set descr 'Test dummynet on NATed fragmented traffic' 575 atf_set require.user root 576} 577 578dummynet_fragmented_body() 579{ 580 pft_init 581 dummynet_init 582 583 # No test for IPv6. IPv6 fragment reassembly can't be disabled. 584 setup_router_dummy_ipv4 585 586 jexec router dnctl pipe 1 config delay 1 587 588 pft_set_rules router \ 589 "set reassemble no" \ 590 "block" \ 591 "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ 592 "pass in on ${epair_tester}b inet proto udp dnpipe (1, 1)" \ 593 "pass out on ${epair_server}a inet proto udp" \ 594 595 ping_dummy_check_request exit:0 --ping-type=udp --send-length=10000 --send-frag-length=1280 596 597 rules=$(mktemp) || exit 1 598 jexec router pfctl -qvsr | normalize_pfctl_s > $rules 599 600 # Count that fragmented packets have hit the rule only once and that 601 # they have not created states. There is no stateful firewall support 602 # for fragmented packets. 603 grep -qE 'pass in on epair0b inet proto udp all keep state dnpipe\(1, 1\) .* Packets: 8 Bytes: 10168 States: 0 ' $rules || 604 atf_fail "Fragmented packets not counted correctly" 605} 606 607dummynet_fragmented_cleanup() 608{ 609 pft_cleanup 610} 611 612atf_init_test_cases() 613{ 614 atf_add_test_case "too_many_fragments" 615 atf_add_test_case "v6" 616 atf_add_test_case "v6_route_to" 617 atf_add_test_case "mtu_diff" 618 atf_add_test_case "overreplace" 619 atf_add_test_case "overindex" 620 atf_add_test_case "overlimit" 621 atf_add_test_case "reassemble" 622 atf_add_test_case "no_df" 623 atf_add_test_case "reassemble_slowpath" 624 atf_add_test_case "dummynet" 625 atf_add_test_case "dummynet_nat" 626 atf_add_test_case "dummynet_fragmented" 627} 628