diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d387685 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +install: + cp systemd/openvpn-netns-client@.service /etc/systemd/system/openvpn-netns-client@.service + cp openvpn-netns /usr/local/bin/openvpn-netns + cp openvpn-netns-shell /usr/local/bin/openvpn-netns-shell + cp openvpn-netns-service /usr/local/bin/openvpn-netns-service + cp -r openvpn-scripts /usr/local/bin/ + +uninstall: + rm /etc/systemd/system/openvpn-netns-client@.service + rm /usr/local/bin/openvpn-netns + rm /usr/local/bin/openvpn-netns-shell + rm /usr/local/bin/openvpn-netns-service + rm -r /usr/local/bin/openvpn-scripts diff --git a/README.md b/README.md index 58713b3..67f14d0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ openvpn-netns ============= -Start OpenVPN connection inside Linux network namespace. +Start an OpenVPN connection inside a Linux network namespace (netns). These scripts allow some programs to use the VPN connection while the rest of the system uses the normal network connection. For programs @@ -10,6 +10,58 @@ is through the VPN tunnel. This prevents VPN leaks. Multiple VPN connections can be opened at the same time each in its separate namespace. +Installing +---------- + +Run `sudo make install`. +Run `sudo systemctl daemon-reload` to refresh the systemd service if necessary. + +Uninstalling +---------- + +Run `sudo make uninstall`. + +Systemd service +--------------- + +To create a new service which will start an OpenVPN connection in +a new network namespace: + + Choose a name for the netns (in this example: vpn0) + Create the corresponding folder in /etc/openvpn-netns/: + + sudo mkdir -p /etc/openvpn-netns/vpn0 + + Put in that folder: + + - a `params` file containing the params used by openvpn + echo "--auth-user-pass pass --dev tun0" > /etc/openvpn-netns/vpn0/params + + - a `config.ovpn` OpenVPN configuration file + + - a `pass` file containing the password + +Once the files are in place, you can start the service with: + + sudo systemctl start openvpn-netns-client@vpn0.service + +You can check the logs with: + + journalctl -u openvpn-netns-client@vpn0.service -f + +You can enable it at boot with: + + sudo systemctl enable openvpn-netns-client@vpn0.service + +Systemd service with multiple failover backend vpn providers +------------------------------------------------------------ + +The systemd service can be configured to try multiple vpn providers, +trying another one in the list if the current one fails. + +To do that, instead of providing the `config.ovpn` file and `params` file to the +`/etc/openvpn-netns/vpn0` folder, you can put multiple folders in there, each containing +the necessary files. The systemd service script will try each folder in succession. Scripts ------- @@ -63,7 +115,6 @@ even if openvpn reconnects immediately, all apps started via `ip netns exec vpn COMMAND` will break and will have to be restarted. This is because the former namespace to which they were attached is destroyed. - Settings -------- @@ -83,7 +134,6 @@ file doesn't exist, it is automatically generated from DNS settings from the server when the connection is started and deleted when the connection is terminated. - IPv6 ---- @@ -93,11 +143,4 @@ experimental. To turn on IPv6 support, use command line option `--setenv IPV6 on`. -Installing ----------- - - sudo ln -s "$PWD"/openvpn-netns /usr/local/bin/openvpn-netns - sudo ln -s "$PWD"/openvpn-netns-shell /usr/local/bin/openvpn-netns-shell - - [netns-exec]: https://github.com/pekman/netns-exec diff --git a/openvpn-netns b/openvpn-netns index 526b745..c89b54e 100755 --- a/openvpn-netns +++ b/openvpn-netns @@ -8,9 +8,9 @@ case "$1" in esac exec sudo openvpn \ + $config_arg "$@" \ --ifconfig-noexec --route-noexec \ --script-security 2 \ --setenv NETNS "$NETNS" \ --up "$SCRIPT_DIR"/netns \ - --route-up "$SCRIPT_DIR"/netns \ - $config_arg "$@" + --route-up "$SCRIPT_DIR"/netns diff --git a/openvpn-netns-service b/openvpn-netns-service new file mode 100755 index 0000000..ae98fb0 --- /dev/null +++ b/openvpn-netns-service @@ -0,0 +1,89 @@ +#!/bin/bash + +if [ "$EUID" -ne 0 ] + then echo "Please run as root" + exit +fi + +NETNS=$1 + +if [ -z "$NETNS" ]; then + echo "$0 should be run with a netns parameter." + exit -1 +fi +# Variables +NETNS_FOLDER=/etc/openvpn-netns/$NETNS +RUN_FOLDER=/var/run/openvpn-netns/$NETNS +INDEX_FILE=$RUN_FOLDER/index + +# Function to run openvpn-netns +openvpn_netns_run() { + local folder=$1 + echo "Using folder $folder" + + local params_file=${folder}params + local conf_file=${folder}config.ovpn + + # Check if params file exists + if [ ! -e "$params_file" ]; then + echo "File '$params_file' is not found" + exit -1 + fi + + # Check if config.ovpn file exists + if [ ! -e "$conf_file" ]; then + echo "File '$conf_file' is not found" + exit -1 + fi + + # Read params + read params < "$params_file" + + # Run the command with the selected folder as the working directory + echo "Running openvpn-netns on netns $NETNS with params: $params in folder $folder" + (cd "$folder" && NETNS=$NETNS /usr/local/bin/openvpn-netns --config "$conf_file" $params) + +} + +# Check for a single config.ovpn file in the netns folder +if [ -e "$NETNS_FOLDER/config.ovpn" ]; then + openvpn_netns_run "$NETNS_FOLDER/" + exit 0 +fi + +# Ensure the run folder exists +if [ ! -d "$RUN_FOLDER" ]; then + mkdir -p "$RUN_FOLDER" +fi + +# Ensure the index file exists +if [ ! -e "$INDEX_FILE" ]; then + echo "0" > "$INDEX_FILE" +fi + +# Read the current index +current_index=$(cat "$INDEX_FILE") + +# List all directories in the NETNS_FOLDER and sort them alphabetically +folders=($(ls -d $NETNS_FOLDER/*/ | sort)) + +# Check if there are any folders +if [ ${#folders[@]} -eq 0 ]; then + echo "No folders found in $NETNS_FOLDER" + exit -1 +fi + +# Get the folder to use +selected_folder=${folders[$current_index]} + +# Calculate the next index +next_index=$((current_index + 1)) +if [ $next_index -ge ${#folders[@]} ]; then + next_index=0 +fi + +# Update the index file +echo "$next_index" > "$INDEX_FILE" + +# Run openvpn-netns with the selected folder +openvpn_netns_run "$selected_folder" diff --git a/systemd/openvpn-netns-client@.service b/systemd/openvpn-netns-client@.service new file mode 100644 index 0000000..c786b98 --- /dev/null +++ b/systemd/openvpn-netns-client@.service @@ -0,0 +1,17 @@ +[Unit] +Description=OpenVPN tunnel for %I +After=network-online.target +Wants=network-online.target +Documentation=man:openvpn(8) +Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage +Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO + +[Service] +ExecStart=/usr/local/bin/openvpn-netns-service %i +CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE CAP_SYS_ADMIN +LimitNPROC=10 +Restart=always +RestartSec=3 + +[Install] +WantedBy=multi-user.target