We fetched Mullvad's relay list at 05:22 UTC on 13 October 2026. It held 566 relays, 553 WireGuard servers and 13 bridges, and Mullvad marks only 124 of them as hardware it owns. One of the owned ones, 185.213.155.73 in Frankfurt, is registered in WHOIS to "31173 Services Germany", has no reverse DNS, and is announced by AS39351. Nothing in its network record says "Mullvad". Only the list does.
That is the whole trick behind every "which VPN is this IP" tool, and almost none of them say so. Below we list the endpoints where providers publish their servers, give a tested Python matcher, and show what our API returned for the provider-listed servers we looked up, plus controls, misses included. It ends with a policy table. For the detection side, meaning how a VPN is caught at all, read how VPN detection works, signal by signal.

Can you tell which VPN an IP address belongs to?
Yes, when the IP is on a list the provider publishes. A VPN app has to know where its servers are before it can connect, so providers serve that list to their apps, and most of those lists are public. If the address is on no list, you can usually still tell it is a VPN from probes and hosting signals, but not whose.
Here is 185.213.155.73 traced end to end. Mullvad's list, at api.mullvad.net/www/relays/all/, has a row for it with hostname "de-fra-wg-001", type "wireguard", city_name "Frankfurt", owned true and provider "31173". That last field is the hosting company, and here it is Mullvad's own.
The registry tells a different story. RIPE's RDAP record, which we opened at 05:28 UTC, names the range NET-31173-185-213-155-0-24 and the registrant "31173 Services Germany". The RIPE whois route object gives origin AS39351. We ran dig -x 185.213.155.73 and got no answer at all.
Then we looked it up in our API at 05:27 UTC. This is a trimmed copy, values unedited:
{
"ip": "185.213.155.73",
"asn": {
"asn": 39351,
"org": "ESAB-AS - 31173 Services AB"
},
"whois": {
"org": "31173 Services AB infrastructure in Frankfurt, DE.",
"netname": "NET-31173-185-213-155-0-24",
"has_vpn_keywords": false
},
"detection": {
"is_vpn": true,
"vpn_provider": "Mullvad",
"vpn_confidence": 95
},
"scoring": {
"fraud_score": 100,
"recommended_action": "block",
"detection_methods": ["known_vpn_server", "wireguard_open", "datacenter_with_vpn_proxy", "no_ptr_datacenter"]
}
}
Look at whois.has_vpn_keywords. It is false, on a Mullvad server, and it was false on every address we looked up. The WHOIS text never mentions a VPN. The name "Mullvad" came from the list match, and vpn_confidence 95 is the value our API gives for that path. The block came from the evidence: an open WireGuard port on a hosting address.
Why WHOIS, reverse DNS and the ASN name the host, not the VPN
Most VPN servers run on rented machines, so the network record describes the landlord. In our sample, M247 (AS9009) hosts listed servers of NordVPN, PIA, AirVPN, IVPN and FastestVPN. Datacamp (AS212238) hosts a Mullvad New York server and an IVPN Buenos Aires server. A rule that says "M247 means VPN" is a guess about a hosting company. The provider's list is evidence about a server.
Mullvad makes the point for us. Its list marks every relay owned true or false and names the host in provider. On 13 October, 124 of its 566 relays were owned: true, and the most common hosts were DataPacket (128 relays), Tzulo (127) and M247 (98). We looked up two rented Mullvad relays at 05:33 UTC:
| Mullvad relay, per its list | Host in the list | Our asn.org | vpn_provider, vpn_confidence | Score, action |
|---|---|---|---|---|
| 149.22.83.2, ar-bue-wg-001, owned false | DataPacket | CDNEXT - Datacamp Limited | Mullvad, 95 | 99, block |
| 91.90.123.2, be-bru-wg-101, owned false | M247 | M247 - M247 Europe SRL | Mullvad, 95 | 100, block |
An ASN check on either says "hosting company". The list says Mullvad. The New York relay us-nyc-wg-301, 143.244.47.65, tells the same story on Datacamp.
Reverse DNS is weaker still. We ran dig -x on 20 of the provider-listed addresses at 05:28 UTC. Eleven returned nothing, and none of the other nine named a VPN brand:
| IP | Listed by | What dig -x returned |
|---|---|---|
| 143.244.47.65 | Mullvad | unn-143-244-47-65.datapacket.com |
| 149.22.83.100 | IVPN | unn-149-22-83-100.datapacket.com |
| 198.44.137.44 | Windscribe | static-198-44-137-44.cust.tzulo.com |
| 204.13.164.252 | Riseup | leapgwv6.bitmask.net |
| 185.244.212.69 | IVPN | 185.244.212.69.adsl.inet-telecom.org |
| 185.213.155.73 | Mullvad | no PTR |
The Riseup name hints at the VPN software, LEAP and Bitmask, not at a brand. The IVPN Vienna name says "adsl", which reads like a home connection, on a server IVPN lists. That is the danger of reading too much into a PTR.
The ASN names the VPN only when the provider runs its own network, as Mullvad does with AS39351 and Riseup with AS16652. If you want the background, here is what an ASN is and who it names. Our API keeps a short table of networks run by VPN providers, with Mullvad's AS39351 on it, and that table is one of the four naming paths below.
Where VPN providers publish their server IPs
These are the lists the providers' own apps read. "Fetched today" means our network got a 200 response on 13 October 2026; "not reachable today" means the request failed from our network after two tries.
| Provider | List the app reads | Where the IP is | Status on 13 October 2026 |
|---|---|---|---|
| Mullvad | api.mullvad.net/www/relays/all/ | ipv4_addr_in, ipv6_addr_in | Fetched today, 05:22 UTC: 566 relays, 124 owned |
| AirVPN | airvpn.org/api/status/ | ip_v4_in1 to ip_v4_in4 | Fetched today, 05:22 UTC: 250 servers |
| IVPN | api.ivpn.net/v5/servers.json | WireGuard and OpenVPN host entries | Fetched today, 05:22 UTC: 89 WireGuard hosts in 59 locations |
| PrivadoVPN | privadovpn.com/apps/servers_export.json | ip | Fetched today, 05:22 UTC: 167 servers |
| Riseup | api.black.riseup.net/3/config/eip-service.json, found via riseup.net/provider.json | ip_address | Fetched today, 05:23 UTC: 21 gateways |
| NordVPN | api.nordvpn.com/v2/servers, per gluetun's NordVPN updater | station | Not reachable today (timed out) |
| Surfshark | api.surfshark.com/v4/server/clusters, per gluetun's Surfshark updater | Hostnames only | Not reachable today (TLS error, then timeout) |
| Private Internet Access | serverlist.piaservers.net/vpninfo/servers/v6, per PIA's own get_region.sh | Server IPs per region | Not reachable today (TLS error) |
| Windscribe | assets.windscribe.com/serverlist/mob-v2/1/, per gluetun's Windscribe updater | ip, ip2, ip3 | Not reachable today (timed out) |
The four we could not reach are real endpoints. We know them from the providers' official or open-source clients, and gluetun's NordVPN code even comments that the station field "is, it seems, the entry IP address." Their APIs block requests from data centers, which is where our scanner runs, and on 13 October they did not answer the network we used for this post either.
So our API names VPNs from the providers' own server lists plus a public third-party list. For NordVPN, PIA and Windscribe, our scanner falls back to saved copies of their API responses, dated 4 October 2026. We hold no Surfshark copy. The third-party list is gluetun-servers, the community-maintained server data behind gluetun, an open-source VPN client container. We load its files for more than 20 providers, and it is our only source for FastestVPN. The four of its files we fetched today, for ExpressVPN, FastestVPN, NordVPN and PIA, all carry a timestamp of 6 August 2026.
Identify a VPN provider by IP yourself: Mullvad and NordVPN
Download the provider's list and look for an exact match on the address. Mullvad is the easy case because its list answered every time we asked. This is the script we ran at 05:29 UTC on 13 October 2026, on Python 3.9.6, standard library only:
"""Check IPs against Mullvad's public relay list. Standard library only."""
import ipaddress, json, sys, urllib.request
URL = "https://api.mullvad.net/www/relays/all/"
def load_relays(url=URL):
with urllib.request.urlopen(url, timeout=30) as resp:
relays = json.load(resp)
index = {}
for r in relays:
for key in ("ipv4_addr_in", "ipv6_addr_in"):
if r.get(key):
index[ipaddress.ip_address(r[key])] = r
return relays, index
def match(index, ip):
try:
addr = ipaddress.ip_address(ip.strip())
except ValueError:
return None
if addr.version == 6 and addr.ipv4_mapped:
addr = addr.ipv4_mapped # ::ffff:141.98.252.67 becomes 141.98.252.67
return index.get(addr)
if __name__ == "__main__":
try:
relays, index = load_relays()
except Exception as e:
sys.exit(f"could not load Mullvad's list: {e}")
print(f"{len(relays)} relays, {len(index)} addresses")
ips = sys.argv[1:] or [line for line in sys.stdin if line.strip()]
for ip in ips:
r = match(index, ip)
if r:
result = f"{r['hostname']} {r['type']} {r['city_name']} owned={r['owned']} host={r['provider']}"
else:
result = "not on Mullvad's list"
print(f"{ip.strip():22} {result}")
We passed seven inputs on the command line, and it printed:
566 relays, 1122 addresses
185.213.155.73 de-fra-wg-001 wireguard Frankfurt owned=True host=31173
143.244.47.65 us-nyc-wg-301 wireguard New York, NY owned=False host=DataPacket
45.83.220.68 se-mma-wg-101 wireguard Malmö owned=True host=31173
45.83.220.7 not on Mullvad's list
::ffff:141.98.252.67 gb-lon-wg-001 wireguard London owned=True host=31173
102.129.235.17 not on Mullvad's list
not-an-ip not on Mullvad's list
We also piped three lines with blanks and padding through stdin, the way you would feed it a log column, and it matched 45.83.220.70 to se-mma-wg-103. Pointed at a URL that returns 404, it printed "could not load Mullvad's list: HTTP Error 404: Not Found" and exited with status 1. Two caveats: an invalid input is reported as not on the list rather than as an error, and the 13 bridges are matched too, so read the type column.
How to detect NordVPN the same way. NordVPN's list puts each server's IP in a station field, and our saved copy from 4 October has one per server. The live endpoint timed out from our network on 13 October, twice, so we are not publishing NordVPN code we could not run. Run the same exact-match logic from a network NordVPN answers.
For one address at a time, you can check any IP for a VPN and its provider; the tool returns the name in detection.vpn_provider. In code, it is one request with the IP in the path:
curl https://api.geoiphub.com/v1/lookup/185.213.155.73 \
-H "x-api-key: YOUR_API_KEY"
vpn_provider is on the free tier, which includes every data field at 1,500 lookups a day. If you key anything on the name, match its start, not the whole string: our API returned "Mullvad" for listed servers and "Mullvad (31173 Services)" for the ASN path. This is the snippet we ran at 05:34 UTC, without a key:
import json, sys, urllib.request
def lookup(ip, key=None):
# A custom User-Agent: our API answered Python's default one with a 403.
headers = {"User-Agent": "vpn-provider-check/1.0"}
if key:
headers["x-api-key"] = key
req = urllib.request.Request(f"https://api.geoiphub.com/v1/lookup/{ip}", headers=headers)
with urllib.request.urlopen(req, timeout=10) as resp:
return json.load(resp)
for ip in sys.argv[1:]:
data = lookup(ip)
provider = data["detection"]["vpn_provider"]
named = provider != "none"
is_mullvad = provider.startswith("Mullvad") # "Mullvad" or "Mullvad (31173 Services)"
print(ip, repr(provider), "named" if named else "unnamed",
"mullvad" if is_mullvad else "-", "is_vpn" if data["detection"]["is_vpn"] else "not_vpn",
data["scoring"]["recommended_action"])
185.213.155.73 'Mullvad' named mullvad is_vpn block
45.83.220.7 'Mullvad (31173 Services)' named mullvad is_vpn review
102.129.235.17 'none' unnamed - is_vpn block
The third line is the one to design for: no name, still a VPN, still a block.
If you are asking the other question, whether your own connection shows as NordVPN, open see the IP your connection shows while connected.
What our API returned for provider-listed IPs
Listed servers from every provider we sampled came back named, and vpn_confidence shows which of four paths named them. On a named row, the value maps to the path:
| vpn_confidence | Path that named the IP |
|---|---|
| 95 | The provider's own server list |
| 90 | A server hostname from gluetun's files, resolved by us to this IP |
| 85 | A short table of networks run by a VPN provider |
| 80 | The public gluetun server list |
We ran these lookups between 05:27 and 05:28 UTC on 13 October 2026. The last column shows only VPN handshake probes that answered; we left the rest of detection_methods out of the table.
| IP | Provider and server, per its list | Where we found the IP | vpn_provider | vpn_confidence | Score, action | Probe that answered |
|---|---|---|---|---|---|---|
| 185.213.155.73 | Mullvad, de-fra-wg-001 | Mullvad, fetched today | Mullvad | 95 | 100, block | wireguard_open |
| 143.244.47.65 | Mullvad, us-nyc-wg-301, owned false | Mullvad, fetched today | Mullvad | 95 | 99, block | wireguard_open |
| 82.102.19.137 | NordVPN, be148 | NordVPN copy of 4 Oct; also in gluetun | NordVPN | 80 | 99, block | wireguard_open |
| 173.239.247.129 | PIA, Vietnam | PIA copy of 4 Oct; also in gluetun | PIA | 80 | 51, step_up | none |
| 198.44.137.44 | Windscribe, Dallas, us-central-117 | Windscribe copy of 4 Oct | Windscribe | 95 | 100, block | ipsec_open, wireguard_open |
| 185.156.175.170 | AirVPN, Achernar, Zurich | AirVPN, fetched today | AirVPN | 95 | 99, block | wireguard_open |
| 149.22.83.100 | IVPN, ar1.wg, Buenos Aires | IVPN, fetched today | IVPN | 95 | 99, block | wireguard_open |
| 85.12.5.56 | PrivadoVPN, hkg-006 | PrivadoVPN, fetched today | PrivadoVPN | 90 | 36, review | none |
| 204.13.164.252 | Riseup, vpn01-sea | Riseup, fetched today | Riseup | 95 | 48, review | none |
| 31.171.152.205 | ExpressVPN, Albania | gluetun file of 6 Aug | ExpressVPN | 80 | 51, step_up | none |
| 46.102.153.134 | FastestVPN, au-stream, Sydney | gluetun file of 6 Aug | FastestVPN | 90 | 99, block | wireguard_open |
| 45.83.220.7 | Not on Mullvad's list | None | Mullvad (31173 Services) | 85 | 46, review | none |
Three rows need a word. The NordVPN and PIA servers are on our saved copies, but they came back at 80, the gluetun value, and both are in gluetun's files. The PrivadoVPN server is on PrivadoVPN's own export today, yet it came back at 90, not 95: its name came from resolving its hostname, hkg-006.vpn.privado.io, which gluetun's PrivadoVPN file also carries. Read the path from vpn_confidence, not from the list where you found the IP. ExpressVPN is not one of the nine providers whose own lists we pull. One gluetun-listed ExpressVPN address came back named, which shows the path works, not that we cover ExpressVPN.
The last row is the ASN path. 45.83.220.7 is not on Mullvad's list; today's list has .68, .69 and .70 in that /24, not .7. It is named because its network, AS39351, belongs to Mullvad's operator:
{
"ip": "45.83.220.7",
"asn": {
"asn": 39351,
"org": "ESAB-AS - 31173 Services AB"
},
"whois": {
"org": "31173 Services AB infrastructure in Malmo, SE.",
"netname": "NET-31173-45-83-220-0-24",
"has_vpn_keywords": false
},
"detection": {
"is_vpn": true,
"vpn_provider": "Mullvad (31173 Services)",
"vpn_confidence": 85
},
"scoring": {
"fraud_score": 46,
"recommended_action": "review",
"detection_methods": ["known_vpn_server", "datacenter_ip"]
}
}
Note that known_vpn_server fires here too. That method name does not mean "on a provider's list"; on this row it comes from the network table. Read vpn_confidence for the path, and only on rows where vpn_provider is not "none".
Why some VPN IPs come back "none"
"none" means the IP is on none of the lists we hold right now. It does not mean the IP is not a VPN, and it does not mean a provider's neighbouring address is clean.
NordVPN's server pl128, 194.99.105.99, is in the NordVPN response we saved on 4 October, listed as online. Today it returned vpn_provider "none", yet is_vpn true, score 98 and block, with ipsec_open among its methods. Its IPsec handshake caught it; nothing named it. PIA's Liechtenstein server, 91.90.122.25, is in PIA's list from the same day. Today it returned is_vpn false and a score of 64, step_up, from blocklist and hosting signals alone.
Neither of those two addresses is in gluetun's files, while the named NordVPN and PIA rows above both are. We could not re-fetch NordVPN's or PIA's API today, so either server may have been retired or re-addressed since 4 October. What we can say is narrower and certain: a server is named only when it is on a list we currently hold.
We also have a miss on a provider whose list we did fetch today. 91.90.123.29 sits in the same /24 as the listed Mullvad relay 91.90.123.2, but it is not on Mullvad's list. IPinfo's provider page showed it as its Mullvad example IP on 13 October. Our API returned is_vpn false, vpn_provider "none", score 12, allow. It may be an exit or an unlisted address next to a listed one; that is suggestive, not proof. Either way, a list match covers the listed address and nothing beside it.
The documented control shows the unnamed but detected case. 102.129.235.17, on AS834 IPXO, returned is_vpn true, vpn_provider "none", score 92, block, with known_vpn_server, openvpn_open and ipsec_open. An unnamed server is still caught when it completes an OpenVPN, WireGuard or IPsec handshake with our scanner; the hub post linked above covers the probes.
Common reasons a VPN IP stays unnamed:
- No public list. Some providers publish none, and a self-hosted VPN never appears on one.
- List unreachable. Four of the nine lists we pull block data centers, so we work from saved copies where we have them, and from gluetun.
- Rotation. A server can leave the list or change address after our last copy.
- It is a proxy, not a VPN. Proxies have no provider list to match; see datacenter, residential and mobile proxies.
iCloud Private Relay and Cloudflare WARP are not VPN providers in this sense. They get their own field, relay_provider, and their own policy, covered in iCloud Private Relay and Cloudflare WARP.
A named VPN is not a riskier VPN
The name says who runs the server; the score comes from the evidence, such as open handshake ports, hosting and abuse history. Some of the lowest scores in our sample went to named servers, and one of the highest went to an unnamed one.
| IP | vpn_provider | Score, action |
|---|---|---|
| 85.12.5.56 | PrivadoVPN | 36, review |
| 45.83.220.7 | Mullvad (31173 Services) | 46, review |
| 204.13.164.252 | Riseup | 48, review |
| 102.129.235.17 | none | 92, block |
Our bands are allow up to 25, review up to 50, step_up up to 75 and block above 75. PrivadoVPN's server answered no handshake probe in our data, so only known_vpn_server fired and it stayed in review. The unnamed server answered two. That is the right way round: a rule should weigh what we observed, not whose logo is on the server. The signal weights are on the how the score is built page.
Entry IPs, rotated servers and stale names
A provider list tells you the address the app connects to. For most servers in our sample, that same address answered our probes, but we verified only that listed addresses are named, not that every exit address a provider uses is on a list.
The field names say "in". Mullvad uses ipv4_addr_in, and AirVPN publishes four addresses per server as ip_v4_in1 to ip_v4_in4. Surfshark's list gives hostnames only, so someone has to resolve names to IPs before anything can match. Our 90 path does that for the server hostnames in gluetun's files. It is how FastestVPN's au-stream.jumptoserver.com, 46.102.153.134, got its name.
Lists also carry state you should read. Mullvad's list today marks 24 relays active: false, including se-mma-wg-101, 45.83.220.68, which our API still names "Mullvad" at 95. A listed server is a fact about the provider's fleet, not proof that the server carried traffic today. This is also why vendors' VPN IP counts disagree so widely. They count different things, such as servers, listed entry addresses, observed exit addresses or whole ranges, on different dates. Mullvad's own list is the only count we quote. We do not publish a refresh schedule for provider lists here; if you run the matcher yourself, fetch the list before each batch.
What to do with a provider name
Use the name for policy and investigation, not as a block switch. Key decisions on recommended_action and the evidence behind it, and key exceptions and reporting on the name.
| What you see | Action | Why |
|---|---|---|
Named VPN (vpn_provider set) | Follow recommended_action; use the name for allow-lists you choose, licensing logs and grouping abuse by operator | The name is attribution, not risk: PrivadoVPN scored 36, review, and Mullvad's Frankfurt server 100, block |
Unnamed VPN (is_vpn true, vpn_provider "none") | Treat it exactly like a named VPN at the same score | 102.129.235.17 scored 92 without a name |
Relay (is_relay true) | Allow and score the session | Relays are not VPN providers; they use relay_provider |
Clean (is_vpn false, no relay) | Allow unless other signals fire | No anonymizer evidence, though a listed server can drop out, as PIA's 91.90.122.25 did |
The usual mistake is the first row turned into a block rule, which turns a provider's customers into VPN detection false positives. Two checks to run on your own logs this week:
- Find rules keyed on the name. Search your rules for
vpn_provider. A rule like "block if a provider is named" lets the unnamed 92 through and blocks the named 36. Key on the action and the evidence instead, and match names by prefix. - Match your logs against one list. Feed the last 30 days of signup or login IPs to the Mullvad matcher and count the matches. Compare that with how many of those requests your rules declined, then spot-check a few in the IP lookup tool.
Frequently Asked Questions
Can you tell which VPN an IP address belongs to?
Yes, when the IP is on a server list the VPN provider publishes for its own apps. If it is on no list, you can usually still tell it is a VPN, but not whose.
Is there a list of NordVPN IP addresses?
NordVPN's apps read one from api.nordvpn.com, which gives each server's IP in a station field. On 13 October 2026 it did not answer requests from our network, so we used a saved copy.
Does WHOIS or reverse DNS show the VPN provider?
Rarely. Most VPN servers sit on rented hosting networks such as M247, so WHOIS and reverse DNS name the host. Even Mullvad's own Frankfurt range is registered to 31173 Services.
What does vpn_provider none mean?
The IP is on none of the server lists we hold. It does not mean the IP is not a VPN: check is_vpn and scoring.detection_methods.
Does a named VPN get a higher fraud score?
No. A listed PrivadoVPN server scored 36, review, while an unnamed VPN scored 92, block. The name says who runs the server; the score comes from the evidence.
Which VPN providers publish their server lists?
Mullvad, AirVPN, IVPN, PrivadoVPN and Riseup answered public requests from us on 13 October 2026. NordVPN, Surfshark, PIA and Windscribe publish lists for their apps but did not answer from our network.