diff --git a/Dockerfile b/Dockerfile index 02333c9c..ee72ff53 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ LABEL org.label-schema.schema-version="1.0.0-rc1" \ org.label-schema.docker.cmd.devel="docker run -it --rm --init --cap-add=NET_ADMIN --device=/dev/net/tun -e USER=js89ds7 -e PASSWORD=8fd9s239G qmcgaw/private-internet-access" \ org.label-schema.docker.params="REGION=PIA region,PROTOCOL=udp/tcp,ENCRYPTION=strong/normal,BLOCK_MALICIOUS=on/off,BLOCK_NSA=on/off,UNBLOCK=allowed hostnames,USER=PIA user,PASSWORD=PIA password,EXTRA_SUBNETS=extra subnets to allow on the firewall,NONROOT=yes/no" \ org.label-schema.version="" \ - image-size="19.8MB" \ + image-size="19.9MB" \ ram-usage="13MB to 80MB" \ cpu-usage="Low to Medium" ENV USER= \ @@ -29,7 +29,6 @@ ENV USER= \ BLOCK_MALICIOUS=off \ BLOCK_NSA=off \ UNBLOCK= \ - FIREWALL=on \ EXTRA_SUBNETS= \ PROXY=on \ PROXY_LOG_LEVEL=Critical \ diff --git a/README.md b/README.md index 1463619c..c2bd04d9 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ | Image size | RAM usage | CPU usage | | --- | --- | --- | -| 19.8MB | 14MB to 80MB | Low to Medium | +| 19.9MB | 14MB to 80MB | Low to Medium |
Click to show base components

@@ -46,31 +46,33 @@ - DNS over TLS - Malicious DNS blocking - Internal firewall - - Web HTTP proxy (**not working yet**) + - Web HTTP proxy - Run openvpn without root

