OpenWrt 21.02 openvpn client up/down scripts configuration ignored

Hi, I upgraded to OpenWRT 21.02, unfortunately my openvpn tunnels no longer work correctly because the up/down scripts setting my ip rules/routes are ignored.

These are configured as follows in /etc/config/openvpn:

    option script_security  '2'
    option up               '/etc/openvpn/bin/vpn-up'
    option down             '/etc/openvpn/bin/vpn-down'

however the above options are missing from the generated /tmp/etc/openvpn-mytunnel.conf file.

Is this a known issue?

1 Like

I found out that the reason options up/down no longer work is because someone decided to hijack them as follows:

7015 root 4324 S /usr/sbin/openvpn --syslog openvpn(myvpn) --status /var/run/openvpn.myvpn.status --cd /var/etc --config openvpn-myvpn.conf --up /usr/libexec/openvpn-hotplug up myvpn --down /usr/libexec/openvpn-hotplug down myvpn --script-security 2

and then forgot to mention it in any documentation.

I am wondering, what is the rationale for this change, and where is the documentation to get scripts executed as required?

2 Likes

After further reverse engineering of the undocumented changes, I have seen that /usr/libexec/openvpn-hotplug
ignores the most fundamental parameters like tun device name and IP address/netmask assigned to the openvpn tunnel by the server, thus making it impossible to run a scripts that sets up IP rules and routes as required.

Just so that the author of the openvpn behaviour change in OpenWRT 21.02 understands the issue he created, please see below my vpn up script:

#!/bin/sh
export PATH=$PATH:/sbin

echo "running vpn-up"

INTERFACE=$1
MTU=$2
LINK_MTU=$3
IP_ADDRESS=$4
NETMASK=$5
COMMAND=$6

if [ "x${COMMAND}" != "xinit" ]; then
   echo "invalid syntax"
   exit 1
fi

echo "INTERFACE=${INTERFACE}, IP ADDRESS=${IP_ADDRESS}, COMMAND=${COMMAND}"
ip route add 192.168.8.0/24 dev ${INTERFACE} src ${IP_ADDRESS} table ${INTERFACE}
ip route add default via ${IP_ADDRESS} dev ${INTERFACE} table ${INTERFACE}
ip rule add from ${IP_ADDRESS}/32 table ${INTERFACE}
ip rule add to ${IP_ADDRESS}/32 table ${INTERFACE}
1 Like

You should report the issue to the bug tracker, otherwise the maintainer won't know about it.

Please see my proposed fix in the following PR:

1 Like

hello everybody openwrt 21.02 is released ?

The openwrt bug tracker for packages lead me here. What is the correct one then?

It isn't clear I pulled openwrt 21.02 branch and built it from there

The rationale for this change was to introduce hotplug events for OpenVPN actions. To support that, up and down options are set to a common helper executable which triggers hotplug handlers and one hotplug handler shipped by default (01-user) is then supposed to trigger the actual user configured commands exactly as if they were executed by openvpn itself.

This is supposed to be transparent. If this doesn't work as intended then this clearly is a bug. I took a brief look at your suggested fix in the PR and while I do not doubt that it solves your problem, I do not understand the fix - or more specifically why this fix is needed in the first place and what is broken about the current code.

Most of the usual expected values like MTU, interface name etc. are passed as positional arguments to the invoked up/down commands, and not as environment variables - so you can access them as $1, $2 and so on.

The line exec /sbin/hotplug-call openvpn "$@" in /usr/libexec/openvpn-hotplug should forward all positional arguments to the hotplug handlers through $@. The /etc/hotplug.d/openvpn/01-user file should then in turn forward these args to the configured up or down command through $*.

You appear to make this implicit behaviour explicit by exporting the $@ values one-by one as env variables which you then pass back in the same order in the exec /bin/sh -c "$command ... line.

While this certainly works I am wondering why it is needed. Maybe /sbin/hotplug-call is swallowing the additional arguments after openvpn so they'll never end up as $1, $2 or $* in /etc/hotplug.d/openvpn/01-user.

Another thing I noticed in your PR is that you replace get_openvpn_option "$config" command "$ACTION" with command=$(uci get "openvpn.${INSTANCE}.${ACTION}") - this will break setups using native OpenVPN configuration instead of uci.

3 Likes

Please see the simpler PR:

PR #15284

openvpn parameters "up" and "down" are essential for some vpn links to setup route and rules upon connection.
01-user, as previously explained, tries to get openvpn parameters from the generated ovpn file, however, because of the changes in openwrt 21.02, the generated ovpn file

/tmp/etc/openvpn-[myvpn].conf

is missing "up" and "down" parameters (present instead in /etc/config/openvpn.conf), therefore the scripts never get executed.

My latest patch fixes the problem by reading 'uci' openvpn configuration instead

I agree that there is a conflict between uci openvpn configuration and native openvpn configuration. But if one uses native configuration with up and down included hotplug is overriden and never called anyway (please do try and test it!). If one wants scripts to be executed, these are added with their native 'up' and 'down' parameters. If there are no scripts to run, 'up' and 'down' will not be added and the hotplug feature remains unused.

In a nutshell, due to this conflict, the issues introduced by breaking compatibility with uci and native configurations, and a dubious value added, I would totally remove this new redundant 'hotplug' feature which is made un-necessary by the already existing native 'up' and 'down' openvpn parameters.

From my own debugging exercise due to this report, I believe the root cause is that the get_openvpn_option function attempts to parse the values for up and down from the native configuration file, while at the same time the up and down options were removed from openvpn.options with the introduction of the hotplug handler. Thus, for openvpn native config files generated by /etc/init.d/openvpn from an UCI configured OpenVPN instance, there are no values for up or down to parse. The only working approach for UCI configured OpenVPN instances are to add them in /etc/openvpn.user introduced with the hotplug handler.

My own understanding summarized, there are three scenarios to consider:

  1. UCI configured OpenVPN instance, up/down actions added in /etc/openvpn.user. This currently works, and still works with PR 15285 applied. Git history wise, this is the "current" approach, albeit only documented in Git history and code.
  2. UCI configured OpenVPN instance, option up and option down set in /etc/config/openvpn. Git history wise this is implicitly deprecated, but still supposed to work. This is broken at present, and fixed with PR 15285. The simplest fix is basically what @ezplanet attempted to do, although reading it with config_get seems like a cleaner approach and was where I was when you submitted your PR.
  3. Native OpenVPN configuration with up and down set in the OpenVPN configuration file. This remains broken at present and with PR 15285 applied, due to /etc/init.d/openvpn passing --up and --down to the openvpn executable, overriding the options in the native configuration file.

Looking at openvpn_add_instance() in /etc/init.d/openvpn I believe there are more options than up and down that should not be overridden when the user provides a native configuration file. To fix the third scenario I got an idea to add an additional parameter to this function to tell the function if it's called for a native instance or an UCI instance, and to handle some of the options differently depending on its value. Any thoughts on what this might break or if it's a poor choice of style for init scripts?

Edit: Tested scenario 3 more thoroughly, and scenario 3 works. Technically there is a fourth scenario, as native configurations can be executed in two ways: implicitly by saving them as *.conf in /etc/openvpn, and explicitly by using option config in /etc/config/openvpn as shown below. I tested both variants and added up and down options to the native OpenVPN file, and they both execute on up and down.

config openvpn 'native2'
        option enabled '1'
        option config '/tmp/ovpntest/native2.conf'

Contents of /tmp/ovpntest/native2.conf, for reference:

client
nobind
persist-key
persist-tun
tls-client
ca /etc/openvpn/ca.crt
cert /etc/openvpn/testvm251.crt
dev tun
key /etc/openvpn/testvm251.key
proto udp
remote 172.18.1.1 1194
remote-cert-tls server
resolv-retry infinite
verb 5
data-ciphers CHACHA20-POLY1305:AES-256-GCM:AES-128-GCM
up "logger -t native2 \"ovpn up\""
down "logger -t native2 \"ovpn down\""

@ezplanet Please investigate further and provide more details if your up/down scripts do not execute. I am not able to imagine additional test cases, and for now all the cases I can come up with do in fact work.

2 Likes