Attention is currently required from: chugly, flichtenheld, plaisthos.
Hello flichtenheld, plaisthos,
I'd like you to reexamine a change. Please visit
http://gerrit.openvpn.net/c/openvpn/+/1949?usp=email
to look at the new patch set (#2).
The following approvals got outdated and were removed:
Code-Review-1 by flichtenheld
Change subject: tests: add an end-to-end test for --route gateway keywords
......................................................................
tests: add an end-to-end test for --route gateway keywords
Nothing self-contained checks that a route openvpn says it installed
actually reached the kernel with the gateway it reported. t_client.sh does
compare routes, but it needs a t_client.rc and reachable servers, so it
skips for contributors and in CI.
Run a TLS loopback pair inside a throwaway network namespace, ask the
client for a route via net_gateway, and check where it lands. route.c
tracks two gateways, the system default route and the route towards the
peer, and net_gateway is the former. The peer here is on loopback, so the
two differ and the assertion can tell them apart: resolving from the wrong
one leaves the route with no gateway and the install fails outright.
The namespace also means the fixed loopback ports cannot collide, so this
needs none of the retry-on-address-in-use handling t_cltsrv.sh has.
The part that does not depend on how the environment is isolated lives in
t_route_common.sh: starting the openvpn pair, waiting for the route to
appear, and comparing the gateway. t_route.sh supplies the three hooks
that do depend on the platform, running a command inside the namespace and
the two routing table queries. The comparison is against the gateway the
platform reports rather than the text of the routing table entry, because
every routing tool spells that entry differently. A front end for a
system without network namespaces can then reuse the whole driver.
Both files are POSIX sh. Nothing here needed bash, and with a /bin/sh
shebang the runtime skips below can do their job on a platform without
bash rather than the script failing to start.
Skips rather than fails when it cannot run: not Linux, no iproute2, or no
way to get the privileges a namespace needs. Containers commonly disallow
namespace creation, so this will skip there and run on VMs and bare metal.
RUN_SUDO is picked up from t_client.rc the same way t_net.sh does.
Change-Id: I2e8f1449fe54e7f628e2bdb042ee2a567f25e02d
Signed-off-by: Charlie Vigue <[email protected]>
---
M tests/Makefile.am
A tests/t_route.sh
A tests/t_route_common.sh
3 files changed, 200 insertions(+), 1 deletion(-)
git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/49/1949/2
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3907965..5cfbf67e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -18,7 +18,7 @@
SH_LOG_DRIVER = $(SHELL) $(top_srcdir)/forked-test-driver
if !WIN32
-test_scripts = t_client.sh t_lpback.sh t_cltsrv.sh t_server_null.sh
+test_scripts = t_client.sh t_lpback.sh t_cltsrv.sh t_server_null.sh t_route.sh
check_PROGRAMS = ntlm_support
if HAVE_SITNL
@@ -35,6 +35,8 @@
t_cltsrv-down.sh \
t_lpback.sh \
t_net.sh \
+ t_route.sh \
+ t_route_common.sh \
t_server_null.sh \
t_server_null_client.sh \
t_server_null_server.sh \
diff --git a/tests/t_route.sh b/tests/t_route.sh
new file mode 100755
index 0000000..16ac293
--- /dev/null
+++ b/tests/t_route.sh
@@ -0,0 +1,129 @@
+#!/bin/sh
+#
+# t_route.sh - check that --route installs a route where it says it will
+#
+# The special gateway keywords (net_gateway, vpn_gateway, remote_host) are
+# resolved in route.c from data gathered off the system routing table. The
+# unit tests cover the resolution itself; this checks that the answer
+# reaches the kernel.
+#
+# route.c keeps two gateways: the system default route, and the route
+# towards the peer. net_gateway is the former. Here the peer is on
+# loopback, so the two are necessarily different and an assertion on the
+# installed gateway tells them apart.
+#
+# This is the network namespace front end, so the host routing table is not
+# touched and the fixed loopback ports cannot collide with anything. The
+# part that drives openvpn and checks the result lives in
+# t_route_common.sh, so a front end for a platform without namespaces can
+# reuse it.
+
+srcdir="${srcdir:-.}"
+top_builddir="${top_builddir:-..}"
+top_srcdir="${top_srcdir:-${srcdir}/..}"
+openvpn="${openvpn:-${top_builddir}/src/openvpn/openvpn}"
+
+# Namespace topology: one interface carrying a default route, which is
+# what net_gateway has to resolve to.
+NS="ovpnroute$$"
+TUN="ovpnt$$"
+LAN_GW="10.71.1.1"
+TARGET="10.71.250.1" # what we ask to be routed via net_gateway
+VPN_LOCAL="10.71.8.2"
+VPN_REMOTE="10.71.8.1"
+
+# Namespaces and dummy interfaces are Linux-only. A front end for another
+# platform would set its own environment up and reuse t_route_common.sh.
+if [ "$(uname -s)" != "Linux" ]; then
+ echo "$0: this front end runs only on Linux. SKIPPING TEST."
+ exit 77
+fi
+
+if [ ! -x "${openvpn}" ]; then
+ echo "$0: no (executable) openvpn binary in current build tree. FAIL." >&2
+ exit 1
+fi
+
+if ! command -v ip >/dev/null 2>&1; then
+ echo "$0: no iproute2 'ip' command in \$PATH. SKIPPING TEST." >&2
+ exit 77
+fi
+
+# t_client.rc is read only for a RUN_SUDO definition, as t_net.sh does
+if [ -r "${top_builddir}"/t_client.rc ]; then
+ . "${top_builddir}"/t_client.rc
+elif [ -r "${srcdir}"/t_client.rc ]; then
+ . "${srcdir}"/t_client.rc
+fi
+
+if [ "$(id -u)" -ne 0 ]; then
+ if [ -z "$RUN_SUDO" ]; then
+ RUN_SUDO="sudo"
+ fi
+else
+ RUN_SUDO=""
+fi
+
+# A namespace needs the same privileges the rest of the test does, so use
+# it as the probe.
+if ! $RUN_SUDO ip netns add "$NS"; then
+ echo "$0: cannot create a network namespace with '$RUN_SUDO'." >&2
+ echo "$0: containers commonly disallow this. SKIPPING TEST." >&2
+ exit 77
+fi
+
+srv_pid=""
+clt_pid=""
+logdir=$(mktemp -d) || exit 1
+
+cleanup()
+{
+ [ -n "$clt_pid" ] && kill "$clt_pid"
+ [ -n "$srv_pid" ] && kill "$srv_pid"
+ wait
+ # deleting the namespace takes every interface and route in it with it
+ $RUN_SUDO ip netns del "$NS"
+ [ -n "$logdir" ] && rm -rf "$logdir"
+ return 0
+}
+trap cleanup EXIT
+
+plat_exec()
+{
+ $RUN_SUDO ip netns exec "$NS" "$@"
+}
+
+plat_route_show()
+{
+ # absence is the expected state while polling, so the error iproute2
+ # prints for an unreachable address is noise rather than a diagnostic
+ plat_exec ip route show "$1" 2>/dev/null
+}
+
+plat_route_gateway()
+{
+ plat_route_show "$1" | sed -n
's/.*[[:space:]]via[[:space:]]\([^[:space:]]*\).*/\1/p'
+}
+
+. "${srcdir}"/t_route_common.sh
+
+set -e
+plat_exec ip link set lo up
+plat_exec ip link add lan0 type dummy
+plat_exec ip link set lan0 up
+plat_exec ip addr add 10.71.1.2/24 dev lan0
+plat_exec ip route add default via "$LAN_GW" dev lan0
+set +e
+
+route_start_pair
+
+if ! route_wait_for "$TARGET"; then
+ echo "$0: route to $TARGET was never installed. FAIL." >&2
+ echo "--- client log ---" >&2
+ cat "$logdir"/clt.log >&2
+ exit 1
+fi
+
+route_assert_gateway "$LAN_GW" || exit 1
+
+exit 0
diff --git a/tests/t_route_common.sh b/tests/t_route_common.sh
new file mode 100755
index 0000000..3a1fdd0
--- /dev/null
+++ b/tests/t_route_common.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+#
+# t_route_common.sh - platform-independent part of the --route gateway test
+#
+# Sourced by a front end that supplies the environment the test runs in and
+# the routing-table queries for the platform:
+#
+# plat_exec CMD... run CMD inside the test environment
+# plat_route_show ADDR print the routing table entry for ADDR, if any
+# plat_route_gateway ADDR print just the gateway of that entry, if any
+#
+# The front end also sets openvpn, top_srcdir, logdir, TUN, TARGET,
+# VPN_LOCAL and VPN_REMOTE before sourcing this file.
+#
+# Nothing here knows how the environment is isolated or which tools report
+# the routing table, so a front end for a platform without network
+# namespaces can reuse all of it.
+
+# A TLS loopback pair, as t_cltsrv.sh uses. Options after --config override
+# the config file, which is how the client gets a tun and a route.
+route_start_pair()
+{
+ plat_exec "${openvpn}" --cd "${top_srcdir}/sample" \
+ --config sample-config-files/loopback-server \
+ --verb 3 --ping-exit 60 >"$logdir"/srv.log 2>&1 &
+ srv_pid=$!
+
+ plat_exec "${openvpn}" --cd "${top_srcdir}/sample" \
+ --config sample-config-files/loopback-client \
+ --dev "$TUN" --dev-type tun \
+ --ifconfig "$VPN_LOCAL" "$VPN_REMOTE" \
+ --route "$TARGET" 255.255.255.255 net_gateway \
+ --verb 4 --ping-exit 60 >"$logdir"/clt.log 2>&1 &
+ clt_pid=$!
+}
+
+# Wait for the route to show up rather than guessing at a sleep. Sets
+# route_out to the entry that appeared.
+route_wait_for()
+{
+ i=0
+ route_out=""
+ while [ "$i" -lt 30 ]; do
+ route_out=$(plat_route_show "$1")
+ [ -n "$route_out" ] && return 0
+ i=$((i + 1))
+ sleep 1
+ done
+ return 1
+}
+
+# net_gateway is the system default gateway, not the route to the peer.
+# Compare the gateway the platform reports rather than the text of the
+# entry, which is spelled differently by every routing tool.
+route_assert_gateway()
+{
+ _want=$1
+ _got=$(plat_route_gateway "$TARGET")
+
+ if [ "$_got" = "$_want" ]; then
+ echo "$0: net_gateway resolved to $_want as expected"
+ return 0
+ fi
+
+ echo "$0: expected the route via the default gateway $_want," >&2
+ echo " got gateway '$_got' in: $route_out. FAIL." >&2
+ return 1
+}
--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1949?usp=email
To unsubscribe, or for help writing mail filters, visit
http://gerrit.openvpn.net/settings?usp=email
Gerrit-MessageType: newpatchset
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I2e8f1449fe54e7f628e2bdb042ee2a567f25e02d
Gerrit-Change-Number: 1949
Gerrit-PatchSet: 2
Gerrit-Owner: chugly <[email protected]>
Gerrit-Reviewer: flichtenheld <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: chugly <[email protected]>
Gerrit-Attention: plaisthos <[email protected]>
Gerrit-Attention: flichtenheld <[email protected]>
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel