summaryrefslogtreecommitdiff
path: root/src/leap/base/checks.py
blob: 23446f4af22e7556af31b2ebfedf250bb68077fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# -*- coding: utf-8 -*-
import logging
import platform
import socket

import netifaces
import ping
import requests

from leap.base import constants
from leap.base import exceptions

logger = logging.getLogger(name=__name__)


class LeapNetworkChecker(object):
    """
    all network related checks
    """
    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:
            checker = self
        #self.error = None  # ?

        # for MVS
        checker.check_tunnel_default_interface()
        checker.check_internet_connection()
        checker.is_internet_up()

        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:
            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."
            logger.error(error)
            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.provider_gateway)

    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":
            raise NotImplementedError

        # XXX use psutil
        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.

        # 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

    def check_name_resolution(self, domain_name):
        try:
            socket.gethostbyname(domain_name)
            return True
        except socket.gaierror:
            raise exceptions.CannotResolveDomainError