Connect VPN Using Python

Connect VPN Using Python

  1. What is a VPN
  2. Connect VPN Using Python
  3. Conclusion

In the world, security and privacy have become major concerns for people. In search of a solution, developers made VPNs.

What is a VPN

A Virtual Private Network, also known as VPN, is a software where it creates a private network to protect our online privacy. VPN gives us many benefits but protected privacy and data encryption are the main advantages for the users.

  1. Protected Privacy

    Since VPN creates a private network within the public network, what we do on the internet can’t be virtually traced. It hides our IP address, so third parties can’t track our activities.

    Hiding the IP means the website we visit through a VPN sees the VPN server as the origin of the traffic.

    So, VPN will mask the user’s IP address, and the IP of the VPN server will be visible. Most importantly, this process prevents exploitation of the user’s location and the traffic; therefore, the user’s privacy is protected.

  2. Data Encryption

    VPN also encrypts our online data. The VPN encrypts the data we send throughout the internet so that hackers and other third parties can’t retrieve them.

    Even if they retrieve them, they will not be able to understand the content or decrypt the data.

    Since we have a good understanding of what a VPN is now, let’s try to connect it. In this article, we discuss how to connect VPN using Python.

Connect VPN Using Python

This tutorial will use a free VPN service from VPNGate and OpenVPN software. VPNGate is a public VPN cloud service that we can use for free.

To use OpenVPN, we need to install it on our system. For Windows OS, you can manually download and install it.

For Linux or Ubuntu users, use the below command.

Install OpenVPN:

$ apt-get install openvpn easy-rsa

After installing it, we can build a Python script to connect to the VPN. When we run this script in the terminal, we have to provide a country as an argument.

The syntax is below.

Python3 <filename.py> <countryname>

When giving the country name, there are two options.

  1. Long name of the country

    $ python3 vpn.py Japan
    
  2. Short name of the country

    $ python3 vpn.py JP
    

As the first step, we must import the following libraries to the script.

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

Sometimes a user may enter more than one country when running the script. To prevent that, we can use the below code chunk.

As the first step, we must import the libraries below to the script.

if len(sys.argv) != 2:
    print ('Enter one country at a time!')
    exit(1)
cntry = sys.argv[1]

Here in the first line, we check whether the total arguments are not equal to two. If it equals, we continue with the given country; otherwise, we put caution and exit.

Next, we can check whether the user has given the country’s long or short name. If the user enters one letter, we can throw an error message.

if len(cntry) > 2:
    j = 5
elif len(cntry) == 2:
    j = 6
else:
    print ('Cannot identify the country. Name is too short.')
    exit(1)

So now we can retrieve a list of available free VPN servers from the VPNGate website. Along with the list, we can get labels of the VPN servers, such as HostName, IP, Score, Ping, etc., and their values.

try:
    vpnServerListData = requests.get('http://www.vpngate.net/api/iphone/').text.replace('\r','')
    freeServers = [line.split(',') for line in vpnServerListData.split('\n')]
    serverLabels = freeServers[1]
    serverLabels[0] = serverLabels[0][1:]
    freeServers = [srvrs for srvrs in freeServers[2:] if len(srvrs) > 1]
except:
    print ("Something is wrong! Cannot load the VPN server's data")
    exit(1)

Then we need to retrieve the available servers and get the total number. Then we can display the number of available servers.

We can throw a message mentioning it and exit if no servers are available. To achieve this task, we can use the below code chunk.

availableServers = [srvrs for srvrs in freeServers if cntry.lower() in srvrs[j].lower()]
numOfServers = len(availableServers)
print ('We found ' + str(numOfServers) + ' servers for ' + cntry)
if numOfServers == 0:
    exit(1)

Now we should display how many servers support the OpenVPN tool. Since we use this tool to connect to VPN, it is essential to have supporting VPN servers, and then we can filter them out.

supporteServers = [srvrs for srvrs in availableServers if len(srvrs[-1]) > 0]
print ('There are ' + str(len(supporteServers)) + ' servers that support OpenVPN')

As we have filtered the supported servers, we need to choose the best server among them, with the lowest ping and the highest speed and score.

Then we can display its attributes (labels) using a for loop. And finally, the country can be displayed.

bestServer = sorted(supporteServers, key=lambda srvrs: float(srvrs[2].replace(',','.')), reverse=True)[0]
print ("\n------------------Best server------------------")
labelPair = list(zip(serverLabels, bestServer))[:-1]
for (l, d) in labelPair[:4]:
    print (l + ': ' + d)
print (labelPair[4][0] + ': ' + str(float(labelPair[4][1]) / 10**6) + ' MBps')
print ("Country: " + labelPair[5][1])

Output:

best server

Before launching the VPN, we should update the resolveconf with DNS settings. Also, they should be in string format.

By default, it comes in binary format. Using base64 decode, we can convert them into strings.

Then we can launch the VPN.

print ("\nLaunching VPN...")
_, path = tempfile.mkstemp()
file = open(path, 'wb')
file.write(base64.b64decode(bestServer[-1]))
file.write(b'\nscript-security 2\nup /etc/openvpn/update-resolv-conf\ndown /etc/openvpn/update-resolv-conf')
file.close()
vpnR = subprocess.Popen(['sudo', 'openvpn', '--config', path])

After we launch it, we can get the following output.

launch vpn

We have a successful connection if you get a message like Initialization Sequence Competed.

Initialization Sequence Competed

Now we have successfully connected to the VPN. Below you can see the VPNGate server information that we can see after a successful connection.

Also, we can set the time required to connect OpenVPN to the VPN server. Through the below code chunk, we can achieve it.

try:
     #time required to connect the openvpn to connect the vpn server
 time.sleep(60)
 start_time = time.time()
 nUrl = "http://bot.whatismyipaddress.com/"
 nRet = requests.get(nUrl)
 if nRet.status_code == 200:
  with open('resp', "wb") as txtFile:
   txtFile.write(nRet.text)
 print ('Time took to check Ip address  ',(time.time() - start_time))
 vpnR.kill()

To terminate the VPN connection, use Ctrl+C. Then, the connection will terminate, and the system will throw a message to notify the user.

except Exception as ex:
    try:
        vpnR.kill()
    except:
        pass
    while vpnR.poll() != 0:
        time.sleep(1)
    print ('\nVPN has terminated')

Output:

vpn terminated

Full code:

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

if len(sys.argv) != 2:
    print('Enter one country at a time!')
    exit(1)
cntry = sys.argv[1]

if len(cntry) > 2:
    j = 5
elif len(cntry) == 2:
    j = 6
else:
    print('Cannot identify the country. Name is too short.')
    exit(1)

try:
    vpnServerListData = requests.get('http://www.vpngate.net/api/iphone/').text.replace('\r', '')
    freeServers = [line.split(',') for line in vpnServerListData.split('\n')]
    serverLabels = freeServers[1]
    serverLabels[0] = serverLabels[0][1:]
    freeServers = [srvrs for srvrs in freeServers[2:] if len(srvrs) > 1]
except:
    print("Something is wrong! Cannot load the VPN server's data")
    exit(1)

    availableServers = [srvrs for srvrs in freeServers if cntry.lower() in srvrs[j].lower()]
    numOfServers = len(availableServers)
    print('We found ' + str(numOfServers) + ' servers for ' + cntry)
    if numOfServers == 0:
        exit(1)

    supporteServers = [srvrs for srvrs in availableServers if len(srvrs[-1]) > 0]
    print(str(len(supporteServers)) + ' of these servers support OpenVPN')

    bestServer = sorted(supporteServers, key=lambda srvrs: float(srvrs[2].replace(',', '.')), reverse=True)[0]
    print("\n== Best server ==")
    labelPair = list(zip(serverLabels, bestServer))[:-1]
    for (l, d) in labelPair[:4]:
        print(l + ': ' + d)
    print(labelPair[4][0] + ': ' + str(float(labelPair[4][1]) / 10 ** 6) + ' MBps')
    print("Country: " + labelPair[5][1])

    print("\nLaunching VPN...")
    _, path = tempfile.mkstemp()
    file = open(path, 'wb')
    file.write(base64.b64decode(bestServer[-1]))
    file.write(b'\nscript-security 2\nup /etc/openvpn/update-resolv-conf\ndown /etc/openvpn/update-resolv-conf')
    file.close()
    vpnR = subprocess.Popen(['sudo', 'openvpn', '--config', path])

try:
    # time required to connect the openvpn to connect the vpn server
    time.sleep(60)
    timeS = time.time()
    nUrl = "http://bot.whatismyipaddress.com/"
    nRet = requests.get(nUrl)
    if nRet.status_code == 200:
        with open('resp', "wb") as txtFile:
            txtFile.write(nRet.text)
    print('Time took to check Ip address  ', (time.time() - timeS))
    vpnR.kill()

except Exception as ex:
    try:
        vpnR.kill()
    except:
        pass
    while vpnR.poll() != 0:
        time.sleep(1)
    print('\nVPN has terminated')

Output (without terminating):

without terminating

Conclusion

Throughout this article, we discussed what a VPN is and its benefits. Then we connect a free VPN service using Python.

There are other methods to reach our goal, but we can easily understand the basic concepts of connecting to a VPN through this method.

Migel Hewage Nimesha avatar Migel Hewage Nimesha avatar

Nimesha is a Full-stack Software Engineer for more than five years, he loves technology, as technology has the power to solve our many problems within just a minute. He have been contributing to various projects over the last 5+ years and working with almost all the so-called 03 tiers(DB, M-Tier, and Client). Recently, he has started working with DevOps technologies such as Azure administration, Kubernetes, Terraform automation, and Bash scripting as well.