Add the public VPN server lists, with is_vpn and vpn_providers (closes #235)
check / check (push) Successful in 1m36s

The IP lookup now checks Mullvad, NordVPN, Private Internet Access, IVPN and X4BNet's community list, each downloaded once a day. Each result has `flags.is_vpn` and `vpn_providers`.

Judgement call: X4BNet publishes IPv4 and IPv6 as two files, so they are two lists, `x4bnet` and `x4bnet_v6`.
Judgement call: Private Internet Access's signature is not read or checked.
Rule suppressed: `tagliatelle` on the structs holding the publishers' field names.

Model: opus-5-5
This commit is contained in:
clawbot committed 2026-11-10 10:56:24 +00:00
1 parent 3204b7ee4b
commit 601bc812b9
8 files changed
+584 -28

No files matched your search

+73 -1
View File
@@ -1,6 +1,9 @@
package iplist
import "time"
import (
"slices"
"time"
)
// TorExitsList is the name of the list of Tor exit nodes.
const TorExitsList = "tor_exits"
@@ -32,12 +35,20 @@ const (
// Onionoo sets no download limit:
// https://metrics.torproject.org/onionoo.html
torExitsInterval = time.Hour
// A VPN service's servers change slowly, so once a day is enough.
vpnListInterval = 24 * time.Hour
)
// Lists returns the public IP lists routewatch downloads. Each can be
// downloaded whole without an account or a key. Spamhaus merged its EDROP
// list into DROP, so DROP covers both.
func Lists() []List {
return slices.Concat(nonVPNLists(), vpnLists())
}
// nonVPNLists returns the public lists that are not lists of VPN servers.
func nonVPNLists() []List {
return []List{
{
Name: "dshield",
@@ -96,3 +107,64 @@ func Lists() []List {
},
}
}
// vpnLists returns the public lists of VPN servers. Their names are what
// vpn_providers reports.
func vpnLists() []List {
return []List{
{
Name: "ivpn",
Description: "A server of the IVPN service",
URL: "https://api.ivpn.net/v5/servers.json",
Interval: vpnListInterval,
Format: FormatIVPNJSON,
VPN: true,
},
{
Name: "mullvad",
Description: "A server of the Mullvad VPN service",
URL: "https://api.mullvad.net/www/relays/all/",
Interval: vpnListInterval,
Format: FormatMullvadJSON,
VPN: true,
},
{
Name: "nordvpn",
Description: "A server of the NordVPN service",
URL: "https://api.nordvpn.com/v1/servers?limit=0" +
"&fields[servers.station]&fields[servers.ipv6_station]" +
"&fields[servers.hostname]",
Interval: vpnListInterval,
Format: FormatNordVPNJSON,
VPN: true,
},
{
Name: "pia",
Description: "A server of the Private Internet Access VPN service",
URL: "https://serverlist.piaservers.net/vpninfo/servers/v6",
Interval: vpnListInterval,
Format: FormatPIAJSON,
VPN: true,
},
{
Name: "x4bnet",
Description: "In an IPv4 network of a VPN service, according to " +
"X4BNet's community list",
URL: "https://raw.githubusercontent.com/X4BNet/lists_vpn/main/" +
"output/vpn/ipv4.txt",
Interval: vpnListInterval,
Format: FormatLines,
VPN: true,
},
{
Name: "x4bnet_v6",
Description: "In an IPv6 network of a VPN service, according to " +
"X4BNet's community list",
URL: "https://raw.githubusercontent.com/X4BNet/lists_vpn/main/" +
"output/vpn/ipv6.txt",
Interval: vpnListInterval,
Format: FormatLines,
VPN: true,
},
}
}