Will Hall's

journey through everything.

Using a VPN to hop around the world is kinda sweet, especially when all the Ad vendors think you're Swedish; their adverts are so much better!

ProtonVPN was a decent choice for me, reasonably cheap and also with a good threat model. They actively stand up in issues of net neutrality, freedom of speech and other pretty good stuff. The one place they fall short, though, is in their Linux client implementation.

It's not that their CLI client is bad, but for most people (including me), having a visual way of navigating connections is much easier and more intuitive. Plus, having an instant way of monitoring your connection status is crucial for ensuring you get those sweet Swedish car adverts reliably. ProtonVPN does have an in-development Linux GUI, but for now I found myself wanting for more.

So, I decided to try my hand at Linux GTK development with Python. It was my first Python project since GCSEs (UK middle/high school studies), so I was a tad rusty. But after some 'baptism of fire' type learning, I whipped up something not half bad: A tray app that reports key stats, monitors your connection, and provides some handy connection functions. If you use ProtonVPN on Linux, you might find it handy. The full source code, and installation instructions, are available here. I also shared this with the ProtonVPN community over on Reddit.

Disclaimer

I'll be perfectly honest with you: I have no idea what I'm doing. There, I said it. This tray is probably fundamentally flawed in some epic way, or written in a way that would make a real GTK developer cringe and compose a strongly worded email. I have basically cobbled together as much as possible from many places, filling in the gaps in my knowledge along the way. If you're reading the source and have some advice to throw my way, I would absolutely love to hear it. Drop me a line at [email protected].

If you do use this, please know; it is not fool-proof. It might break. Don't rely on it fully. It's more of a helpful hand than a bulletproof client. Put it this way: It ships with an MIT license for a reason...

Features

  • A tray icon to reflect overall connection status. Red is disconnected. Amber is a VPN session connection loss. Green is connected.
  • Reports time connected, location and data transfer.
  • Reports internet connection status. Handy to see if the ProtonVPN kill switch is working.
  • Reports any authentication errors. Handy to try and diagnose connection issues e.g. too many active connections on your account.
  • Reports kill switch and DNS leak protection status.
  • Reconnect or disconnect from current server.
  • Connect to the fastest or a random server.
  • Support for connection profiles, such as countries or specific servers.
  • Support for use of PolyKit, if you have not configured password-less sudo for protonvpn-cli.
All is well with the world! Three profiles are ready, and the kill switch is on! You already know I'm getting some sweet Swiss cheese adverts right now. 
Uh oh. Looks like we might have an unstable connection. The dreaded amber hue!
Ah, looks like we have an authentication error. Time to check my creds, or double check the number of concurrent connections I'm making.

Under The Hood

At the end of the day, this app is basically a fancy wrapper for the ProtonVPN CLI, with the only difference being a regular ICMP heartbeat to check if you have a connection to the internet. Every second the tray reads in data from the local ProtonVPN CLI config files and transforms it into somewhat useful information. Every 8 seconds (don't ask why), it checks to see if you can reach api.protonvpn.ch over the internet. This also has a dual purpose; to determine if ProtonVPN is blocked by your ISP. It also reports if you have an authentication issue, which is great to determine if you set up the connection properly with protonvpn init, but also to report if you have too many active connections on your account.

To display a tray, AppIndicator3 was used, a neat package which makes tray apps a breeze. I also used GObject from Glib to run repeated functions such as updating the info each second and checking for a connection.

The basic connection status reporting is handled by a ProtonVPN CLI function called is_connected, which in itself simply uses pgrep to see if an OpenVPN session is active. This gives the connected and disconnected status represented by a green or red tray icon respectively. A sub-state of connected is when an OpenVPN session is active, but there is no connection to the internet. This is represented as an amber icon, next to the closest Unicode character I could find to represent a lack of connection: 🔗.

You can also specify any number of connection profiles when you launch the tray. The following will give three profiles; one for Switzerland, one for specifically server 13 in the UK, and one for the United States:

python3 ./tray.py --profiles CH UK#13 US

I feel like there must be a better way of parsing arguments with Python, but I basically just used some list manipulation to try and extract the collection of arguments immediately after the --profiles flag, but no further than either the end of the argument list, or up until the next flag e.g. --polykit. There is also no sanitisation or checks to see if the entered server is valid. Then again, its only your own connection you will much up. So there we are.

Thanks for reading this far! I hope you found my first brave steps into Python and GTK development fun, interesting and epic.

Here is a treat for reaching the end; a thicc boogie classic!
you might like

© Will Hall 2020