summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkali <kali@leap.se>2012-08-22 07:49:19 +0900
committerkali <kali@leap.se>2012-08-22 07:49:19 +0900
commit24f288b5214b814e2e7daa6ef41b226a27d96b81 (patch)
tree51dff8de10f0276786c0c83a55932a7f8932f6e9
parent83ac2efaa10de68f7fd35189f6cf272b03d60a30 (diff)
bye bye conductor, watcher (after refactor)
-rw-r--r--src/leap/eip/conductor.py305
-rw-r--r--src/leap/eip/vpnwatcher.py169
2 files changed, 0 insertions, 474 deletions
diff --git a/src/leap/eip/conductor.py b/src/leap/eip/conductor.py
deleted file mode 100644
index f528d63..0000000
--- a/src/leap/eip/conductor.py
+++ /dev/null
@@ -1,305 +0,0 @@
-"""
-stablishes a vpn connection and monitors its state
-"""
-from __future__ import (division, unicode_literals, print_function)
-#import threading
-from functools import partial
-import logging
-
-from leap.util.coroutines import spawn_and_watch_process
-
-# XXX from leap.eip import config as eipconfig
-# from leap.eip import exceptions as eip_exceptions
-
-from leap.eip.config import (get_config, build_ovpn_command,
- check_or_create_default_vpnconf,
- check_vpn_keys,
- EIPNoPkexecAvailable,
- EIPNoPolkitAuthAgentAvailable,
- EIPInitNoProviderError,
- EIPInitBadProviderError,
- EIPInitNoKeyFileError,
- EIPInitBadKeyFilePermError)
-from leap.eip.vpnwatcher import EIPConnectionStatus, status_watcher
-from leap.eip.vpnmanager import OpenVPNManager, ConnectionRefusedError
-
-logger = logging.getLogger(name=__name__)
-
-
-#
-# Openvpn related classes
-#
-# XXX deprecated! moved to eipconnection
-
-
-class OpenVPNConnection(object):
- """
- All related to invocation
- of the openvpn binary
- """
- # Connection Methods
-
- def __init__(self, config_file=None,
- watcher_cb=None, debug=False):
- #XXX FIXME
- #change watcher_cb to line_observer
- """
- :param config_file: configuration file to read from
- :param watcher_cb: callback to be \
-called for each line in watched stdout
- :param signal_map: dictionary of signal names and callables \
-to be triggered for each one of them.
- :type config_file: str
- :type watcher_cb: function
- :type signal_map: dict
- """
- # XXX get host/port from config
- self.manager = OpenVPNManager()
- self.debug = debug
- #print('conductor:%s' % debug)
-
- self.config_file = config_file
- self.watcher_cb = watcher_cb
- #self.signal_maps = signal_maps
-
- self.subp = None
- self.watcher = None
-
- self.server = None
- self.port = None
- self.proto = None
-
- self.missing_pkexec = False
- self.missing_auth_agent = False
- self.bad_keyfile_perms = False
- self.missing_vpn_keyfile = False
- self.missing_provider = False
- self.bad_provider = False
-
- self.command = None
- self.args = None
-
- self.autostart = True
- self._get_or_create_config()
- self._check_vpn_keys()
-
- def _set_autostart(self):
- config = self.config
- if config.has_option('openvpn', 'autostart'):
- autostart = config.getboolean('openvpn',
- 'autostart')
- self.autostart = autostart
- else:
- if config.has_option('DEFAULT', 'autostart'):
- autostart = config.getboolean('DEFAULT',
- 'autostart')
- self.autostart = autostart
-
- def _set_ovpn_command(self):
- config = self.config
- if config.has_option('openvpn', 'command'):
- commandline = config.get('openvpn', 'command')
-
- command_split = commandline.split(' ')
- command = command_split[0]
- if len(command_split) > 1:
- args = command_split[1:]
- else:
- args = []
-
- self.command = command
- self.args = args
- else:
- # no command in config, we build it up.
- # XXX check also for command-line --command flag
- try:
- command, args = build_ovpn_command(config,
- debug=self.debug)
- except EIPNoPolkitAuthAgentAvailable:
- command = args = None
- self.missing_auth_agent = True
- except EIPNoPkexecAvailable:
- command = args = None
- self.missing_pkexec = True
-
- # XXX if not command, signal error.
- self.command = command
- self.args = args
-
- def _check_ovpn_config(self):
- """
- checks if there is a default openvpn config.
- if not, it writes one with info from the provider
- definition file
- """
- # TODO
- # - get --with-openvpn-config from opts
- try:
- check_or_create_default_vpnconf(self.config)
- except EIPInitNoProviderError:
- logger.error('missing default provider definition')
- self.missing_provider = True
- except EIPInitBadProviderError:
- logger.error('bad provider definition')
- self.bad_provider = True
-
- def _get_or_create_config(self):
- """
- retrieves the config options from defaults or
- home file, or config file passed in command line.
- populates command and args to be passed to subprocess.
- """
- config = get_config(config_file=self.config_file)
- self.config = config
-
- self._set_autostart()
- self._set_ovpn_command()
- self._check_ovpn_config()
-
- def _check_vpn_keys(self):
- """
- checks for correct permissions on vpn keys
- """
- try:
- check_vpn_keys(self.config)
- except EIPInitNoKeyFileError:
- self.missing_vpn_keyfile = True
- except EIPInitBadKeyFilePermError:
- logger.error('error while checking vpn keys')
- self.bad_keyfile_perms = True
-
- def _launch_openvpn(self):
- """
- invocation of openvpn binaries in a subprocess.
- """
- #XXX TODO:
- #deprecate watcher_cb,
- #use _only_ signal_maps instead
-
- if self.watcher_cb is not None:
- linewrite_callback = self.watcher_cb
- else:
- #XXX get logger instead
- linewrite_callback = lambda line: print('watcher: %s' % line)
-
- observers = (linewrite_callback,
- partial(status_watcher, self.status))
- subp, watcher = spawn_and_watch_process(
- self.command,
- self.args,
- observers=observers)
- self.subp = subp
- self.watcher = watcher
-
- #conn_result = self.status.CONNECTED
- #return conn_result
-
- def _try_connection(self):
- """
- attempts to connect
- """
- if self.command is None:
- raise EIPNoCommandError
- if self.subp is not None:
- print('cowardly refusing to launch subprocess again')
- return
- self._launch_openvpn()
-
- def cleanup(self):
- """
- terminates child subprocess
- """
- if self.subp:
- self.subp.terminate()
-
-
-class EIPConductor(OpenVPNConnection):
- """
- Manages the execution of the OpenVPN process, auto starts, monitors the
- network connection, handles configuration, fixes leaky hosts, handles
- errors, etc.
- Preferences will be stored via the Storage API. (TBD)
- Status updates (connected, bandwidth, etc) are signaled to the GUI.
- """
-
- def __init__(self, *args, **kwargs):
- self.settingsfile = kwargs.get('settingsfile', None)
- self.logfile = kwargs.get('logfile', None)
- self.error_queue = []
- self.desired_con_state = None # ???
-
- status_signals = kwargs.pop('status_signals', None)
- self.status = EIPConnectionStatus(callbacks=status_signals)
-
- super(EIPConductor, self).__init__(*args, **kwargs)
-
- def connect(self):
- """
- entry point for connection process
- """
- self.manager.forget_errors()
- self._try_connection()
- # XXX should capture errors here?
-
- def disconnect(self):
- """
- disconnects client
- """
- self._disconnect()
- self.status.change_to(self.status.DISCONNECTED)
-
- def poll_connection_state(self):
- """
- """
- try:
- state = self.manager.get_connection_state()
- except ConnectionRefusedError:
- # connection refused. might be not ready yet.
- return
- if not state:
- return
- (ts, status_step,
- ok, ip, remote) = state
- self.status.set_vpn_state(status_step)
- status_step = self.status.get_readable_status()
- return (ts, status_step, ok, ip, remote)
-
- def get_icon_name(self):
- """
- get icon name from status object
- """
- return self.status.get_state_icon()
-
- #
- # private methods
- #
-
- def _disconnect(self):
- """
- private method for disconnecting
- """
- if self.subp is not None:
- self.subp.terminate()
- self.subp = None
- # XXX signal state changes! :)
-
- def _is_alive(self):
- """
- don't know yet
- """
- pass
-
- def _connect(self):
- """
- entry point for connection cascade methods.
- """
- #conn_result = ConState.DISCONNECTED
- try:
- conn_result = self._try_connection()
- except UnrecoverableError as except_msg:
- logger.error("FATAL: %s" % unicode(except_msg))
- conn_result = self.status.UNRECOVERABLE
- except Exception as except_msg:
- self.error_queue.append(except_msg)
- logger.error("Failed Connection: %s" %
- unicode(except_msg))
diff --git a/src/leap/eip/vpnwatcher.py b/src/leap/eip/vpnwatcher.py
deleted file mode 100644
index 09bd581..0000000
--- a/src/leap/eip/vpnwatcher.py
+++ /dev/null
@@ -1,169 +0,0 @@
-"""generic watcher object that keeps track of connection status"""
-# This should be deprecated in favor of daemon mode + management
-# interface. But we can leave it here for debug purposes.
-
-
-class EIPConnectionStatus(object):
- """
- Keep track of client (gui) and openvpn
- states.
-
- These are the OpenVPN states:
- CONNECTING -- OpenVPN's initial state.
- WAIT -- (Client only) Waiting for initial response
- from server.
- AUTH -- (Client only) Authenticating with server.
- GET_CONFIG -- (Client only) Downloading configuration options
- from server.
- ASSIGN_IP -- Assigning IP address to virtual network
- interface.
- ADD_ROUTES -- Adding routes to system.
- CONNECTED -- Initialization Sequence Completed.
- RECONNECTING -- A restart has occurred.
- EXITING -- A graceful exit is in progress.
-
- We add some extra states:
-
- DISCONNECTED -- GUI initial state.
- UNRECOVERABLE -- An unrecoverable error has been raised
- while invoking openvpn service.
- """
- CONNECTING = 1
- WAIT = 2
- AUTH = 3
- GET_CONFIG = 4
- ASSIGN_IP = 5
- ADD_ROUTES = 6
- CONNECTED = 7
- RECONNECTING = 8
- EXITING = 9
-
- # gui specific states:
- UNRECOVERABLE = 11
- DISCONNECTED = 0
-
- def __init__(self, callbacks=None):
- """
- EIPConnectionStatus is initialized with a tuple
- of signals to be triggered.
- :param callbacks: a tuple of (callable) observers
- :type callbacks: tuple
- """
- # (callbacks to connect to signals in Qt-land)
- self.current = self.DISCONNECTED
- self.previous = None
- self.callbacks = callbacks
-
- def get_readable_status(self):
- # XXX DRY status / labels a little bit.
- # think we'll want to i18n this.
- human_status = {
- 0: 'disconnected',
- 1: 'connecting',
- 2: 'waiting',
- 3: 'authenticating',
- 4: 'getting config',
- 5: 'assigning ip',
- 6: 'adding routes',
- 7: 'connected',
- 8: 'reconnecting',
- 9: 'exiting',
- 11: 'unrecoverable error',
- }
- return human_status[self.current]
-
- def get_state_icon(self):
- """
- returns the high level icon
- for each fine-grain openvpn state
- """
- connecting = (self.CONNECTING,
- self.WAIT,
- self.AUTH,
- self.GET_CONFIG,
- self.ASSIGN_IP,
- self.ADD_ROUTES)
- connected = (self.CONNECTED,)
- disconnected = (self.DISCONNECTED,
- self.UNRECOVERABLE)
-
- # this can be made smarter,
- # but it's like it'll change,
- # so +readability.
-
- if self.current in connecting:
- return "connecting"
- if self.current in connected:
- return "connected"
- if self.current in disconnected:
- return "disconnected"
-
- def set_vpn_state(self, status):
- """
- accepts a state string from the management
- interface, and sets the internal state.
- :param status: openvpn STATE (uppercase).
- :type status: str
- """
- if hasattr(self, status):
- self.change_to(getattr(self, status))
-
- def set_current(self, to):
- """
- setter for the 'current' property
- :param to: destination state
- :type to: int
- """
- self.current = to
-
- def change_to(self, to):
- """
- :param to: destination state
- :type to: int
- """
- if to == self.current:
- return
- changed = False
- from_ = self.current
- self.current = to
-
- # We can add transition restrictions
- # here to ensure no transitions are
- # allowed outside the fsm.
-
- self.set_current(to)
- changed = True
-
- #trigger signals (as callbacks)
- #print('current state: %s' % self.current)
- if changed:
- self.previous = from_
- if self.callbacks:
- for cb in self.callbacks:
- if callable(cb):
- cb(self)
-
-
-def status_watcher(cs, line):
- """
- a wrapper that calls to ConnectionStatus object
- :param cs: a EIPConnectionStatus instance
- :type cs: EIPConnectionStatus object
- :param line: a single line of the watched output
- :type line: str
- """
- #print('status watcher watching')
-
- # from the mullvad code, should watch for
- # things like:
- # "Initialization Sequence Completed"
- # "With Errors"
- # "Tap-Win32"
-
- if "Completed" in line:
- cs.change_to(cs.CONNECTED)
- return
-
- if "Initial packet from" in line:
- cs.change_to(cs.CONNECTING)
- return