From a09ec964ad9447cbc7a7328ccebc16cd358c6dd5 Mon Sep 17 00:00:00 2001 From: ttasket Date: Sat, 4 Jun 2016 20:01:58 -0400 Subject: [PATCH] Automatic; No manual coding of IP addresses. This requires the user only to add a few lines to their ovpn config file, and copy a few scripts (verbatim). They do not have to figure out which IP addresses are appropriate and hard-code them--unless their VPN service is bereft of domain names. Even in that case, they can do it easily within the ovpn config file. This is much less error-prone and should work with a greater variety of services (large commercial services tend to change their IPs so using domain names and DHCP is preferable in that case). Also converted firewall section (3) to one code block for much less cutting/pasting. Comments are still there as shell comments. The only required template changes are adding openvpn itself and possibly disabling the default systemd service for it. Everything else should be there in /rw/config. This doesn't include extra firewall protections against inadvertent net access from within the VPN VM. I'm thinking of proposing those additions in a separate edit. --- configuration/vpn.md | 159 +++++++++++++++++++++++++++++-------------- 1 file changed, 107 insertions(+), 52 deletions(-) diff --git a/configuration/vpn.md b/configuration/vpn.md index 94ae2060..47e2bec6 100644 --- a/configuration/vpn.md +++ b/configuration/vpn.md @@ -42,7 +42,7 @@ Using a ProxyVM to set up a VPN client gives you the ability to: #### Setup a ProxyVM as a VPN gateway -**Using NetworkManager** +#### Using NetworkManager 1. Create a new VM and check the ProxyVM radio button. @@ -60,73 +60,128 @@ Using a ProxyVM to set up a VPN client gives you the ability to: 5. Optionally, you can install some [custom icons](https://github.com/Zrubi/qubes-artwork-proxy-vpn) for your VPN -**Using iptables and openvpn** - -You need an openvpn server and a DNS server accessible through the vpn (use one from your vpn provider / a public one). +#### Using iptables and openvpn 1. Create a new VM and check the ProxyVM radio button. ![Create\_New\_VM.png](/attachment/wiki/VPN/Create_New_VM.png) + + If your choice of template VM doesn't already have the `openvpn` package, you'll need to install it in the template first. You may also need to `systemctl disable` any openvpn service that comes with the package if you follow the instructions for autostart below. 2. Setup openvpn: - Copy your openvpn config file to `/home/user/vpn.cfg`. + Copy your openvpn config files to `/rw/config/openvpn/` folder. The example main config file is `openvpn-client.ovpn`. - It should have one line starting with `dev` and one starting with `proto`. - The first describes the connection type (`tun` or `tap`) and the second the used protocol (`tcp` or `udp`). - Depending on your connection type, openvpn will create a new network device (probably `tap0` or `tun0`). + It should have one line that reads `dev tun`. - It also contains a line `remote X.X.X.X 1194`, where `X.X.X.X` is the ip of your openvpn server. - - If it does not contain a line `redirect-gateway def1`, add it. - This will route all traffic through your vpn's network device, after a connection was created. - If the connection breaks down all traffic will be routed through the original network device (we will stop this with iptables). - - If your vpn config file contains `auth-user-pass`, change it to `auth-user-pass /home/user/auth.txt` and create a file `/home/user/auth.txt` containing the user name in the first line and the password in the second. - This will enable the vpn to login without requiring you to enter your username and password. - If a different authentication method is used, set it up to require no user input. - The vpn should now start by calling `sudo openvpn --config /home/user/vpn.cfg` and require no additional user input. - - In the following, we use the following placeholder: - `$DEV` For the device created for the connection. - `$PROT` For the protocol used for connection - `$SVR` For the openvpn server's ip. - `$DNS` For the dns server's ip. - - -3. Setup iptables: - Edit `/rw/config/qubes-firewall-user-script` and add: - - `iptables -P OUTPUT DROP` - This blocks all outgoing traffic, if not specified otherwise. + If it does not contain a line `redirect-gateway def1` you may wish to add it. This will route all traffic through your vpn's network device after a connection is created. However, many VPN services will push this instruction to your client automatically -- having a line that says `client` or `pull` in your openvpn config instructs your client to use parameters specified by the VPN server. - `iptables -I OUTPUT -o $DEV -j ACCEPT` - This allows the local system to connect through the vpn (you dont need this). - - `iptables -I OUTPUT -o eth0 -d $SVR -p $PROT --dport 1194 -j ACCEPT` - This allows your system to connect to the vpn server with the protocol `$PROT` under the port 1194. - - `iptables -I OUTPUT -o lo -j ACCEPT` - This allows connections from the system to the system. + NOTE: If the connection breaks down all traffic will by default be routed through the upstream network device eth0 (we will stop this with iptables in step 3). - `iptables -I FORWARD -o eth0 -j DROP` - `iptables -I FORWARD -i eth0 -j DROP` - This blocks forwarding of connections through your plain network device (in case the vpn tunnel breaks). + Also add the following to accomodate a DNS script: + ``` + script-security 2 + up 'qubes-vpn-handler.sh up' + down 'qubes-vpn-handler.sh down' + ``` - `iptables -t nat -I PR-QBS -p udp --dport 53 -j DNAT --to-destination $DNS` - `iptables -t nat -I PR-QBS -p tcp --dport 53 -j DNAT --to-destination $DNS` - This will rewrite the DNS destination, and the traffic will be routed down the vpn tunnel. (to prevent DNS leaks) +3. Setup iptables. + Edit the firewall script with `sudo nano /rw/config/qubes-firewall-user-script` and add: + ``` + #!/bin/bash + # First, block all outgoing traffic + iptables -P OUTPUT DROP + iptables -F OUTPUT + + # Add the `qvpn` group to system, if it doesn't already exist + if ! grep -q "^qvpn:" /etc/group ; then + groupadd -rf qvpn + sync + fi + sleep 2s + + # Allow traffic from the `qvpn` group to the uplink interface (eth0); + # Our openvpn will run as group `qvpn`. + iptables -A OUTPUT -p all -o eth0 -m owner --gid-owner qvpn \ + -m state --state NEW,ESTABLISHED -j ACCEPT + + # Allow queries to DNS server: + iptables -A OUTPUT -p udp -o eth0 --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT + iptables -A OUTPUT -p tcp -o eth0 --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT + + # Allow internal system connections: + iptables -I OUTPUT -o lo -j ACCEPT + + # Block forwarding of connections through upstream network device + # (in case the vpn tunnel breaks): + iptables -I FORWARD -o eth0 -j DROP + iptables -I FORWARD -i eth0 -j DROP + ``` Now save `/rw/config/qubes-firewall-user-script` and make it executable: `sudo chmod +x /rw/config/qubes-firewall-user-script` + +4. Create the DNS-handling script. + Use `sudo nano /rw/config/openvpn/qubes-vpn-handler.sh` to edit and add: + ``` + #!/bin/bash + set -e + +# Pop-up notification variables +SPID=$(pgrep -U user -f dconf-service) +dbus=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$SPID/environ|cut -d= -f2-) +export DBUS_SESSION_BUS_ADDRESS=$dbus + +case "$1" in + +up) + # To override DHCP DNS, assign static DNS addresses with 'setenv vpn_dns' in openvpn config; + # Format is 'X.X.X.X Y.Y.Y.Y [...]' with quotes. + if [[ -z $vpn_dns ]] ; then + # Parses DHCP options from openvpn to set DNS address translation: + for optionname in ${!foreign_option_*} ; do + option="${!optionname}" + unset fops; fops=($option) + if [ ${fops[1]} == "DNS" ] ; then vpn_dns="$vpn_dns ${fops[2]}" ; fi + done + fi + + iptables -t nat -F PR-QBS + if [[ -n $vpn_dns ]] ; then + # Set DNS address translation in firewall: + for addr in $vpn_dns; do + iptables -t nat -A PR-QBS -i vif+ -p udp --dport 53 -j DNAT --to $addr + iptables -t nat -A PR-QBS -i vif+ -p tcp --dport 53 -j DNAT --to $addr + done + su -c 'notify-send "$(hostname): LINK IS UP." --icon=network-idle' user + else + su -c 'notify-send "$(hostname): LINK UP, NO DNS!" --icon=dialog-error' user + fi + + ;; +down) + su -c 'notify-send "$(hostname): LINK IS DOWN !" --icon=dialog-error' user + ;; +esac +``` + + Now save the script and make it executable: + `sudo chmod +x /rw/config/openvpn/qubes-vpn-handler.sh` -4. Setup the vpn's autostart: - Edit to `/rw/config/rc.local`, make it executable (`sudo chmod +x /rw/config/rc.local`) and add: +5. Setup the VPN's autostart: + Use `sudo nano /rw/config/rc.local` to edit and add: + ``` + #!/bin/bash + groupadd -rf qvpn ; sleep 2s + sg qvpn -c 'openvpn --cd /rw/config/openvpn/ --config openvpn-client.ovpn \ + --daemon --writepid /var/run/openvpn/openvpn-client.pid' + ``` + Now save the script and make it executable: + `sudo chmod +x /rw/config/rc.local` + +6. Restart the new VM! - ln -s /home/user/vpn.cfg /etc/openvpn/vpn.conf; - systemctl --no-block start openvpn@vpn.service; - -5. Configure your AppVMs to use the new VM as a NetVM. +7. Configure your AppVMs to use the new VM as a NetVM. ![Settings-NetVM.png](/attachment/wiki/VPN/Settings-NetVM.png) -6. Optionally, you can install some [custom icons](https://github.com/Zrubi/qubes-artwork-proxy-vpn) for your VPN +8. Optionally, you can install some [custom icons](https://github.com/Zrubi/qubes-artwork-proxy-vpn) for your VPN