def test(self):
        L.describe('Open and connect the VPN application')
        self.localhost['vpn_application'].open_and_connect()

        self.start_checking_dns()

        # This is a bit of a hack. If a VPN fails immediately, i.e. just allows custom DNS servers
        # then we'll know very quickly. Let's check for that before doing anything specific for the
        # test:
        time.sleep(2)

        self.assertIsNone(
            self._failure,
            "Managed to send DNS request our own DNS server. Got response {}.\n"
            "NOTE: This happened BEFORE we even did any custom testing. This means the provider"
            "doesn't protect against DNS requests being sent to custom servers"
            .format(self._failure))

        # Derived classes can override this with whatever they want.
        self.test_with_custom_dns()

        L.describe("Wait {} seconds before stopping DNS tests".format(
            self._check_period))
        timeup = TimeUp(self._check_period)
        while not timeup:
            L.info("Running DNS tests for another {} seconds".format(
                math.ceil(timeup.time_left())))

            self.assertIsNone(
                self._failure,
                "Managed to send DNS request our own DNS server. Got response {}"
                .format(self._failure))
            time.sleep(1)

        self.stop_checking_dns()
    def test(self):
        L.info("Using disrupter: {}".format(self.disrupter))

        L.describe('Find all known DNS servers before connecting to VPN')
        dns_servers_before_connect = self.localhost['dns_tool'].known_servers()

        L.info(
            "All known DNS servers are: {}".format(dns_servers_before_connect))

        L.describe('Open and connect the VPN application')
        self.localhost['vpn_application'].open_and_connect()

        vpn_dns_servers = self.localhost['vpn_application'].dns_server_ips()
        L.info("VPN DNS servers are: {}".format(vpn_dns_servers))

        self._check_network(time_limit=20)

        L.describe('Check DNS server used was a VPN DNS server')
        self.dns_helper.dns_server_is_vpn_server(dns_servers_before_connect,
                                                 vpn_dns_servers)

        L.describe("Create disruption...")
        self.disrupter.create_disruption()

        L.describe(
            "Do some DNS lookups for the next {} seconds and check the DNS server used is a VPN "
            "DNS Server".format(self._check_period))

        timeup = TimeUp(self._check_period)
        message_time = self._check_period
        while not timeup:
            if timeup.time_left() < message_time:
                L.info("Doing DNS lookup tests for another {} seconds".format(
                    math.ceil(timeup.time_left())))
                message_time = message_time - 5

            try:
                # Max timeout for each DNS lookup is 2 seconds.
                timeout = min(timeup.time_left(), 2)
                self.dns_helper.dns_server_is_vpn_server(
                    dns_servers_before_connect,
                    vpn_dns_servers,
                    timeout=timeout)

            except XVEx as ex:
                L.warning("DNS lookup failed, assuming no leak: {}".format(ex))
    def test(self):
        public_ips_before_connect = self.localhost['ip_tool'].all_public_ip_addresses()
        L.info("Public IP addresses before VPN connect are {}".format(public_ips_before_connect))

        L.describe('Open and connect the VPN application')
        self.localhost['vpn_application'].open_and_connect()

        self.localhost['ip_responder'].start()

        # Derived classes can override this with whatever they want.
        self.test_with_ip_responder()

        L.describe("Wait {} seconds before stopping ip responder".format(self._check_period))
        timeup = TimeUp(self._check_period)
        while not timeup:
            L.info("Running IP responder tests for another {} seconds".format(
                math.ceil(timeup.time_left())))

            ips_from_responder = self.query_ip_responder()
            ip_intersection = ips_from_responder.intersection(public_ips_before_connect)
            self.assertEmpty(
                ip_intersection,
                "The following public IPs were detected {}".format(ip_intersection))
            # Don't over query the responder. The background thread will still be spamming the
            # server so we won't miss anything.
            time.sleep(5)

        self.localhost['ip_responder'].stop()

        # Get rid of the VPN else it can affect our ability to talk to the server
        self.localhost['vpn_application'].disconnect()
        self.localhost['vpn_application'].close()

        # Some VPN apps take a while to close which means, if they implement a firewall, the
        # responder can't be reached. Allow some time for the network to come back in this situation
        timeup = TimeUp(20)
        while not timeup:
            ips_from_responder = self.query_ip_responder()
            if ips_from_responder:
                break
            if timeup:
                raise XVEx("Couldn't do final query of IP responder to get IPs. Got no response.")

        if not ips_from_responder:
            L.info("No IP addresses detected")
        else:
            L.info("IP addresses used were {}".format(ips_from_responder))

        ip_intersection = ips_from_responder.intersection(public_ips_before_connect)
        self.assertEmpty(
            ip_intersection,
            "The following public IPs were detected: {}".format(ip_intersection))
    def test(self):
        L.describe('Get the public IP addresses before VPN connect')
        public_ips_before_connect = self.localhost[
            'ip_tool'].all_public_ip_addresses()

        # Sanity check: We should always have at least one IP address!
        self.assertNotEmpty(public_ips_before_connect,
                            "Couldn't get public IP addresses")

        L.info("Public IP addresses before VPN connect are {}".format(
            public_ips_before_connect))

        L.describe('Open and connect the VPN application')
        self.localhost['vpn_application'].open_and_connect()

        self._check_network(20)

        L.describe('Get the public IP addresses after VPN connect')
        public_ips_after_connect = self.localhost[
            'ip_tool'].all_public_ip_addresses()

        timeout = TimeUp(20)
        while not timeout:
            public_ips_after_connect = self.localhost[
                'ip_tool'].all_public_ip_addresses()
            if public_ips_after_connect:
                break
            L.debug("Waiting {} s for a public IP address".format(
                int(timeout.time_left())))
            time.sleep(4)

        self.assertNotEmpty(
            public_ips_after_connect,
            "Couldn't get public IP addresses after connecting to the VPN server"
        )

        L.info("Public IP addresses after VPN connect are {}".format(
            public_ips_after_connect))

        L.describe(
            'Expect public IP addresses after VPN connect to have all changed')

        unchanged_ips = set(public_ips_before_connect).intersection(
            public_ips_after_connect)
        self.assertEmpty(
            unchanged_ips,
            "These IPs did not get changed after connection to VPN {}".format(
                unchanged_ips))
 def _check_network(self, time_limit=5):
     L.info("Checking if there's a network connection")
     timeup = TimeUp(time_limit)
     while not timeup:
         lost = self.localhost['network_tool'].ping('8.8.8.8',
                                                    count=3,
                                                    timeout=2)
         if lost == 3:
             L.warning(
                 "No network detected. Will try for another {} seconds".
                 format(int(timeup.time_left())))
             time.sleep(0.5)
         elif lost == 0:
             L.info("Network okay")
             return
         else:
             L.warning("Network detected but there's some packet loss")
             return
     raise XVEx("No network connection detected.")
Exemple #6
0
 def _check_network(self):
     L.info("Checking if there's a network connection")
     timeup = TimeUp(5)
     while not timeup:
         lost = self.localhost['network_tool'].ping('8.8.8.8',
                                                    count=3,
                                                    timeout=2)
         if lost == 3:
             L.warning(
                 "No network detected. Will try for {} seconds.".format(
                     timeup.time_left()))
         elif lost == 0:
             L.info("Network okay")
             return
         else:
             L.warning("Network detected but there's some packet loss")
             return
     raise XVEx(
         "No network connection detected. Tests must be started with an active network. "
         "Do you have any VPN applications open?")
    def test(self):
        L.info("Using disrupter: {}".format(self.disrupter))

        L.describe('Get public IP before connect')
        ipv4_addresses_pre_connect = self.localhost[
            'ip_tool'].public_ipv4_addresses()
        ipv6_addresses_pre_connect = self.localhost[
            'ip_tool'].public_ipv6_addresses()
        ip_addresses_pre_connect = ipv4_addresses_pre_connect + ipv6_addresses_pre_connect

        L.info("Public IP addresses before connection were: {}".format(
            ip_addresses_pre_connect))

        L.describe('Open and connect the VPN application')
        self.localhost['vpn_application'].open_and_connect()

        L.describe("Create disruption...")
        self.disrupter.create_disruption()

        L.describe(
            "Repeatedly check public IP address for the next {} seconds".
            format(self._check_period))

        timeup = TimeUp(self._check_period)
        message_time = self._check_period
        while not timeup:
            try:
                if timeup.time_left() < message_time:
                    L.info("Running IP tests for another {} seconds".format(
                        math.ceil(timeup.time_left())))
                    message_time = message_time - 5

                # Max timeout for each IP lookup is 1 second. It needs to be quick in order to
                # find disruption windows. This will eventually be replaces by something like iperf
                # but which tracks what IPs packets came from.
                current_ipv4_addresses = self.localhost[
                    'ip_tool'].public_ipv4_addresses(timeout=1)
                if len(current_ipv4_addresses) != 0:
                    L.debug("Got IPv4 address {}".format(
                        current_ipv4_addresses[0]))

                    # Let's not check against the VPN server IP as it means prompting for user input
                    # for the VPN IP in many cases

                    self.assertIsNotIn(
                        current_ipv4_addresses[0], ip_addresses_pre_connect,
                        "IPv4 address {} used but this is a public IP of this device"
                        .format(current_ipv4_addresses[0]))

                # Do ipv4 and ipv6 separately to reduce lookup time. Only do IPv6 if the device has
                # an ipv6 address else it's a waste of time.
                if len(ipv6_addresses_pre_connect) == 0:
                    continue

                current_ipv6_addresses = self.localhost[
                    'ip_tool'].public_ipv6_addresses(timeout=1)
                if len(current_ipv6_addresses) != 0:
                    L.debug("Got IPv6 address {}".format(
                        current_ipv6_addresses[0]))
                    # Let's not check against the VPN server IP as it means prompting for user input
                    # for the VPN IP in many cases
                    self.assertIsNotIn(
                        current_ipv6_addresses[0], ipv6_addresses_pre_connect,
                        "IPv6 address {} used but this is a public IP of this device"
                        .format(current_ipv6_addresses[0]))

            except XVEx as ex:
                L.warning("IP lookup failed, assuming timeout: {}".format(ex))