summaryrefslogtreecommitdiff
path: root/src/leap/eip/eipconnection.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/eip/eipconnection.py')
-rw-r--r--src/leap/eip/eipconnection.py405
1 files changed, 0 insertions, 405 deletions
diff --git a/src/leap/eip/eipconnection.py b/src/leap/eip/eipconnection.py
deleted file mode 100644
index d012c567..00000000
--- a/src/leap/eip/eipconnection.py
+++ /dev/null
@@ -1,405 +0,0 @@
-"""
-EIP Connection Class
-"""
-from __future__ import (absolute_import,)
-import logging
-import Queue
-import sys
-import time
-
-from dateutil.parser import parse as dateparse
-
-from leap.eip.checks import ProviderCertChecker
-from leap.eip.checks import EIPConfigChecker
-from leap.eip import config as eipconfig
-from leap.eip import exceptions as eip_exceptions
-from leap.eip.openvpnconnection import OpenVPNConnection
-
-logger = logging.getLogger(name=__name__)
-
-
-class StatusMixIn(object):
-
- # a bunch of methods related with querying the connection
- # state/status and displaying useful info.
- # Needs to get clear on what is what, and
- # separate functions.
- # Should separate EIPConnectionStatus (self.status)
- # from the OpenVPN state/status command and parsing.
-
- ERR_CONNREFUSED = False
-
- def connection_state(self):
- """
- returns the current connection state
- """
- return self.status.current
-
- def get_icon_name(self):
- """
- get icon name from status object
- """
- return self.status.get_state_icon()
-
- def get_leap_status(self):
- return self.status.get_leap_status()
-
- def poll_connection_state(self):
- """
- """
- try:
- state = self.get_connection_state()
- except eip_exceptions.ConnectionRefusedError:
- # connection refused. might be not ready yet.
- if not self.ERR_CONNREFUSED:
- logger.warning('connection refused')
- self.ERR_CONNREFUSED = True
- return
- if not state:
- #logger.debug('no 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 make_error(self):
- """
- capture error and wrap it in an
- understandable format
- """
- # mostly a hack to display errors in the debug UI
- # w/o breaking the polling.
- #XXX get helpful error codes
- self.with_errors = True
- now = int(time.time())
- return '%s,LAUNCHER ERROR,ERROR,-,-' % now
-
- def state(self):
- """
- Sends OpenVPN command: state
- """
- state = self._send_command("state")
- if not state:
- return None
- if isinstance(state, str):
- return state
- if isinstance(state, list):
- if len(state) == 1:
- return state[0]
- else:
- return state[-1]
-
- def vpn_status(self):
- """
- OpenVPN command: status
- """
- status = self._send_command("status")
- return status
-
- def vpn_status2(self):
- """
- OpenVPN command: last 2 statuses
- """
- return self._send_command("status 2")
-
- #
- # parse info as the UI expects
- #
-
- def get_status_io(self):
- status = self.vpn_status()
- if isinstance(status, str):
- lines = status.split('\n')
- if isinstance(status, list):
- lines = status
- try:
- (header, when, tun_read, tun_write,
- tcp_read, tcp_write, auth_read) = tuple(lines)
- except ValueError:
- return None
-
- when_ts = dateparse(when.split(',')[1]).timetuple()
- sep = ','
- # XXX clean up this!
- tun_read = tun_read.split(sep)[1]
- tun_write = tun_write.split(sep)[1]
- tcp_read = tcp_read.split(sep)[1]
- tcp_write = tcp_write.split(sep)[1]
- auth_read = auth_read.split(sep)[1]
-
- # XXX this could be a named tuple. prettier.
- return when_ts, (tun_read, tun_write, tcp_read, tcp_write, auth_read)
-
- def get_connection_state(self):
- state = self.state()
- if state is not None:
- ts, status_step, ok, ip, remote = state.split(',')
- ts = time.gmtime(float(ts))
- # XXX this could be a named tuple. prettier.
- return ts, status_step, ok, ip, remote
-
-
-class EIPConnection(OpenVPNConnection, StatusMixIn):
- """
- Aka conductor.
- Manages the execution of the OpenVPN process, auto starts, monitors the
- network connection, handles configuration, fixes leaky hosts, handles
- errors, etc.
- Status updates (connected, bandwidth, etc) are signaled to the GUI.
- """
-
- # XXX change name to EIPConductor ??
-
- def __init__(self,
- provider_cert_checker=ProviderCertChecker,
- config_checker=EIPConfigChecker,
- *args, **kwargs):
- #self.settingsfile = kwargs.get('settingsfile', None)
- #self.logfile = kwargs.get('logfile', None)
- self.provider = kwargs.pop('provider', None)
- self._providercertchecker = provider_cert_checker
- self._configchecker = config_checker
-
- self.error_queue = Queue.Queue()
-
- status_signals = kwargs.pop('status_signals', None)
- self.status = EIPConnectionStatus(callbacks=status_signals)
-
- checker_signals = kwargs.pop('checker_signals', None)
- self.checker_signals = checker_signals
-
- self.init_checkers()
-
- host = eipconfig.get_socket_path()
- kwargs['host'] = host
-
- super(EIPConnection, self).__init__(*args, **kwargs)
-
- def connect(self, **kwargs):
- """
- entry point for connection process
- """
- # in OpenVPNConnection
- self.try_openvpn_connection()
-
- def disconnect(self, shutdown=False):
- """
- disconnects client
- """
- self.terminate_openvpn_connection(shutdown=shutdown)
- self.status.change_to(self.status.DISCONNECTED)
-
- def has_errors(self):
- return True if self.error_queue.qsize() != 0 else False
-
- def init_checkers(self):
- """
- initialize checkers
- """
- self.provider_cert_checker = self._providercertchecker(
- domain=self.provider)
- self.config_checker = self._configchecker(domain=self.provider)
-
- def set_provider_domain(self, domain):
- """
- sets the provider domain.
- used from the first run wizard when we launch the run_checks
- and connect process after having initialized the conductor.
- """
- # This looks convoluted, right.
- # We have to reinstantiate checkers cause we're passing
- # the domain param that we did not know at the beginning
- # (only for the firstrunwizard case)
- self.provider = domain
- self.init_checkers()
-
- def run_checks(self, skip_download=False, skip_verify=False):
- """
- run all eip checks previous to attempting a connection
- """
- logger.debug('running conductor checks')
-
- def push_err(exc):
- # keep the original traceback!
- exc_traceback = sys.exc_info()[2]
- self.error_queue.put((exc, exc_traceback))
-
- try:
- # network (1)
- if self.checker_signals:
- for signal in self.checker_signals:
- signal('checking encryption keys')
- self.provider_cert_checker.run_all(skip_verify=skip_verify)
- except Exception as exc:
- push_err(exc)
- try:
- if self.checker_signals:
- for signal in self.checker_signals:
- signal('checking provider config')
- self.config_checker.run_all(skip_download=skip_download)
- except Exception as exc:
- push_err(exc)
- try:
- self.run_openvpn_checks()
- except Exception as exc:
- push_err(exc)
-
-
-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
- """
- self.current = self.DISCONNECTED
- self.previous = None
- # (callbacks to connect to signals in Qt-land)
- 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_leap_status(self):
- # XXX improve nomenclature
- leap_status = {
- 0: 'disconnected',
- 1: 'connecting to gateway',
- 2: 'connecting to gateway',
- 3: 'authenticating',
- 4: 'establishing network encryption',
- 5: 'establishing network encryption',
- 6: 'establishing network encryption',
- 7: 'connected',
- 8: 'reconnecting',
- 9: 'exiting',
- 11: 'unrecoverable error',
- }
- return leap_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)