VPN autostart
published on Friday, February 24, 2017
In VPN in a Nutshell I have described a command
prefix vpnbox. This precommand executes applications in a network
namespace but does not take care to check if VPN is already up and
automatically start if it is not.
Unfortunately, I know no good (simple) way to do this. Please tell me if
you've got any better solutions.
First, modify the vpnbox command as follows:
/usr/local/bin/vpnbox
#! /usr/bin/bash
user=$(whoami)
# check if there is a default route in the netns going over tun0:
# NOTE: 'tun0' may not be the correct interface name
vpn_online() {
sudo ip netns exec vpn sudo -u $user -- ip route \
| grep default | grep tun0
}
if ! vpn_online; then
# Execute openvpn in daemon mode:
sudo /bin/openvpn --config /etc/vpn/CONFIG.conf --daemon
# Wait for completion. Otherwise routes/DNS information may not be
# setup when the main program starts:
echo "Waiting for route."
while ! vpn_online; do
sleep 0.1
done
fi
# Execute the actual command as before:
sudo ip netns exec vpn sudo -u $user -- "$@"
To make this work without passwords, type sudo visudo to add the following
to your sudoers:
/etc/sudoers
# put this near the end of the file:
# this line is unchanged from the previous post:
alice ALL=(ALL:ALL) NOPASSWD: /usr/bin/ip netns exec vpn sudo -u alice -- *
# The following line is new and allows to start the vpn without password:
alice ALL=(ALL:ALL) NOPASSWD: /usr/bin/openvpn --config /etc/openvpn/CONFIG.conf --daemon
WARNING: You must specify the exact line here. You must not use the *
as a lazy shortcut here, otherwise a user can specify as additional parameters
any script and it will be executed as root.
Advanced version
Personally, I'm using another (more complex) solution that does not provide
much benefit over the simpler one given above. But since I've gone through the
development effort and learnt something from it and also it's slightly nicer,
I cannot let go yet.
The difference is that it does print some output of the openvpn command to
standard output and can exit early if an error occurs during the
initialization phase.
This is accomplished by exchanging the plain sudo openvpn statement in the
vpnbox script above by the crazier command:
sudo openvpn-daemonize /etc/openvpn/CONFIG.conf || exit 1
Huh? This wasn't so bad, was it?
Yeah, but you will also have to provide the openvpn-daemonize script. This
time I highly recommend to put it actually in /usr/local/bin and not in a
user path. Make it writable by root only (because we are executing it with
sudo).
/usr/local/bin/openvpn-daemonize
#! /bin/zsh
cd /etc/openvpn
config=$1
basename=$(basename ${config%.*})
log=/var/log/vpn/$basename.log
writepid=/var/log/vpn/$basename.pid
# Truncate log file to make sure it doesn't contain remnants
echo >$log
# Start VPN in background, this does not block
/bin/openvpn --config $config --log $log --writepid $writepid --daemon
# Create a temporary pipe that will be used to connect the standard IO of
# the next two processes
pipe=$(mktemp -u)
mkfifo $pipe
# Search for markers in the fifo stream, quit with exit code when found
sed -e '/Initialization Sequence Completed/q0' \
-e '/Connection refused/q1' <$pipe & sed_PID=$!
# Follow the log, write output to pipe, but also exit when 'sed' exits
tail -n +0 -f $log --pid $sed_PID >> $pipe
exitcode=$?
# Cleanup and exit
rm $pipe
exit $exitcode
Also, convenience demands to add the following additional line in sudoers:
alice ALL=(ALL:ALL) NOPASSWD: /usr/local/bin/openvpn-daemonize /etc/openvpn/CONFIG.conf
This entry was tagged
config,
gist,
linux,
privacy,
utility and
vpn