From 9f89da6522a2ab38ec01db2843e8785507898845 Mon Sep 17 00:00:00 2001 From: Dean Bailey Date: Sun, 4 Mar 2018 23:39:38 -0800 Subject: [PATCH 1/2] Added UFW_ALLOW_GW_NET. Changes firewall rules from using GW to the GW network when set to true. Extended LOCAL_NETWORK to support comma seperated list of /CIDR. Minor firewall cleanups. Removed specified TCP in range allow. No point, we don't specify tcp/udp anywhere else. Formatting changes (BASH 3+ style). Cleaned removed external [ ] calls. Use builtin [[ ]]. Use ${VAR,,} to lowercase isntead of TR. --- DockerEnv | 1 + Dockerfile | 1 + Dockerfile.alpine | 2 + Dockerfile.armhf | 1 + README.md | 4 +- openvpn/start.sh | 156 +++++++++++++++++++++++++++------------------- 6 files changed, 100 insertions(+), 65 deletions(-) diff --git a/DockerEnv b/DockerEnv index 65cab3f6e..19d7f937c 100644 --- a/DockerEnv +++ b/DockerEnv @@ -6,6 +6,7 @@ #OPENVPN_OPTS=--inactive 3600 --ping 10 --ping-exit 60 #LOCAL_NETWORK= #ENABLE_UFW=false +#UFW_ALLOW_GW_NET=false #UFW_EXTRA_PORTS= #TRANSMISSION_ALT_SPEED_DOWN=50 #TRANSMISSION_ALT_SPEED_ENABLED=false diff --git a/Dockerfile b/Dockerfile index 435d65c0b..a0dc75b50 100644 --- a/Dockerfile +++ b/Dockerfile @@ -110,6 +110,7 @@ ENV OPENVPN_USERNAME=**None** \ TRANSMISSION_WATCH_DIR_ENABLED=true \ TRANSMISSION_HOME=/data/transmission-home \ ENABLE_UFW=false \ + UFW_ALLOW_GW_NET=false \ UFW_EXTRA_PORTS= \ TRANSMISSION_WEB_UI= \ PUID= \ diff --git a/Dockerfile.alpine b/Dockerfile.alpine index e6bae372c..114112f39 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -101,6 +101,8 @@ ENV OPENVPN_USERNAME=**None** \ TRANSMISSION_WATCH_DIR_ENABLED=true \ TRANSMISSION_HOME=/data/transmission-home \ ENABLE_UFW=false \ + UFW_ALLOW_GW_NET=false \ + UFW_EXTRA_PORTS= \ TRANSMISSION_WEB_UI= \ PUID= \ PGID= \ diff --git a/Dockerfile.armhf b/Dockerfile.armhf index c5b3ff76b..e7fa38cd7 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -101,6 +101,7 @@ ENV OPENVPN_USERNAME=**None** \ TRANSMISSION_WATCH_DIR_ENABLED=true \ TRANSMISSION_HOME=/data/transmission-home \ ENABLE_UFW=false \ + UFW_ALLOW_GW_NET=false \ UFW_EXTRA_PORTS= \ TRANSMISSION_WEB_UI=\ PUID=\ diff --git a/README.md b/README.md index cb28fadba..8c6e02ee0 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ This is a list of providers that are bundled within the image. Feel free to crea |----------|----------|-------| |`OPENVPN_CONFIG` | Sets the OpenVPN endpoint to connect to. | `OPENVPN_CONFIG=UK Southampton`| |`OPENVPN_OPTS` | Will be passed to OpenVPN on startup | See [OpenVPN doc](https://openvpn.net/index.php/open-source/documentation/manuals/65-openvpn-20x-manpage.html) | -|`LOCAL_NETWORK` | Sets the local network that should have access. | `LOCAL_NETWORK=192.168.0.0/24`| +|`LOCAL_NETWORK` | Sets the local network that should have access. Accepts comma separated list. | `LOCAL_NETWORK=192.168.0.0/24`| ### Firewall configuration options When enabled, the firewall blocks everything except traffic to the peer port and traffic to the rpc port from the LOCAL_NETWORK and the internal docker gateway. @@ -147,6 +147,8 @@ If TRANSMISSION_PEER_PORT_RANDOM_ON_START is enabled then it allows traffic to t | Variable | Function | Example | |----------|----------|-------| |`ENABLE_UFW` | Enables the firewall | `ENABLE_UFW=true`| +|`UFW_ALLOW_GW_NET` | Allows the gateway network through the firewall. Off defaults to only allowing the gateway. | `UFW_ALLOW_GW_NET=true`| +|`UFW_EXTRA_PORTS` | Allows the comma separated list of ports through the firewall. Respsects UFW_ALLOW_GW_NET. | `UFW_EXTRA_PORTS=9910,23561,443`| ### Alternative web UIs You can override the default web UI by setting the ```TRANSMISSION_WEB_HOME``` environment variable. If set, Transmission will look there for the Web Interface files, such as the javascript, html, and graphics files. diff --git a/openvpn/start.sh b/openvpn/start.sh index f123a2dce..5db8035fe 100755 --- a/openvpn/start.sh +++ b/openvpn/start.sh @@ -1,42 +1,40 @@ #!/bin/bash -vpn_provider="$(echo $OPENVPN_PROVIDER | tr '[A-Z]' '[a-z]')" -vpn_provider_configs="/etc/openvpn/$vpn_provider" -if [ ! -d "$vpn_provider_configs" ]; then - echo "Could not find OpenVPN provider: $OPENVPN_PROVIDER" - echo "Please check your settings." - exit 1 +VPN_PROVIDER="${OPENVPN_PROVIDER,,}" +VPN_PROVIDER_CONFIGS="/etc/openvpn/${VPN_PROVIDER}" +if [[ ! -d "${VPN_PROVIDER_CONFIGS}" ]]; then + echo "Could not find OpenVPN provider: ${OPENVPN_PROVIDER}" + echo "Please check your settings." + exit 1 fi -echo "Using OpenVPN provider: $OPENVPN_PROVIDER" +echo "Using OpenVPN provider: ${OPENVPN_PROVIDER}" -if [ ! -z "$OPENVPN_CONFIG" ] -then - n=$(echo "$OPENVPN_CONFIG" | wc -w) - if [ $n -gt 1 ] - then - rnd=$((RANDOM%n+1)) - srv=$(echo "$OPENVPN_CONFIG" | awk -vrnd=$rnd '{print $rnd}') - echo "$n servers found in OPENVPN_CONFIG, $srv chosen randomly" - OPENVPN_CONFIG=$srv - fi +if [[ ! -z "${OPENVPN_CONFIG}" ]]; then + n=$(echo "$OPENVPN_CONFIG" | wc -w) + if [ $n -gt 1 ] + then + rnd=$((RANDOM%n+1)) + srv=$(echo "$OPENVPN_CONFIG" | awk -vrnd=$rnd '{print $rnd}') + echo "$n servers found in OPENVPN_CONFIG, $srv chosen randomly" + OPENVPN_CONFIG=$srv + fi - if [ -f $vpn_provider_configs/"${OPENVPN_CONFIG}".ovpn ] - then - echo "Starting OpenVPN using config ${OPENVPN_CONFIG}.ovpn" - OPENVPN_CONFIG=$vpn_provider_configs/${OPENVPN_CONFIG}.ovpn - else - echo "Supplied config ${OPENVPN_CONFIG}.ovpn could not be found." - echo "Using default OpenVPN gateway for provider ${vpn_provider}" - OPENVPN_CONFIG=$vpn_provider_configs/default.ovpn - fi + if [[ -f "${VPN_PROVIDER_CONFIGS}/${OPENVPN_CONFIG}".ovpn ]]; then + echo "Starting OpenVPN using config ${OPENVPN_CONFIG}.ovpn" + OPENVPN_CONFIG="${VPN_PROVIDER_CONFIGS}/${OPENVPN_CONFIG}.ovpn" + else + echo "Supplied config ${OPENVPN_CONFIG}.ovpn could not be found." + echo "Using default OpenVPN gateway for provider ${VPN_PROVIDER}" + OPENVPN_CONFIG="${VPN_PROVIDER_CONFIGS}/default.ovpn" + fi else - echo "No VPN configuration provided. Using default." - OPENVPN_CONFIG=$vpn_provider_configs/default.ovpn + echo "No VPN configuration provided. Using default." + OPENVPN_CONFIG="${VPN_PROVIDER_CONFIGS}/default.ovpn" fi # add OpenVPN user/pass -if [ "${OPENVPN_USERNAME}" = "**None**" ] || [ "${OPENVPN_PASSWORD}" = "**None**" ] ; then - if [ ! -f /config/openvpn-credentials.txt ] ; then +if [[ "${OPENVPN_USERNAME}" == "**None**" ]] || [[ "${OPENVPN_PASSWORD}" == "**None**" ]] ; then + if [[ ! -f /config/openvpn-credentials.txt ]] ; then echo "OpenVPN credentials not set. Exiting." exit 1 fi @@ -44,67 +42,97 @@ if [ "${OPENVPN_USERNAME}" = "**None**" ] || [ "${OPENVPN_PASSWORD}" = "**None** else echo "Setting OPENVPN credentials..." mkdir -p /config - echo $OPENVPN_USERNAME > /config/openvpn-credentials.txt - echo $OPENVPN_PASSWORD >> /config/openvpn-credentials.txt + echo "${OPENVPN_USERNAME}" > /config/openvpn-credentials.txt + echo "${OPENVPN_PASSWORD}" >> /config/openvpn-credentials.txt chmod 600 /config/openvpn-credentials.txt fi # add transmission credentials from env vars -echo $TRANSMISSION_RPC_USERNAME > /config/transmission-credentials.txt -echo $TRANSMISSION_RPC_PASSWORD >> /config/transmission-credentials.txt +echo "${TRANSMISSION_RPC_USERNAME}" > /config/transmission-credentials.txt +echo "${TRANSMISSION_RPC_PASSWORD}" >> /config/transmission-credentials.txt # Persist transmission settings for use by transmission-daemon dockerize -template /etc/transmission/environment-variables.tmpl:/etc/transmission/environment-variables.sh TRANSMISSION_CONTROL_OPTS="--script-security 2 --up-delay --up /etc/openvpn/tunnelUp.sh --down /etc/openvpn/tunnelDown.sh" -if [ "true" = "$ENABLE_UFW" ]; then +## If we use UFW or the LOCAL_NETWORK we need to grab network config info +if [[ "${ENABLE_UFW,,}" == "true" ]] || [[ -n "${LOCAL_NETWORK-}" ]]; then + eval $(/sbin/ip r l m 0.0.0.0 | awk '{if($5!="tun0"){print "GW="$3"\nINT="$5; exit}}') + ## IF we use UFW_ALLOW_GW_NET along with ENABLE_UFW we need to know what our netmask CIDR is + if [[ "${ENABLE_UFW,,}" == "true" ]] && [[ "${UFW_ALLOW_GW_NET,,}" == "true" ]]; then + eval $(ip r l dev ${INT} | awk '{if($5=="link"){print "GW_CIDR="$1; exit}}') + fi +fi + +## Open port to any address +function ufwAllowPort { + typeset -n portNum=${1} + if [[ "${ENABLE_UFW,,}" == "true" ]] && [[ -n "${portNum-}" ]]; then + echo "allowing ${portNum} through the firewall" + ufw allow ${portNum} + fi +} + +## Open port to specific address. +function ufwAllowPortLong { + typeset -n portNum=${1} sourceAddress=${2} + + if [[ "${ENABLE_UFW,,}" == "true" ]] && [[ -n "${portNum-}" ]] && [[ -n "${sourceAddress-}" ]]; then + echo "allowing ${sourceAddress} through the firewall to port ${portNum}" + ufw allow from ${sourceAddress} to any port ${portNum} + fi +} + +if [[ "${ENABLE_UFW,,}" == "true" ]]; then # Enable firewall echo "enabling firewall" sed -i -e s/IPV6=yes/IPV6=no/ /etc/default/ufw ufw enable - if [ "true" = "$TRANSMISSION_PEER_PORT_RANDOM_ON_START" ]; then - PEER_PORT="$TRANSMISSION_PEER_PORT_RANDOM_LOW:$TRANSMISSION_PEER_PORT_RANDOM_HIGH/tcp" + if [[ "${TRANSMISSION_PEER_PORT_RANDOM_ON_START,,}" == "true" ]]; then + PEER_PORT="${TRANSMISSION_PEER_PORT_RANDOM_LOW}:${TRANSMISSION_PEER_PORT_RANDOM_HIGH}" else - PEER_PORT=$TRANSMISSION_PEER_PORT + PEER_PORT="${TRANSMISSION_PEER_PORT}" fi - echo "allowing $PEER_PORT through the firewall" - ufw allow $PEER_PORT + ufwAllowPort PEER_PORT - if [ "true" = "$WEBPROXY_ENABLED" ]; then - echo "allowing $WEBPROXY_PORT through the firewall" - ufw allow $WEBPROXY_PORT + if [[ "${WEBPROXY_ENABLED,,}" == "true" ]]; then + ufwAllowPort WEBPROXY_PORT + fi + if [[ "${UFW_ALLOW_GW_NET,,}" == "true" ]]; then + ufwAllowPortLong TRANSMISSION_RPC_PORT GW_CIDR + else + ufwAllowPortLong TRANSMISSION_RPC_PORT GW fi - eval $(/sbin/ip r l m 0.0.0.0 | awk '{if($5!="tun0"){print "GW="$3"\nINT="$5; exit}}') - echo "allowing access to $TRANSMISSION_RPC_PORT from $GW" - ufw allow proto tcp from $GW to any port $TRANSMISSION_RPC_PORT - if [ ! -z "${UFW_EXTRA_PORTS}" ]; then + if [[ -n "${UFW_EXTRA_PORTS-}" ]]; then for port in ${UFW_EXTRA_PORTS//,/ }; do - echo "allowing access to ${port} from $GW" - ufw allow proto tcp from $GW to any port ${port} + if [[ "${UFW_ALLOW_GW_NET,,}" == "true" ]]; then + ufwAllowPortLong port GW_CIDR + else + ufwAllowPortLong port GW + fi done fi fi -if [ -n "${LOCAL_NETWORK-}" ]; then - eval $(/sbin/ip r l m 0.0.0.0 | awk '{if($5!="tun0"){print "GW="$3"\nINT="$5; exit}}') - if [ -n "${GW-}" -a -n "${INT-}" ]; then - echo "adding route to local network $LOCAL_NETWORK via $GW dev $INT" - /sbin/ip r a "$LOCAL_NETWORK" via "$GW" dev "$INT" - if [ "true" = "$ENABLE_UFW" ]; then - echo "allowing access to $TRANSMISSION_RPC_PORT from $LOCAL_NETWORK" - ufw allow proto tcp from $LOCAL_NETWORK to any port $TRANSMISSION_RPC_PORT - if [ ! -z "${UFW_EXTRA_PORTS}" ]; then - for port in ${UFW_EXTRA_PORTS//,/ }; do - echo "allowing access to ${port} from $LOCAL_NETWORK" - ufw allow proto tcp from $LOCAL_NETWORK to any port ${port} - done +if [[ -n "${LOCAL_NETWORK-}" ]]; then + if [[ -n "${GW-}" ]] && [[ -n "${INT-}" ]]; then + for localNet in ${LOCAL_NETWORK//,/ }; do + echo "adding route to local network ${localNet} via ${GW} dev ${INT}" + /sbin/ip r a "${localNet}" via "${GW}" dev "${INT}" + if [[ "${ENABLE_UFW,,}" == "true" ]]; then + ufwAllowPortLong TRANSMISSION_RPC_PORT localNet + if [[ -n "${UFW_EXTRA_PORTS-}" ]]; then + for port in ${UFW_EXTRA_PORTS//,/ }; do + ufwAllowPortLong port localNet + done + fi fi - fi + done fi fi -exec openvpn $TRANSMISSION_CONTROL_OPTS $OPENVPN_OPTS --config "$OPENVPN_CONFIG" +exec openvpn ${TRANSMISSION_CONTROL_OPTS} ${OPENVPN_OPTS} --config "${OPENVPN_CONFIG}" From 6649edeedf0dc67b53310c4ed19832a31ab704be Mon Sep 17 00:00:00 2001 From: Dean Bailey Date: Sun, 4 Mar 2018 23:58:13 -0800 Subject: [PATCH 2/2] Fixed breakage caused by splitting on SPACE in OPENVPN_CONFIG Changed to split on comma as many openvpn configs have space in the name. Added a bit more validation that a provider is set. Updated docs. --- README.md | 4 ++-- openvpn/start.sh | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8c6e02ee0..3cb648bbd 100644 --- a/README.md +++ b/README.md @@ -65,10 +65,10 @@ Find available OpenVPN configurations by looking in the openvpn folder of the Gi -e "OPENVPN_CONFIG=ipvanish-AT-Vienna-vie-c02" ``` -You can also provide a list of openvpn configuration filenames separated by a space. +You can also provide a comma separated list of openvpn configuration filenames. If you provide a list, a file will be randomly chosen in the list, this is useful for redundancy setups. For example: ``` --e "OPENVPN_CONFIG=ipvanish-AT-Vienna-vie-c02 ipvanish-FR-Paris-par-a01 ipvanish-DE-Frankfurt-fra-a01" +-e "OPENVPN_CONFIG=ipvanish-AT-Vienna-vie-c02,ipvanish-FR-Paris-par-a01,ipvanish-DE-Frankfurt-fra-a01" ``` If you provide a list and the selected server goes down, after the value of ping-timeout the container will be restarted and a server will be randomly chosen, note that the faulty server can be chosen again, if this should occur, the container will be restarted again until a working server is selected. diff --git a/openvpn/start.sh b/openvpn/start.sh index 5db8035fe..96303dc8f 100755 --- a/openvpn/start.sh +++ b/openvpn/start.sh @@ -1,7 +1,11 @@ #!/bin/bash VPN_PROVIDER="${OPENVPN_PROVIDER,,}" VPN_PROVIDER_CONFIGS="/etc/openvpn/${VPN_PROVIDER}" -if [[ ! -d "${VPN_PROVIDER_CONFIGS}" ]]; then + +if [[ "${OPENVPN_PROVIDER}" == "**None**" ]] || [[ -z "${OPENVPN_PROVIDER-}" ]]; then + echo "OpenVPN provider not set. Exiting." + exit 1 +elif [[ ! -d "${VPN_PROVIDER_CONFIGS}" ]]; then echo "Could not find OpenVPN provider: ${OPENVPN_PROVIDER}" echo "Please check your settings." exit 1 @@ -9,14 +13,12 @@ fi echo "Using OpenVPN provider: ${OPENVPN_PROVIDER}" -if [[ ! -z "${OPENVPN_CONFIG}" ]]; then - n=$(echo "$OPENVPN_CONFIG" | wc -w) - if [ $n -gt 1 ] - then - rnd=$((RANDOM%n+1)) - srv=$(echo "$OPENVPN_CONFIG" | awk -vrnd=$rnd '{print $rnd}') - echo "$n servers found in OPENVPN_CONFIG, $srv chosen randomly" - OPENVPN_CONFIG=$srv +if [[ -n "${OPENVPN_CONFIG-}" ]]; then + readarray -t OPENVPN_CONFIG_ARRAY <<< "${OPENVPN_CONFIG//,/$'\n'}" + if (( ${#OPENVPN_CONFIG_ARRAY[@]} > 1 )); then + OPENVPN_CONFIG_RANDOM=$((RANDOM%${#OPENVPN_CONFIG_ARRAY[@]})) + echo "${#OPENVPN_CONFIG_ARRAY[@]} servers found in OPENVPN_CONFIG, ${OPENVPN_CONFIG_ARRAY[${OPENVPN_CONFIG_RANDOM}]} chosen randomly" + OPENVPN_CONFIG="${OPENVPN_CONFIG_ARRAY[${OPENVPN_CONFIG_RANDOM}]}" fi if [[ -f "${VPN_PROVIDER_CONFIGS}/${OPENVPN_CONFIG}".ovpn ]]; then