Create a gist now

Instantly share code, notes, and snippets.

@Lazza /README.md
Last active Dec 5, 2017

What would you like to do?
VPNGate Python script

vpngate.py

This script allows to use the free VPN service provided by VPNGate in an easy way. The user just needs to provide the desidered output country, and the script automatically chooses the best server.

After this step, OpenVPN is launched with the proper configuration. The VPN can be terminated by pressing Ctrl+C.

Usage

Run the script by providing the desired output country:

vpngate.py US

Both country codes and country names are supported, as listed on the VPNGate website, e.g.:

vpngate.py "United Kingdom"

Moreover, the script allows to input countries with any case (Italy, italy, ItALy all work) and with partial names:

  • Korea will work for Korea Republic Of
  • Russia will work for Russian Federation
  • ... and so on

Demo

Here is a short Youtube video showcasing an example usage:

YT video

Requirements

OpenVPN needs to be installed.

The script should run on any Linux distribution with the Python Requests module installed. The user running the script must be able to run sudo commands in order to start openvpn.

#!/usr/bin/env python
"""Pick server and start connection with VPNGate (http://www.vpngate.net/en/)"""
import requests, os, sys, tempfile, subprocess, base64, time
__author__ = "Andrea Lazzarotto"
__copyright__ = "Copyright 2014+, Andrea Lazzarotto"
__license__ = "GPLv3"
__version__ = "1.0"
__maintainer__ = "Andrea Lazzarotto"
__email__ = "andrea.lazzarotto@gmail.com"
if len(sys.argv) != 2:
print 'usage: ' + sys.argv[0] + ' [country name | country code]'
exit(1)
country = sys.argv[1]
if len(country) == 2:
i = 6 # short name for country
elif len(country) > 2:
i = 5 # long name for country
else:
print 'Country is too short!'
exit(1)
try:
vpn_data = requests.get('http://www.vpngate.net/api/iphone/').text.replace('\r','')
servers = [line.split(',') for line in vpn_data.split('\n')]
labels = servers[1]
labels[0] = labels[0][1:]
servers = [s for s in servers[2:] if len(s) > 1]
except:
print 'Cannot get VPN servers data'
exit(1)
desired = [s for s in servers if country.lower() in s[i].lower()]
found = len(desired)
print 'Found ' + str(found) + ' servers for country ' + country
if found == 0:
exit(1)
supported = [s for s in desired if len(s[-1]) > 0]
print str(len(supported)) + ' of these servers support OpenVPN'
# We pick the best servers by score
winner = sorted(supported, key=lambda s: float(s[2].replace(',','.')), reverse=True)[0]
print "\n== Best server =="
pairs = zip(labels, winner)[:-1]
for (l, d) in pairs[:4]:
print l + ': ' + d
print pairs[4][0] + ': ' + str(float(pairs[4][1]) / 10**6) + ' MBps'
print "Country: " + pairs[5][1]
print "\nLaunching VPN..."
_, path = tempfile.mkstemp()
f = open(path, 'w')
f.write(base64.b64decode(winner[-1]))
f.write('\nscript-security 2\nup /etc/openvpn/update-resolv-conf\ndown /etc/openvpn/update-resolv-conf')
f.close()
x = subprocess.Popen(['sudo', 'openvpn', '--config', path])
try:
while True:
time.sleep(600)
# termination with Ctrl+C
except:
try:
x.kill()
except:
pass
while x.poll() != 0:
time.sleep(1)
print '\nVPN terminated'

Geptun commented Jul 21, 2016

Hi there, I run with arch linux, with python 3 as the default python, it throws this error.

[geppie@geppie-arch ~]$ ./vpngate.py
File "./vpngate.py", line 22
print 'usage: ' + sys.argv[0] + ' [country name | country code]'
^
SyntaxError: Missing parentheses in call to 'print

what's needed to fix that?

Hy @Geptun in python 3 print works as a function so you have to replace print 'usage: ' + sys.argv[0] + ' [country name | country code]'

with print ('usage: ' + sys.argv[0] + ' [country name | country code]')

Can you make this for windows ?

Franc15 commented Sep 2, 2016

like dat its cool

MasterCATZ commented Sep 2, 2016

./vpngate.ph France
Found 5 servers for country France
5 of these servers support OpenVPN

== Best server ==
HostName: vpn609832782
IP: 78.235.96.205
Score: 9516
Ping: -
Speed: 0.0 MBps
Country: France

