From 26ace9a7b92020bffebe85897cd3790342820612 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 6 Sep 2019 18:09:50 +0200 Subject: openvpn: T1548: always restart OpenVPN Previous implementations sent a SIGUSR1 to OpenVPN to initialte a restart after the configuration changed - as this was the same as the client keepalive mechanism did. Unfortunately on SIGUSR1 OpenVPN does not re-read the configuration file. Thus changed options were never taken into account. --- src/conf_mode/interface-openvpn.py | 54 +++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/conf_mode/interface-openvpn.py b/src/conf_mode/interface-openvpn.py index fe08cd51e..548c78535 100755 --- a/src/conf_mode/interface-openvpn.py +++ b/src/conf_mode/interface-openvpn.py @@ -25,10 +25,11 @@ import jinja2 from copy import deepcopy from grp import getgrnam from ipaddress import ip_address,ip_network,IPv4Interface +from netifaces import interfaces from psutil import pid_exists from pwd import getpwnam -from signal import SIGUSR1 from subprocess import Popen, PIPE +from time import sleep from vyos.config import Config from vyos import ConfigError @@ -819,47 +820,46 @@ def generate(openvpn): return None def apply(openvpn): - interface = openvpn['intf'] - pid = 0 - pidfile = '/var/run/openvpn/{}.pid'.format(interface) + pidfile = '/var/run/openvpn/{}.pid'.format(openvpn['intf']) if os.path.isfile(pidfile): pid = 0 with open(pidfile, 'r') as f: pid = int(f.read()) - # If tunnel interface has been deleted - stop service - if openvpn['deleted'] or openvpn['disable']: - directory = os.path.dirname(get_config_name(interface)) - - # we only need to stop the demon if it's running - # daemon could have died or killed by someone - if pid_exists(pid): - cmd = 'start-stop-daemon --stop --quiet' - cmd += ' --pidfile ' + pidfile - subprocess_cmd(cmd) + # Always stop OpenVPN service. We can not send a SIGUSR1 for restart of the + # service as the configuration is not re-read. Stop daemon only if it's + # running - it could have died or killed by someone evil + if pid_exists(pid): + cmd = 'start-stop-daemon --stop --quiet' + cmd += ' --pidfile ' + pidfile + subprocess_cmd(cmd) - # cleanup old PID file - if os.path.isfile(pidfile): - os.remove(pidfile) + # cleanup old PID file + if os.path.isfile(pidfile): + os.remove(pidfile) + # Do some cleanup when OpenVPN is disabled/deleted + if openvpn['deleted'] or openvpn['disable']: # cleanup old configuration file - if os.path.isfile(get_config_name(interface)): - os.remove(get_config_name(interface)) + if os.path.isfile(get_config_name(openvpn['intf'])): + os.remove(get_config_name(openvpn['intf'])) # cleanup client config dir - if os.path.isdir(directory + '/ccd/' + interface): + directory = os.path.dirname(get_config_name(openvpn['intf'])) + if os.path.isdir(directory + '/ccd/' + openvpn['intf']): try: - os.remove(directory + '/ccd/' + interface + '/*') + os.remove(directory + '/ccd/' + openvpn['intf'] + '/*') except: pass return None - # Send SIGUSR1 to the process instead of creating a new process - if pid_exists(pid): - os.kill(pid, SIGUSR1) - return None + # On configuration change we need to wait for the 'old' interface to + # vanish from the Kernel, if it is not gone, OpenVPN will report: + # ERROR: Cannot ioctl TUNSETIFF vtun10: Device or resource busy (errno=16) + while openvpn['intf'] in interfaces(): + sleep(0.250) # 250ms # No matching OpenVPN process running - maybe it got killed or none # existed - nevertheless, spawn new OpenVPN process @@ -868,13 +868,13 @@ def apply(openvpn): cmd += ' --exec /usr/sbin/openvpn' # now pass arguments to openvpn binary cmd += ' --' - cmd += ' --config ' + get_config_name(interface) + cmd += ' --config ' + get_config_name(openvpn['intf']) # execute assembled command subprocess_cmd(cmd) - return None + if __name__ == '__main__': try: c = get_config() -- cgit v1.2.3