diff options
Diffstat (limited to 'src/leap/bitmask/services/eip')
-rw-r--r-- | src/leap/bitmask/services/eip/connection.py | 1 | ||||
-rw-r--r-- | src/leap/bitmask/services/eip/linuxvpnlauncher.py | 10 | ||||
-rw-r--r-- | src/leap/bitmask/services/eip/vpnlauncher.py | 26 | ||||
-rw-r--r-- | src/leap/bitmask/services/eip/vpnprocess.py | 96 |
4 files changed, 118 insertions, 15 deletions
diff --git a/src/leap/bitmask/services/eip/connection.py b/src/leap/bitmask/services/eip/connection.py index 08b29070..962d9cf2 100644 --- a/src/leap/bitmask/services/eip/connection.py +++ b/src/leap/bitmask/services/eip/connection.py @@ -46,4 +46,5 @@ class EIPConnectionSignals(QtCore.QObject): class EIPConnection(AbstractLEAPConnection): def __init__(self): + # XXX this should be public instead self._qtsigs = EIPConnectionSignals() diff --git a/src/leap/bitmask/services/eip/linuxvpnlauncher.py b/src/leap/bitmask/services/eip/linuxvpnlauncher.py index c2c28627..efb23285 100644 --- a/src/leap/bitmask/services/eip/linuxvpnlauncher.py +++ b/src/leap/bitmask/services/eip/linuxvpnlauncher.py @@ -61,9 +61,13 @@ def _is_auth_agent_running(): :return: True if it's running, False if it's not. :rtype: boolean """ - ps = 'ps aux | grep polkit-%s-authentication-agent-1' - opts = (ps % case for case in ['[g]nome', '[k]de']) - is_running = map(lambda l: commands.getoutput(l), opts) + # the [x] thing is to avoid grep match itself + polkit_options = [ + 'ps aux | grep polkit-[g]nome-authentication-agent-1', + 'ps aux | grep polkit-[k]de-authentication-agent-1', + 'ps aux | grep [l]xpolkit' + ] + is_running = [commands.getoutput(cmd) for cmd in polkit_options] return any(is_running) diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py index 935d75f1..bce3599b 100644 --- a/src/leap/bitmask/services/eip/vpnlauncher.py +++ b/src/leap/bitmask/services/eip/vpnlauncher.py @@ -102,6 +102,8 @@ class VPNLauncher(object): UPDOWN_FILES = None OTHER_FILES = None + UP_SCRIPT = None + DOWN_SCRIPT = None @classmethod @abstractmethod @@ -164,7 +166,7 @@ class VPNLauncher(object): if not gateways: logger.error('No gateway was found!') - raise VPNLauncherException(kls.tr('No gateway was found!')) + raise VPNLauncherException('No gateway was found!') logger.debug("Using gateways ips: {0}".format(', '.join(gateways))) @@ -211,15 +213,17 @@ class VPNLauncher(object): '--script-security', '2' ] - if _has_updown_scripts(kls.UP_SCRIPT): - args += [ - '--up', '\"%s\"' % (kls.UP_SCRIPT,), - ] + if kls.UP_SCRIPT is not None: + if _has_updown_scripts(kls.UP_SCRIPT): + args += [ + '--up', '\"%s\"' % (kls.UP_SCRIPT,), + ] - if _has_updown_scripts(kls.DOWN_SCRIPT): - args += [ - '--down', '\"%s\"' % (kls.DOWN_SCRIPT,) - ] + if kls.DOWN_SCRIPT is not None: + if _has_updown_scripts(kls.DOWN_SCRIPT): + args += [ + '--down', '\"%s\"' % (kls.DOWN_SCRIPT,) + ] ########################################################### # For the time being we are disabling the usage of the @@ -241,6 +245,10 @@ class VPNLauncher(object): '--ca', providerconfig.get_ca_cert_path() ] + args += [ + '--ping', '10', + '--ping-restart', '30'] + command_and_args = [openvpn] + args logger.debug("Running VPN with command:") logger.debug(" ".join(command_and_args)) diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index 707967e0..19e1aa7b 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -24,6 +24,8 @@ import psutil.error import shutil import socket +from itertools import chain, repeat + from PySide import QtCore from leap.bitmask.config.providerconfig import ProviderConfig @@ -50,14 +52,93 @@ class VPNSignals(QtCore.QObject): They are instantiated in the VPN object and passed along till the VPNProcess. """ + # signals for the process state_changed = QtCore.Signal(dict) status_changed = QtCore.Signal(dict) process_finished = QtCore.Signal(int) + # signals that come from parsing + # openvpn output + network_unreachable = QtCore.Signal() + process_restart_tls = QtCore.Signal() + process_restart_ping = QtCore.Signal() + def __init__(self): QtCore.QObject.__init__(self) +class VPNObserver(object): + """ + A class containing different patterns in the openvpn output that + we can react upon. + """ + + # TODO this is i18n-sensitive, right? + # in that case, we should add the translations :/ + # until we find something better. + + _events = { + 'NETWORK_UNREACHABLE': ( + 'Network is unreachable (code=101)',), + 'PROCESS_RESTART_TLS': ( + "SIGUSR1[soft,tls-error]",), + 'PROCESS_RESTART_PING': ( + "SIGUSR1[soft,ping-restart]",), + 'INITIALIZATION_COMPLETED': ( + "Initialization Sequence Completed",), + } + + def __init__(self, qtsigs): + """ + Initializer. Keeps a reference to the passed qtsigs object + :param qtsigs: an object containing the different qt signals to + be used to communicate with different parts of + the application (the EIP state machine, for instance). + """ + self._qtsigs = qtsigs + + def watch(self, line): + """ + Inspects line searching for the different patterns. If a match + is found, try to emit the corresponding signal. + + :param line: a line of openvpn output + :type line: str + """ + chained_iter = chain(*[ + zip(repeat(key, len(l)), l) + for key, l in self._events.iteritems()]) + for event, pattern in chained_iter: + if pattern in line: + logger.debug('pattern matched! %s' % pattern) + break + else: + return + + sig = self._get_signal(event) + if sig: + sig.emit() + return + else: + logger.debug( + 'We got %s event from openvpn output but we ' + 'could not find a matching signal for it.' + % event) + + def _get_signal(self, event): + """ + Tries to get the matching signal from the eip signals + objects based on the name of the passed event (in lowercase) + + :param event: the name of the event that we want to get a signal + for + :type event: str + :returns: a QtSignal, or None + :rtype: QtSignal or None + """ + return getattr(self._qtsigs, event.lower(), None) + + class OpenVPNAlreadyRunning(Exception): message = ("Another openvpn instance is already running, and could " "not be stopped.") @@ -160,10 +241,14 @@ class VPN(object): tries += 1 reactor.callLater(self.TERMINATE_WAIT, self._kill_if_left_alive, tries) + return # after running out of patience, we try a killProcess logger.debug("Process did not died. Sending a SIGKILL.") - self.killit() + try: + self.killit() + except OSError: + logger.error("Could not kill process!") def killit(self): """ @@ -703,8 +788,12 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): self._last_status = None self._alive = False + # XXX use flags, maybe, instead of passing + # the parameter around. self._openvpn_verb = openvpn_verb + self._vpn_observer = VPNObserver(qtsigs) + # processProtocol methods def connectionMade(self): @@ -726,8 +815,9 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): .. seeAlso: `http://twistedmatrix.com/documents/13.0.0/api/twisted.internet.protocol.ProcessProtocol.html` # noqa """ # truncate the newline - # should send this to the logging window - vpnlog.info(data[:-1]) + line = data[:-1] + vpnlog.info(line) + self._vpn_observer.watch(line) def processExited(self, reason): """ |