Launching VPN...
Fri Sep  2 23:26:31 2016 OpenVPN 2.3.10 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [MH] [IPv6] built on Feb  2 2016
Fri Sep  2 23:26:31 2016 library versions: OpenSSL 1.0.2g-fips  1 Mar 2016, LZO 2.08
Fri Sep  2 23:26:31 2016 WARNING: No server certificate verification method has been enabled.  See http://openvpn.net/howto.html#mitm for more info.
Fri Sep  2 23:26:31 2016 NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
Fri Sep  2 23:26:31 2016 Socket Buffers: R=[87380->87380] S=[16384->16384]
Fri Sep  2 23:26:31 2016 Attempting to establish TCP connection with [AF_INET]78.235.96.205:1529 [nonblock]
Fri Sep  2 23:26:32 2016 TCP connection established with [AF_INET]78.235.96.205:1529
Fri Sep  2 23:26:32 2016 TCPv4_CLIENT link local: [undef]
Fri Sep  2 23:26:32 2016 TCPv4_CLIENT link remote: [AF_INET]78.235.96.205:1529
Fri Sep  2 23:26:32 2016 TLS: Initial packet from [AF_INET]78.235.96.205:1529, sid=0d106267 d8500a69
Fri Sep  2 23:26:32 2016 VERIFY OK: depth=0, CN=54nh715hprfx.org, O=t2akbbviuk f77c, C=US
Fri Sep  2 23:26:33 2016 Data Channel Encrypt: Cipher 'AES-128-CBC' initialized with 128 bit key
Fri Sep  2 23:26:33 2016 Data Channel Encrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
Fri Sep  2 23:26:33 2016 Data Channel Decrypt: Cipher 'AES-128-CBC' initialized with 128 bit key
Fri Sep  2 23:26:33 2016 Data Channel Decrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
Fri Sep  2 23:26:33 2016 Control Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 2048 bit RSA
Fri Sep  2 23:26:33 2016 [54nh715hprfx.org] Peer Connection Initiated with [AF_INET]78.235.96.205:1529
Fri Sep  2 23:26:35 2016 SENT CONTROL [54nh715hprfx.org]: 'PUSH_REQUEST' (status=1)
Fri Sep  2 23:26:35 2016 PUSH: Received control message: 'PUSH_REPLY,ping 3,ping-restart 10,ifconfig 10.211.1.21 10.211.1.22,dhcp-option DNS 10.211.254.254,dhcp-option DNS 8.8.8.8,route-gateway 10.211.1.22,redirect-gateway def1'
Fri Sep  2 23:26:35 2016 OPTIONS IMPORT: timers and/or timeouts modified
Fri Sep  2 23:26:35 2016 OPTIONS IMPORT: --ifconfig/up options modified
Fri Sep  2 23:26:35 2016 OPTIONS IMPORT: route options modified
Fri Sep  2 23:26:35 2016 OPTIONS IMPORT: route-related options modified
Fri Sep  2 23:26:35 2016 OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options modified
Fri Sep  2 23:26:35 2016 ROUTE_GATEWAY 37.59.36.254/255.255.255.0 IFACE=eth0 HWADDR=00:22:4d:7b:49:d0
Fri Sep  2 23:26:35 2016 TUN/TAP device tun0 opened
Fri Sep  2 23:26:35 2016 TUN/TAP TX queue length set to 100
Fri Sep  2 23:26:35 2016 do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
Fri Sep  2 23:26:35 2016 /sbin/ip link set dev tun0 up mtu 1500
Fri Sep  2 23:26:35 2016 /sbin/ip addr add dev tun0 local 10.211.1.21 peer 10.211.1.22
Fri Sep  2 23:26:35 2016 /etc/openvpn/update-resolv-conf tun0 1500 1559 10.211.1.21 10.211.1.22 init
Fri Sep  2 23:26:35 2016 /sbin/ip route add 78.235.96.205/32 via x.x.x.254
Fri Sep  2 23:26:35 2016 /sbin/ip route add 0.0.0.0/1 via 10.211.1.22

and then I lost connection to my box

Owner

Lazza commented Sep 12, 2016

@devwhatsapp use Linux.

@MasterCATZ, which "box"? Are you running vpngate.py on a remote server via SSH? I am not sure that is going to work.

You may use nmcli command.Using it, you can run command without sudo.

What's wrong?

C:\Users\Xin Zhang>vpn.py "United Kingdom"
  File "C:\Users\Xin Zhang\vpn.py", line 45
    print (str(len(supported)) + ' of these servers support OpenVPN')
             ^
SyntaxError: invalid character in identifier

fezu95 commented Dec 2, 2016

