OpenVPN supports a plugin architecture, where external plugins can be used to extend the functionality of OpenVPN. Plugins are special modules or libraries that adhere to the OpenVPN Plugin API. One of these plugins is the down-root
plugin, which is available only on Linux. This allows the user to run specified commands as a user root
plugin when OpenVPN shuts down. Normally, the OpenVPN process drops root privileges (if the --user
directive is used) for security reasons. While this is a good security measure, it makes it difficult to undo some of the actions that an up
script can perform, which is run as a user root
plugin. For this, the down-root
plugin was developed. This recipe will demonstrate how the down-root
plugin can be used to remove a file that was created by an up
script.
Set up the client and server certificates using the Setting up public and private keys recipe from Chapter 2, Client-server IP-only Networks. For this recipe, the server computer was running CentOS 6 Linux and OpenVPN 2.3.10. No client computer was required.
proto udp port 1194 dev tun server 10.200.0.0 255.255.255.0 ca /etc/openvpn/cookbook/ca.crt cert /etc/openvpn/cookbook/server.crt key /etc/openvpn/cookbook/server.key dh /etc/openvpn/cookbook/dh2048.pem tls-auth /etc/openvpn/cookbook/ta.key 0 persist-key persist-tun keepalive 10 60 topology subnet user nobody group nobody # nogroup on some distros daemon log-append /var/log/openvpn.log script-security 2 cd /etc/openvpn/cookbook up "example5-9.sh" plugin /usr/lib64/openvpn/plugin/lib/openvpn-down-root.so "./example5-9.sh --down" suppress-timestamps verb 5
example5-9-server.conf
.up
script, which we will also use for the down-root
plugin:#!/bin/sh if [ "$script_type" = "up" ] then touch /tmp/example5-9.tempfile fi if [ "$1" = "--down" ] then rm /tmp/example5-9.tempfile fi
example5-9.sh
and make sure that it is executable.[root@server]# openvpn --config example5-9-server.conf
The server log file will now show the following:
PLUGIN_CALL: POST /usr/lib64/openvpn/plugin/lib/openvpn-down- root.so/PLUGIN_UP status=0 example5-9.sh tun0 1500 1541 10.200.0.1 10.200.0.2 init
This indicates the plugin has started. The fact that there were no error codes right after the up
script was executed indicates that it ran successfully.
/tmp/example5-9.tempfile
file was created on the server.PLUGIN_CALL: POST /usr/lib64/openvpn/plugin/lib/openvpn-down- root.so/PLUGIN_DOWN status=0 PLUGIN_CLOSE: /usr/lib64/openvpn/plugin/lib/openvpn-down- root.so
/tmp/example5-9.tempfile
file has been removed.The down-root
plugin is registered at system startup when the OpenVPN server process is still running with root
privileges. Plugins are spawned off in a separate thread, meaning that when the main OpenVPN process drops its root privileges, the plugins will still have full root
access. When OpenVPN shuts down, the plugin is called and it removes the file created by the user root
plugin when the server started.
Here is an interesting part of the server log file is:
/sbin/ifconfig tun0 0.0.0.0 SIOCSIFADDR: Permission denied SIOCSIFFLAGS: Permission denied Linux ip addr del failed: external program exited with error status: 255 PLUGIN_CALL: POST /usr/lib64/openvpn/plugin/lib/openvpn-down-root.so/PLUGIN_DOWN status=0 PLUGIN_CLOSE: /usr/lib64/openvpn/plugin/lib/openvpn-down-root.so
This indicates that the OpenVPN process was indeed not capable of running the command /sbin/ifconfig tun0 0.0.0.0
, proving that root
privileges had been successfully dropped. The plugin was then called, which did have root
privileges, so that it could remove the root-owned file in /tmp
.
Note that it is required to specify a path starting with ./
for the script that the plugin runs. If the leading ./
is not specified on Linux or Mac OS, then OpenVPN will not be able to find the script that the plugin needs to run, as the current directory (.
) normally is not part of the PATH environment variable.
Also note that the up
script is called with the script_type
environment variable set but that this is not true for plugins. To overcome this, an extra parameter was added so that the same script could be used as both the up
and down-root
scripts.
Plugins are supported on Linux, Net/FreeBSD, and on Windows. The following script callbacks can be intercepted using a plugin:
up
down
route-up
ipchange
tls-verify
auth-user-pass-verify
client-connect
client-disconnect
learn-address
18.117.91.187