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