1#!/bin/bash 2# 3# This test is for basic NAT functionality: snat, dnat, redirect, masquerade. 4# 5 6# Kselftest framework requirement - SKIP code is 4. 7ksft_skip=4 8ret=0 9test_inet_nat=true 10 11sfx=$(mktemp -u "XXXXXXXX") 12ns0="ns0-$sfx" 13ns1="ns1-$sfx" 14ns2="ns2-$sfx" 15 16cleanup() 17{ 18 for i in 0 1 2; do ip netns del ns$i-"$sfx";done 19} 20 21nft --version > /dev/null 2>&1 22if [ $? -ne 0 ];then 23 echo "SKIP: Could not run test without nft tool" 24 exit $ksft_skip 25fi 26 27ip -Version > /dev/null 2>&1 28if [ $? -ne 0 ];then 29 echo "SKIP: Could not run test without ip tool" 30 exit $ksft_skip 31fi 32 33ip netns add "$ns0" 34if [ $? -ne 0 ];then 35 echo "SKIP: Could not create net namespace $ns0" 36 exit $ksft_skip 37fi 38 39trap cleanup EXIT 40 41ip netns add "$ns1" 42if [ $? -ne 0 ];then 43 echo "SKIP: Could not create net namespace $ns1" 44 exit $ksft_skip 45fi 46 47ip netns add "$ns2" 48if [ $? -ne 0 ];then 49 echo "SKIP: Could not create net namespace $ns2" 50 exit $ksft_skip 51fi 52 53ip link add veth0 netns "$ns0" type veth peer name eth0 netns "$ns1" > /dev/null 2>&1 54if [ $? -ne 0 ];then 55 echo "SKIP: No virtual ethernet pair device support in kernel" 56 exit $ksft_skip 57fi 58ip link add veth1 netns "$ns0" type veth peer name eth0 netns "$ns2" 59 60ip -net "$ns0" link set lo up 61ip -net "$ns0" link set veth0 up 62ip -net "$ns0" addr add 10.0.1.1/24 dev veth0 63ip -net "$ns0" addr add dead:1::1/64 dev veth0 64 65ip -net "$ns0" link set veth1 up 66ip -net "$ns0" addr add 10.0.2.1/24 dev veth1 67ip -net "$ns0" addr add dead:2::1/64 dev veth1 68 69for i in 1 2; do 70 ip -net ns$i-$sfx link set lo up 71 ip -net ns$i-$sfx link set eth0 up 72 ip -net ns$i-$sfx addr add 10.0.$i.99/24 dev eth0 73 ip -net ns$i-$sfx route add default via 10.0.$i.1 74 ip -net ns$i-$sfx addr add dead:$i::99/64 dev eth0 75 ip -net ns$i-$sfx route add default via dead:$i::1 76done 77 78bad_counter() 79{ 80 local ns=$1 81 local counter=$2 82 local expect=$3 83 local tag=$4 84 85 echo "ERROR: $counter counter in $ns has unexpected value (expected $expect) at $tag" 1>&2 86 ip netns exec $ns nft list counter inet filter $counter 1>&2 87} 88 89check_counters() 90{ 91 ns=$1 92 local lret=0 93 94 cnt=$(ip netns exec $ns nft list counter inet filter ns0in | grep -q "packets 1 bytes 84") 95 if [ $? -ne 0 ]; then 96 bad_counter $ns ns0in "packets 1 bytes 84" "check_counters 1" 97 lret=1 98 fi 99 cnt=$(ip netns exec $ns nft list counter inet filter ns0out | grep -q "packets 1 bytes 84") 100 if [ $? -ne 0 ]; then 101 bad_counter $ns ns0out "packets 1 bytes 84" "check_counters 2" 102 lret=1 103 fi 104 105 expect="packets 1 bytes 104" 106 cnt=$(ip netns exec $ns nft list counter inet filter ns0in6 | grep -q "$expect") 107 if [ $? -ne 0 ]; then 108 bad_counter $ns ns0in6 "$expect" "check_counters 3" 109 lret=1 110 fi 111 cnt=$(ip netns exec $ns nft list counter inet filter ns0out6 | grep -q "$expect") 112 if [ $? -ne 0 ]; then 113 bad_counter $ns ns0out6 "$expect" "check_counters 4" 114 lret=1 115 fi 116 117 return $lret 118} 119 120check_ns0_counters() 121{ 122 local ns=$1 123 local lret=0 124 125 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0in | grep -q "packets 0 bytes 0") 126 if [ $? -ne 0 ]; then 127 bad_counter "$ns0" ns0in "packets 0 bytes 0" "check_ns0_counters 1" 128 lret=1 129 fi 130 131 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0in6 | grep -q "packets 0 bytes 0") 132 if [ $? -ne 0 ]; then 133 bad_counter "$ns0" ns0in6 "packets 0 bytes 0" 134 lret=1 135 fi 136 137 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0out | grep -q "packets 0 bytes 0") 138 if [ $? -ne 0 ]; then 139 bad_counter "$ns0" ns0out "packets 0 bytes 0" "check_ns0_counters 2" 140 lret=1 141 fi 142 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0out6 | grep -q "packets 0 bytes 0") 143 if [ $? -ne 0 ]; then 144 bad_counter "$ns0" ns0out6 "packets 0 bytes 0" "check_ns0_counters3 " 145 lret=1 146 fi 147 148 for dir in "in" "out" ; do 149 expect="packets 1 bytes 84" 150 cnt=$(ip netns exec "$ns0" nft list counter inet filter ${ns}${dir} | grep -q "$expect") 151 if [ $? -ne 0 ]; then 152 bad_counter "$ns0" $ns$dir "$expect" "check_ns0_counters 4" 153 lret=1 154 fi 155 156 expect="packets 1 bytes 104" 157 cnt=$(ip netns exec "$ns0" nft list counter inet filter ${ns}${dir}6 | grep -q "$expect") 158 if [ $? -ne 0 ]; then 159 bad_counter "$ns0" $ns$dir6 "$expect" "check_ns0_counters 5" 160 lret=1 161 fi 162 done 163 164 return $lret 165} 166 167reset_counters() 168{ 169 for i in 0 1 2;do 170 ip netns exec ns$i-$sfx nft reset counters inet > /dev/null 171 done 172} 173 174test_local_dnat6() 175{ 176 local family=$1 177 local lret=0 178 local IPF="" 179 180 if [ $family = "inet" ];then 181 IPF="ip6" 182 fi 183 184ip netns exec "$ns0" nft -f /dev/stdin <<EOF 185table $family nat { 186 chain output { 187 type nat hook output priority 0; policy accept; 188 ip6 daddr dead:1::99 dnat $IPF to dead:2::99 189 } 190} 191EOF 192 if [ $? -ne 0 ]; then 193 echo "SKIP: Could not add add $family dnat hook" 194 return $ksft_skip 195 fi 196 197 # ping netns1, expect rewrite to netns2 198 ip netns exec "$ns0" ping -q -c 1 dead:1::99 > /dev/null 199 if [ $? -ne 0 ]; then 200 lret=1 201 echo "ERROR: ping6 failed" 202 return $lret 203 fi 204 205 expect="packets 0 bytes 0" 206 for dir in "in6" "out6" ; do 207 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 208 if [ $? -ne 0 ]; then 209 bad_counter "$ns0" ns1$dir "$expect" "test_local_dnat6 1" 210 lret=1 211 fi 212 done 213 214 expect="packets 1 bytes 104" 215 for dir in "in6" "out6" ; do 216 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 217 if [ $? -ne 0 ]; then 218 bad_counter "$ns0" ns2$dir "$expect" "test_local_dnat6 2" 219 lret=1 220 fi 221 done 222 223 # expect 0 count in ns1 224 expect="packets 0 bytes 0" 225 for dir in "in6" "out6" ; do 226 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 227 if [ $? -ne 0 ]; then 228 bad_counter "$ns1" ns0$dir "$expect" "test_local_dnat6 3" 229 lret=1 230 fi 231 done 232 233 # expect 1 packet in ns2 234 expect="packets 1 bytes 104" 235 for dir in "in6" "out6" ; do 236 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns0${dir} | grep -q "$expect") 237 if [ $? -ne 0 ]; then 238 bad_counter "$ns2" ns0$dir "$expect" "test_local_dnat6 4" 239 lret=1 240 fi 241 done 242 243 test $lret -eq 0 && echo "PASS: ipv6 ping to $ns1 was $family NATted to $ns2" 244 ip netns exec "$ns0" nft flush chain ip6 nat output 245 246 return $lret 247} 248 249test_local_dnat() 250{ 251 local family=$1 252 local lret=0 253 local IPF="" 254 255 if [ $family = "inet" ];then 256 IPF="ip" 257 fi 258 259ip netns exec "$ns0" nft -f /dev/stdin <<EOF 2>/dev/null 260table $family nat { 261 chain output { 262 type nat hook output priority 0; policy accept; 263 ip daddr 10.0.1.99 dnat $IPF to 10.0.2.99 264 } 265} 266EOF 267 if [ $? -ne 0 ]; then 268 if [ $family = "inet" ];then 269 echo "SKIP: inet nat tests" 270 test_inet_nat=false 271 return $ksft_skip 272 fi 273 echo "SKIP: Could not add add $family dnat hook" 274 return $ksft_skip 275 fi 276 277 # ping netns1, expect rewrite to netns2 278 ip netns exec "$ns0" ping -q -c 1 10.0.1.99 > /dev/null 279 if [ $? -ne 0 ]; then 280 lret=1 281 echo "ERROR: ping failed" 282 return $lret 283 fi 284 285 expect="packets 0 bytes 0" 286 for dir in "in" "out" ; do 287 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 288 if [ $? -ne 0 ]; then 289 bad_counter "$ns0" ns1$dir "$expect" "test_local_dnat 1" 290 lret=1 291 fi 292 done 293 294 expect="packets 1 bytes 84" 295 for dir in "in" "out" ; do 296 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 297 if [ $? -ne 0 ]; then 298 bad_counter "$ns0" ns2$dir "$expect" "test_local_dnat 2" 299 lret=1 300 fi 301 done 302 303 # expect 0 count in ns1 304 expect="packets 0 bytes 0" 305 for dir in "in" "out" ; do 306 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 307 if [ $? -ne 0 ]; then 308 bad_counter "$ns1" ns0$dir "$expect" "test_local_dnat 3" 309 lret=1 310 fi 311 done 312 313 # expect 1 packet in ns2 314 expect="packets 1 bytes 84" 315 for dir in "in" "out" ; do 316 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns0${dir} | grep -q "$expect") 317 if [ $? -ne 0 ]; then 318 bad_counter "$ns2" ns0$dir "$expect" "test_local_dnat 4" 319 lret=1 320 fi 321 done 322 323 test $lret -eq 0 && echo "PASS: ping to $ns1 was $family NATted to $ns2" 324 325 ip netns exec "$ns0" nft flush chain $family nat output 326 327 reset_counters 328 ip netns exec "$ns0" ping -q -c 1 10.0.1.99 > /dev/null 329 if [ $? -ne 0 ]; then 330 lret=1 331 echo "ERROR: ping failed" 332 return $lret 333 fi 334 335 expect="packets 1 bytes 84" 336 for dir in "in" "out" ; do 337 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 338 if [ $? -ne 0 ]; then 339 bad_counter "$ns1" ns1$dir "$expect" "test_local_dnat 5" 340 lret=1 341 fi 342 done 343 expect="packets 0 bytes 0" 344 for dir in "in" "out" ; do 345 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 346 if [ $? -ne 0 ]; then 347 bad_counter "$ns0" ns2$dir "$expect" "test_local_dnat 6" 348 lret=1 349 fi 350 done 351 352 # expect 1 count in ns1 353 expect="packets 1 bytes 84" 354 for dir in "in" "out" ; do 355 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 356 if [ $? -ne 0 ]; then 357 bad_counter "$ns0" ns0$dir "$expect" "test_local_dnat 7" 358 lret=1 359 fi 360 done 361 362 # expect 0 packet in ns2 363 expect="packets 0 bytes 0" 364 for dir in "in" "out" ; do 365 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns0${dir} | grep -q "$expect") 366 if [ $? -ne 0 ]; then 367 bad_counter "$ns2" ns0$dir "$expect" "test_local_dnat 8" 368 lret=1 369 fi 370 done 371 372 test $lret -eq 0 && echo "PASS: ping to $ns1 OK after $family nat output chain flush" 373 374 return $lret 375} 376 377test_local_dnat_portonly() 378{ 379 local family=$1 380 local daddr=$2 381 local lret=0 382 local sr_s 383 local sr_r 384 385ip netns exec "$ns0" nft -f /dev/stdin <<EOF 386table $family nat { 387 chain output { 388 type nat hook output priority 0; policy accept; 389 meta l4proto tcp dnat to :2000 390 391 } 392} 393EOF 394 if [ $? -ne 0 ]; then 395 if [ $family = "inet" ];then 396 echo "SKIP: inet port test" 397 test_inet_nat=false 398 return 399 fi 400 echo "SKIP: Could not add $family dnat hook" 401 return 402 fi 403 404 echo SERVER-$family | ip netns exec "$ns1" timeout 5 socat -u STDIN TCP-LISTEN:2000 & 405 sc_s=$! 406 407 sleep 1 408 409 result=$(ip netns exec "$ns0" timeout 1 socat TCP:$daddr:2000 STDOUT) 410 411 if [ "$result" = "SERVER-inet" ];then 412 echo "PASS: inet port rewrite without l3 address" 413 else 414 echo "ERROR: inet port rewrite" 415 ret=1 416 fi 417} 418 419test_masquerade6() 420{ 421 local family=$1 422 local natflags=$2 423 local lret=0 424 425 ip netns exec "$ns0" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null 426 427 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 428 if [ $? -ne 0 ] ; then 429 echo "ERROR: cannot ping $ns1 from $ns2 via ipv6" 430 return 1 431 lret=1 432 fi 433 434 expect="packets 1 bytes 104" 435 for dir in "in6" "out6" ; do 436 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 437 if [ $? -ne 0 ]; then 438 bad_counter "$ns1" ns2$dir "$expect" "test_masquerade6 1" 439 lret=1 440 fi 441 442 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 443 if [ $? -ne 0 ]; then 444 bad_counter "$ns2" ns1$dir "$expect" "test_masquerade6 2" 445 lret=1 446 fi 447 done 448 449 reset_counters 450 451# add masquerading rule 452ip netns exec "$ns0" nft -f /dev/stdin <<EOF 453table $family nat { 454 chain postrouting { 455 type nat hook postrouting priority 0; policy accept; 456 meta oif veth0 masquerade $natflags 457 } 458} 459EOF 460 if [ $? -ne 0 ]; then 461 echo "SKIP: Could not add add $family masquerade hook" 462 return $ksft_skip 463 fi 464 465 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 466 if [ $? -ne 0 ] ; then 467 echo "ERROR: cannot ping $ns1 from $ns2 with active $family masquerade $natflags" 468 lret=1 469 fi 470 471 # ns1 should have seen packets from ns0, due to masquerade 472 expect="packets 1 bytes 104" 473 for dir in "in6" "out6" ; do 474 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 475 if [ $? -ne 0 ]; then 476 bad_counter "$ns1" ns0$dir "$expect" "test_masquerade6 3" 477 lret=1 478 fi 479 480 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 481 if [ $? -ne 0 ]; then 482 bad_counter "$ns2" ns1$dir "$expect" "test_masquerade6 4" 483 lret=1 484 fi 485 done 486 487 # ns1 should not have seen packets from ns2, due to masquerade 488 expect="packets 0 bytes 0" 489 for dir in "in6" "out6" ; do 490 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 491 if [ $? -ne 0 ]; then 492 bad_counter "$ns1" ns0$dir "$expect" "test_masquerade6 5" 493 lret=1 494 fi 495 496 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 497 if [ $? -ne 0 ]; then 498 bad_counter "$ns0" ns1$dir "$expect" "test_masquerade6 6" 499 lret=1 500 fi 501 done 502 503 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 504 if [ $? -ne 0 ] ; then 505 echo "ERROR: cannot ping $ns1 from $ns2 with active ipv6 masquerade $natflags (attempt 2)" 506 lret=1 507 fi 508 509 ip netns exec "$ns0" nft flush chain $family nat postrouting 510 if [ $? -ne 0 ]; then 511 echo "ERROR: Could not flush $family nat postrouting" 1>&2 512 lret=1 513 fi 514 515 test $lret -eq 0 && echo "PASS: $family IPv6 masquerade $natflags for $ns2" 516 517 return $lret 518} 519 520test_masquerade() 521{ 522 local family=$1 523 local natflags=$2 524 local lret=0 525 526 ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 527 ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 528 529 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 530 if [ $? -ne 0 ] ; then 531 echo "ERROR: cannot ping $ns1 from "$ns2" $natflags" 532 lret=1 533 fi 534 535 expect="packets 1 bytes 84" 536 for dir in "in" "out" ; do 537 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 538 if [ $? -ne 0 ]; then 539 bad_counter "$ns1" ns2$dir "$expect" "test_masquerade 1" 540 lret=1 541 fi 542 543 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 544 if [ $? -ne 0 ]; then 545 bad_counter "$ns2" ns1$dir "$expect" "test_masquerade 2" 546 lret=1 547 fi 548 done 549 550 reset_counters 551 552# add masquerading rule 553ip netns exec "$ns0" nft -f /dev/stdin <<EOF 554table $family nat { 555 chain postrouting { 556 type nat hook postrouting priority 0; policy accept; 557 meta oif veth0 masquerade $natflags 558 } 559} 560EOF 561 if [ $? -ne 0 ]; then 562 echo "SKIP: Could not add add $family masquerade hook" 563 return $ksft_skip 564 fi 565 566 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 567 if [ $? -ne 0 ] ; then 568 echo "ERROR: cannot ping $ns1 from $ns2 with active $family masquerade $natflags" 569 lret=1 570 fi 571 572 # ns1 should have seen packets from ns0, due to masquerade 573 expect="packets 1 bytes 84" 574 for dir in "in" "out" ; do 575 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 576 if [ $? -ne 0 ]; then 577 bad_counter "$ns1" ns0$dir "$expect" "test_masquerade 3" 578 lret=1 579 fi 580 581 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 582 if [ $? -ne 0 ]; then 583 bad_counter "$ns2" ns1$dir "$expect" "test_masquerade 4" 584 lret=1 585 fi 586 done 587 588 # ns1 should not have seen packets from ns2, due to masquerade 589 expect="packets 0 bytes 0" 590 for dir in "in" "out" ; do 591 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 592 if [ $? -ne 0 ]; then 593 bad_counter "$ns1" ns0$dir "$expect" "test_masquerade 5" 594 lret=1 595 fi 596 597 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 598 if [ $? -ne 0 ]; then 599 bad_counter "$ns0" ns1$dir "$expect" "test_masquerade 6" 600 lret=1 601 fi 602 done 603 604 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 605 if [ $? -ne 0 ] ; then 606 echo "ERROR: cannot ping $ns1 from $ns2 with active ip masquerade $natflags (attempt 2)" 607 lret=1 608 fi 609 610 ip netns exec "$ns0" nft flush chain $family nat postrouting 611 if [ $? -ne 0 ]; then 612 echo "ERROR: Could not flush $family nat postrouting" 1>&2 613 lret=1 614 fi 615 616 test $lret -eq 0 && echo "PASS: $family IP masquerade $natflags for $ns2" 617 618 return $lret 619} 620 621test_redirect6() 622{ 623 local family=$1 624 local lret=0 625 626 ip netns exec "$ns0" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null 627 628 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 629 if [ $? -ne 0 ] ; then 630 echo "ERROR: cannnot ping $ns1 from $ns2 via ipv6" 631 lret=1 632 fi 633 634 expect="packets 1 bytes 104" 635 for dir in "in6" "out6" ; do 636 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 637 if [ $? -ne 0 ]; then 638 bad_counter "$ns1" ns2$dir "$expect" "test_redirect6 1" 639 lret=1 640 fi 641 642 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 643 if [ $? -ne 0 ]; then 644 bad_counter "$ns2" ns1$dir "$expect" "test_redirect6 2" 645 lret=1 646 fi 647 done 648 649 reset_counters 650 651# add redirect rule 652ip netns exec "$ns0" nft -f /dev/stdin <<EOF 653table $family nat { 654 chain prerouting { 655 type nat hook prerouting priority 0; policy accept; 656 meta iif veth1 meta l4proto icmpv6 ip6 saddr dead:2::99 ip6 daddr dead:1::99 redirect 657 } 658} 659EOF 660 if [ $? -ne 0 ]; then 661 echo "SKIP: Could not add add $family redirect hook" 662 return $ksft_skip 663 fi 664 665 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 666 if [ $? -ne 0 ] ; then 667 echo "ERROR: cannot ping $ns1 from $ns2 via ipv6 with active $family redirect" 668 lret=1 669 fi 670 671 # ns1 should have seen no packets from ns2, due to redirection 672 expect="packets 0 bytes 0" 673 for dir in "in6" "out6" ; do 674 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 675 if [ $? -ne 0 ]; then 676 bad_counter "$ns1" ns0$dir "$expect" "test_redirect6 3" 677 lret=1 678 fi 679 done 680 681 # ns0 should have seen packets from ns2, due to masquerade 682 expect="packets 1 bytes 104" 683 for dir in "in6" "out6" ; do 684 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 685 if [ $? -ne 0 ]; then 686 bad_counter "$ns1" ns0$dir "$expect" "test_redirect6 4" 687 lret=1 688 fi 689 done 690 691 ip netns exec "$ns0" nft delete table $family nat 692 if [ $? -ne 0 ]; then 693 echo "ERROR: Could not delete $family nat table" 1>&2 694 lret=1 695 fi 696 697 test $lret -eq 0 && echo "PASS: $family IPv6 redirection for $ns2" 698 699 return $lret 700} 701 702test_redirect() 703{ 704 local family=$1 705 local lret=0 706 707 ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 708 ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 709 710 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 711 if [ $? -ne 0 ] ; then 712 echo "ERROR: cannot ping $ns1 from $ns2" 713 lret=1 714 fi 715 716 expect="packets 1 bytes 84" 717 for dir in "in" "out" ; do 718 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 719 if [ $? -ne 0 ]; then 720 bad_counter "$ns1" $ns2$dir "$expect" "test_redirect 1" 721 lret=1 722 fi 723 724 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 725 if [ $? -ne 0 ]; then 726 bad_counter "$ns2" ns1$dir "$expect" "test_redirect 2" 727 lret=1 728 fi 729 done 730 731 reset_counters 732 733# add redirect rule 734ip netns exec "$ns0" nft -f /dev/stdin <<EOF 735table $family nat { 736 chain prerouting { 737 type nat hook prerouting priority 0; policy accept; 738 meta iif veth1 ip protocol icmp ip saddr 10.0.2.99 ip daddr 10.0.1.99 redirect 739 } 740} 741EOF 742 if [ $? -ne 0 ]; then 743 echo "SKIP: Could not add add $family redirect hook" 744 return $ksft_skip 745 fi 746 747 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 748 if [ $? -ne 0 ] ; then 749 echo "ERROR: cannot ping $ns1 from $ns2 with active $family ip redirect" 750 lret=1 751 fi 752 753 # ns1 should have seen no packets from ns2, due to redirection 754 expect="packets 0 bytes 0" 755 for dir in "in" "out" ; do 756 757 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 758 if [ $? -ne 0 ]; then 759 bad_counter "$ns1" ns0$dir "$expect" "test_redirect 3" 760 lret=1 761 fi 762 done 763 764 # ns0 should have seen packets from ns2, due to masquerade 765 expect="packets 1 bytes 84" 766 for dir in "in" "out" ; do 767 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 768 if [ $? -ne 0 ]; then 769 bad_counter "$ns0" ns0$dir "$expect" "test_redirect 4" 770 lret=1 771 fi 772 done 773 774 ip netns exec "$ns0" nft delete table $family nat 775 if [ $? -ne 0 ]; then 776 echo "ERROR: Could not delete $family nat table" 1>&2 777 lret=1 778 fi 779 780 test $lret -eq 0 && echo "PASS: $family IP redirection for $ns2" 781 782 return $lret 783} 784 785# test port shadowing. 786# create two listening services, one on router (ns0), one 787# on client (ns2), which is masqueraded from ns1 point of view. 788# ns2 sends udp packet coming from service port to ns1, on a highport. 789# Later, if n1 uses same highport to connect to ns0:service, packet 790# might be port-forwarded to ns2 instead. 791 792# second argument tells if we expect the 'fake-entry' to take effect 793# (CLIENT) or not (ROUTER). 794test_port_shadow() 795{ 796 local test=$1 797 local expect=$2 798 local daddrc="10.0.1.99" 799 local daddrs="10.0.1.1" 800 local result="" 801 local logmsg="" 802 803 # make shadow entry, from client (ns2), going to (ns1), port 41404, sport 1405. 804 echo "fake-entry" | ip netns exec "$ns2" timeout 1 socat -u STDIN UDP:"$daddrc":41404,sourceport=1405 805 806 echo ROUTER | ip netns exec "$ns0" timeout 5 socat -u STDIN UDP4-LISTEN:1405 & 807 sc_r=$! 808 809 echo CLIENT | ip netns exec "$ns2" timeout 5 socat -u STDIN UDP4-LISTEN:1405,reuseport & 810 sc_c=$! 811 812 sleep 0.3 813 814 # ns1 tries to connect to ns0:1405. With default settings this should connect 815 # to client, it matches the conntrack entry created above. 816 817 result=$(echo "data" | ip netns exec "$ns1" timeout 1 socat - UDP:"$daddrs":1405,sourceport=41404) 818 819 if [ "$result" = "$expect" ] ;then 820 echo "PASS: portshadow test $test: got reply from ${expect}${logmsg}" 821 else 822 echo "ERROR: portshadow test $test: got reply from \"$result\", not $expect as intended" 823 ret=1 824 fi 825 826 kill $sc_r $sc_c 2>/dev/null 827 828 # flush udp entries for next test round, if any 829 ip netns exec "$ns0" conntrack -F >/dev/null 2>&1 830} 831 832# This prevents port shadow of router service via packet filter, 833# packets claiming to originate from service port from internal 834# network are dropped. 835test_port_shadow_filter() 836{ 837 local family=$1 838 839ip netns exec "$ns0" nft -f /dev/stdin <<EOF 840table $family filter { 841 chain forward { 842 type filter hook forward priority 0; policy accept; 843 meta iif veth1 udp sport 1405 drop 844 } 845} 846EOF 847 test_port_shadow "port-filter" "ROUTER" 848 849 ip netns exec "$ns0" nft delete table $family filter 850} 851 852# This prevents port shadow of router service via notrack. 853test_port_shadow_notrack() 854{ 855 local family=$1 856 857ip netns exec "$ns0" nft -f /dev/stdin <<EOF 858table $family raw { 859 chain prerouting { 860 type filter hook prerouting priority -300; policy accept; 861 meta iif veth0 udp dport 1405 notrack 862 } 863 chain output { 864 type filter hook output priority -300; policy accept; 865 meta oif veth0 udp sport 1405 notrack 866 } 867} 868EOF 869 test_port_shadow "port-notrack" "ROUTER" 870 871 ip netns exec "$ns0" nft delete table $family raw 872} 873 874# This prevents port shadow of router service via sport remap. 875test_port_shadow_pat() 876{ 877 local family=$1 878 879ip netns exec "$ns0" nft -f /dev/stdin <<EOF 880table $family pat { 881 chain postrouting { 882 type nat hook postrouting priority -1; policy accept; 883 meta iif veth1 udp sport <= 1405 masquerade to : 1406-65535 random 884 } 885} 886EOF 887 test_port_shadow "pat" "ROUTER" 888 889 ip netns exec "$ns0" nft delete table $family pat 890} 891 892test_port_shadowing() 893{ 894 local family="ip" 895 896 conntrack -h >/dev/null 2>&1 897 if [ $? -ne 0 ];then 898 echo "SKIP: Could not run nat port shadowing test without conntrack tool" 899 return 900 fi 901 902 socat -h > /dev/null 2>&1 903 if [ $? -ne 0 ];then 904 echo "SKIP: Could not run nat port shadowing test without socat tool" 905 return 906 fi 907 908 ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 909 ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 910 911 ip netns exec "$ns0" nft -f /dev/stdin <<EOF 912table $family nat { 913 chain postrouting { 914 type nat hook postrouting priority 0; policy accept; 915 meta oif veth0 masquerade 916 } 917} 918EOF 919 if [ $? -ne 0 ]; then 920 echo "SKIP: Could not add add $family masquerade hook" 921 return $ksft_skip 922 fi 923 924 # test default behaviour. Packet from ns1 to ns0 is redirected to ns2. 925 test_port_shadow "default" "CLIENT" 926 927 # test packet filter based mitigation: prevent forwarding of 928 # packets claiming to come from the service port. 929 test_port_shadow_filter "$family" 930 931 # test conntrack based mitigation: connections going or coming 932 # from router:service bypass connection tracking. 933 test_port_shadow_notrack "$family" 934 935 # test nat based mitigation: fowarded packets coming from service port 936 # are masqueraded with random highport. 937 test_port_shadow_pat "$family" 938 939 ip netns exec "$ns0" nft delete table $family nat 940} 941 942test_stateless_nat_ip() 943{ 944 local lret=0 945 946 ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 947 ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 948 949 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 950 if [ $? -ne 0 ] ; then 951 echo "ERROR: cannot ping $ns1 from $ns2 before loading stateless rules" 952 return 1 953 fi 954 955ip netns exec "$ns0" nft -f /dev/stdin <<EOF 956table ip stateless { 957 map xlate_in { 958 typeof meta iifname . ip saddr . ip daddr : ip daddr 959 elements = { 960 "veth1" . 10.0.2.99 . 10.0.1.99 : 10.0.2.2, 961 } 962 } 963 map xlate_out { 964 typeof meta iifname . ip saddr . ip daddr : ip daddr 965 elements = { 966 "veth0" . 10.0.1.99 . 10.0.2.2 : 10.0.2.99 967 } 968 } 969 970 chain prerouting { 971 type filter hook prerouting priority -400; policy accept; 972 ip saddr set meta iifname . ip saddr . ip daddr map @xlate_in 973 ip daddr set meta iifname . ip saddr . ip daddr map @xlate_out 974 } 975} 976EOF 977 if [ $? -ne 0 ]; then 978 echo "SKIP: Could not add ip statless rules" 979 return $ksft_skip 980 fi 981 982 reset_counters 983 984 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 985 if [ $? -ne 0 ] ; then 986 echo "ERROR: cannot ping $ns1 from $ns2 with stateless rules" 987 lret=1 988 fi 989 990 # ns1 should have seen packets from .2.2, due to stateless rewrite. 991 expect="packets 1 bytes 84" 992 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect") 993 if [ $? -ne 0 ]; then 994 bad_counter "$ns1" ns0insl "$expect" "test_stateless 1" 995 lret=1 996 fi 997 998 for dir in "in" "out" ; do 999 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 1000 if [ $? -ne 0 ]; then 1001 bad_counter "$ns2" ns1$dir "$expect" "test_stateless 2" 1002 lret=1 1003 fi 1004 done 1005 1006 # ns1 should not have seen packets from ns2, due to masquerade 1007 expect="packets 0 bytes 0" 1008 for dir in "in" "out" ; do 1009 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 1010 if [ $? -ne 0 ]; then 1011 bad_counter "$ns1" ns0$dir "$expect" "test_stateless 3" 1012 lret=1 1013 fi 1014 1015 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 1016 if [ $? -ne 0 ]; then 1017 bad_counter "$ns0" ns1$dir "$expect" "test_stateless 4" 1018 lret=1 1019 fi 1020 done 1021 1022 reset_counters 1023 1024 socat -h > /dev/null 2>&1 1025 if [ $? -ne 0 ];then 1026 echo "SKIP: Could not run stateless nat frag test without socat tool" 1027 if [ $lret -eq 0 ]; then 1028 return $ksft_skip 1029 fi 1030 1031 ip netns exec "$ns0" nft delete table ip stateless 1032 return $lret 1033 fi 1034 1035 local tmpfile=$(mktemp) 1036 dd if=/dev/urandom of=$tmpfile bs=4096 count=1 2>/dev/null 1037 1038 local outfile=$(mktemp) 1039 ip netns exec "$ns1" timeout 3 socat -u UDP4-RECV:4233 OPEN:$outfile < /dev/null & 1040 sc_r=$! 1041 1042 sleep 1 1043 # re-do with large ping -> ip fragmentation 1044 ip netns exec "$ns2" timeout 3 socat - UDP4-SENDTO:"10.0.1.99:4233" < "$tmpfile" > /dev/null 1045 if [ $? -ne 0 ] ; then 1046 echo "ERROR: failed to test udp $ns1 to $ns2 with stateless ip nat" 1>&2 1047 lret=1 1048 fi 1049 1050 wait 1051 1052 cmp "$tmpfile" "$outfile" 1053 if [ $? -ne 0 ]; then 1054 ls -l "$tmpfile" "$outfile" 1055 echo "ERROR: in and output file mismatch when checking udp with stateless nat" 1>&2 1056 lret=1 1057 fi 1058 1059 rm -f "$tmpfile" "$outfile" 1060 1061 # ns1 should have seen packets from 2.2, due to stateless rewrite. 1062 expect="packets 3 bytes 4164" 1063 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect") 1064 if [ $? -ne 0 ]; then 1065 bad_counter "$ns1" ns0insl "$expect" "test_stateless 5" 1066 lret=1 1067 fi 1068 1069 ip netns exec "$ns0" nft delete table ip stateless 1070 if [ $? -ne 0 ]; then 1071 echo "ERROR: Could not delete table ip stateless" 1>&2 1072 lret=1 1073 fi 1074 1075 test $lret -eq 0 && echo "PASS: IP statless for $ns2" 1076 1077 return $lret 1078} 1079 1080# ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99 1081for i in 0 1 2; do 1082ip netns exec ns$i-$sfx nft -f /dev/stdin <<EOF 1083table inet filter { 1084 counter ns0in {} 1085 counter ns1in {} 1086 counter ns2in {} 1087 1088 counter ns0out {} 1089 counter ns1out {} 1090 counter ns2out {} 1091 1092 counter ns0in6 {} 1093 counter ns1in6 {} 1094 counter ns2in6 {} 1095 1096 counter ns0out6 {} 1097 counter ns1out6 {} 1098 counter ns2out6 {} 1099 1100 map nsincounter { 1101 type ipv4_addr : counter 1102 elements = { 10.0.1.1 : "ns0in", 1103 10.0.2.1 : "ns0in", 1104 10.0.1.99 : "ns1in", 1105 10.0.2.99 : "ns2in" } 1106 } 1107 1108 map nsincounter6 { 1109 type ipv6_addr : counter 1110 elements = { dead:1::1 : "ns0in6", 1111 dead:2::1 : "ns0in6", 1112 dead:1::99 : "ns1in6", 1113 dead:2::99 : "ns2in6" } 1114 } 1115 1116 map nsoutcounter { 1117 type ipv4_addr : counter 1118 elements = { 10.0.1.1 : "ns0out", 1119 10.0.2.1 : "ns0out", 1120 10.0.1.99: "ns1out", 1121 10.0.2.99: "ns2out" } 1122 } 1123 1124 map nsoutcounter6 { 1125 type ipv6_addr : counter 1126 elements = { dead:1::1 : "ns0out6", 1127 dead:2::1 : "ns0out6", 1128 dead:1::99 : "ns1out6", 1129 dead:2::99 : "ns2out6" } 1130 } 1131 1132 chain input { 1133 type filter hook input priority 0; policy accept; 1134 counter name ip saddr map @nsincounter 1135 icmpv6 type { "echo-request", "echo-reply" } counter name ip6 saddr map @nsincounter6 1136 } 1137 chain output { 1138 type filter hook output priority 0; policy accept; 1139 counter name ip daddr map @nsoutcounter 1140 icmpv6 type { "echo-request", "echo-reply" } counter name ip6 daddr map @nsoutcounter6 1141 } 1142} 1143EOF 1144done 1145 1146# special case for stateless nat check, counter needs to 1147# be done before (input) ip defragmentation 1148ip netns exec ns1-$sfx nft -f /dev/stdin <<EOF 1149table inet filter { 1150 counter ns0insl {} 1151 1152 chain pre { 1153 type filter hook prerouting priority -400; policy accept; 1154 ip saddr 10.0.2.2 counter name "ns0insl" 1155 } 1156} 1157EOF 1158 1159sleep 3 1160# test basic connectivity 1161for i in 1 2; do 1162 ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99 > /dev/null 1163 if [ $? -ne 0 ];then 1164 echo "ERROR: Could not reach other namespace(s)" 1>&2 1165 ret=1 1166 fi 1167 1168 ip netns exec "$ns0" ping -c 1 -q dead:$i::99 > /dev/null 1169 if [ $? -ne 0 ];then 1170 echo "ERROR: Could not reach other namespace(s) via ipv6" 1>&2 1171 ret=1 1172 fi 1173 check_counters ns$i-$sfx 1174 if [ $? -ne 0 ]; then 1175 ret=1 1176 fi 1177 1178 check_ns0_counters ns$i 1179 if [ $? -ne 0 ]; then 1180 ret=1 1181 fi 1182 reset_counters 1183done 1184 1185if [ $ret -eq 0 ];then 1186 echo "PASS: netns routing/connectivity: $ns0 can reach $ns1 and $ns2" 1187fi 1188 1189reset_counters 1190test_local_dnat ip 1191test_local_dnat6 ip6 1192 1193reset_counters 1194test_local_dnat_portonly inet 10.0.1.99 1195 1196reset_counters 1197$test_inet_nat && test_local_dnat inet 1198$test_inet_nat && test_local_dnat6 inet 1199 1200for flags in "" "fully-random"; do 1201reset_counters 1202test_masquerade ip $flags 1203test_masquerade6 ip6 $flags 1204reset_counters 1205$test_inet_nat && test_masquerade inet $flags 1206$test_inet_nat && test_masquerade6 inet $flags 1207done 1208 1209reset_counters 1210test_redirect ip 1211test_redirect6 ip6 1212reset_counters 1213$test_inet_nat && test_redirect inet 1214$test_inet_nat && test_redirect6 inet 1215 1216test_port_shadowing 1217test_stateless_nat_ip 1218 1219if [ $ret -ne 0 ];then 1220 echo -n "FAIL: " 1221 nft --version 1222fi 1223 1224exit $ret 1225