diff options
| author | Kali Kaneko <kali@leap.se> | 2017-06-08 15:36:37 -0700 | 
|---|---|---|
| committer | Kali Kaneko (leap communications) <kali@leap.se> | 2017-06-09 00:48:40 +0200 | 
| commit | a003e13cec2c44160b46047d0fee8d52dfc6253f (patch) | |
| tree | 6322f118707e5ce5da435873744024eee9afb3d6 | |
| parent | 6f961fc09dd633d0bcf5397787139c0032e0661e (diff) | |
[bug] make openvpn and firewall able to launch
with these fixes, I'm able to finally launch openvpn and firewall on
osx. :)
all that's left for a minimum vpn release is packaging and installing
all the helpers in the proper place.
| -rw-r--r-- | src/leap/bitmask/vpn/_control.py | 10 | ||||
| -rw-r--r-- | src/leap/bitmask/vpn/fw/firewall.py | 47 | ||||
| -rwxr-xr-x | src/leap/bitmask/vpn/fw/osx/bitmask-helper | 19 | ||||
| -rw-r--r-- | src/leap/bitmask/vpn/launcher.py | 27 | ||||
| -rw-r--r-- | src/leap/bitmask/vpn/launchers/darwin.py | 7 | ||||
| -rw-r--r-- | src/leap/bitmask/vpn/process.py | 20 | 
6 files changed, 85 insertions, 45 deletions
| diff --git a/src/leap/bitmask/vpn/_control.py b/src/leap/bitmask/vpn/_control.py index 74182a9e..bf33b1bc 100644 --- a/src/leap/bitmask/vpn/_control.py +++ b/src/leap/bitmask/vpn/_control.py @@ -54,7 +54,7 @@ class VPNControl(object):          args = [self._vpnconfig, self._providerconfig, self._host,                  self._port] -        kwargs = {'openvpn_verb': 7, 'remotes': self._remotes, +        kwargs = {'openvpn_verb': 4, 'remotes': self._remotes,                    'restartfun': self.restart}          vpnproc = VPNProcess(*args, **kwargs) @@ -63,6 +63,11 @@ class VPNControl(object):              vpnproc.stop_if_already_running()          try: +            vpnproc.preUp() +        except Exception as e: +            log.error('Error on vpn pre-up {0!r}'.format(e)) +            raise +        try:              cmd = vpnproc.getCommand()          except Exception as e:              log.error('Error while getting vpn command... {0!r}'.format(e)) @@ -70,7 +75,8 @@ class VPNControl(object):          env = os.environ -        reactor.spawnProcess(vpnproc, cmd[0], cmd, env) +        runningproc = reactor.spawnProcess(vpnproc, cmd[0], cmd, env) +        vpnproc.pid = runningproc.pid          self._vpnproc = vpnproc          # add pollers for status and state diff --git a/src/leap/bitmask/vpn/fw/firewall.py b/src/leap/bitmask/vpn/fw/firewall.py index 23bdbd91..dcd956d4 100644 --- a/src/leap/bitmask/vpn/fw/firewall.py +++ b/src/leap/bitmask/vpn/fw/firewall.py @@ -25,14 +25,12 @@ import subprocess  from twisted.logger import Logger -from leap.bitmask.vpn.constants import IS_MAC +from leap.bitmask.vpn.constants import IS_MAC, IS_LINUX  from leap.common.events import catalog, emit_async -log = Logger() - - -# TODO -- subclass it for osx/windows, not only for linux. +from leap.bitmask.vpn.launchers import darwin +log = Logger()  # A regular user should not run bitmask as root, but we contemplate  # this case for tests inside docker. @@ -46,7 +44,34 @@ def check_root(cmd):      return cmd -class FirewallManager(object): +class _OSXFirewallManager(object): +    def __init__(self, remotes): +        self._remotes = list(remotes) +        self._helper = darwin.HelperCommand() + +    def start(self, restart=False): +        gateways = [gateway for gateway, port in self._remotes] +        cmd = 'firewall_start %s' % (' '.join(gateways),) +        self._helper.send(cmd) +        # TODO parse OK from result +        return True + +    def stop(self): +        cmd = 'firewall_stop' +        self._helper.send(cmd) +        return True + +    def is_up(self): +        # TODO implement!!! +        return True + +    @property +    def status(self): +        # TODO implement!!! -- factor out, too +        return {'status': 'on', 'error': None} + + +class _LinuxFirewallManager(object):      """      Firewall manager that blocks/unblocks all the internet traffic with some @@ -100,10 +125,6 @@ class FirewallManager(object):          """          Tear the firewall down using the privileged wrapper.          """ -        # We don't support Mac so far -        if IS_MAC: -            return True -          cmd = [self.BITMASK_ROOT, "firewall", "stop"]          cmd = check_root(cmd)          exitCode = subprocess.call(cmd) @@ -133,3 +154,9 @@ class FirewallManager(object):              status = 'on'          return {'status': status, 'error': None} + + +if IS_LINUX: +    FirewallManager = _LinuxFirewallManager +elif IS_MAC: +    FirewallManager = _OSXFirewallManager diff --git a/src/leap/bitmask/vpn/fw/osx/bitmask-helper b/src/leap/bitmask/vpn/fw/osx/bitmask-helper index 68be7dbb..2990219f 100755 --- a/src/leap/bitmask/vpn/fw/osx/bitmask-helper +++ b/src/leap/bitmask/vpn/fw/osx/bitmask-helper @@ -2,7 +2,7 @@  # -*- coding: utf-8 -*-  #  # Author: Kali Kaneko -# Copyright (C) 2015-2016 LEAP Encryption Access Project +# Copyright (C) 2015-2017 LEAP Encryption Access Project  #  # 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 @@ -42,11 +42,10 @@ To see the loaded rules:  To test the commands, you can write directly to the unix socket. Remember to  terminate the command properly: -  echo 'firewall_stop/CMD' | socat - UNIX-CONNECT:/tmp/bitmask-helper.socket + echo 'firewall_stop/CMD' | socat - UNIX-CONNECT:/tmp/bitmask-helper.socket  """  import os -import re  import socket  import signal  import subprocess @@ -75,7 +74,6 @@ FIXED_FLAGS = [      "--setenv", "LEAPOPENVPN", "1",      "--nobind",      "--client", -    "--dev", "tun",      "--tls-client",      "--remote-cert-tls", "server",      "--management-signal", @@ -243,14 +241,19 @@ def openvpn_start(*args):      opts += ['--dhcp-option', 'DNS', '10.42.0.1',               '--up', RESOURCES_PATH + 'client.up.sh',               '--down', RESOURCES_PATH + 'client.down.sh'] +    opts += ["--dev", "tun"]      binary = [RESOURCES_PATH + 'openvpn.leap'] - -    syslog.syslog(syslog.LOG_WARNING, ' '.join(binary + opts)) +    cmd = binary + opts +    #syslog.syslog(syslog.LOG_WARNING, 'LAUNCHING VPN: ' + ' '.join(cmd))      # TODO sanitize options      global openvpn_proc -    openvpn_proc = subprocess.Popen(binary + opts, shell=False) -    syslog.syslog(syslog.LOG_WARNING, "OpenVPN PID: %s" % str(openvpn_proc.pid)) +    openvpn_proc = subprocess.Popen(cmd, shell=False, bufsize=-1) +    #try: +    #    result = subprocess.check_output(cmd, shell=False, stderr=subprocess.STDOUT) +    #except Exception as exc: +    #    syslog.syslog(syslog.LOG_WARNING, exc.output) +    #syslog.syslog(syslog.LOG_WARNING, "OpenVPN PID: %s" % str(openvpn_proc.pid))  def openvpn_stop(sig='TERM'): diff --git a/src/leap/bitmask/vpn/launcher.py b/src/leap/bitmask/vpn/launcher.py index f412acef..8ce2660f 100644 --- a/src/leap/bitmask/vpn/launcher.py +++ b/src/leap/bitmask/vpn/launcher.py @@ -29,7 +29,7 @@ from twisted.logger import Logger  from abc import ABCMeta, abstractmethod  from functools import partial -from leap.bitmask.vpn.constants import IS_LINUX +from leap.bitmask.vpn.constants import IS_LINUX, IS_MAC  from leap.bitmask.vpn.utils import force_eval @@ -186,16 +186,6 @@ class VPNLauncher(object):          :return: A VPN command ready to be launched.          :rtype: list          """ -        # leap_assert_type(vpnconfig, VPNConfig) -        # leap_assert_type(providerconfig, ProviderConfig) - -        # XXX this still has to be changed on osx and windows accordingly -        # kwargs = {} -        # openvpn_possibilities = which(kls.OPENVPN_BIN, **kwargs) -        # if not openvpn_possibilities: -        #     raise OpenVPNNotFoundException() -        # openvpn = first(openvpn_possibilities) -        # -----------------------------------------          openvpn_path = force_eval(kls.OPENVPN_BIN_PATH)          if not os.path.isfile(openvpn_path): @@ -215,7 +205,6 @@ class VPNLauncher(object):          if openvpn_verb is not None:              args += ['--verb', '%d' % (openvpn_verb,)] -        # gateways = kls.get_gateways(vpnconfig, providerconfig)          gateways = remotes          for ip, port in gateways: @@ -224,7 +213,6 @@ class VPNLauncher(object):          args += [              '--client',              '--dev', ' tun', -            '--persist-key',              '--tls-client',              '--remote-cert-tls',              'server' @@ -269,13 +257,12 @@ class VPNLauncher(object):              '--ca', providerconfig.get_ca_cert_path()          ] -        args += [ -            '--ping', '5', -            '--ping-restart', '10'] - -        args += [ -            '--persist-key', -            '--persist-local-ip', '--persist-remote-ip'] +        if not IS_MAC: +            args += [ +                '--ping', '5', +                '--ping-restart', '10', +                '--persist-key', +                '--persist-local-ip', '--persist-remote-ip']          command_and_args = [openvpn_path] + args          return command_and_args diff --git a/src/leap/bitmask/vpn/launchers/darwin.py b/src/leap/bitmask/vpn/launchers/darwin.py index 3d64c857..80cacc4b 100644 --- a/src/leap/bitmask/vpn/launchers/darwin.py +++ b/src/leap/bitmask/vpn/launchers/darwin.py @@ -119,8 +119,8 @@ class DarwinVPNLauncher(VPNLauncher):          return os.path.join(resources_path, "bitmask.tiff")      @classmethod -    def get_vpn_command(kls, eipconfig, providerconfig, socket_host, -                        socket_port="unix", openvpn_verb=1): +    def get_vpn_command(kls, vpnconfig, providerconfig, socket_host, +                        remotes, socket_port="unix", openvpn_verb=1):          """          Returns the OSX implementation for the vpn launching command. @@ -149,7 +149,8 @@ class DarwinVPNLauncher(VPNLauncher):          # we use `super` in order to send the class to use          command = super(DarwinVPNLauncher, kls).get_vpn_command( -            eipconfig, providerconfig, socket_host, socket_port, openvpn_verb) +            vpnconfig, providerconfig, socket_host, socket_port, remotes, +            openvpn_verb)          command.extend(['--setenv', "LEAPUSER", getpass.getuser()])          return command diff --git a/src/leap/bitmask/vpn/process.py b/src/leap/bitmask/vpn/process.py index 895cd0a2..844cd0ff 100644 --- a/src/leap/bitmask/vpn/process.py +++ b/src/leap/bitmask/vpn/process.py @@ -50,6 +50,10 @@ class _VPNProcess(protocol.ProcessProtocol, _management.VPNManagement):      log = Logger() +    # HACK - reactor is expected to set this up when the process is spawned. +    # should try to get it from within this class. +    pid = None +      # TODO do we really need the vpnconfig/providerconfig objects in here???      def __init__(self, vpnconfig, providerconfig, socket_host, socket_port, @@ -183,6 +187,9 @@ class _VPNProcess(protocol.ProcessProtocol, _management.VPNManagement):      # launcher +    def preUp(self): +        pass +      def getCommand(self):          """          Gets the vpn command from the aproppriate launcher. @@ -252,11 +259,19 @@ elif IS_MAC:          This is a workaround to allow the state machine to be notified when          openvpn process is spawned by the privileged helper.          """ +          def setupHelper(self): +            # TODO use get_vpn_launcher instead              self.helper = darwin.HelperCommand() +        def preUp(self): +            self.setupHelper() +            cmd = self.getVPNCommand() +            self.helper.send('openvpn_start %s' % ' '.join(cmd)) +          def connectionMade(self): -            VPNProcess.connectionMade(self) +            super(_VPNProcess, self).connectionMade() +            self.setupHelper()              reactor.callLater(2, self.registerPID)          def registerPID(self): @@ -268,7 +283,8 @@ elif IS_MAC:              self.helper.send(cmd)          def getVPNCommand(self): -            return VPNProcess.getCommand(self) +            vpncmd = _VPNProcess.getCommand(self) +            return vpncmd          def getCommand(self):              canary = '''import sys, signal, time | 
