From b3428331a04bc4d8843b4ef2d4a62eaf3f7beafe Mon Sep 17 00:00:00 2001 From: "Kali Kaneko (leap communications)" Date: Fri, 16 Jun 2017 16:15:27 +0200 Subject: [refactor] class and module renaming --- src/leap/bitmask/vpn/manager.py | 103 ------------------------------ src/leap/bitmask/vpn/process.py | 1 - src/leap/bitmask/vpn/service.py | 24 +++---- src/leap/bitmask/vpn/tunnel.py | 114 +++++++++++++++++++++++++++++++++ src/leap/bitmask/vpn/tunnelmanager.py | 115 ++++++++++++++++++++++++++++++++++ src/leap/bitmask/vpn/vpn.py | 107 ------------------------------- 6 files changed, 241 insertions(+), 223 deletions(-) delete mode 100644 src/leap/bitmask/vpn/manager.py create mode 100644 src/leap/bitmask/vpn/tunnel.py create mode 100644 src/leap/bitmask/vpn/tunnelmanager.py delete mode 100644 src/leap/bitmask/vpn/vpn.py (limited to 'src/leap') diff --git a/src/leap/bitmask/vpn/manager.py b/src/leap/bitmask/vpn/manager.py deleted file mode 100644 index 2b113a75..00000000 --- a/src/leap/bitmask/vpn/manager.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- -# manager.py -# Copyright (C) 2015 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -VPN Manager -""" - -import os -import tempfile - -from ._control import VPNControl -from ._config import _TempVPNConfig, _TempProviderConfig -from .constants import IS_WIN - - -# TODO this is very badly named. There is another class that is called manager. -# TODO Call it Tunnel? Tunnel = vpn + firewall - -class TunnelManager(object): - - def __init__(self, provider, remotes, cert_path, key_path, ca_path, - extra_flags): - """ - :param remotes: a list of gateways tuple (ip, port) looking like this: - ((ip1, portA), (ip2, portB), ...) - :type remotes: tuple of tuple(str, int) - """ - # TODO we can set all the needed ports, gateways and paths in here - # TODO need gateways here - # sorting them doesn't belong in here - # gateways = ((ip1, portA), (ip2, portB), ...) - - ports = [] - - self._remotes = remotes - - self._vpnconfig = _TempVPNConfig(extra_flags, cert_path, ports) - self._providerconfig = _TempProviderConfig(provider, ca_path) - - host, port = self._get_management_location() - self._vpn = VPNControl(remotes=remotes, - vpnconfig=self._vpnconfig, - providerconfig=self._providerconfig, - socket_host=host, socket_port=port) - - def start(self): - """ - Start the VPN process. - """ - result = self._vpn.start() - return result - - def stop(self): - """ - Bring openvpn down using the privileged wrapper. - - :returns: True if succeeded, False otherwise. - :rtype: bool - """ - # TODO how to return False if this fails - result = self._vpn.stop(False, False) # TODO review params - return result - - @property - def status(self): - return self._vpn.status - - @property - def traffic_status(self): - return self._vpn.traffic_status - - def _get_management_location(self): - """ - Return a tuple with the host (socket) and port to be used for VPN. - - :return: (host, port) - :rtype: tuple (str, str) - """ - if IS_WIN: - host = "localhost" - port = "9876" - else: - # XXX cleanup this on exit too - # XXX atexit.register ? - host = os.path.join(tempfile.mkdtemp(prefix="leap-tmp"), - 'openvpn.socket') - port = "unix" - - return host, port diff --git a/src/leap/bitmask/vpn/process.py b/src/leap/bitmask/vpn/process.py index 9b235260..3de652ff 100644 --- a/src/leap/bitmask/vpn/process.py +++ b/src/leap/bitmask/vpn/process.py @@ -138,7 +138,6 @@ class _VPNProcess(protocol.ProcessProtocol, _management.VPNManagement): if 'SIGTERM[soft,ping-restart]' in line: self.restarting = True self.log.info(line) - # self._status.watch(line) def processExited(self, failure): """ diff --git a/src/leap/bitmask/vpn/service.py b/src/leap/bitmask/vpn/service.py index a792d1e6..fc39bcc8 100644 --- a/src/leap/bitmask/vpn/service.py +++ b/src/leap/bitmask/vpn/service.py @@ -26,7 +26,7 @@ from time import strftime from twisted.internet import defer from leap.bitmask.hooks import HookableService -from leap.bitmask.vpn.vpn import VPNManager +from leap.bitmask.vpn.tunnelmanager import TunnelManager from leap.bitmask.vpn._checks import is_service_ready, get_vpn_cert_path from leap.bitmask.vpn import privilege, helpers from leap.bitmask.vpn.privilege import NoPolkitAuthAgentAvailable @@ -53,7 +53,7 @@ class VPNService(HookableService): super(VPNService, self).__init__() self._started = False - self._vpn = None + self._tunnelmanager = None self._domain = '' if basepath is None: @@ -87,7 +87,7 @@ class VPNService(HookableService): yield self._setup(domain) try: - started = self._vpn.start() + started = self._tunnelmanager.start() # XXX capture it inside start method # here I'd like to get (status, message) @@ -108,15 +108,15 @@ class VPNService(HookableService): # TODO ----------------------------- # when shutting down the main bitmaskd daemon, this should be called. - if not self._vpn: + if not self._tunnelmanager: raise Exception('VPN was not running') if self._started: - self._vpn.stop() + self._tunnelmanager.stop() self._started = False return {'result': 'vpn stopped'} - elif self._vpn.is_firewall_up(): - self._vpn.stop_firewall() + elif self._tunnelmanager.is_firewall_up(): + self._tunnelmanager.stop_firewall() return {'result': 'firewall stopped'} else: raise Exception('VPN was not running') @@ -128,8 +128,8 @@ class VPNService(HookableService): 'childrenStatus': {} } - if self._vpn: - status = self._vpn.get_status() + if self._tunnelmanager: + status = self._tunnelmanager.get_status() if self._domain: status['domain'] = self._domain @@ -179,7 +179,7 @@ class VPNService(HookableService): @defer.inlineCallbacks def _setup(self, provider): - """Set up VPNManager for a specified provider. + """Set up TunnelManager for a specified provider. :param provider: the provider to use, e.g. 'demo.bitmask.net' :type provider: str""" @@ -203,8 +203,8 @@ class VPNService(HookableService): 'Cannot find provider certificate. ' 'Please configure provider.') - self._vpn = VPNManager(provider, remotes, cert_path, key_path, ca_path, - extra_flags) + self._tunnelmanager = TunnelManager( + provider, remotes, cert_path, key_path, ca_path, extra_flags) def _cert_expires(self, provider): path = os.path.join(self._basepath, "leap", "providers", provider, diff --git a/src/leap/bitmask/vpn/tunnel.py b/src/leap/bitmask/vpn/tunnel.py new file mode 100644 index 00000000..4236edf5 --- /dev/null +++ b/src/leap/bitmask/vpn/tunnel.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +# manager.py +# Copyright (C) 2015 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +VPN Tunnel. +""" + +import os +import tempfile + +from ._control import VPNControl +from ._config import _TempVPNConfig, _TempProviderConfig +from .constants import IS_WIN + + +# TODO refactor - this class is still a very light proxy around the +# underlying VPNControl. The main methods here are start/stop, so this +# looks like it could better use the Service interface. +# TODO gateway selection should be done in this class. +# TODO DO NOT pass VPNConfig/ProviderConfig beyond this class. +# TODO split sync/async vpn control mechanisms. + + +class VPNTunnel(object): + + """ + A VPN Tunnel holds the configuration for a VPN connection, and allows to + control that connection. + """ + + def __init__(self, provider, remotes, cert_path, key_path, ca_path, + extra_flags): + """ + :param remotes: a list of gateways tuple (ip, port) looking like this: + ((ip1, portA), (ip2, portB), ...) + :type remotes: tuple of tuple(str, int) + """ + # TODO we can set all the needed ports, gateways and paths in here + # TODO need gateways here + # sorting them doesn't belong in here + # gateways = ((ip1, portA), (ip2, portB), ...) + + ports = [] + + self._remotes = remotes + + self._vpnconfig = _TempVPNConfig(extra_flags, cert_path, ports) + self._providerconfig = _TempProviderConfig(provider, ca_path) + + host, port = self._get_management_location() + + self._vpn = VPNControl(remotes=remotes, + vpnconfig=self._vpnconfig, + providerconfig=self._providerconfig, + socket_host=host, socket_port=port) + + def start(self): + """ + Start the VPN process. + """ + result = self._vpn.start() + return result + + def stop(self): + """ + Bring openvpn down using the privileged wrapper. + + :returns: True if succeeded, False otherwise. + :rtype: bool + """ + # TODO how to return False if this fails + result = self._vpn.stop(False, False) # TODO review params + return result + + @property + def status(self): + return self._vpn.status + + @property + def traffic_status(self): + return self._vpn.traffic_status + + def _get_management_location(self): + """ + Return a tuple with the host (socket) and port to be used for VPN. + + :return: (host, port) + :rtype: tuple (str, str) + """ + if IS_WIN: + host = "localhost" + port = "9876" + else: + # XXX cleanup this on exit too + # XXX atexit.register ? + host = os.path.join(tempfile.mkdtemp(prefix="leap-tmp"), + 'openvpn.socket') + port = "unix" + + return host, port diff --git a/src/leap/bitmask/vpn/tunnelmanager.py b/src/leap/bitmask/vpn/tunnelmanager.py new file mode 100644 index 00000000..5faac662 --- /dev/null +++ b/src/leap/bitmask/vpn/tunnelmanager.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# cli.py +# Copyright (C) 2015 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from colorama import Fore + +from leap.bitmask.util import merge_status + +from leap.bitmask.vpn.fw.firewall import FirewallManager +from leap.bitmask.vpn.tunnel import VPNTunnel + + +# TODO further refactor pending: merge with VPNService? + + +class TunnelManager(object): + + """ + A TunnelManager controls VPN and Firewall + """ + + def __init__(self, provider, remotes, cert, key, ca, flags): + + self._vpntunnel = VPNTunnel( + provider, remotes, cert, key, ca, flags) + self._firewall = FirewallManager(remotes) + self.starting = False + + def start(self): + # TODO we should have some way of switching this flag to False + # other than parsing the result of the status command. + self.starting = True + print(Fore.BLUE + "Firewall: starting..." + Fore.RESET) + fw_ok = self._firewall.start() + if not fw_ok: + print(Fore.RED + "Firewall: problem!") + self.starting = False + return False + print(Fore.GREEN + "Firewall: started" + Fore.RESET) + + try: + vpn_ok = self._vpntunnel.start() + except Exception: + self.starting = False + return False + + if not vpn_ok: + print (Fore.RED + "VPN: Error starting." + Fore.RESET) + self._firewall.stop() + print(Fore.GREEN + "Firewall: stopped." + Fore.RESET) + self.starting = False + return False + print(Fore.GREEN + "VPN: started" + Fore.RESET) + return True + + def stop(self): + self.starting = False + print(Fore.BLUE + "Firewall: stopping..." + Fore.RESET) + fw_ok = self._firewall.stop() + + if not fw_ok: + print (Fore.RED + "Firewall: Error stopping." + Fore.RESET) + return False + + print(Fore.GREEN + "Firewall: stopped." + Fore.RESET) + print(Fore.BLUE + "VPN: stopping..." + Fore.RESET) + + vpn_ok = self._vpntunnel.stop() + if not vpn_ok: + print (Fore.RED + "VPN: Error stopping." + Fore.RESET) + return False + + print(Fore.GREEN + "VPN: stopped." + Fore.RESET) + return True + + def stop_firewall(self): + self._firewall.stop() + + def is_firewall_up(self): + return self._firewall.is_up() + + def get_status(self): + childrenStatus = { + "vpn": self._vpntunnel.status, + "firewall": self._firewall.status + } + if self.starting: + # XXX small correction to the merge: if we are starting fw+vpn, + # we report vpn as starting so that is consistent with the ui or + # cli action. this state propagates from the parent + # object to the vpn child, and we revert it when we reach + # the 'on' state. this needs to be revisited in the formal state + # machine, and mainly needs a way of setting that state directly + # and resetting the 'starting' flag without resorting to hijack + # this command. + vpnstatus = childrenStatus['vpn']['status'] + if vpnstatus == 'off': + childrenStatus['vpn']['status'] = 'starting' + if vpnstatus == 'on': + self.starting = False + return merge_status(childrenStatus) diff --git a/src/leap/bitmask/vpn/vpn.py b/src/leap/bitmask/vpn/vpn.py deleted file mode 100644 index 23f0a582..00000000 --- a/src/leap/bitmask/vpn/vpn.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# cli.py -# Copyright (C) 2015 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from colorama import Fore - -from leap.bitmask.util import merge_status -from leap.bitmask.vpn.manager import TunnelManager -from leap.bitmask.vpn.fw.firewall import FirewallManager - - -class VPNManager(object): - - def __init__(self, provider, remotes, cert, key, ca, flags): - - self._vpn = TunnelManager( - provider, remotes, cert, key, ca, flags) - self._firewall = FirewallManager(remotes) - self.starting = False - - def start(self): - # TODO we should have some way of switching this flag to False - # other than parsing the result of the status command. - self.starting = True - print(Fore.BLUE + "Firewall: starting..." + Fore.RESET) - fw_ok = self._firewall.start() - if not fw_ok: - print(Fore.RED + "Firewall: problem!") - self.starting = False - return False - print(Fore.GREEN + "Firewall: started" + Fore.RESET) - - try: - vpn_ok = self._vpn.start() - except Exception: - self.starting = False - return False - - if not vpn_ok: - print (Fore.RED + "VPN: Error starting." + Fore.RESET) - self._firewall.stop() - print(Fore.GREEN + "Firewall: stopped." + Fore.RESET) - self.starting = False - return False - print(Fore.GREEN + "VPN: started" + Fore.RESET) - return True - - def stop(self): - self.starting = False - print(Fore.BLUE + "Firewall: stopping..." + Fore.RESET) - fw_ok = self._firewall.stop() - - if not fw_ok: - print (Fore.RED + "Firewall: Error stopping." + Fore.RESET) - return False - - print(Fore.GREEN + "Firewall: stopped." + Fore.RESET) - print(Fore.BLUE + "VPN: stopping..." + Fore.RESET) - - vpn_ok = self._vpn.stop() - if not vpn_ok: - print (Fore.RED + "VPN: Error stopping." + Fore.RESET) - return False - - print(Fore.GREEN + "VPN: stopped." + Fore.RESET) - return True - - def stop_firewall(self): - self._firewall.stop() - - def is_firewall_up(self): - return self._firewall.is_up() - - def get_status(self): - childrenStatus = { - "vpn": self._vpn.status, - "firewall": self._firewall.status - } - if self.starting: - # XXX small correction to the merge: if we are starting fw+vpn, - # we report vpn as starting so that is consistent with the ui or - # cli action. this state propagates from the parent - # object to the vpn child, and we revert it when we reach - # the 'on' state. this needs to be revisited in the formal state - # machine, and mainly needs a way of setting that state directly - # and resetting the 'starting' flag without resorting to hijack - # this command. - vpnstatus = childrenStatus['vpn']['status'] - if vpnstatus == 'off': - childrenStatus['vpn']['status'] = 'starting' - if vpnstatus == 'on': - self.starting = False - return merge_status(childrenStatus) -- cgit v1.2.3