From 097376db755f7abc08c60d82233a20ced9551e4e Mon Sep 17 00:00:00 2001 From: Dave Burke Date: Sat, 28 May 2016 21:39:47 -0500 Subject: [PATCH 1/4] Set working dir in ovpn_run instead of Dockerfile --- Dockerfile | 1 - bin/ovpn_run | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2cac8e2..49f09f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,6 @@ VOLUME ["/etc/openvpn"] # Internally uses port 1194/udp, remap using `docker run -p 443:1194/tcp` EXPOSE 1194/udp -WORKDIR /etc/openvpn CMD ["ovpn_run"] ADD ./bin /usr/local/bin diff --git a/bin/ovpn_run b/bin/ovpn_run index 920200c..f848780 100755 --- a/bin/ovpn_run +++ b/bin/ovpn_run @@ -10,6 +10,8 @@ fi set -e +cd $OPENVPN + # Build runtime arguments array based on environment ARGS=("--config" "$OPENVPN/openvpn.conf") From d77ba5e1e872c0d9612d57f9ea59aed644c4ffed Mon Sep 17 00:00:00 2001 From: Dave Burke Date: Sat, 28 May 2016 21:36:02 -0500 Subject: [PATCH 2/4] Combine user args with generated args Generated arguments will be added only if matching arguments were not specified by the user. User arguments will be placed after generated arguments. This allows the user to override any generated configuration values. --- bin/ovpn_run | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/bin/ovpn_run b/bin/ovpn_run index f848780..7ba16b1 100755 --- a/bin/ovpn_run +++ b/bin/ovpn_run @@ -13,7 +13,29 @@ set -e cd $OPENVPN # Build runtime arguments array based on environment -ARGS=("--config" "$OPENVPN/openvpn.conf") +USER_ARGS=("${@}") +ARGS=() + +# Checks if ARGS already contains the given value +function hasArg { + local element + for element in "${@:2}"; do + [ "${element}" == "${1}" ] && return 0 + done + return 1 +} + +# Adds the given argument if it's not already specified. +function addArg { + local arg="${1}" + [ $# -ge 1 ] && local val="${2}" + if ! hasArg "${arg}" "${USER_ARGS[@]}"; then + ARGS+=("${arg}") + [ $# -ge 1 ] && ARGS+=("${val}") + fi +} + +addArg "--config" "$OPENVPN/openvpn.conf" source "$OPENVPN/ovpn_env.sh" @@ -23,7 +45,7 @@ if [ ! -c /dev/net/tun ]; then fi if [ -d "$OPENVPN/ccd" ]; then - ARGS+=("--client-config-dir" "$OPENVPN/ccd") + addArg "--client-config-dir" "$OPENVPN/ccd" fi # When using --net=host, use this to specify nat device. @@ -48,7 +70,7 @@ if [ -r "$EASYRSA_PKI/crl.pem" ]; then ln "$EASYRSA_PKI/crl.pem" "$OPENVPN/crl.pem" chmod 644 "$OPENVPN/crl.pem" fi - ARGS+=("--crl-verify" "$OPENVPN/crl.pem") + addArg "--crl-verify" "$OPENVPN/crl.pem" fi ip -6 route show default 2>/dev/null @@ -61,8 +83,6 @@ if [ $? = 0 ]; then sysctl -w net.ipv6.conf.all.forwarding=1 || echo "Failed to enable IPv6 Forwarding" fi -if [ "$#" -gt 0 ]; then - exec openvpn "$@" -else - exec openvpn ${ARGS[@]} -fi +echo "Running 'openvpn ${ARGS[@]} ${USER_ARGS[@]}'" +exec openvpn ${ARGS[@]} ${USER_ARGS[@]} + From 5d436643b2b8704d5874f68783b8be58668265c1 Mon Sep 17 00:00:00 2001 From: Dave Burke Date: Sun, 29 May 2016 22:15:27 -0500 Subject: [PATCH 3/4] Add dual protocol test --- tests/dual-proto.sh | 72 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 tests/dual-proto.sh diff --git a/tests/dual-proto.sh b/tests/dual-proto.sh new file mode 100755 index 0000000..9c862e4 --- /dev/null +++ b/tests/dual-proto.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -ex + +OVPN_DATA=dual-data +CLIENT_UDP=travis-client +CLIENT_TCP=travis-client-tcp +IMG=kylemanna/openvpn + +# +# Create a docker container with the config data +# +docker run --name $OVPN_DATA -v /etc/openvpn busybox + +ip addr ls +SERV_IP=$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1) + +# get temporary TCP config +docker run --volumes-from $OVPN_DATA --rm $IMG ovpn_genconfig -u tcp://$SERV_IP:443 + +# nopass is insecure +docker run --volumes-from $OVPN_DATA --rm -it -e "EASYRSA_BATCH=1" -e "EASYRSA_REQ_CN=Travis-CI Test CA" $IMG ovpn_initpki nopass + +# gen TCP client +docker run --volumes-from $OVPN_DATA --rm -it $IMG easyrsa build-client-full $CLIENT_TCP nopass +docker run --volumes-from $OVPN_DATA --rm $IMG ovpn_getclient $CLIENT_TCP | tee client/config-tcp.ovpn + +# switch to UDP config and gen UDP client +docker run --volumes-from $OVPN_DATA --rm $IMG ovpn_genconfig -u udp://$SERV_IP +docker run --volumes-from $OVPN_DATA --rm -it $IMG easyrsa build-client-full $CLIENT_UDP nopass +docker run --volumes-from $OVPN_DATA --rm $IMG ovpn_getclient $CLIENT_UDP | tee client/config.ovpn + +#Verify client configs +docker run --volumes-from $OVPN_DATA --rm $IMG ovpn_listclients | grep $CLIENT_TCP +docker run --volumes-from $OVPN_DATA --rm $IMG ovpn_listclients | grep $CLIENT_UDP + +# +# Fire up the server +# +sudo iptables -N DOCKER +sudo iptables -I FORWARD -j DOCKER + +# run in shell bg to get logs +docker run --name "ovpn-test-udp" --volumes-from $OVPN_DATA --rm -p 1194:1194/udp --privileged $IMG & +docker run --name "ovpn-test-tcp" --volumes-from $OVPN_DATA --rm -p 443:1194/tcp --privileged $IMG ovpn_run --proto tcp & + +# +# Fire up a clients in a containers since openvpn is disallowed by Travis-CI, don't NAT +# the host as it confuses itself: +# "Incoming packet rejected from [AF_INET]172.17.42.1:1194[2], expected peer address: [AF_INET]10.240.118.86:1194" +# +docker run --rm --net=host --privileged --volume $PWD/client:/client $IMG /client/wait-for-connect.sh +docker run --rm --net=host --privileged --volume $PWD/client:/client $IMG /client/wait-for-connect.sh "/client/config-tcp.ovpn" + +# +# Client either connected or timed out, kill server +# +kill %1 + +# +# Celebrate +# +cat < < both ways! > + ------------ ------------ + \ ^__^ ^__^ / + \ (oo)\______/(oo) / + (__)\ /(__) + ||w---w|| + || || +EOF + From a5b9ade314bea96024cc4e39a777805fcecb7f0a Mon Sep 17 00:00:00 2001 From: Dave Burke Date: Tue, 31 May 2016 21:09:41 -0500 Subject: [PATCH 4/4] Add dual protocol documentation --- docs/tcp.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/tcp.md b/docs/tcp.md index e342ea4..87afc3b 100644 --- a/docs/tcp.md +++ b/docs/tcp.md @@ -5,6 +5,8 @@ By default, OpenVPN is configured to use the UDP protocol. Because UDP incurs m As an example, users connecting from an airplane wifi network may experience high packet drop rates, where the error detection and sliding window control of TCP can more readily adjust to the inconsistent connection. +Another example would be trying to open a VPN connection from within a very restrictive network. In some cases port 1194, or even UDP traffic on any port, may be restricted by network policy. Because TCP traffic on port 443 is used for normal TLS (https) web browsing, it is very unlikely to be blocked. + ## Using TCP Those requiring TCP connections should initialize the data container by specifying the TCP protocol and port number: @@ -16,3 +18,14 @@ specified protocol, adjust the mapping appropriately: docker run --volumes-from $OVPN_DATA -d -p 443:1194/tcp --cap-add=NET_ADMIN kylemanna/openvpn +## Running a Second Fallback TCP Container +Instead of choosing between UDP and TCP, you can use both. A single instance of OpenVPN can only listen for a single protocol on a single port, but this image makes it easy to run two instances simultaneously. After building, configuring, and starting a standard container listening for UDP traffic on 1194, you can start a second container listening for tcp traffic on port 443: + + docker run --volumes-from $OVPN_DATA --rm -p 443:1194/tcp --privileged kylemanna/openvpn ovpn_run --proto tcp + +`ovpn_run` will load all the values from the default config file, and `--proto tcp` will override the protocol setting. + +This allows you to use UDP most of the time, but fall back to TCP on the rare occasion that you need it. + +Note that you will need to configure client connections manually. At this time it is not possible to generate a client config that will automatically fall back to the TCP connection. +