pocc / merlink

This program will connect desktop clients to Meraki firewalls
Apache License 2.0
3 stars 1 forks source link

Error if not connected to internet #24

Closed pocc closed 6 years ago

pocc commented 6 years ago

Immediately fail if device is not online

Problem

If users don't have a working internet connection, they're wasting time by trying to use this program as this is a requirement for VPN.

Proposed Solution

  1. Before calling the login window class, check whether there is a working internet connection
  2. If there is not, create a QMessageBox with a critical icon and error message
  3. This QMessageBox's only option should be to press a button with text "Quit"
  4. Hitting the quit button should exit the program

Version info

Notes

pocc commented 6 years ago

Use WMI to get that data

apierson27 commented 6 years ago

PowerShell has a cmdlet called Get-NetConnectionProfile that should work; getting that data does involve using subprocess to get the output though, so it could get a bit gross with insufficient permissions to run it.

Will do some more looking myself, but if you can find a library that lets Python interface with PowerShell more cleanly, that could also work =)

apierson27 commented 6 years ago

Here's a rough start to get this going:

#! /usr/bin/python

import subprocess
import re

process = subprocess.Popen(["powershell", "Get-NetConnectionProfile"],
                             stdout=subprocess.PIPE)

# resultant data is a tuple of bytes, so just decode to a string
result = process.communicate()[0].decode("utf-8")

connection_data = {}

for line in result.split("\r\n"):
    if line:
        squeezed = re.sub('\s+', '', line)
        connection_data.update([squeezed.split(':')])

for key, value in connection_data.items():      
    print("%s : %s" % (key, value))

From there, checking whether Windows thinks it has a working Inet connection is just a matter of checking if the "IPv4Connectivity" key has a value of "Internet" (see here for reference: https://docs.microsoft.com/en-us/powershell/module/netconnection/get-netconnectionprofile?view=win10-ps)

This has some obvious concerns about error handling that I didn't get a chance to look into yet, but I can do some more digging on what subprocess might raise if it runs into a permissions issue if you think this is a viable route to take.

pocc commented 6 years ago

I think part of this is my fault for not being clearer for the issue description. I'm going to edit my initial comment to be more detailed.

A sidenote is that QNetworkConfigurationManager has a public function isOnline() that may be more appropriate here so that we don't need to rewrite code for more platforms as they become supported. We haven't hit MVP though, so whatever works.

apierson27 commented 6 years ago

It really comes down to whether you want OS independence or not - I think this'll do the job for Windows if you just return a boolean true/false based on whether IPV4Connectivity's value is Internet or not and raise the appropriate alert if it's not

pocc commented 6 years ago

Writeup of a speed comparison between Qt function, powershell, and ping

I created code snippets with the Powershell cmdlet, the Qt function, and python + ping to see which one was fastest by timing them.

Analysis

Of these three, the Qt version just fails to notice that the connection has died. Code is included below for completeness, but I am not collecting speed data for it.

Methodology

Below, each cell value consists of 10 tries in that scenario. The testing connection was wireless and an 'offline' state was produced by disconnecting from the SSID.

Data

Py + ICMP Py + PS
Avg online (s) 0.18 2.22
Avg offline (s) 1.76 2.19

Results

Python + Powershell is more consistent at around ~2.2s, but Python + ICMP is faster. As ICMP is both faster and cross-platform, I plan on using this code snippet.

Code

Python + Ping

import subprocess, time
result = ''
i = 0
starttime = time.time()
# We may want to ignore a time out in case the next ping is successful
# 300ms timeout because a 300ms+ connection is a bad connection 
while 'unreachable' not in result and 'failure' not in result and i < 4:
    result = subprocess.Popen(['ping','-n','1','-w','300','8.8.8.8'], \
            stdout = subprocess.PIPE).communicate()[0].decode('utf-8')
    i += 1
online = 'unreachable' not in result and 'timed out' not in result and 'failure' not in result
print("Device is online:", online, "\nTook " + str(time.time()-starttime)+ " seconds") 

Python + Powershell (Get-NetConnectionProfile)

import subprocess, time
starttime = time.time()
# This gets a network connection profile (if it exists) and then parses it
# If we detect "Internet" in the PS response, then we have a working connection
connections = subprocess.Popen(["powershell", "$Connectivity = Get-NetConnectionProfile \
    | select -expandProperty IPv4Connectivity; if ($Connectivity -like \"Internet\") \
    {return \"True\"} else {return \"False\"}"],stdout=subprocess.PIPE)
online = connections.communicate()[0].decode("utf-8").strip()
print("Device is online:", online, "\nTook " + str(time.time()-starttime)+ " seconds") 

PyQt5

import time
starttime = time.time()
from PyQt5.QtNetwork import QNetworkConfigurationManager
connections = QNetworkConfigurationManager()
online = connections.isOnline()
print("Device is online:", online, "\nTook " + str(time.time()-starttime)+ " seconds")