I keep getting the following error message. Can someone tell me what is the issue?
`federico@federico-ThinkPad-X230 ~/Downloads $ ./vpngate.py italy

bash: ./vpngate.py: Permission denied
`

Gouenji commented Jan 6, 2017

instead of ./vpngate.py italy
use
sudo vpngate.py italy

First make it executable by typing "chmod +x vpngate.py" in vpngate direcotery.

I am facing this error
Traceback (most recent call last):
File "./vpngate.py", line 38, in
desired = [s for s in servers if country.lower() in s[i].lower()]
IndexError: list index out of range

gg4u commented Feb 3, 2017

Could you post an example on how to requests specific urls / domains against through a vpn server?
I don't want to tunnel all traffic.

Owner

Lazza commented Jun 29, 2017

I've fixed a bug in the ordering criterion. Thanks to Eyal Foni for writing me about this issue.

chrufru commented Aug 19, 2017

Hello Lazza,

i have Python 3.6.2. The Script is not working regardless as pranjalAI saying: the print option need to be in brackets (). So i have all the print functions go to work but at the end of the skript i have an error mesage: "TypeError: expected bytes-like object, not list"

After 2 hours i can't get the script to work on new python version. Please help. I'm abslolute newbe in phython. Here is the complete edited script:

#!/usr/bin/env python

"""Pick server and start connection with VPNGate (http://www.vpngate.net/en/)"""

import requests, os, sys, tempfile, subprocess, base64, time

author = "Andrea Lazzarotto"
copyright = "Copyright 2014+, Andrea Lazzarotto"
license = "GPLv3"
version = "1.0"
maintainer = "Andrea Lazzarotto"
email = "andrea.lazzarotto@gmail.com"

if len(sys.argv) != 2:
print ('usage: ' + sys.argv[0] + ' [country name | country code]')
exit(1)
country = sys.argv[1]

if len(country) == 2:
i = 6 # short name for country
elif len(country) > 2:
i = 5 # long name for country
else:
print ('Country is too short!')
exit(1)

try:
vpn_data = requests.get('http://www.vpngate.net/api/iphone/').text.replace('\r','')
servers = [line.split(',') for line in vpn_data.split('\n')]
labels = servers[1]
labels[0] = labels[0][1:]
servers = [s for s in servers[2:] if len(s) > 1]
except:
print ('Cannot get VPN servers data')
exit(1)

desired = [s for s in servers if country.lower() in s[i].lower()]
found = len(desired)
print ('Found ' + str(found) + ' servers for country ' + country)
if found == 0:
exit(1)

supported = ([s for s in desired if len(s[-1]) > 0])
print (str(len(supported)) + ' of these servers support OpenVPN')

winner = (sorted(supported, key=lambda s: float(s[2].replace(',','.')),
reverse=True)[0])

print ("\n== Best server ==")

pairs = list(zip(labels, winner))[:-1]
for (l, d) in pairs[:4]:
print (l + ': ' + d)

print (pairs[4][0] + ': ' + str(float(pairs[4][1]) / 10**6) + ' MBps')
print ("Country: " + pairs[5][1])

print ("\nLaunching VPN...")
_, path = tempfile.mkstemp()

f = open(path, 'w')
f.write(base64.b64decode(winner[-1]))
f.write('\nscript-security 2\nup /etc/openvpn/update-resolv-conf\ndown /etc/openvpn/update-resolv-conf')
f.close()

x = subprocess.Popen(['sudo', 'openvpn', '--config', path])

try:
while True:
time.sleep(600)

except:
try:
x.kill()
except:
pass
while x.poll() != 0:
time.sleep(1)
print ('\nVPN terminated')

chrufru commented Aug 19, 2017

Hello Lazza,

i have found a converter script: "2to3"
but when i run your code to the converter, i get the same Error mesagge:

Launching VPN...
Traceback (most recent call last):
File "./vpngate.py", line 61, in
f.write(base64.b64decode(winner[-1]))
TypeError: write() argument must be str, not bytes

supig commented Sep 5, 2017

chrufru: you must change argument of open in line 60 to "wb" and add b in front of string on line 62: All like this:
f = open(path, 'wb')
f.write(base64.b64decode(winner[-1]))
f.write(b'\nscript-security 2\nup /etc/openvpn/update-resolv-conf\ndown /etc/openvpn/update-resolv-conf')
f.close()

supig commented Sep 5, 2017

someone can help me: I have launched VPN but it show me must entry password for sudo, when i finished, it just showed: "sudo: openvpn : commande introuvable"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment