Skip to content

Instantly share code, notes, and snippets.

@rduplain
Last active October 10, 2021 10:11
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rduplain/d0fb0ecaf444eb5b64cef06ec6a0dd16 to your computer and use it in GitHub Desktop.
Save rduplain/d0fb0ecaf444eb5b64cef06ec6a0dd16 to your computer and use it in GitHub Desktop.
OpenVPN rc.d script for VPN client on BSD (i.e. jail): connect to VPN, start another service once VPN is connected.
#!/bin/sh
# PROVIDE: vpn
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
# vpn: connect to VPN, start another service once VPN is connected.
#
# Uses OpenVPN and assumes the configuration does not need any authentication
# beyond the given .conf file. Consider an approach using `expect` if needed:
#
# github.com/amussey/FreeNAS-Transmission-OpenVPN/blob/master/run.sh.template
#
# Install as an executable at /usr/local/etc/rc.d/vpn, install OpenVPN .conf
# at the path specified by openvpn_conf below, and install packages with:
#
# pkg install -y openvpn
#
# Add the following configuration to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# vpn_enable (bool): Set to NO by default; enable with YES.
# vpn_service (string): Set to service to start/stop with VPN.
#
# For the service specified in vpn_service, set its _enable to NO.
#
# When using vpn up/down precmd/postcmd, be sure to thoroughly test.
# OpenVPN might exit on an error without cleaning up the service.
. /etc/rc.subr
name=vpn
rcvar=${name}_enable
load_rc_config ${name}
: ${vpn_enable:=NO}
: ${vpn_pidfile:="/var/run/$service/vpn.pid"}
: ${vpn_conf:="/usr/local/etc/openvpn/client.conf"}
: ${vpn_log:="/var/log/openvpn.log"}
: ${vpn_up_postcmd:="/bin/echo"}
: ${vpn_up_precmd:="/bin/echo"}
: ${vpn_down_precmd:="/bin/echo"}
: ${vpn_down_postcmd:="/bin/echo"}
if [ -z "$vpn_service" ]; then
err 3 'Set vpn_service=SERVICE in rc.conf to control SERVICE.'
fi
pidfile=${vpn_pidfile}
command=/usr/local/sbin/openvpn
service=/usr/sbin/service
vpn_flags="--config $vpn_conf --writepid $pidfile --daemon vpn --log $vpn_log"
vpn_flags="$vpn_flags --script-security 2"
vpn_flags="$vpn_flags --up '$service $name up' --up-delay"
vpn_flags="$vpn_flags --up-delay --down '$service $name down' --down-pre"
on_up() {
$vpn_up_precmd "$@"
$service $vpn_service onerestart
$vpn_up_postcmd "$@" &
}
on_down() {
$vpn_down_precmd "$@"
$service $vpn_service onestop
$vpn_down_postcmd "$@" &
}
if [ "$1" = "up" ]; then
shift
on_up "$@"
elif [ "$1" = "down" ]; then
shift
on_down "$@"
else
run_rc_command "$1"
fi
@rduplain
Copy link
Author

Note that GitHub does not send notifications for comments on gists, so I probably will not see any comments here.

@rduplain
Copy link
Author

The purpose of this vpn service is to connect to a VPN via openvpn at boot and start/stop a service when the VPN client process starts/stops. The script is documented; to summarize, install at:

/usr/local/etc/rc.d/vpn

Edit /etc/rc.conf to add:

vpn_enable="YES"
vpn_service="SERVICE"

... where SERVICE is the name of the service to control on VPN start/stop. Load OpenVPN configuration at:

/usr/local/etc/openvpn/client.conf

Install OpenVPN:

pkg install -y openvpn

Start:

service vpn start

@rduplain
Copy link
Author

Tested on FreeBSD 11.

@rduplain
Copy link
Author

Check your IP address:

pkg install -y dns/bind-tools
dig +short myip.opendns.com @resolver1.opendns.com

@rduplain
Copy link
Author

rduplain commented Oct 4, 2018

I recently ran into DNS resolution issues. While workarounds are best avoided, I wanted a workaround without using the many heavy-handed "fix resolv.conf" solutions out there.

In /usr/local/bin/vpn-fix-resolvconf:

#!/bin/sh
# Rewrite resolv.conf using presumed OpenVPN gateway,
# if DNS queries resolve using the presume gateway IP,
# which assumes the gateway server may provide a DNS server.
#
# Call via vpn_up_postcmd in rc.conf.

# tun1 1500 1555 10.8.0.6 10.8.0.5 init
ip=$4
ns="${ip%.*}.1"

if /usr/local/bin/dig +time=2 +tries=3 @$ns; then
    echo "Overwriting /etc/resolv.conf from $0" >&2
    echo "# Generated by $0" >  /etc/resolv.conf
    echo "nameserver $ns"    >> /etc/resolv.conf
else
    echo "No DNS server found at $ns" >&2
fi

In rc.conf:

vpn_up_postcmd="/usr/local/bin/vpn-fix-resolvconf"

@maniac0s
Copy link

Sorry but what is "... where SERVICE is the name of the service to control on VPN start/stop. " supposed to mean?

@rduplain
Copy link
Author

This rc.d script is for a VPN client on BSD that controls another service alongside the OpenVPN connection. I updated the title of the gist to clarify that up front:

OpenVPN rc.d script for VPN client on BSD (i.e. jail): connect to VPN, start another service once VPN is connected.

The idea is to have a FreeBSD jail that starts some service (SERVICE) -- jails are often about one service -- only after the OpenVPN connection is established. SERVICE is the name of the service to pass to /usr/sbin/service, i.e. some other rc.d service by name.

If you are are looking to just start/stop the OpenVPN connection, most of this rc.d script is unnecessary.

Looking back, I did use this rc.d script successfully, but ultimately abandoned the idea. I found it much simpler to move the service up to the VPN-originating network, then just sync the data down (rsync, sftp, https, ...), bypassing any need for OpenVPN and its maintenance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment