#!/bin/sh #- # Copyright (c) 2010, "Bjoern A. Zeeb" # Copyright (c) 2011, Sandvine Incorporated ULC. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # # # Test ipfw fwd for IPv4 and IPv6 using VIMAGE, testing that as well. # For no test the packet header contents must be changed but always # keeping the original destination. # case `id -u` in 0) ;; *) echo "ERROR: Must be run as superuser." >&2 exit 2 esac epair_base() { local ep ep=`ifconfig epair create` expr ${ep} : '\(.*\).' } debug_err() { local _p _p="$1" case "${DEBUG}" in "") ;; *) echo " ~~ start of debug ~~" echo " ~~ left:" jexec ${ljid} /sbin/ipfw show echo " ~~ middle:" jexec ${mjid} /sbin/ipfw show echo " ~~ right:" jexec ${rjid} /sbin/ipfw show echo " ~~ result file:" cat ${_p}.1 echo " ~~ log file:" cat ${_p} echo " ~~ end of debug ~~" ;; esac } check_cleanup_result_file() { local _p _p="$1" if test ! -s ${_p}.1; then echo "FAIL (output file empty)." debug_err ${_p} else read line < ${_p}.1 # Netcat adds 'X's in udp mode. l="/${line#*/}" if test "${l}" = "${_p}"; then echo "PASS." else echo "FAIL (expected: '${_p}' got '${l}')." debug_err ${_p} fi fi rm -f ${_p}.1 rm -f ${_p} } # Transparent proxy scenario (local address). run_test_tp() { local _descr local _sip _dip _fip _fport _dport _p local _nc_af _nc_p local _lport descr="$1" _sip="$2" _dip="$3" _fip="$4" _fport="$5" _dport="$6" _p="$7" _nc_af="$8" _lport=${_dport} case "${_fport}" in "") _lport="${_dport}" ;; *) _lport="${_fport#,}" ;; esac case "${_p}" in udp) _nc_p="-u" ;; esac OUT=`mktemp -t "ipfwfwd$$-XXXXXX"` echo -n "${descr} (${OUT}).." ( jexec ${ljid} /sbin/ipfw -f flush jexec ${ljid} /sbin/ipfw -f zero jexec ${mjid} /sbin/ipfw -f flush jexec ${mjid} /sbin/ipfw -f zero jexec ${rjid} /sbin/ipfw -f flush jexec ${rjid} /sbin/ipfw -f zero jexec ${mjid} /sbin/ipfw add 100 fwd ${_fip}${_fport} ${_p} from ${_sip} to ${_dip} jexec ${mjid} /bin/sh -c "nc -w 10 ${_nc_af} -n ${_nc_p} -l ${_fip} ${_lport} > ${OUT}.1 &" jexec ${rjid} /bin/sh -c "echo '${OUT}' | nc -w 1 -v ${_nc_af} -n ${_nc_p} ${_dip} ${_dport}" ) > ${OUT} 2>&1 check_cleanup_result_file "${OUT}" } # Transparent redirect scenario (non-local address). run_test_nh() { local _descr local _sip _dip _fip _fport _dport _p local _nc_af _nc_p local _lport descr="$1" _sip="$2" _dip="$3" _fip="$4" _fport="$5" _dport="$6" _p="$7" _nc_af="$8" _lport=${_dport} case "${_fport}" in "") _lport="${_dport}" ;; *) _lport="${_fport#,}" ;; esac case "${_p}" in udp) _nc_p="-u" ;; esac OUT=`mktemp -t "ipfwfwd$$-XXXXXX"` echo -n "${descr} (${OUT}).." ( jexec ${ljid} /sbin/ipfw -f flush jexec ${ljid} /sbin/ipfw -f zero jexec ${mjid} /sbin/ipfw -f flush jexec ${mjid} /sbin/ipfw -f zero jexec ${rjid} /sbin/ipfw -f flush jexec ${rjid} /sbin/ipfw -f zero jexec ${mjid} /sbin/ipfw add 100 fwd ${_fip} ${_p} from ${_sip} to ${_dip} jexec ${ljid} /bin/sh -c "nc -w 10 ${_nc_af} -n ${_nc_p} -l ${_dip} ${_lport} > ${OUT}.1 &" jexec ${rjid} /bin/sh -c "echo '${OUT}' | nc -w 1 -v ${_nc_af} -n ${_nc_p} ${_dip} ${_dport}" ) > ${OUT} 2>&1 check_cleanup_result_file "${OUT}" } echo "==> Setting up test network" kldload -q ipfw > /dev/null 2>&1 # Start left (sender) jail. ljid=`jail -i -c -n lef$$ host.hostname=left.example.net vnet persist` # Start middle (ipfw) jail. mjid=`jail -i -c -n mid$$ host.hostname=center.example.net vnet persist` # Start right (non-local ip redirects go to here) jail. rjid=`jail -i -c -n right$$ host.hostname=right.example.net vnet persist` echo "left ${ljid} middle ${mjid} right ${rjid}" # Create networking. # # jail: left middle right # ifaces: lmep:a ---- lmep:b mrep:a ---- mrep:b # jexec ${mjid} sysctl net.inet.ip.forwarding=1 jexec ${mjid} sysctl net.inet6.ip6.forwarding=1 jexec ${mjid} sysctl net.inet6.ip6.accept_rtadv=0 lmep=$(epair_base) ifconfig ${lmep}a vnet ${ljid} ifconfig ${lmep}b vnet ${mjid} jexec ${ljid} ifconfig lo0 inet 127.0.0.1/8 jexec ${ljid} ifconfig lo0 inet 192.0.2.5/32 alias # Test 9-10 jexec ${ljid} ifconfig lo0 inet6 2001:db8:1::1/128 alias # Test 11-12 jexec ${ljid} ifconfig ${lmep}a inet 192.0.2.1/30 up jexec ${ljid} ifconfig ${lmep}a inet6 2001:db8::1/64 alias jexec ${ljid} route add default 192.0.2.2 jexec ${ljid} route add -inet6 default 2001:db8::2 jexec ${mjid} ifconfig lo0 inet 127.0.0.1/8 jexec ${mjid} ifconfig lo0 inet 192.0.2.255/32 alias # Test 1-4 jexec ${mjid} ifconfig lo0 inet6 2001:db8:ffff::1/128 alias # Test 5-8 jexec ${mjid} ifconfig ${lmep}b inet 192.0.2.2/30 up jexec ${mjid} ifconfig ${lmep}b inet6 2001:db8::2/64 alias jexec ${mjid} route add default 192.0.2.1 mrep=$(epair_base) ifconfig ${mrep}a vnet ${mjid} ifconfig ${mrep}b vnet ${rjid} jexec ${mjid} ifconfig ${mrep}a inet 192.0.2.5/30 up jexec ${mjid} ifconfig ${mrep}a inet6 2001:db8:1::1/64 alias jexec ${rjid} ifconfig lo0 inet 127.0.0.1/8 jexec ${rjid} ifconfig ${mrep}b inet 192.0.2.6/30 up jexec ${rjid} ifconfig ${mrep}b inet6 2001:db8:1::2/64 alias jexec ${rjid} route add default 192.0.2.5 jexec ${rjid} route add -inet6 default 2001:db8:1::1 # ------------------------------------------------------------------------------ # Tests # # The jails are not chrooted to they all share the same base filesystem. # This means we can put results into /tmp and just collect them from here. # echo "==> Running tests" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=1 run_test_tp "TEST ${i} IPv4 UDP redirect local to other local address, same port" \ 192.0.2.6 192.0.2.5 192.0.2.255 "" 12345 udp "-4" i=$((i + 1)) run_test_tp "TEST ${i} IPv4 UDP redirect local to other local address, different port" \ 192.0.2.6 192.0.2.5 192.0.2.255 ",65534" 12345 udp "-4" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=$((i + 1)) run_test_tp "TEST ${i} IPv4 TCP redirect local to other local address, same port" \ 192.0.2.6 192.0.2.5 192.0.2.255 "" 12345 tcp "-4" i=$((i + 1)) run_test_tp "TEST ${i} IPv4 TCP redirect local to other local address, different port" \ 192.0.2.6 192.0.2.5 192.0.2.255 ",65534" 12345 tcp "-4" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=$((i + 1)) run_test_tp "TEST ${i} IPv4 UDP redirect foreign to local address, same port" \ 192.0.2.6 192.0.2.1 192.0.2.255 "" 12345 udp "-4" i=$((i + 1)) run_test_tp "TEST ${i} IPv4 UDP redirect foreign to local address, different port" \ 192.0.2.6 192.0.2.1 192.0.2.255 ",65534" 12345 udp "-4" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=$((i + 1)) run_test_tp "TEST ${i} IPv4 TCP redirect foreign to local address, same port" \ 192.0.2.6 192.0.2.1 192.0.2.255 "" 12345 tcp "-4" i=$((i + 1)) run_test_tp "TEST ${i} IPv4 TCP redirect foreign to local address, different port" \ 192.0.2.6 192.0.2.1 192.0.2.255 ",65534" 12345 tcp "-4" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=$((i + 1)) run_test_tp "TEST ${i} IPv6 UDP redirect local to other local address, same port" \ 2001:db8:1::2 2001:db8::1 2001:db8:ffff::1 "" 12345 udp "-6" i=$((i + 1)) run_test_tp "TEST ${i} IPv6 UDP redirect local to other local address, different port" \ 2001:db8:1::2 2001:db8::1 2001:db8:ffff::1 ",65534" 12345 udp "-6" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=$((i + 1)) run_test_tp "TEST ${i} IPv6 TCP redirect local to other local address, same port" \ 2001:db8:1::2 2001:db8::1 2001:db8:ffff::1 "" 12345 tcp "-6" i=$((i + 1)) run_test_tp "TEST ${i} IPv6 TCP redirect local to other local address, different port" \ 2001:db8:1::2 2001:db8::1 2001:db8:ffff::1 ",65534" 12345 tcp "-6" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=$((i + 1)) run_test_tp "TEST ${i} IPv6 UDP redirect foreign to local address, same port" \ 2001:db8:1::2 2001:db8::1 2001:db8:ffff::1 "" 12345 udp "-6" i=$((i + 1)) run_test_tp "TEST ${i} IPv6 UDP redirect foreign to local address, different port" \ 2001:db8:1::2 2001:db8::1 2001:db8:ffff::1 ",65534" 12345 udp "-6" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=$((i + 1)) run_test_tp "TEST ${i} IPv6 TCP redirect foreign to local address, same port" \ 2001:db8:1::2 2001:db8::1 2001:db8:ffff::1 "" 12345 tcp "-6" i=$((i + 1)) run_test_tp "TEST ${i} IPv6 TCP redirect foreign to local address, different port" \ 2001:db8:1::2 2001:db8::1 2001:db8:ffff::1 ",65534" 12345 tcp "-6" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=$((i + 1)) run_test_nh "TEST ${i} IPv4 UDP redirect to foreign address" \ 192.0.2.6 192.0.2.5 192.0.2.1 "" 12345 udp "-4" i=$((i + 1)) run_test_nh "TEST ${i} IPv4 TCP redirect to foreign address" \ 192.0.2.6 192.0.2.5 192.0.2.1 "" 12345 tcp "-4" #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i=$((i + 1)) run_test_nh "TEST ${i} IPv6 UDP redirect to foreign address" \ 2001:db8:1::2 2001:db8:1::1 2001:db8::1 "" 12345 udp "-6" i=$((i + 1)) run_test_nh "TEST ${i} IPv6 TCP redirect to foreign address" \ 2001:db8:1::2 2001:db8:1::1 2001:db8::1 "" 12345 tcp "-6" ################################################################################ # # Cleanup # echo "==> Cleaning up in 3 seconds" # Let VIMAGE network stacks settle to avoid panics while still "experimental". sleep 3 jail -r ${rjid} jail -r ${mjid} jail -r ${ljid} for jid in ${rjid} ${mjid} ${ljid}; do while : ; do x=`jls -as -j ${jid} jid 2>/dev/null` case "${x}" in jid=*) echo "Waiting for jail ${jid} to stop." >&2 sleep 1 continue ;; esac break done done ifconfig ${lmep}a destroy ifconfig ${mrep}a destroy # end