From 15b017656e6865b7b85ae389ab3b462c562a1e42 Mon Sep 17 00:00:00 2001 From: antialias Date: Tue, 25 Sep 2012 16:05:02 -0400 Subject: moved LeapNetworkChecker and test in base. --- src/leap/base/checks.py | 80 +++++++++++++++++++++++++++++++++++ src/leap/base/exceptions.py | 19 +++++++++ src/leap/base/tests/test_checks.py | 86 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 src/leap/base/checks.py create mode 100644 src/leap/base/tests/test_checks.py (limited to 'src/leap/base') diff --git a/src/leap/base/checks.py b/src/leap/base/checks.py new file mode 100644 index 00000000..c5438b09 --- /dev/null +++ b/src/leap/base/checks.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +import platform + +import ping +import requests + +from leap.base import constants +from leap.base import exceptions + + +class LeapNetworkChecker(object): + """ + all network related checks + """ + # TODO eventually, use a more portable solution + # like psutil + + def run_all(self, checker=None): + if not checker: + checker = self + self.error = None # ? + + # for MVS + checker.check_internet_connection() + checker.is_internet_up() + checker.ping_gateway() + + def check_internet_connection(self): + try: + # XXX remove this hardcoded random ip + requests.get('http://216.172.161.165') + except (requests.HTTPError, requests.RequestException) as e: + raise exceptions.NoInternetConnection(e.message) + except requests.ConnectionError as e: + error = "Unidentified Connection Error" + if e.message == "[Errno 113] No route to host": + if not self.is_internet_up(): + error = "No valid internet connection found." + else: + error = "Provider server appears to be down." + raise exceptions.NoInternetConnection(error) + + def is_internet_up(self): + iface, gateway = self.get_default_interface_gateway() + self.ping_gateway(self) + + def get_default_interface_gateway(self): + """only impletemented for linux so far.""" + if not platform.system() == "Linux": + raise NotImplementedError + + f = open("/proc/net/route") + route_table = f.readlines() + f.close() + #toss out header + route_table.pop(0) + + default_iface = None + gateway = None + while route_table: + line = route_table.pop(0) + iface, destination, gateway = line.split('\t')[0:3] + if destination == '00000000': + default_iface = iface + break + + if not default_iface: + raise exceptions.NoDefaultInterfaceFoundError + + if default_iface not in netifaces.interfaces(): + raise exceptions.InterfaceNotFoundError + + return default_iface, gateway + + def ping_gateway(self, gateway): + #TODO: Discuss how much packet loss (%) is acceptable. + packet_loss = ping.quiet_ping(gateway)[0] + if packet_loss > constants.MAX_ICMP_PACKET_LOSS: + raise exceptions.NoConnectionToGateway diff --git a/src/leap/base/exceptions.py b/src/leap/base/exceptions.py index 9c4aa77b..7771d1f9 100644 --- a/src/leap/base/exceptions.py +++ b/src/leap/base/exceptions.py @@ -4,3 +4,22 @@ class MissingConfigFileError(Exception): class ImproperlyConfigured(Exception): pass + + +class NoDefaultInterfaceFoundError(Exception): + message = "no default interface found" + usermessage = "Looks like your computer is not connected to the internet" + + +class InterfaceNotFoundError(Exception): + # XXX should take iface arg on init maybe? + message = "interface not found" + + +class NoConnectionToGateway(Exception): + message = "no connection to gateway" + usermessage = "Looks like there are problems with your internet connection" + + +class NoInternetConnection(Exception): + message = "No Internet connection found" diff --git a/src/leap/base/tests/test_checks.py b/src/leap/base/tests/test_checks.py new file mode 100644 index 00000000..a3b3ea91 --- /dev/null +++ b/src/leap/base/tests/test_checks.py @@ -0,0 +1,86 @@ +try: + import unittest2 as unittest +except ImportError: + import unittest +import os + +from mock import (patch, Mock) +from StringIO import StringIO + +import ping +import requests + +from leap.base import checks +from leap.base import exceptions +from leap.testing.basetest import BaseLeapTest + +_uid = os.getuid() + + +class LeapNetworkCheckTest(BaseLeapTest): + __name__ = "leap_network_check_tests" + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_checker_should_implement_check_methods(self): + checker = checks.LeapNetworkChecker() + + self.assertTrue(hasattr(checker, "check_internet_connection"), + "missing meth") + self.assertTrue(hasattr(checker, "is_internet_up"), + "missing meth") + self.assertTrue(hasattr(checker, "ping_gateway"), + "missing meth") + + def test_checker_should_actually_call_all_tests(self): + checker = checks.LeapNetworkChecker() + + mc = Mock() + checker.run_all(checker=mc) + self.assertTrue(mc.check_internet_connection.called, "not called") + self.assertTrue(mc.ping_gateway.called, "not called") + self.assertTrue(mc.is_internet_up.called, "not called") + + def test_get_default_interface_no_interface(self): + checker = checks.LeapNetworkChecker() + with patch('leap.base.checks.open', create=True) as mock_open: + with self.assertRaises(exceptions.NoDefaultInterfaceFoundError): + mock_open.return_value = StringIO( + "Iface\tDestination Gateway\t" + "Flags\tRefCntd\tUse\tMetric\t" + "Mask\tMTU\tWindow\tIRTT") + checker.get_default_interface_gateway() + + def test_ping_gateway_fail(self): + checker = checks.LeapNetworkChecker() + with patch.object(ping, "quiet_ping") as mocked_ping: + with self.assertRaises(exceptions.NoConnectionToGateway): + mocked_ping.return_value = [11, "", ""] + checker.ping_gateway("4.2.2.2") + + def test_check_internet_connection_failures(self): + checker = checks.LeapNetworkChecker() + with patch.object(requests, "get") as mocked_get: + mocked_get.side_effect = requests.HTTPError + with self.assertRaises(exceptions.NoInternetConnection): + checker.check_internet_connection() + + with patch.object(requests, "get") as mocked_get: + mocked_get.side_effect = requests.RequestException + with self.assertRaises(exceptions.NoInternetConnection): + checker.check_internet_connection() + + #TODO: Mock possible errors that can be raised by is_internet_up + with patch.object(requests, "get") as mocked_get: + mocked_get.side_effect = requests.ConnectionError + with self.assertRaises(exceptions.NoInternetConnection): + checker.check_internet_connection() + + @unittest.skipUnless(_uid == 0, "root only") + def test_ping_gateway(self): + checker = checks.LeapNetworkChecker() + checker.ping_gateway("4.2.2.2") -- cgit v1.2.3 From 3fd7b55de96484e02accb991fb2c0c3ce0aa9883 Mon Sep 17 00:00:00 2001 From: antialias Date: Tue, 25 Sep 2012 17:37:48 -0400 Subject: First check for threaded network checks. TODO: tests. --- src/leap/base/constants.py | 2 ++ src/leap/base/network.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/leap/base/network.py (limited to 'src/leap/base') diff --git a/src/leap/base/constants.py b/src/leap/base/constants.py index 7a1415fb..8a76b6b4 100644 --- a/src/leap/base/constants.py +++ b/src/leap/base/constants.py @@ -28,3 +28,5 @@ DEFAULT_PROVIDER_DEFINITION = { u'version': u'0.1.0'} MAX_ICMP_PACKET_LOSS = 10 + +ROUTE_CHECK_INTERVAL = 120 diff --git a/src/leap/base/network.py b/src/leap/base/network.py new file mode 100644 index 00000000..58f903e1 --- /dev/null +++ b/src/leap/base/network.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +from __future__ import (print_function) + +from leap.base.checks import LeapNetworkChecker +from leap.base.constants import ROUTE_CHECK_INTERVAL +from leap.util.coroutines import (launch_thread, process_events) + +from time import sleep + +class NetworkChecker(object): + """ + Manages network checking thread that makes sure we have a working network + connection. + """ + def __init__(self, *args, **kwargs): + self.status_signals = kwargs.pop('status_signals', None) + self.watcher_cb = kwargs.pop('status_signals', None) + + def start(self): + self._launch_recurrent_network_checks((self.watcher_cb,)) + + def stop(self): + raise NotImplementedError + + def run_checks(self): + pass + + #private methods + + #here all the observers in fail_callbacks expect one positional argument, + #which is exception so we can try by passing a lambda with logger to + #check it works. + def _network_checks_thread(self, fail_callbacks): + print('fail_callbacks: %s' % fail_callbacks) + print(len(fail_callbacks)) + observer_dict = dict((( + observer, process_events(observer)) for observer in fail_callbacks)) + netchecker = LeapNetworkChecker() + while True: + try: + netchecker.check_internet_connection() + sleep(ROUTE_CHECK_INTERVAL) + except Exception as exc: + for obs in observer_dict: + observer_dict[obs].send(exc) + + + def _launch_recurrent_network_checks(fail_callbacks): + print(type(fail_callbacks)) + watcher = launch_thread( + network_checks_thread, + (fail_callbacks,)) + return watcher + + -- cgit v1.2.3 From 202345940e12d4633c5d46d5ed21c3a433573d48 Mon Sep 17 00:00:00 2001 From: antialias Date: Fri, 28 Sep 2012 18:15:47 -0400 Subject: Added check that default route is tun0. --- src/leap/base/checks.py | 27 +++++++++++++++++++++++++++ src/leap/base/exceptions.py | 4 ++++ src/leap/base/tests/test_checks.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) (limited to 'src/leap/base') diff --git a/src/leap/base/checks.py b/src/leap/base/checks.py index c5438b09..a775e162 100644 --- a/src/leap/base/checks.py +++ b/src/leap/base/checks.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import logging import platform import ping @@ -8,6 +9,7 @@ import requests from leap.base import constants from leap.base import exceptions +logger = logging.getLogger(name=__name__) class LeapNetworkChecker(object): """ @@ -22,6 +24,7 @@ class LeapNetworkChecker(object): self.error = None # ? # for MVS + checker.check_tunnel_default_interface() checker.check_internet_connection() checker.is_internet_up() checker.ping_gateway() @@ -40,11 +43,35 @@ class LeapNetworkChecker(object): else: error = "Provider server appears to be down." raise exceptions.NoInternetConnection(error) + logger.debug('Network appears to be up.') def is_internet_up(self): iface, gateway = self.get_default_interface_gateway() self.ping_gateway(self) + def check_tunnel_default_interface(self): + """ + Raises an TunnelNotDefaultRouteError + (including when no routes are present) + """ + if not platform.system() == "Linux": + raise NotImplementedError + + f = open("/proc/net/route") + route_table = f.readlines() + f.close() + #toss out header + route_table.pop(0) + + if not route_table: + raise exceptions.TunnelNotDefaultRouteError() + + line = route_table.pop(0) + iface, destination = line.split('\t')[0:2] + if not destination == '00000000' or not iface == 'tun0': + raise exceptions.TunnelNotDefaultRouteError() + + def get_default_interface_gateway(self): """only impletemented for linux so far.""" if not platform.system() == "Linux": diff --git a/src/leap/base/exceptions.py b/src/leap/base/exceptions.py index 7771d1f9..48d827f5 100644 --- a/src/leap/base/exceptions.py +++ b/src/leap/base/exceptions.py @@ -23,3 +23,7 @@ class NoConnectionToGateway(Exception): class NoInternetConnection(Exception): message = "No Internet connection found" + + +class TunnelNotDefaultRouteError(Exception): + message = "VPN Maybe be down." diff --git a/src/leap/base/tests/test_checks.py b/src/leap/base/tests/test_checks.py index a3b3ea91..30746991 100644 --- a/src/leap/base/tests/test_checks.py +++ b/src/leap/base/tests/test_checks.py @@ -31,6 +31,8 @@ class LeapNetworkCheckTest(BaseLeapTest): self.assertTrue(hasattr(checker, "check_internet_connection"), "missing meth") + self.assertTrue(hasattr(checker, "check_tunnel_default_interface"), + "missing meth") self.assertTrue(hasattr(checker, "is_internet_up"), "missing meth") self.assertTrue(hasattr(checker, "ping_gateway"), @@ -42,6 +44,7 @@ class LeapNetworkCheckTest(BaseLeapTest): mc = Mock() checker.run_all(checker=mc) self.assertTrue(mc.check_internet_connection.called, "not called") + self.assertTrue(mc.check_tunnel_default_interface.called, "not called") self.assertTrue(mc.ping_gateway.called, "not called") self.assertTrue(mc.is_internet_up.called, "not called") @@ -55,6 +58,33 @@ class LeapNetworkCheckTest(BaseLeapTest): "Mask\tMTU\tWindow\tIRTT") checker.get_default_interface_gateway() + def test_check_tunnel_default_interface(self): + checker = checks.LeapNetworkChecker() + with patch('leap.base.checks.open', create=True) as mock_open: + with self.assertRaises(exceptions.TunnelNotDefaultRouteError): + mock_open.return_value = StringIO( + "Iface\tDestination Gateway\t" + "Flags\tRefCntd\tUse\tMetric\t" + "Mask\tMTU\tWindow\tIRTT") + checker.check_tunnel_default_interface() + + with patch('leap.base.checks.open', create=True) as mock_open: + with self.assertRaises(exceptions.TunnelNotDefaultRouteError): + mock_open.return_value = StringIO( + "Iface\tDestination Gateway\t" + "Flags\tRefCntd\tUse\tMetric\t" + "Mask\tMTU\tWindow\tIRTT\n" + "wlan0\t00000000\t0102A8C0\t0003\t0\t0\t0\t00000000\t0\t0\t0") + checker.check_tunnel_default_interface() + + with patch('leap.base.checks.open', create=True) as mock_open: + mock_open.return_value = StringIO( + "Iface\tDestination Gateway\t" + "Flags\tRefCntd\tUse\tMetric\t" + "Mask\tMTU\tWindow\tIRTT\n" + "tun0\t00000000\t01002A0A\t0003\t0\t0\t0\t00000080\t0\t0\t0") + checker.check_tunnel_default_interface() + def test_ping_gateway_fail(self): checker = checks.LeapNetworkChecker() with patch.object(ping, "quiet_ping") as mocked_ping: -- cgit v1.2.3 From 58344bb28c1c0f25ed37624ff487cc8f24821d52 Mon Sep 17 00:00:00 2001 From: antialias Date: Fri, 28 Sep 2012 18:16:47 -0400 Subject: Functionality to shutdown network checker when openvpn is stopped. But thread not being successfully killed. --- src/leap/base/network.py | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'src/leap/base') diff --git a/src/leap/base/network.py b/src/leap/base/network.py index 58f903e1..a1e7c880 100644 --- a/src/leap/base/network.py +++ b/src/leap/base/network.py @@ -1,12 +1,18 @@ # -*- coding: utf-8 -*- from __future__ import (print_function) +import logging +import threading from leap.base.checks import LeapNetworkChecker from leap.base.constants import ROUTE_CHECK_INTERVAL -from leap.util.coroutines import (launch_thread, process_events) +from leap.base.exceptions import TunnelNotDefaultRouteError +from leap.util.coroutines import (launch_thread_no_daemon, process_events) from time import sleep +logger = logging.getLogger(name=__name__) + + class NetworkChecker(object): """ Manages network checking thread that makes sure we have a working network @@ -15,12 +21,17 @@ class NetworkChecker(object): def __init__(self, *args, **kwargs): self.status_signals = kwargs.pop('status_signals', None) self.watcher_cb = kwargs.pop('status_signals', None) + self.excp_logger = lambda exc: logger.error("%s", exc.message) + self.checker = LeapNetworkChecker() def start(self): - self._launch_recurrent_network_checks((self.watcher_cb,)) + self.process_handle = self._launch_recurrent_network_checks((self.excp_logger,)) def stop(self): - raise NotImplementedError + #TODO: Thread still not being stopped when openvpn is stopped. + logger.debug("stopping network checker...") + self.process_handle._Thread__stop() + logger.debug("network checked stopped.") def run_checks(self): pass @@ -31,24 +42,31 @@ class NetworkChecker(object): #which is exception so we can try by passing a lambda with logger to #check it works. def _network_checks_thread(self, fail_callbacks): - print('fail_callbacks: %s' % fail_callbacks) - print(len(fail_callbacks)) + #TODO: replace this with waiting for a signal from openvpn + while True: + try: + self.checker.check_tunnel_default_interface() + break + except TunnelNotDefaultRouteError: + sleep(1) + observer_dict = dict((( observer, process_events(observer)) for observer in fail_callbacks)) - netchecker = LeapNetworkChecker() while True: try: - netchecker.check_internet_connection() + self.checker.check_tunnel_default_interface() + self.checker.check_internet_connection() sleep(ROUTE_CHECK_INTERVAL) except Exception as exc: for obs in observer_dict: observer_dict[obs].send(exc) + sleep(ROUTE_CHECK_INTERVAL) - def _launch_recurrent_network_checks(fail_callbacks): - print(type(fail_callbacks)) - watcher = launch_thread( - network_checks_thread, + def _launch_recurrent_network_checks(self, fail_callbacks): + #we need to wrap the fail callback in a turple + watcher = launch_thread_no_daemon( + self._network_checks_thread, (fail_callbacks,)) return watcher -- cgit v1.2.3 From c75b27484a999f70a6e28e521f236cf2d403edd1 Mon Sep 17 00:00:00 2001 From: antialias Date: Mon, 1 Oct 2012 11:02:40 -0400 Subject: Checker starting and stopping correctly. --- src/leap/base/network.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/leap/base') diff --git a/src/leap/base/network.py b/src/leap/base/network.py index a1e7c880..92fb7635 100644 --- a/src/leap/base/network.py +++ b/src/leap/base/network.py @@ -6,7 +6,7 @@ import threading from leap.base.checks import LeapNetworkChecker from leap.base.constants import ROUTE_CHECK_INTERVAL from leap.base.exceptions import TunnelNotDefaultRouteError -from leap.util.coroutines import (launch_thread_no_daemon, process_events) +from leap.util.coroutines import (launch_thread, process_events) from time import sleep @@ -22,6 +22,7 @@ class NetworkChecker(object): self.status_signals = kwargs.pop('status_signals', None) self.watcher_cb = kwargs.pop('status_signals', None) self.excp_logger = lambda exc: logger.error("%s", exc.message) + self.shutdown = threading.Event() self.checker = LeapNetworkChecker() def start(self): @@ -29,8 +30,7 @@ class NetworkChecker(object): def stop(self): #TODO: Thread still not being stopped when openvpn is stopped. - logger.debug("stopping network checker...") - self.process_handle._Thread__stop() + self.shutdown.set() logger.debug("network checked stopped.") def run_checks(self): @@ -52,7 +52,7 @@ class NetworkChecker(object): observer_dict = dict((( observer, process_events(observer)) for observer in fail_callbacks)) - while True: + while not self.shutdown.is_set(): try: self.checker.check_tunnel_default_interface() self.checker.check_internet_connection() @@ -61,11 +61,12 @@ class NetworkChecker(object): for obs in observer_dict: observer_dict[obs].send(exc) sleep(ROUTE_CHECK_INTERVAL) - + #reset event + self.shutdown.clear() def _launch_recurrent_network_checks(self, fail_callbacks): #we need to wrap the fail callback in a turple - watcher = launch_thread_no_daemon( + watcher = launch_thread( self._network_checks_thread, (fail_callbacks,)) return watcher -- cgit v1.2.3 From 95ce59c8833cb2ba951630080cdbc1e6d756a666 Mon Sep 17 00:00:00 2001 From: antialias Date: Mon, 1 Oct 2012 15:10:55 -0400 Subject: Still some QT related problems. Hand off to kali to fix. --- src/leap/base/network.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/leap/base') diff --git a/src/leap/base/network.py b/src/leap/base/network.py index 92fb7635..159e9b21 100644 --- a/src/leap/base/network.py +++ b/src/leap/base/network.py @@ -21,15 +21,15 @@ class NetworkChecker(object): def __init__(self, *args, **kwargs): self.status_signals = kwargs.pop('status_signals', None) self.watcher_cb = kwargs.pop('status_signals', None) - self.excp_logger = lambda exc: logger.error("%s", exc.message) + self.error_cb = kwargs.pop('error_cb', + lambda exc: logger.error("%s", exc.message)) self.shutdown = threading.Event() self.checker = LeapNetworkChecker() def start(self): - self.process_handle = self._launch_recurrent_network_checks((self.excp_logger,)) + self.process_handle = self._launch_recurrent_network_checks((self.error_cb,)) def stop(self): - #TODO: Thread still not being stopped when openvpn is stopped. self.shutdown.set() logger.debug("network checked stopped.") @@ -70,5 +70,3 @@ class NetworkChecker(object): self._network_checks_thread, (fail_callbacks,)) return watcher - - -- cgit v1.2.3 From 31c0afa5eb9bc7566ca39099520e8adc7b531e22 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 5 Oct 2012 20:15:12 +0900 Subject: pep8 --- src/leap/base/checks.py | 5 +++-- src/leap/base/network.py | 13 ++++++++----- src/leap/base/tests/test_checks.py | 3 ++- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src/leap/base') diff --git a/src/leap/base/checks.py b/src/leap/base/checks.py index a775e162..d02c9a3d 100644 --- a/src/leap/base/checks.py +++ b/src/leap/base/checks.py @@ -3,6 +3,7 @@ import logging import platform +import netifaces import ping import requests @@ -11,6 +12,7 @@ from leap.base import exceptions logger = logging.getLogger(name=__name__) + class LeapNetworkChecker(object): """ all network related checks @@ -51,7 +53,7 @@ class LeapNetworkChecker(object): def check_tunnel_default_interface(self): """ - Raises an TunnelNotDefaultRouteError + Raises an TunnelNotDefaultRouteError (including when no routes are present) """ if not platform.system() == "Linux": @@ -71,7 +73,6 @@ class LeapNetworkChecker(object): if not destination == '00000000' or not iface == 'tun0': raise exceptions.TunnelNotDefaultRouteError() - def get_default_interface_gateway(self): """only impletemented for linux so far.""" if not platform.system() == "Linux": diff --git a/src/leap/base/network.py b/src/leap/base/network.py index 159e9b21..4a90f2f4 100644 --- a/src/leap/base/network.py +++ b/src/leap/base/network.py @@ -21,13 +21,15 @@ class NetworkChecker(object): def __init__(self, *args, **kwargs): self.status_signals = kwargs.pop('status_signals', None) self.watcher_cb = kwargs.pop('status_signals', None) - self.error_cb = kwargs.pop('error_cb', - lambda exc: logger.error("%s", exc.message)) + self.error_cb = kwargs.pop( + 'error_cb', + lambda exc: logger.error("%s", exc.message)) self.shutdown = threading.Event() self.checker = LeapNetworkChecker() def start(self): - self.process_handle = self._launch_recurrent_network_checks((self.error_cb,)) + self.process_handle = self._launch_recurrent_network_checks( + (self.error_cb,)) def stop(self): self.shutdown.set() @@ -51,7 +53,8 @@ class NetworkChecker(object): sleep(1) observer_dict = dict((( - observer, process_events(observer)) for observer in fail_callbacks)) + observer, + process_events(observer)) for observer in fail_callbacks)) while not self.shutdown.is_set(): try: self.checker.check_tunnel_default_interface() @@ -65,7 +68,7 @@ class NetworkChecker(object): self.shutdown.clear() def _launch_recurrent_network_checks(self, fail_callbacks): - #we need to wrap the fail callback in a turple + #we need to wrap the fail callback in a tuple watcher = launch_thread( self._network_checks_thread, (fail_callbacks,)) diff --git a/src/leap/base/tests/test_checks.py b/src/leap/base/tests/test_checks.py index 30746991..bec09ce6 100644 --- a/src/leap/base/tests/test_checks.py +++ b/src/leap/base/tests/test_checks.py @@ -74,7 +74,8 @@ class LeapNetworkCheckTest(BaseLeapTest): "Iface\tDestination Gateway\t" "Flags\tRefCntd\tUse\tMetric\t" "Mask\tMTU\tWindow\tIRTT\n" - "wlan0\t00000000\t0102A8C0\t0003\t0\t0\t0\t00000000\t0\t0\t0") + "wlan0\t00000000\t0102A8C0\t" + "0003\t0\t0\t0\t00000000\t0\t0\t0") checker.check_tunnel_default_interface() with patch('leap.base.checks.open', create=True) as mock_open: -- cgit v1.2.3 From 1cbf954d9eda71cabfa58811c09bc63cfe9465d5 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 5 Oct 2012 21:21:22 +0900 Subject: add comments to netchecks --- src/leap/base/checks.py | 40 +++++++++++++++++++++++++++++++++++++--- src/leap/base/network.py | 15 ++++++++++----- 2 files changed, 47 insertions(+), 8 deletions(-) (limited to 'src/leap/base') diff --git a/src/leap/base/checks.py b/src/leap/base/checks.py index d02c9a3d..0dbb2846 100644 --- a/src/leap/base/checks.py +++ b/src/leap/base/checks.py @@ -17,8 +17,15 @@ class LeapNetworkChecker(object): """ all network related checks """ - # TODO eventually, use a more portable solution - # like psutil + # TODO refactor to use psutil --- + + # #718 + # XXX get provider gateway as a parameter + # for constructor. + # def __init__(self, *args, **kwargs): + # ... + # provider_gw = kwargs.pop('provider_gw', None) + # self.provider_gateway = provider_gw def run_all(self, checker=None): if not checker: @@ -29,12 +36,23 @@ class LeapNetworkChecker(object): checker.check_tunnel_default_interface() checker.check_internet_connection() checker.is_internet_up() + + # XXX We are pinging the default gateway for our connection right? + # kali: 2012-10-05 20:59 -- I think we should get + # also the default gateway and ping it instead. checker.ping_gateway() + # something like: ? + # see __init__ above + # if self.provider_gateway: + # checker.ping_gateway(self.provider_gateway) + def check_internet_connection(self): try: # XXX remove this hardcoded random ip + # ping leap.se or eip provider instead...? requests.get('http://216.172.161.165') + except (requests.HTTPError, requests.RequestException) as e: raise exceptions.NoInternetConnection(e.message) except requests.ConnectionError as e: @@ -44,6 +62,7 @@ class LeapNetworkChecker(object): error = "No valid internet connection found." else: error = "Provider server appears to be down." + logger.error(error) raise exceptions.NoInternetConnection(error) logger.debug('Network appears to be up.') @@ -78,6 +97,7 @@ class LeapNetworkChecker(object): if not platform.system() == "Linux": raise NotImplementedError + # XXX use psutil f = open("/proc/net/route") route_table = f.readlines() f.close() @@ -102,7 +122,21 @@ class LeapNetworkChecker(object): return default_iface, gateway def ping_gateway(self, gateway): - #TODO: Discuss how much packet loss (%) is acceptable. + # TODO: Discuss how much packet loss (%) is acceptable. + + # XXX -- validate gateway + # -- is it a valid ip? (there's something in util) + # -- is it a domain? + # -- can we resolve? -- raise NoDNSError if not. packet_loss = ping.quiet_ping(gateway)[0] if packet_loss > constants.MAX_ICMP_PACKET_LOSS: raise exceptions.NoConnectionToGateway + + # XXX check for name resolution servers + # dunno what's the best way to do this... + # check for etc/resolv entries or similar? + # just try to resolve? + # is there something in psutil? + + # def check_name_resolution(self): + # pass diff --git a/src/leap/base/network.py b/src/leap/base/network.py index 4a90f2f4..e90139c4 100644 --- a/src/leap/base/network.py +++ b/src/leap/base/network.py @@ -13,18 +13,22 @@ from time import sleep logger = logging.getLogger(name=__name__) -class NetworkChecker(object): +class NetworkCheckerThread(object): """ Manages network checking thread that makes sure we have a working network connection. """ def __init__(self, *args, **kwargs): self.status_signals = kwargs.pop('status_signals', None) - self.watcher_cb = kwargs.pop('status_signals', None) + #self.watcher_cb = kwargs.pop('status_signals', None) self.error_cb = kwargs.pop( 'error_cb', lambda exc: logger.error("%s", exc.message)) self.shutdown = threading.Event() + + # XXX get provider_gateway and pass it to checker + # see in eip.config for function + # #718 self.checker = LeapNetworkChecker() def start(self): @@ -50,9 +54,10 @@ class NetworkChecker(object): self.checker.check_tunnel_default_interface() break except TunnelNotDefaultRouteError: + # XXX ??? why do we sleep here??? sleep(1) - observer_dict = dict((( + fail_observer_dict = dict((( observer, process_events(observer)) for observer in fail_callbacks)) while not self.shutdown.is_set(): @@ -61,8 +66,8 @@ class NetworkChecker(object): self.checker.check_internet_connection() sleep(ROUTE_CHECK_INTERVAL) except Exception as exc: - for obs in observer_dict: - observer_dict[obs].send(exc) + for obs in fail_observer_dict: + fail_observer_dict[obs].send(exc) sleep(ROUTE_CHECK_INTERVAL) #reset event self.shutdown.clear() -- cgit v1.2.3 From 6728eb9afb21bad867e4052a6190a9bdb34c928a Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 8 Oct 2012 07:50:24 +0900 Subject: popup dialog error when network error happens we are shutting down for now. we should be acting upon failures in the near future. lowered the recurrent checks interval to 10 seconds. --- src/leap/base/checks.py | 3 --- src/leap/base/constants.py | 2 +- src/leap/base/exceptions.py | 55 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 50 insertions(+), 10 deletions(-) (limited to 'src/leap/base') diff --git a/src/leap/base/checks.py b/src/leap/base/checks.py index 0dbb2846..84f9dd46 100644 --- a/src/leap/base/checks.py +++ b/src/leap/base/checks.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - import logging import platform @@ -17,8 +16,6 @@ class LeapNetworkChecker(object): """ all network related checks """ - # TODO refactor to use psutil --- - # #718 # XXX get provider gateway as a parameter # for constructor. diff --git a/src/leap/base/constants.py b/src/leap/base/constants.py index 8a76b6b4..3f32176f 100644 --- a/src/leap/base/constants.py +++ b/src/leap/base/constants.py @@ -29,4 +29,4 @@ DEFAULT_PROVIDER_DEFINITION = { MAX_ICMP_PACKET_LOSS = 10 -ROUTE_CHECK_INTERVAL = 120 +ROUTE_CHECK_INTERVAL = 10 diff --git a/src/leap/base/exceptions.py b/src/leap/base/exceptions.py index 48d827f5..f12a49d5 100644 --- a/src/leap/base/exceptions.py +++ b/src/leap/base/exceptions.py @@ -1,3 +1,43 @@ +""" +Exception attributes and their meaning/uses +------------------------------------------- + +* critical: if True, will abort execution prematurely, + after attempting any cleaning + action. + +* failfirst: breaks any error_check loop that is examining + the error queue. + +* message: the message that will be used in the __repr__ of the exception. + +* usermessage: the message that will be passed to user in ErrorDialogs + in Qt-land. +""" + + +class LeapException(Exception): + """ + base LeapClient exception + sets some parameters that we will check + during error checking routines + """ + critical = False + failfirst = False + warning = False + + +class CriticalError(LeapException): + """ + we cannot do anything about it + """ + critical = True + failfirst = True + + +# In use ??? +# don't thing so. purge if not... + class MissingConfigFileError(Exception): pass @@ -6,24 +46,27 @@ class ImproperlyConfigured(Exception): pass -class NoDefaultInterfaceFoundError(Exception): +class NoDefaultInterfaceFoundError(LeapException): message = "no default interface found" usermessage = "Looks like your computer is not connected to the internet" -class InterfaceNotFoundError(Exception): +class InterfaceNotFoundError(LeapException): # XXX should take iface arg on init maybe? message = "interface not found" -class NoConnectionToGateway(Exception): +class NoConnectionToGateway(CriticalError): message = "no connection to gateway" usermessage = "Looks like there are problems with your internet connection" -class NoInternetConnection(Exception): +class NoInternetConnection(CriticalError): message = "No Internet connection found" + usermessage = "It looks like there is no internet connection." + # and now we try to connect to our web to troubleshoot LOL :P -class TunnelNotDefaultRouteError(Exception): - message = "VPN Maybe be down." +class TunnelNotDefaultRouteError(CriticalError): + message = "Tunnel connection dissapeared. VPN down?" + usermessage = "The Encrypted Connection was lost. Shutting down..." -- cgit v1.2.3