- Connect other containers to it, [see this](https://github.com/qdm12/private-internet-access-docker#connect-to-it) +- **ARM** compatible +- Port forwarding +- HTTP proxy for LAN devices - The *iptables* firewall allows traffic only with needed PIA servers (IP addresses, port, protocol) combinations - OpenVPN reconnects automatically on failure - Docker healthcheck pings the DNS 1.1.1.1 to verify the connection is up - Unbound DNS runs *without root* - OpenVPN can run *without root* but this disallows OpenVPN reconnecting, it can be set with `NONROOT=yes` -- **ARM** compatible -- Port forwarding -- HTTP proxy for LAN devices (**not working yet**) + ## Setup 1.
Requirements

- A Private Internet Access **username** and **password** - [Sign up](https://www.privateinternetaccess.com/pages/buy-vpn/) - - Firewall requirements + - External firewall requirements, if you have one - Allow outbound TCP 853 to 1.1.1.1 to allow Unbound to resolve the PIA domain name at start. You can then block it once the container is started. - For UDP strong encryption, allow outbound UDP 1197 - For UDP normal encryption, allow outbound UDP 1198 - For TCP strong encryption, allow outbound TCP 501 - For TCP normal encryption, allow outbound TCP 502 + - For the built-in web HTTP proxy, allow inbound TCP 8888

@@ -124,9 +126,10 @@ docker-compose up -d ``` - Note that you can change all the [environment variables](#environment-variables). - - If you want to use the **HTTP proxy**, add `-p 8888:8888/tcp` so that it is accessible from LAN devices. + Note that you can: + - Change the many [environment variables](#environment-variables) available + - Use `-p 8888:8888/tcp` to access the HTTP web proxy (and put your LAN in `EXTRA_SUBNETS` environment variable) + - Pass additional arguments to *openvpn* using Docker's command function (commands after the image name) ## Testing @@ -150,7 +153,6 @@ docker run --rm --network=container:pia alpine:3.10 wget -qO- https://ipinfo.io | `BLOCK_MALICIOUS` | `off` | `on` or `off`, blocks malicious hostnames and IPs | | `BLOCK_NSA` | `off` | `on` or `off`, blocks NSA hostnames | | `UNBLOCK` | | comma separated string (i.e. `web.com,web2.ca`) to unblock hostnames | -| `FIREWALL` | `on` | `on` or `off`, to switch the internal killswitch firewall (should be left `on`) | | `EXTRA_SUBNETS` | | comma separated subnets allowed in the container firewall (i.e. `192.168.1.0/24,192.168.10.121,10.0.0.5/28`) | | `PROXY` | `on` | `on` or `off`, to switch the internal HTTP proxy | | `PROXY_LOG_LEVEL` | `Critical` | `Info`, `Warning`, `Error` or `Critical` | @@ -161,24 +163,42 @@ docker run --rm --network=container:pia alpine:3.10 wget -qO- https://ipinfo.io There are various ways to achieve this, depending on your use case. --
Connect other containers to PIA

- - Add `--network=container:pia` when launching the container - -

--
Connect containers from another docker-compose.yml

- - Add `network_mode: "container:pia"` to your *docker-compose.yml* - -

-
Connect containers in the same docker-compose.yml as PIA

Add `network_mode: "service:pia"` to your *docker-compose.yml* (no need for `depends_on`) +

+-
Connect other containers to PIA

+ + Add `--network=container:pia` when launching the container, provided PIA is already running + +

+-
Connect containers from another docker-compose.yml

+ + Add `network_mode: "container:pia"` to your *docker-compose.yml*, provided PIA is already running + +

+-
Connect LAN devices through the built-in HTTP proxy (i.e. with Chrome, Kodi, etc.)

+ + 1. Setup a HTTP proxy client, such as [SwitchyOmega for Chrome](https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=en) + 1. Ensure the PIA container is launched with: + - port 8888 published `-p 8888:8888/tcp` + - your LAN subnet, i.e. 192.168.1.0/24, set as `-e EXTRA_SUBNETS=192.168.1.0/24` + 1. With your HTTP proxy client, connect to the Docker host (i.e. `192.168.1.10`) on port `8888`. You might need to enter your credentials if you set them with the environment variables `PROXY_USER` and `PROXY_PASSWORD`. + 1. If you set `PROXY_LOG_LEVEL` to `Info`, you can check the log output of tinyproxy with: + + ```sh + docker exec -it pia cat /var/log/tinyproxy/tinyproxy.log + ``` + + `PROXY_LOG_LEVEL` defaults to `Critical` to avoid logging everything, for privacy purposes as well as to save storage. +

-
Access ports of containers connected to PIA

- To access port `8000` of container `xyz` and `9000` of container `abc` connected to PIA, you will need a reverse proxy such as `qmcgaw/caddy-scratch` (you can build it for **ARM**, see its [readme](https://github.com/qdm12/caddy-scratch)) + In example, to access port `8000` of container `xyz` and `9000` of container `abc` connected to PIA: + **With recent changes to the firewall**, you might be able to simply publish ports `8000` and `9000` for the PIA container and access them as you would + with any other container. Otherwise... 1. Create the file *Caddyfile* @@ -246,7 +266,8 @@ There are various ways to achieve this, depending on your use case.

-
Access ports of containers connected to PIA, all in the same docker-compose.yml

- To access port `8000` of container `xyz` and `9000` of container `abc` connected to PIA, you could use: + In example, to access port `8000` of container `xyz` and `9000` of container `abc` connected to PIA, publish port `8000` and `9000` for the PIA container. + The docker-compose.yml file would look like: ```yml version: '3' @@ -276,88 +297,6 @@ There are various ways to achieve this, depending on your use case.

--
Access ports of containers connected to PIA, all in the same docker-compose.yml, using a reverse proxy

- - To access port `8000` of container `xyz` and `9000` of container `abc` connected to PIA, you will need a reverse proxy such as `qmcgaw/caddy-scratch` (you can build it for **ARM**, see its [readme](https://github.com/qdm12/caddy-scratch)) - - 1. Create the file *Caddyfile* - - ```sh - touch Caddyfile - chown 1000 Caddyfile - # chown 1000 because caddy-scratch runs as user ID 1000 by default - chmod 600 Caddyfile - ``` - - with this content: - - ```ruby - :8000 { - proxy / xyz:8000 - } - :9000 { - proxy / abc:9000 - } - ``` - - You can of course make more complicated Caddyfile (such as proxying `/xyz` to xyz:8000 and `/abc` to abc:9000, just ask me!) - - 1. Use this example: - - ```yml - version: '3' - services: - pia: - image: qmcgaw/private-internet-access - container_name: pia - cap_add: - - NET_ADMIN - devices: - - /dev/net/tun - environment: - - USER=js89ds7 - - PASSWORD=8fd9s239G - piaproxy: - image: qmcgaw/caddy-scratch - container_name: piaproxy - ports: - - 8000:8000/tcp - - 9000:9000/tcp - external_links: - - pia:xyz - - pia:abc - volumes: - - ./Caddyfile:/Caddyfile:ro - abc: - image: abc - container_name: abc - network_mode: "service:pia" - xyz: - image: xyz - container_name: xyz - network_mode: "service:pia" - ``` - -

--
Connect to the PIA through an HTTP proxy (i.e. with Chrome, Kodi, etc.)

- - **THIS IS NOT CURRENTLY WORKING, INVESTIGATION IS IN PROGRESS...** - - 1. Setup a HTTP proxy client, such as [SwitchyOmega for Chrome](https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=en) - 1. Make sure the PIA container: - - Has port 8888 published `-p 8888:8888/tcp` - - **Has your LAN** in `EXTRA_SUBNETS` - 1. With your HTTP proxy client, connect to the Docker host (i.e. `192.168.1.10`) on port `8888`. You might need to enter your credentials if you set them with the environment variables `PROXY_USER` and `PROXY_PASSWORD`. - 1. If you set `PROXY_LOG_LEVEL` to `Info`, you can check the log output of tinyproxy with: - - ```sh - docker exec -it pia cat /var/log/tinyproxy/tinyproxy.log - ``` - - `PROXY_LOG_LEVEL` defaults to `Critical` to avoid logging everything, for privacy purposes as well as to save storage. - -

- ## Port forwarding On a running PIA container, say `pia`, simply run: @@ -386,9 +325,9 @@ Note that not all regions support port forwarding. ## TODOs -- Create TUN device: https://github.com/haugene/docker-transmission-openvpn/blob/master/openvpn/start.sh#L7 - Mix logs from unbound, tinyproxy and openvpn in Docker logs -- Maybe use `--inactive 3600 --ping 10 --ping-exit 60` +- Maybe use `--inactive 3600 --ping 10 --ping-exit 60` as default behavior +- Try without tun ## License diff --git a/docker-compose.yml b/docker-compose.yml index 54d65d82..f685fe79 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,7 @@ services: init: true ports: - 8888:8888/tcp + command: environment: - USER=js89ds7 - PASSWORD=8fd9s239G diff --git a/entrypoint.sh b/entrypoint.sh index ae57f897..01cb798b 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,9 +4,9 @@ exitOnError(){ # $1 must be set to $? status=$1 message=$2 - [ "$message" != "" ] || message="Error!" + [ "$message" != "" ] || message="Undefined error" if [ $status != 0 ]; then - printf "$message (status $status)\n" + printf "[ERROR] $message, with status $status)\n" exit $status fi } @@ -15,7 +15,7 @@ exitIfUnset(){ # $1 is the name of the variable to check - not the variable itself var="$(eval echo "\$$1")" if [ -z "$var" ]; then - printf "Environment variable $1 is not set\n" + printf "[ERROR] Environment variable $1 is not set\n" exit 1 fi } @@ -30,7 +30,7 @@ exitIfNotIn(){ return 0 fi done - printf "Environment variable $1 cannot be '$var' and must be one of the following: " + printf "[ERROR] Environment variable $1 cannot be '$var' and must be one of the following: " for value in ${2//,/ } do printf "$value " @@ -61,9 +61,9 @@ exitIfNotIn PROTOCOL "tcp,udp" exitIfNotIn NONROOT "yes,no" cat "/openvpn/$PROTOCOL-$ENCRYPTION/$REGION.ovpn" &> /dev/null exitOnError $? "/openvpn/$PROTOCOL-$ENCRYPTION/$REGION.ovpn is not accessible" -for SUBNET in ${EXTRA_SUBNETS//,/ }; do - if [ $(echo "$SUBNET" | grep -Eo '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/([0-2]?[0-9])|([3]?[0-1]))?$') = "" ]; then - printf "Subnet $SUBNET is not a valid IPv4 subnet of the form 255.255.255.255/31 or 255.255.255.255\n" +for EXTRA_SUBNET in ${EXTRA_SUBNETS//,/ }; do + if [ $(echo "$EXTRA_SUBNET" | grep -Eo '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/([0-2]?[0-9])|([3]?[0-1]))?$') = "" ]; then + printf "Extra subnet $EXTRA_SUBNET is not a valid IPv4 subnet of the form 255.255.255.255/31 or 255.255.255.255\n" exit 1 fi done @@ -79,7 +79,6 @@ if [ "$DOT" == "off" ]; then exit 1 fi fi -exitIfNotIn FIREWALL "on,off" exitIfNotIn PROXY "on,off" exitIfNotIn PROXY_LOG_LEVEL "Info,Warning,Error,Critical" if [ ! -z "$PROXY_USER" ] && [ -z "$PROXY_PASSWORD" ]; then @@ -90,13 +89,40 @@ elif [ -z "$PROXY_USER" ] && [ ! -z "$PROXY_PASSWORD" ]; then exit 1 fi +############################################ +# SHOW PARAMETERS +############################################ +printf "\n" +printf "OpenVPN parameters:\n" +printf " * Region: $REGION\n" +printf " * Encryption: $ENCRYPTION\n" +printf " * Protocol: $PROTOCOL\n" +printf " * Running without root: $NONROOT\n" +printf "DNS over TLS:\n" +printf " * Activated: $DOT\n" +if [ "$DOT" = "on" ]; then + printf " * Malicious hostnames DNS blocking: $BLOCK_MALICIOUS\n" + printf " * NSA related DNS blocking: $BLOCK_NSA\n" + printf " * Unblocked hostnames: $UNBLOCK\n" +fi +printf "Local network parameters:\n" +printf " * Extra subnets: $EXTRA_SUBNETS\n" +printf " * Web proxy activated: $PROXY\n" +proxy_auth=yes +if [ -z $PROXY_USER ]; then + proxy_auth=no +fi +printf " * Web proxy has authentication: $proxy_auth\n" +unset -v proxy_auth +printf "\n" + ##################################################### # Writes to protected file and remove USER, PASSWORD ##################################################### if [ -f /auth.conf ]; then - printf "/auth.conf already exists\n" + printf "[INFO] /auth.conf already exists\n" else - printf "Writing USER and PASSWORD to protected file /auth.conf..." + printf "[INFO] Writing USER and PASSWORD to protected file /auth.conf..." echo "$USER" > /auth.conf exitOnError $? echo "$PASSWORD" >> /auth.conf @@ -106,7 +132,7 @@ else chmod 400 /auth.conf exitOnError $? printf "DONE\n" - printf "Clearing environment variables USER and PASSWORD..." + printf "[INFO] Clearing environment variables USER and PASSWORD..." unset -v USER unset -v PASSWORD printf "DONE\n" @@ -115,34 +141,36 @@ fi ############################################ # CHECK FOR TUN DEVICE ############################################ -while [ "$(cat /dev/net/tun 2>&1 /dev/null)" != "cat: read error: File descriptor in bad state" ]; do - printf "TUN device is not available, sleeping for 30 seconds...\n" - sleep 30 -done -printf "TUN device OK\n" +if [ "$(cat /dev/net/tun 2>&1 /dev/null)" != "cat: read error: File descriptor in bad state" ]; then + printf "[WARNING] TUN device is not available, creating it..." + mkdir -p /dev/net + mknod /dev/net/tun c 10 200 + exitOnError $? + chmod 0666 /dev/net/tun + printf "DONE\n" +fi ############################################ # BLOCKING MALICIOUS HOSTNAMES AND IPs WITH UNBOUND ############################################ if [ "$DOT" == "on" ]; then - printf "Malicious hostnames and ips blocking is $BLOCK_MALICIOUS\n" rm -f /etc/unbound/blocks-malicious.conf if [ "$BLOCK_MALICIOUS" = "on" ]; then tar -xjf /etc/unbound/blocks-malicious.bz2 -C /etc/unbound/ - printf "$(cat /etc/unbound/blocks-malicious.conf | grep "local-zone" | wc -l ) malicious hostnames and $(cat /etc/unbound/blocks-malicious.conf | grep "private-address" | wc -l) malicious IP addresses blacklisted\n" + printf "[INFO] $(cat /etc/unbound/blocks-malicious.conf | grep "local-zone" | wc -l ) malicious hostnames and $(cat /etc/unbound/blocks-malicious.conf | grep "private-address" | wc -l) malicious IP addresses blacklisted\n" else echo "" > /etc/unbound/blocks-malicious.conf fi if [ "$BLOCK_NSA" = "on" ]; then tar -xjf /etc/unbound/blocks-nsa.bz2 -C /etc/unbound/ - printf "$(cat /etc/unbound/blocks-nsa.conf | grep "local-zone" | wc -l ) NSA hostnames blacklisted\n" + printf "[INFO] $(cat /etc/unbound/blocks-nsa.conf | grep "local-zone" | wc -l ) NSA hostnames blacklisted\n" cat /etc/unbound/blocks-nsa.conf >> /etc/unbound/blocks-malicious.conf rm /etc/unbound/blocks-nsa.conf sort -u -o /etc/unbound/blocks-malicious.conf /etc/unbound/blocks-malicious.conf fi for hostname in ${UNBLOCK//,/ } do - printf "Unblocking hostname $hostname\n" + printf "[INFO] Unblocking hostname $hostname\n" sed -i "/$hostname/d" /etc/unbound/blocks-malicious.conf done fi @@ -150,13 +178,12 @@ fi ############################################ # SETTING DNS OVER TLS TO 1.1.1.1 / 1.0.0.1 ############################################ -printf "DNS over TLS is $DOT\n" if [ "$DOT" == "on" ]; then - printf "Launching Unbound daemon to connect to Cloudflare DNS 1.1.1.1 at its TLS endpoint..." + printf "[INFO] Launching Unbound to connect to Cloudflare DNS 1.1.1.1 over TLS..." unbound exitOnError $? printf "DONE\n" - printf "Changing DNS to localhost..." + printf "[INFO] Changing DNS to localhost..." echo "nameserver 127.0.0.1" > /etc/resolv.conf exitOnError $? echo "options ndots:0" >> /etc/resolv.conf @@ -167,22 +194,22 @@ fi ############################################ # Reading chosen OpenVPN configuration ############################################ -printf "Reading configuration for region $REGION, protocol $PROTOCOL and encryption $ENCRYPTION...\n" +printf "[INFO] Reading OpenVPN configuration...\n" CONNECTIONSTRING=$(grep -i "/openvpn/$PROTOCOL-$ENCRYPTION/$REGION.ovpn" -e 'privateinternetaccess.com') exitOnError $? PORT=$(echo $CONNECTIONSTRING | cut -d' ' -f3) if [ "$PORT" = "" ]; then - printf "Port not found in /openvpn/$PROTOCOL-$ENCRYPTION/$REGION.ovpn\n" + printf "[ERROR] Port not found in /openvpn/$PROTOCOL-$ENCRYPTION/$REGION.ovpn\n" exit 1 fi PIADOMAIN=$(echo $CONNECTIONSTRING | cut -d' ' -f2) if [ "$PIADOMAIN" = "" ]; then - printf "Domain not found in /openvpn/$PROTOCOL-$ENCRYPTION/$REGION.ovpn\n" + printf "[ERROR] Domain not found in /openvpn/$PROTOCOL-$ENCRYPTION/$REGION.ovpn\n" exit 1 fi printf " * Port: $PORT\n" printf " * Domain: $PIADOMAIN\n" -printf "Detecting IP addresses corresponding to $PIADOMAIN...\n" +printf "[INFO] Detecting IP addresses corresponding to $PIADOMAIN...\n" VPNIPS=$(nslookup $PIADOMAIN localhost | tail -n +3 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}') exitOnError $? for ip in $VPNIPS; do @@ -193,7 +220,7 @@ done # Writing target OpenVPN files ############################################ TARGET_PATH="/openvpn/target" -printf "Creating target OpenVPN files in $TARGET_PATH..." +printf "[INFO] Creating target OpenVPN files in $TARGET_PATH..." rm -rf $TARGET_PATH/* cd "/openvpn/$PROTOCOL-$ENCRYPTION" cp -f *.crt "$TARGET_PATH" @@ -227,101 +254,135 @@ fi # Note: TUN device re-opening will restart the container due to permissions printf "DONE\n" + + +############################################ +# NETWORKING +############################################ +printf "[INFO] Finding network properties...\n" +printf " * Detecting default gateway..." +DEFAULT_GATEWAY=$(ip r | grep 'default via' | cut -d" " -f 3) +exitOnError $? +printf "$DEFAULT_GATEWAY\n" +printf " * Detecting local interface..." +INTERFACE=$(ip r | grep 'default via' | cut -d" " -f 5) +exitOnError $? +printf "$INTERFACE\n" +printf " * Detecting local subnet..." +SUBNET=$(ip r | grep -v 'default via' | grep $INTERFACE | tail -n 1 | cut -d" " -f 1) +exitOnError $? +printf "$SUBNET\n" +for EXTRASUBNET in ${EXTRA_SUBNETS//,/ } +do + printf " * Adding $EXTRASUBNET as route via $INTERFACE..." + ip route add $EXTRASUBNET via $DEFAULT_GATEWAY dev $INTERFACE + exitOnError $? + printf "DONE\n" +done +printf " * Detecting target VPN interface..." +VPN_DEVICE=$(cat $TARGET_PATH/config.ovpn | grep 'dev ' | cut -d" " -f 2)0 +exitOnError $? +printf "$VPN_DEVICE\n" + + ############################################ # FIREWALL ############################################ -printf "Firewall is $FIREWALL\n" -if [ "$FIREWALL" == "on" ]; then - printf "Setting firewall for killswitch purposes...\n" - printf " * Detecting local subnet..." - SUBNET=$(ip route show | tail -n 1 | cut -d" " -f 1) - exitOnError $? - printf "$SUBNET\n" - printf " * Deleting all iptables rules..." - iptables --flush - exitOnError $? - iptables --delete-chain - exitOnError $? - iptables -t nat --flush - exitOnError $? - iptables -t nat --delete-chain +printf "[INFO] Setting firewall\n" +printf " * Blocking everyting\n" +printf " * Deleting all iptables rules..." +iptables --flush +exitOnError $? +iptables --delete-chain +exitOnError $? +iptables -t nat --flush +exitOnError $? +iptables -t nat --delete-chain +exitOnError $? +printf "DONE\n" +printf " * Block input traffic..." +iptables -P INPUT DROP +exitOnError $? +printf "DONE\n" +printf " * Block output traffic..." +iptables -F OUTPUT +exitOnError $? +iptables -P OUTPUT DROP +exitOnError $? +printf "DONE\n" +printf " * Block forward traffic..." +iptables -P FORWARD DROP +exitOnError $? +printf "DONE\n" + +printf " * Creating general rules\n" +printf " * Accept established and related input and output traffic..." +iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +exitOnError $? +iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +exitOnError $? +printf "DONE\n" +printf " * Accept local loopback input and output traffic..." +iptables -A OUTPUT -o lo -j ACCEPT +exitOnError $? +iptables -A INPUT -i lo -j ACCEPT +exitOnError $? +printf "DONE\n" + +printf " * Creating VPN rules\n" +for ip in $VPNIPS; do + printf " * Accept output traffic to VPN server $ip through $INTERFACE, port $PROTOCOL $PORT..." + iptables -A OUTPUT -d $ip -o $INTERFACE -p $PROTOCOL -m $PROTOCOL --dport $PORT -j ACCEPT exitOnError $? printf "DONE\n" - printf " * Block output traffic..." - iptables -F OUTPUT - exitOnError $? - iptables -P OUTPUT DROP +done +printf " * Accept all output traffic through $VPN_DEVICE..." +iptables -A OUTPUT -o $VPN_DEVICE -j ACCEPT +exitOnError $? +printf "DONE\n" + +printf " * Creating local subnet rules\n" +printf " * Accept input and output traffic to and from $SUBNET..." +iptables -A INPUT -s $SUBNET -d $SUBNET -j ACCEPT +iptables -A OUTPUT -s $SUBNET -d $SUBNET -j ACCEPT +printf "DONE\n" +for EXTRASUBNET in ${EXTRA_SUBNETS//,/ } +do + printf " * Accept input traffic through $INTERFACE from $EXTRASUBNET to $SUBNET..." + iptables -A INPUT -i $INTERFACE -s $EXTRASUBNET -d $SUBNET -j ACCEPT exitOnError $? printf "DONE\n" - printf " * Accept established and related output traffic..." - iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT - exitOnError $? - printf "DONE\n" - printf " * Accept local loopback output traffic..." - iptables -A OUTPUT -o lo -j ACCEPT - exitOnError $? - printf "DONE\n" - printf " * Accept output traffic with local subnet $SUBNET..." - iptables -A OUTPUT -d $SUBNET -j ACCEPT - exitOnError $? - printf "DONE\n" - printf " * Accept connections from $SUBNET to port 8888 for web proxy\n" - iptables -A INPUT -p tcp -s $SUBNET --dport 8888 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT - exitOnError $? - printf " * Accept established and related input traffic for web proxy\n" - iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT - exitOnError $? - for EXTRASUBNET in ${EXTRA_SUBNETS//,/ } - do - printf " * Accept output traffic with extra subnet $EXTRASUBNET..." - iptables -A OUTPUT -d $EXTRASUBNET -j ACCEPT - exitOnError $? - printf "DONE\n" - printf " * Accept connections from $EXTRASUBNET to port 8888 for web proxy\n" - iptables -A INPUT -p tcp -s $EXTRASUBNET --dport 8888 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT - exitOnError $? - done - for ip in $VPNIPS; do - printf " * Accept output traffic to $ip on interface eth0, port $PROTOCOL $PORT..." - iptables -A OUTPUT -j ACCEPT -d $ip -o eth0 -p $PROTOCOL -m $PROTOCOL --dport $PORT - exitOnError $? - printf "DONE\n" - done - printf " * Accept all output traffic on tun0 interface..." - iptables -A OUTPUT -o tun0 -j ACCEPT - exitOnError $? - printf "DONE\n" -fi + # iptables -A OUTPUT -d $EXTRASUBNET -j ACCEPT + # iptables -A OUTPUT -o $INTERFACE -s $SUBNET -d $EXTRASUBNET -j ACCEPT +done ############################################ # TINYPROXY LAUNCH ############################################ -printf "HTTP proxy is $PROXY\n" if [ "$PROXY" == "on" ]; then - printf "Setting TinyProxy log level to $PROXY_LOG_LEVEL\n" + printf "[INFO] Setting TinyProxy log level to $PROXY_LOG_LEVEL..." sed -i "/LogLevel /c\LogLevel $PROXY_LOG_LEVEL" /etc/tinyproxy/tinyproxy.conf + exitOnError $? + printf "DONE\n" if [ ! -z "$PROXY_USER" ]; then - printf "Setting TinyProxy credentials\n" + printf "[INFO] Setting TinyProxy credentials..." echo "BasicAuth $PROXY_USER $PROXY_PASSWORD" >> /etc/tinyproxy/tinyproxy.conf unset -v PROXY_USER unset -v PROXY_PASSWORD + printf "DONE\n" fi - printf "Starting HTTP proxy TinyProxy\n" + printf "[INFO] Launching HTTP proxy TinyProxy..." tinyproxy exitOnError $? + printf "DONE\n" fi ############################################ # OPENVPN LAUNCH ############################################ -printf "Starting OpenVPN using the following parameters:\n" -printf " * Region: $REGION\n" -printf " * Encryption: $ENCRYPTION\n" -printf " * Protocol: $PROTOCOL\n" -printf " * Port: $PORT\n" -printf " * Initial VPN IP address: $(echo "$VPNIPS" | head -n 1)\n\n" +printf "[INFO] Launching OpenVPN\n" cd "$TARGET_PATH" -openvpn --config config.ovpn +openvpn --config config.ovpn "$@" status=$? printf "\n =========================================\n" printf " OpenVPN exit with status $status\n" diff --git a/portforward.sh b/portforward.sh index ca723b41..d18cd8e8 100644 --- a/portforward.sh +++ b/portforward.sh @@ -1,11 +1,34 @@ #!/bin/sh +exitOnError(){ + # $1 must be set to $? + status=$1 + message=$2 + [ "$message" != "" ] || message="Undefined error" + if [ $status != 0 ]; then + printf "[ERROR] $message, with status $status)\n" + exit $status + fi +} + client_id=`head -n 100 /dev/urandom | sha256sum | tr -d " -"` +exitOnError $? json=`wget -qO- "http://209.222.18.222:2000/?client_id=$client_id" 2>/dev/null` +exitOnError $? if [ "$json" == "" ]; then printf "Port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding\n" exit 1 fi port=`echo $json | grep -Eo [0-9]{3,5}` ip=`wget -qO- https://diagnostic.opendns.com/myip` +exitOnError $? printf "Forwarded port for IP $ip is: $port\n" +printf "Detecting target VPN interface..." +TARGET_PATH="/openvpn/target" +vpn_device=$(cat $TARGET_PATH/config.ovpn | grep 'dev ' | cut -d" " -f 2)0 +exitOnError $? +printf "$vpn_device\n" +printf "Accepting input traffic through $vpn_device to port $port..." +iptables -A INPUT -i $vpn_device --dport $PORT -j ACCEPT +exitOnError $? +printf "DONE\n"