summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/leap/bitmask/backend.py42
-rw-r--r--src/leap/bitmask/gui/eip_status.py90
-rw-r--r--src/leap/bitmask/gui/mainwindow.py25
-rw-r--r--src/leap/bitmask/gui/ui/eip_status.ui27
-rw-r--r--src/leap/bitmask/services/eip/conductor.py41
-rw-r--r--src/leap/bitmask/services/eip/vpnprocess.py21
6 files changed, 173 insertions, 73 deletions
diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py
index 4ec20be7..3c97c797 100644
--- a/src/leap/bitmask/backend.py
+++ b/src/leap/bitmask/backend.py
@@ -80,13 +80,13 @@ class ILEAPService(ILEAPComponent):
Interface that every Service needs to implement
"""
- def start(self):
+ def start(self, *args, **kwargs):
"""
Start the service.
"""
pass
- def stop(self):
+ def stop(self, *args, **kwargs):
"""
Stops the service.
"""
@@ -378,9 +378,12 @@ class EIP(object):
if d is not None:
d.cancel()
- def _start_eip(self):
+ def _start_eip(self, restart=False):
"""
Start EIP
+
+ :param restart: whether is is a restart.
+ :type restart: bool
"""
provider_config = self._provider_config
eip_config = eipconfig.EIPConfig()
@@ -404,9 +407,10 @@ class EIP(object):
host, port = get_openvpn_management()
self._vpn.start(eipconfig=eip_config,
providerconfig=provider_config,
- socket_host=host, socket_port=port)
+ socket_host=host, socket_port=port,
+ restart=restart)
- def start(self):
+ def start(self, *args, **kwargs):
"""
Start the service.
"""
@@ -419,7 +423,7 @@ class EIP(object):
return
try:
- self._start_eip()
+ self._start_eip(*args, **kwargs)
except vpnprocess.OpenVPNAlreadyRunning:
signaler.signal(signaler.EIP_OPENVPN_ALREADY_RUNNING)
except vpnprocess.AlienOpenVPNAlreadyRunning:
@@ -440,11 +444,6 @@ class EIP(object):
logger.error("Unexpected problem: {0!r}".format(e))
else:
logger.debug('EIP: no errors')
- # TODO: are we connected here?
- # kali -- no, we are not! CONNECTED should be passed only
- # by the vpn observer. Currently handled by the state updater
- # in eip_status
- #signaler.signal(signaler.EIP_CONNECTED)
def _do_stop(self, shutdown=False, restart=False):
"""
@@ -539,6 +538,12 @@ class EIP(object):
self._signaler.signal(self._signaler.EIP_GET_INITIALIZED_PROVIDERS,
filtered_domains)
+ def tear_fw_down(self):
+ """
+ Tear the firewall down.
+ """
+ self._vpn.tear_down_firewall()
+
def get_gateways_list(self, domain):
"""
Signal a list of gateways for the given provider.
@@ -1181,6 +1186,7 @@ class Signaler(QtCore.QObject):
eip_state_changed = QtCore.Signal(dict)
eip_status_changed = QtCore.Signal(dict)
eip_process_finished = QtCore.Signal(int)
+ eip_tear_fw_down = QtCore.Signal(object)
# signals whether the needed files to start EIP exist or not
eip_can_start = QtCore.Signal(object)
@@ -1282,6 +1288,7 @@ class Signaler(QtCore.QObject):
EIP_STATE_CHANGED = "eip_state_changed"
EIP_STATUS_CHANGED = "eip_status_changed"
EIP_PROCESS_FINISHED = "eip_process_finished"
+ EIP_TEAR_FW_DOWN = "eip_tear_fw_down"
EIP_CAN_START = "eip_can_start"
EIP_CANNOT_START = "eip_cannot_start"
@@ -1717,7 +1724,7 @@ class Backend(object):
"""
self._call_queue.put(("eip", "cancel_setup_eip", None))
- def eip_start(self):
+ def eip_start(self, restart=False):
"""
Start the EIP service.
@@ -1738,8 +1745,11 @@ class Backend(object):
eip_state_changed -> str
eip_status_changed -> tuple of str (download, upload)
eip_vpn_launcher_exception
+
+ :param restart: whether is is a restart.
+ :type restart: bool
"""
- self._call_queue.put(("eip", "start", None))
+ self._call_queue.put(("eip", "start", None, restart))
def eip_stop(self, shutdown=False, restart=False, failed=False):
"""
@@ -1805,6 +1815,12 @@ class Backend(object):
self._call_queue.put(("eip", "can_start",
None, domain))
+ def tear_fw_down(self):
+ """
+ Signal the need to tear the fw down.
+ """
+ self._call_queue.put(("eip", "tear_fw_down", None))
+
def user_login(self, provider, username, password):
"""
Execute the whole authentication process for a user
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py
index e7795083..280ce79e 100644
--- a/src/leap/bitmask/gui/eip_status.py
+++ b/src/leap/bitmask/gui/eip_status.py
@@ -31,6 +31,7 @@ from leap.common.check import leap_assert_type
from ui_eip_status import Ui_EIPStatus
+QtDelayedCall = QtCore.QTimer.singleShot
logger = logging.getLogger(__name__)
@@ -66,6 +67,9 @@ class EIPStatusWidget(QtGui.QWidget):
self._service_name = get_service_display_name(EIP_SERVICE)
self.ui.eip_bandwidth.hide()
+ self.hide_fw_down_button()
+ self.ui.btnFwDown.clicked.connect(
+ self._on_fw_down_button_clicked)
# Set the EIP status icons
self.CONNECTING_ICON = None
@@ -81,6 +85,7 @@ class EIPStatusWidget(QtGui.QWidget):
self._provider = ""
self.is_restart = False
+ self.is_cold_start = True
# Action for the systray
self._eip_disabled_action = QtGui.QAction(
@@ -109,8 +114,12 @@ class EIPStatusWidget(QtGui.QWidget):
signaler.eip_state_changed.connect(self.update_vpn_state)
signaler.eip_status_changed.connect(self.update_vpn_status)
- signaler.eip_network_unreachable.connect(
- self._on_eip_network_unreachable)
+
+ # XXX we cannot connect this signal now because
+ # it interferes with the proper notifications during restarts
+ # without available network.
+ #signaler.eip_network_unreachable.connect(
+ #self._on_eip_network_unreachable)
def _make_status_clickable(self):
"""
@@ -273,6 +282,8 @@ class EIPStatusWidget(QtGui.QWidget):
Disables the start/stop button.
"""
self.set_startstop_enabled(False)
+ msg = self.tr("Encrypted Internet is starting")
+ self.set_eip_message(msg)
@QtCore.Slot()
def disable_eip_start(self):
@@ -314,10 +325,19 @@ class EIPStatusWidget(QtGui.QWidget):
if self.isVisible():
self._eip_status_menu.menuAction().setVisible(True)
- # XXX disable (later) --------------------------
+ def set_eip_message(self, message):
+ """
+ Set the EIP Widget main message.
+
+ :param message: the message to set in the widget
+ :type message: str or unicode
+ """
+ self.ui.lblEIPMessage.setText(message)
+ self.ui.lblEIPMessage.show()
+
def set_eip_status(self, status, error=False):
"""
- Sets the status label at the VPN stage to status
+ Set the status label at the VPN stage to status.
:param status: status message
:type status: str or unicode
@@ -362,6 +382,31 @@ class EIPStatusWidget(QtGui.QWidget):
self.ui.btnEipStartStop.clicked.connect(
self.eipconnection.qtsigs.do_connect_signal)
+ def hide_fw_down_button(self):
+ """
+ Hide firewall-down button.
+ """
+ self.ui.btnFwDown.hide()
+
+ def show_fw_down_button(self):
+ """
+ Enable firewall-down button.
+ """
+ self.ui.btnFwDown.show()
+
+ def _on_fw_down_button_clicked(self):
+ """
+ Raise a signal for tearing down the firewall, and hide the button
+ afterwards.
+ """
+ self.eip_conductor._backend.tear_fw_down()
+ QtDelayedCall(50, self.hide_fw_down_button)
+
+ # XXX do actual check
+ msg = "Traffic is being routed in the clear."
+ self.set_eip_message(msg)
+ self.set_eip_status("")
+
@QtCore.Slot(dict)
def eip_stopped(self, restart=False, failed=False):
"""
@@ -382,7 +427,7 @@ class EIPStatusWidget(QtGui.QWidget):
clear_traffic = self.tr("Traffic is being routed in the clear.")
unreachable_net = self.tr("Network is unreachable.")
- failed_msg = self.tr("Cannot start Encrypted Proxy.")
+ failed_msg = self.tr("Cannot start Encrypted Internet")
if restart:
msg = unreachable_net
@@ -390,18 +435,19 @@ class EIPStatusWidget(QtGui.QWidget):
msg = failed_msg
else:
msg = clear_traffic
- self.ui.lblEIPMessage.setText(msg)
+ self.set_eip_message(msg)
self.ui.lblEIPStatus.show()
+ self.show()
def eip_failed_to_restart(self):
"""
Update EIP messages.
"""
- msg = self.tr("Could not restart Encrypted Proxy")
+ msg = self.tr("Could not restart Encrypted Internet")
self.ui.lblEIPMessage.setText(msg)
self.ui.lblEIPStatus.show()
-
- self.set_eip_status(self.tr("You can start the service manually."))
+ self.set_eip_status(self.tr("You can launch the service manually."))
+ self.show_fw_down_button()
@QtCore.Slot(dict)
def update_vpn_status(self, data=None):
@@ -462,10 +508,18 @@ class EIPStatusWidget(QtGui.QWidget):
# XXX should be handled by the state machine too.
# --- is this currently being sent?
self.eipconnection.qtsigs.connected_signal.emit()
+ self._on_eip_connected()
+ self.is_cold_start = False
# XXX should lookup vpn_state map in EIPConnection
elif vpn_state == "AUTH":
self.set_eip_status(self.tr("Authenticating..."))
+ # we wipe up any previous error info in the EIP message
+ # when we detect vpn authentication is happening
+ msg = self.tr("Encrypted Internet is starting")
+ self.set_eip_message(msg)
+ # on the first-run path, we hadn't showed the button yet.
+ self.eip_button.show()
elif vpn_state == "GET_CONFIG":
self.set_eip_status(self.tr("Retrieving configuration..."))
elif vpn_state == "WAIT":
@@ -478,10 +532,10 @@ class EIPStatusWidget(QtGui.QWidget):
# Put the following calls in Qt's event queue, otherwise
# the UI won't update properly
#self.send_disconnect_signal()
- QtCore.QTimer.singleShot(
+ QtDelayedCall(
0, self.eipconnection.qtsigns.do_disconnect_signal.emit)
msg = self.tr("Unable to start VPN, it's already running.")
- QtCore.QTimer.singleShot(0, partial(self.set_eip_status, msg))
+ QtDelayedCall(0, partial(self.set_eip_status, msg))
else:
self.set_eip_status(vpn_state)
@@ -523,8 +577,10 @@ class EIPStatusWidget(QtGui.QWidget):
def set_provider(self, provider):
self._provider = provider
+
self.ui.lblEIPMessage.setText(
- self.tr("Route traffic through: {0}").format(self._provider))
+ self.tr("Routing traffic through: <b>{0}</b>").format(
+ provider))
def aborted(self):
"""
@@ -544,6 +600,9 @@ class EIPStatusWidget(QtGui.QWidget):
TRIGGERS:
Signaler.eip_connection_aborted
"""
+ # TODO this name is very misleading, since there's a generic signal
+ # that's called connection_aborted / connection_died...
+ # should rename to something more specific about missing config.
logger.error("Tried to start EIP but cannot find any "
"available provider!")
@@ -619,6 +678,13 @@ class EIPStatusWidget(QtGui.QWidget):
self.aborted()
+ def _on_eip_connected(self):
+ """
+ Reconnect the disconnecting signal when we are just connected,
+ so that we restore the disconnecting -> stop behaviour.
+ """
+ self.eip_conductor.reconnect_stop_signal()
+
@QtCore.Slot()
def _on_eip_network_unreachable(self):
"""
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index e7406106..a3b81fde 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -158,8 +158,6 @@ class MainWindow(QtGui.QMainWindow):
self._eip_conductor.connect_signals()
self._eip_conductor.qtsigs.connected_signal.connect(
self._on_eip_connection_connected)
- self._eip_conductor.qtsigs.disconnected_signal.connect(
- self._on_eip_connection_disconnected)
self._eip_conductor.qtsigs.connected_signal.connect(
self._maybe_run_soledad_setup_checks)
@@ -1448,6 +1446,7 @@ class MainWindow(QtGui.QMainWindow):
Enables the EIP start action in the systray menu.
"""
self._action_eip_startstop.setEnabled(True)
+ self._eip_status.enable_eip_start()
@QtCore.Slot()
def _on_eip_connection_connected(self):
@@ -1468,25 +1467,6 @@ class MainWindow(QtGui.QMainWindow):
# check for connectivity
self._check_name_resolution(domain)
- @QtCore.Slot()
- def _on_eip_connection_disconnected(self):
- """
- TRIGGERS:
- self._eip_conductor.qtsigs.disconnected_signal
-
- Workaround for updating the eip_status widget with
- the provider when the eip connection disconnects.
- """
- # TODO
- # We should move this to the conductor<->widget interface.
- # To do that, we need to subscribe to logged_user,
- # for example by using the observer pattern or a proxy object.
- user = self._logged_user
- if user:
- domain = self._login_widget.get_selected_provider()
- full_user_id = make_address(user, domain)
- self._eip_status.set_provider(full_user_id)
-
def _check_name_resolution(self, domain):
# FIXME this has to be moved to backend !!!
# Should move to netchecks module.
@@ -1563,7 +1543,10 @@ class MainWindow(QtGui.QMainWindow):
should_start = self._provides_eip_and_enabled()
if should_start and not self._already_started_eip:
+ if self._eip_status.is_cold_start:
+ self._backend.tear_fw_down()
# XXX this should be handled by the state machine.
+ self._enable_eip_start_action()
self._eip_status.set_eip_status(
self.tr("Starting..."))
self._eip_status.eip_button.setEnabled(False)
diff --git a/src/leap/bitmask/gui/ui/eip_status.ui b/src/leap/bitmask/gui/ui/eip_status.ui
index 64821ad6..01d6b371 100644
--- a/src/leap/bitmask/gui/ui/eip_status.ui
+++ b/src/leap/bitmask/gui/ui/eip_status.ui
@@ -28,7 +28,7 @@
<property name="verticalSpacing">
<number>0</number>
</property>
- <item row="0" column="2">
+ <item row="0" column="3">
<widget class="QPushButton" name="btnEipStartStop">
<property name="text">
<string>Turn On</string>
@@ -86,7 +86,7 @@
</property>
</widget>
</item>
- <item row="0" column="3">
+ <item row="0" column="4">
<widget class="QLabel" name="lblVPNStatusIcon">
<property name="maximumSize">
<size>
@@ -118,7 +118,7 @@
</property>
</spacer>
</item>
- <item row="2" column="1" colspan="3">
+ <item row="2" column="1" colspan="4">
<widget class="QWidget" name="eip_bandwidth" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
@@ -161,12 +161,13 @@
<property name="text">
<string>0.0 KB/s</string>
</property>
+ <property name="icon">
+ <iconset resource="../../../../../data/resources/mainwindow.qrc">
+ <normaloff>:/images/black/32/arrow-down.png</normaloff>:/images/black/32/arrow-down.png</iconset>
+ </property>
<property name="flat">
<bool>true</bool>
</property>
- <property name="icon">
- <pixmap resource="../../../../../data/resources/icons.qrc">:/images/light/16/down-arrow.png</pixmap>
- </property>
</widget>
</item>
<item>
@@ -211,12 +212,13 @@
<property name="text">
<string>0.0 KB/s</string>
</property>
+ <property name="icon">
+ <iconset resource="../../../../../data/resources/mainwindow.qrc">
+ <normaloff>:/images/black/32/arrow-up.png</normaloff>:/images/black/32/arrow-up.png</iconset>
+ </property>
<property name="flat">
<bool>true</bool>
</property>
- <property name="icon">
- <pixmap resource="../../../../../data/resources/icons.qrc">:/images/light/16/up-arrow.png</pixmap>
- </property>
</widget>
</item>
<item>
@@ -237,6 +239,13 @@
</layout>
</widget>
</item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="btnFwDown">
+ <property name="text">
+ <string>Allow unencrypted traffic</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
</layout>
diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py
index 53b1fde9..cde53631 100644
--- a/src/leap/bitmask/services/eip/conductor.py
+++ b/src/leap/bitmask/services/eip/conductor.py
@@ -114,13 +114,19 @@ class EIPConductor(object):
"""
self.qtsigs.do_connect_signal.emit()
+ def tear_fw_down(self):
+ """
+ Tear the firewall down.
+ """
+ self._backend.tear_fw_down()
+
@QtCore.Slot()
def _start_eip(self):
"""
Starts EIP.
"""
- # FIXME --- pass is_restart parameter to here ???
- is_restart = self._eip_status and self._eip_status.is_restart
+ st = self._eip_status
+ is_restart = st and st.is_restart
def reconnect():
self.qtsigs.disconnecting_signal.connect(self._stop_eip)
@@ -130,6 +136,7 @@ class EIPConductor(object):
else:
self._eip_status.eip_pre_up()
self.user_stopped_eip = False
+ self._eip_status.hide_fw_down_button()
# Until we set an option in the preferences window, we'll assume that
# by default we try to autostart. If we switch it off manually, it
@@ -138,7 +145,19 @@ class EIPConductor(object):
self._eip_status.is_restart = False
# DO the backend call!
- self._backend.eip_start()
+ self._backend.eip_start(restart=is_restart)
+
+ def reconnect_stop_signal(self):
+ """
+ Restore the original behaviour associated with the disconnecting
+ signal, this is, trigger a normal stop, and not a restart one.
+ """
+
+ def do_stop(*args):
+ self._stop_eip(restart=False)
+
+ self.qtsigs.disconnecting_signal.disconnect()
+ self.qtsigs.disconnecting_signal.connect(do_stop)
@QtCore.Slot()
def _stop_eip(self, restart=False, failed=False):
@@ -178,10 +197,6 @@ class EIPConductor(object):
def do_stop(*args):
self._stop_eip(restart=False)
- def reconnect_stop_signal():
- self.qtsigs.disconnecting_signal.disconnect()
- self.qtsigs.disconnecting_signal.connect(do_stop)
-
if restart:
# we bypass the on_eip_disconnected here
plug_restart_on_disconnected()
@@ -209,7 +224,7 @@ class EIPConductor(object):
# XXX needed?
if restart:
- QtDelayedCall(3000, reconnect_stop_signal)
+ QtDelayedCall(2000, self.reconnect_stop_signal)
@QtCore.Slot()
def _do_eip_restart(self):
@@ -282,8 +297,11 @@ class EIPConductor(object):
signal = self.qtsigs.connection_aborted_signal
self._backend.eip_terminate()
- # XXX FIXME --- check exitcode is != 0 really
- if exitCode != 0 and not self.user_stopped_eip:
+ # XXX FIXME --- check exitcode is != 0 really.
+ # bitmask-root is masking the exitcode, so we might need
+ # to fix it on that side.
+ #if exitCode != 0 and not self.user_stopped_eip:
+ if not self.user_stopped_eip:
eip_status_label = self._eip_status.tr(
"{0} finished in an unexpected manner!")
eip_status_label = eip_status_label.format(self.eip_name)
@@ -292,6 +310,9 @@ class EIPConductor(object):
self._eip_status.set_eip_status(eip_status_label,
error=True)
signal = self.qtsigs.connection_died_signal
+ self._eip_status.show_fw_down_button()
+ msg = self._eip_status.tr("Outgoing traffic is blocked")
+ self._eip_status.set_eip_message(msg)
if exitCode == 0 and IS_MAC:
# XXX remove this warning after I fix cocoasudo.
diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py
index 1de4a851..f56d464e 100644
--- a/src/leap/bitmask/services/eip/vpnprocess.py
+++ b/src/leap/bitmask/services/eip/vpnprocess.py
@@ -183,6 +183,8 @@ class VPN(object):
kwargs['openvpn_verb'] = self._openvpn_verb
kwargs['signaler'] = self._signaler
+ restart = kwargs.pop('restart', False)
+
# start the main vpn subprocess
vpnproc = VPNProcess(*args, **kwargs)
@@ -193,8 +195,9 @@ class VPN(object):
# we try to bring the firewall up
if IS_LINUX:
gateways = vpnproc.getGateways()
- firewall_up = self._launch_firewall(gateways)
- if not firewall_up:
+ firewall_up = self._launch_firewall(gateways,
+ restart=restart)
+ if not restart and not firewall_up:
logger.error("Could not bring firewall up, "
"aborting openvpn launch.")
return
@@ -216,7 +219,7 @@ class VPN(object):
self._pollers.extend(poll_list)
self._start_pollers()
- def _launch_firewall(self, gateways):
+ def _launch_firewall(self, gateways, restart=False):
"""
Launch the firewall using the privileged wrapper.
@@ -231,8 +234,10 @@ class VPN(object):
# XXX could check that the iptables rules are in place.
BM_ROOT = linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT
- exitCode = subprocess.call(["pkexec",
- BM_ROOT, "firewall", "start"] + gateways)
+ cmd = ["pkexec", BM_ROOT, "firewall", "start"]
+ if restart:
+ cmd.append("restart")
+ exitCode = subprocess.call(cmd + gateways)
return True if exitCode is 0 else False
def is_fw_down(self):
@@ -246,7 +251,7 @@ class VPN(object):
fw_is_down = lambda: commands.getstatusoutput(fw_up_cmd)[0] == 256
return fw_is_down()
- def _tear_down_firewall(self):
+ def tear_down_firewall(self):
"""
Tear the firewall down using the privileged wrapper.
"""
@@ -270,7 +275,7 @@ class VPN(object):
# we try to tear the firewall down
if IS_LINUX and self._user_stopped:
- firewall_down = self._tear_down_firewall()
+ firewall_down = self.tear_down_firewall()
if firewall_down:
logger.debug("Firewall down")
else:
@@ -333,7 +338,7 @@ class VPN(object):
self.TERMINATE_WAIT, self._kill_if_left_alive)
if IS_LINUX and self._user_stopped:
- firewall_down = self._tear_down_firewall()
+ firewall_down = self.tear_down_firewall()
if firewall_down:
logger.debug("Firewall down")
else: