NordVPN: Expert Mode

I’ve occasionally used NordVPN the past few years, but while working on another Cofense Lab Note (coming soon!) I learned about the service’s more advanced features. So I thought I’d share my findings of what lies just beneath that big blue “Quick Connect” button, and also a small script that simplifies getting information from their servers API endpoint.

Exploring Nord’s Server Types

The first thing to know is that Nord offers servers with different capabilities. They call these “categories” or “technologies” in the API and various documentation.

Standard VPN Servers

With Standard VPN Servers, your device makes an encrypted tunnel to a single server and then your traffic goes through it. So your device connects to the UK, and the website you’re visiting sees your connection come from the UK. For speed, you can choose a server that’s closest to you (which is what the “Quick Connect” button in the client does), or if you’d prefer to come from another geographical (or geopolitical) region you can choose a server that’s further away from you.

P2P Servers

The P2P servers are extremely similar to Standard VPN serves, but they are tuned for peer-to-peer file exchanges (like BitTorrent). In fact, every server with the P2P category also has the “Standard VPN Server” category (but not all Standard VPN Servers have the P2P category). It’s not clear what technical differences are, but I suspect they have additional bandwidth to handle the higher traffic demands of downloading large, non-copyrighted, totally legal files.

Double VPN Servers

As the name suggests, when you connect to a Double VPN server your traffic goes through two servers instead of one. This encrypts your traffic twice, and also causes an additional geographic hop between your client and your traffic as it leaves the VPN tunnel and travels across the network. So for example if you’re using nl-uk11, your ISP can see you connecting to the Netherlands while the website you’re accessing sees you coming from the UK.

Onion Over VPN Servers

Similarly, there are a couple Onion Over VPN (a.k.a. “tor”) servers available. With these, you can choose the country you’re connecting to, and then after that your connection goes over The Onion Router (kind of a free, open source, public VPN network) and will pass through at least two tor nodes before making it’s way to the end-service that you’re connecting to. With tor you have no idea what geographical area your connection will be coming out of and the quality of your connection can vary widely.

I suspect these are not very popular because I typically only see one or two available at any given time. In my testing, the performance was often very poor/unusable. If you’re only browsing the web and you want to use tor you’re much better off using Tor Browser, instead.

Obfuscated Servers

There are a few dozen Obfuscated Servers available. While the contents of VPN traffic is (hopefully) extremely difficult for ISPs and governments to decrypt, they can easily identify traffic that is encrypted with a VPN. So they can’t see what you’re doing, but they can see that you’re trying to protect your privacy …and block you from doing so.

Obfuscated Servers apply a very rudimentary way of preventing VPN traffic from being identified: the client and server share a key that is used to XOR bits on the wire. Then any device sitting between the client and server just sees unrecognizable data. This does not add additional protection of your data (the VPN’s encryption is still doing that), it simply defeats automatic blocking of VPN traffic.

But if you are really concerned with getting prosecuted by your government for merely using a VPN ($2,000 fine in China, $5,000 fine in Russia, god knows what in North Korea, …), be warned: anyone could easily get the XOR keys, load them into a device that inspects traffic, and reverse the bits to identify your VPN traffic. (I don’t know how feasible it would be for a government to do that with every XOR key for every VPN server. But it’s not technically difficult at all.)

Dedicated IP Servers

Finally, there are Dedicated IP servers. These require you to purchase a dedicated server from NordVPN, and if you’re doing that, you’re probably not learning anything new from this Lab Note. 🙂

So Many Clients

Nord has clients for many devices, operating systems, and even browser extensions: Windows, macOS, iOS, iPadOS, Android, Linux, Chrome, Firefox, Android TV, Firestick, Xbox, Playstation, Nintendo Switch, Raspberry Pi, Chromebook, Chromecast, and Kindle Fire. What was surprising is that some platforms have multiple clients, and while their UIs might be very similar they can have very different capabilities.

All of their clients support the Standard VPN and P2P server categories, but only certain ones support the more advanced server types. They also use different underlying VPN protocols.

For example, the main Android client is available in the Google Play store. But there is also an APK version that that also includes an ad-blocker that you can side-load onto your device.

For macOS there is the “NordVPN IKE” app (available in the App Store), but that will only let you connect to Standard and P2P servers. There is also a “NordVPN” app (also referred to as “the OpenVPN version”) which does allow you to connect to the other server types detailed in the above section. And you can have both installed on the same machine.

More surprisingly, in some cases they have application-level features (with the same name!) that function very differently. For example, the “Kill-Switch” on the macOS IKE client will cut your system’s internet connection completely in case your VPN goes down, preventing anything on your system from connecting out over an untrusted network. The “OpenVPN version” client’s Kill-Switch feature force-terminates any apps you’ve added to a list when the VPN unexpectedly goes down, while other apps (and the OS) will happily connect out over the untrusted network. Good to know!

I’m sure there are good technical reasons for there to be multiple clients with different capabilities. App stores often limit what applications have access to, while a side-loaded app can do whatever it wants. But it would be nice if Nord more clearly highlighted the different functionality.

Choosing a Server

There are over 5,300 servers available in 60 countries. The official clients do a good job of making it pretty easy to find a server for your needs, and there are sections of Nord’s website that help you filter down to a particular server, but I think they’re kind of clunky.

They also offer an “API” (it’s really not an API at all–it’s just a single endpoint) that returns a JSON representation of their current servers. When I first started exploring this option I found many scripts on Github that hit the https://nordvpn.com/api/server endpoint (psst… don’t use that one; keep reading). That looks something like this:

% # How many servers?
% curl -s https://nordvpn.com/api/server| jq '. | length'
5325

% # Show me the first one
% curl -s https://nordvpn.com/api/server| jq '.[0]'
{
  "id": 929912,
  "ip_address": "172.83.40.219",
  "search_keywords": [
    "sha512",
    "P2P"
  ],
  "categories": [
    {
      "name": "Standard VPN servers"
    },
    {
      "name": "P2P"
    }
  ],
  "name": "Canada #944",
  "domain": "ca944.nordvpn.com",
  "price": 0,
  "flag": "CA",
  "country": "Canada",
  "location": {
    "lat": 49.25,
    "long": -123.133333
  },
  "load": 14,
  "features": {
    "ikev2": true,
    "openvpn_udp": true,
    "openvpn_tcp": true,
    "socks": false,
    "proxy": false,
    "pptp": false,
    "l2tp": false,
    "openvpn_xor_udp": false,
    "openvpn_xor_tcp": false,
    "proxy_cybersec": false,
    "proxy_ssl": true,
    "proxy_ssl_cybersec": true,
    "ikev2_v6": false,
    "openvpn_udp_v6": false,
    "openvpn_tcp_v6": false,
    "wireguard_udp": true,
    "openvpn_udp_tls_crypt": false,
    "openvpn_tcp_tls_crypt": false,
    "openvpn_dedicated_udp": false,
    "openvpn_dedicated_tcp": false,
    "skylark": false,
    "mesh_relay": false
  }
}

Not bad. But while they included the country in the response, I was annoyed that the only more precise geographical information was latitude and longitude. That’s useful when you want to call in an airstrike, but not so much when I’m messing with a scammer and I want it to look like I’m coming from Atlanta.

So I used the excellent geopy python module, which allows you to reverse lookup lat/long coordinates to country, state, street, and in come cases even the building associated with the location. Pretty neat!

% python3
Python 3.9.6 (default, Jun 29 2021, 05:25:02)
[Clang 12.0.5 (clang-1205.0.22.9)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from geopy.geocoders import Nominatim
>>> geolocator = Nominatim(user_agent="A unique client name")
>>> location = geolocator.reverse("49.25, -123.133333")
>>> location.raw
{'place_id': 170205510, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright', 'osm_type': 'way', 'osm_id': 340582044, 'lat': '49.2494072351199', 'lon': '-123.13334259493331', 'display_name': 'West King Edward Avenue, Shaughnessy, Vancouver, District of North Vancouver, Metro Vancouver Regional District, British Columbia, V6H, Canada', 'address': {'road': 'West King Edward Avenue', 'neighbourhood': 'Shaughnessy', 'city_district': 'Shaughnessy', 'city': 'Vancouver', 'municipality': 'District of North Vancouver', 'county': 'Metro Vancouver Regional District', 'state': 'British Columbia', 'postcode': 'V6H', 'country': 'Canada', 'country_code': 'ca'}, 'boundingbox': ['49.2493201', '49.2494778', '-123.1378111', '-123.1275237']}

However, it was a little slow because each call to geolocator.reverse is an API request to their service. I solved that by caching API lookups and figured I was good to go.

…and then I discovered the other, much lesser-known endpoint: https://api.nordvpn.com/v1/servers?limit=9999999. This one has significantly more information, including a more human-friendly representation of the city:

 % curl -s 'https://api.nordvpn.com/v1/servers?limit=9999999' | jq '.[0]'
{
  "id": 929912,
  "created_at": "2018-08-31 10:49:10",
  "updated_at": "2021-07-27 16:53:16",
  "name": "Canada #944",
  "station": "172.83.40.219",
  "ipv6_station": "",
  "hostname": "ca944.nordvpn.com",
  "load": 14,
  "status": "online",
  "locations": [
    {
      "id": 235,
      "created_at": "2017-06-15 14:06:47",
      "updated_at": "2017-06-15 14:06:47",
      "latitude": 49.25,
      "longitude": -123.133333,
      "country": {
        "id": 38,
        "name": "Canada",
        "code": "CA",
        "city": {
          "id": 1054610,
          "name": "Vancouver",
          "latitude": 49.25,
          "longitude": -123.133333,
          "dns_name": "vancouver",
          "hub_score": 0
        }
      }
    }
  ],
  "services": [
    {
      "id": 1,
      "name": "VPN",
      "identifier": "vpn",
      "created_at": "2017-03-21 12:00:45",
      "updated_at": "2017-05-25 13:12:31"
    },
    {
      "id": 5,
      "name": "Proxy",
      "identifier": "proxy",
      "created_at": "2017-05-29 19:38:30",
      "updated_at": "2017-05-29 19:38:30"
    }
  ],
  "technologies": [
    {
      "id": 1,
      "name": "IKEv2/IPSec",
      "identifier": "ikev2",
      "created_at": "2017-03-21 12:00:24",
      "updated_at": "2017-09-05 14:20:16",
      "metadata": [],
      "pivot": {
        "technology_id": 1,
        "server_id": 929912,
        "status": "online"
      }
    },
    {
      "id": 3,
      "name": "OpenVPN UDP",
      "identifier": "openvpn_udp",
      "created_at": "2017-05-04 08:03:24",
      "updated_at": "2017-05-09 19:27:37",
      "metadata": [],
      "pivot": {
        "technology_id": 3,
        "server_id": 929912,
        "status": "online"
      }
    },
    {
      "id": 5,
      "name": "OpenVPN TCP",
      "identifier": "openvpn_tcp",
      "created_at": "2017-05-09 19:28:14",
      "updated_at": "2017-05-09 19:28:14",
      "metadata": [],
      "pivot": {
        "technology_id": 5,
        "server_id": 929912,
        "status": "online"
      }
    },
    {
      "id": 21,
      "name": "HTTP Proxy (SSL)",
      "identifier": "proxy_ssl",
      "created_at": "2017-10-02 12:45:14",
      "updated_at": "2017-10-02 12:45:14",
      "metadata": [],
      "pivot": {
        "technology_id": 21,
        "server_id": 929912,
        "status": "online"
      }
    },
    {
      "id": 23,
      "name": "HTTP CyberSec Proxy (SSL)",
      "identifier": "proxy_ssl_cybersec",
      "created_at": "2017-10-02 12:50:49",
      "updated_at": "2017-10-02 12:50:49",
      "metadata": [],
      "pivot": {
        "technology_id": 23,
        "server_id": 929912,
        "status": "online"
      }
    },
    {
      "id": 35,
      "name": "Wireguard",
      "identifier": "wireguard_udp",
      "created_at": "2019-02-14 14:08:43",
      "updated_at": "2019-02-14 14:08:43",
      "metadata": [
        {
          "name": "public_key",
          "value": "x64VhRToeBFhVlaJGA+R1CE1K3MsT7KVELquTyeQ3j0="
        }
      ],
      "pivot": {
        "technology_id": 35,
        "server_id": 929912,
        "status": "online"
      }
    }
  ],
  "groups": [
    {
      "id": 11,
      "created_at": "2017-06-13 13:43:00",
      "updated_at": "2017-06-13 13:43:00",
      "title": "Standard VPN servers",
      "identifier": "legacy_standard",
      "type": {
        "id": 3,
        "created_at": "2017-06-13 13:40:17",
        "updated_at": "2017-06-13 13:40:23",
        "title": "Legacy category",
        "identifier": "legacy_group_category"
      }
    },
    {
      "id": 15,
      "created_at": "2017-06-13 13:43:38",
      "updated_at": "2017-06-13 13:43:38",
      "title": "P2P",
      "identifier": "legacy_p2p",
      "type": {
        "id": 3,
        "created_at": "2017-06-13 13:40:17",
        "updated_at": "2017-06-13 13:40:23",
        "title": "Legacy category",
        "identifier": "legacy_group_category"
      }
    },
    {
      "id": 21,
      "created_at": "2017-10-27 14:23:03",
      "updated_at": "2017-10-30 08:09:48",
      "title": "The Americas",
      "identifier": "the_americas",
      "type": {
        "id": 5,
        "created_at": "2017-10-27 14:16:30",
        "updated_at": "2017-10-27 14:16:30",
        "title": "Regions",
        "identifier": "regions"
      }
    }
  ],
  "specifications": [
    {
      "id": 8,
      "title": "Version",
      "identifier": "version",
      "values": [
        {
          "id": 257,
          "value": "2.1.0"
        }
      ]
    }
  ],
  "ips": [
    {
      "id": 178500,
      "created_at": "2020-01-17 08:28:48",
      "updated_at": "2020-01-17 08:28:48",
      "server_id": 929912,
      "ip_id": 23225,
      "type": "entry",
      "ip": {
        "id": 23225,
        "ip": "172.83.40.219",
        "version": 4
      }
    }
  ]
}

Using this endpoint was a lot better because I no longer had to wait for the geopy API calls. I was able to remove a dependency and reduced the script’s complexity.

I’m still a little disappointed though. The locations array only ever includes a single object: the ingress (where the VPN client connects to). It would be really great if it had a second object detailing the egress location for Double VPN servers. (Granted, Nord has no way of knowing the egress with Onion Over VPN servers.)

We can at least deduce the egress country from the Name of the Double VPN servers: “ca-us40 (Canada – United States #40)” tells us that the ingress is Canada and the egress is the US. But the only way to get the City would be to connect to each Double VPN, get your egress IP (dig +short myip.opendns.com @resolver1.opendns.com.), and then run that IP through a geo-ip database like Maxmind.

Maybe someday Nord will create a v2 of its API and include that helpful information. Meanwhile, I’ve created a script that makes it easier and more convenient to sift through current NordVPN servers.

nordservers.py

Rather than duplicating the README here and making this note more lengthy that it needs to be, I’ll just point you to the Github repository for the script. Hope you find it useful 🙂

 

All third-party trademarks referenced by Cofense whether in logo form, name form or product form, or otherwise, remain the property of their respective holders, and use of these trademarks in no way indicates any relationship between Cofense and the holders of the trademarks.