Add the ProtonVPN server networks to the IP lookup (closes #236)
check / check (push) Failing after 1m43s

Adds the VPN list `protonvpn`, downloaded once a day. It shows in `flags.is_vpn` and `vpn_providers` with no other change.

Proton's `/vpn/logicals` answers 401 without a logged-in session, even with a current client's `x-pm-appversion`, so the list comes from the public ProtonVPN-IPs mirror. No request header is needed.

Judgement call: the mirror's /24 file, not its exact addresses. Its README says traffic leaves from unpublished addresses in those networks. The cost is that neighbouring addresses are listed too.

Model: opus-5-5
This commit is contained in:
clawbot committed 2026-11-10 11:20:38 +00:00
1 parent 28ef0275ba
commit 5713e6e181
6 files changed
+85 -1

No files matched your search

+17
View File
@@ -58,6 +58,8 @@ func parse(r io.Reader, format Format) (*netipx.IPSet, error) {
return parsePIA(r)
case FormatIVPNJSON:
return parseIVPN(r)
case FormatProtonVPN:
return parseProtonVPN(r)
default:
return nil, errUnknownFormat
}
@@ -329,6 +331,21 @@ func parseIVPN(r io.Reader) (*netipx.IPSet, error) {
return addressSet(texts)
}
// parseProtonVPN returns the networks in a ProtonVPN-IPs list. A file with no
// networks fails, because the service always has servers.
func parseProtonVPN(r io.Reader) (*netipx.IPSet, error) {
addresses, err := parseLines(r, addAddressOrNetwork)
if err != nil {
return nil, err
}
if len(addresses.Ranges()) == 0 {
return nil, errNoAddresses
}
return addresses, nil
}
// readJSON reads r to its end and decodes it, as one JSON document, into v.
func readJSON(r io.Reader, v any) error {
data, err := io.ReadAll(r)