eccbdd061b
Distinguish IPv4 and IPv6 addresses and optional port numbers in user space to set the option for the correct protocol family. Add support in the kernel for carrying the new IPv6 destination address and port. Add support to TCP and UDP for IPv6 and fix UDP IPv4 to not change the address in the IP header. Add support for IPv6 forwarding to a non-local destination. Add a regession test uitilizing VIMAGE to check all 20 possible combinations I could think of. Obtained from: David Dolson at Sandvine Incorporated (original version for ipfw fwd IPv6 support) Sponsored by: Sandvine Incorporated PR: bin/117214 MFC after: 4 weeks Approved by: re (kib)
370 lines
11 KiB
Bash
Executable File
370 lines
11 KiB
Bash
Executable File
#!/bin/sh
|
|
#-
|
|
# Copyright (c) 2010, "Bjoern A. Zeeb" <bz@FreeBSD.org>
|
|
# 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.
|
|
#
|
|
# $FreeBSD$
|
|
#
|
|
|
|
#
|
|
# 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
|