feat(protonvpn): Wireguard support (#2390)

This commit is contained in:
Quentin McGaw 2024-08-03 16:10:35 +02:00 committed by GitHub
parent dea4080a7b
commit ac9446e296
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 9584 additions and 111 deletions

View File

@ -60,7 +60,7 @@ Lightweight swiss-knife-like VPN client to multiple VPN service providers
- Supports: **AirVPN**, **Cyberghost**, **ExpressVPN**, **FastestVPN**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad**, **NordVPN**, **Perfect Privacy**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **SlickVPN**, **Surfshark**, **TorGuard**, **VPNSecure.me**, **VPNUnlimited**, **Vyprvpn**, **WeVPN**, **Windscribe** servers
- Supports OpenVPN for all providers listed
- Supports Wireguard both kernelspace and userspace
- For **AirVPN**, **FastestVPN**, **Ivpn**, **Mullvad**, **NordVPN**, **Perfect privacy**, **Surfshark** and **Windscribe**
- For **AirVPN**, **FastestVPN**, **Ivpn**, **Mullvad**, **NordVPN**, **Perfect privacy**, **ProtonVPN**, **Surfshark** and **Windscribe**
- For **ProtonVPN**, **PureVPN**, **Torguard**, **VPN Unlimited** and **WeVPN** using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
- For custom Wireguard configurations using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
- More in progress, see [#134](https://github.com/qdm12/gluetun/issues/134)

View File

@ -39,6 +39,7 @@ func (p *Provider) validate(vpnType string, storage Storage) (err error) {
providers.Ivpn,
providers.Mullvad,
providers.Nordvpn,
providers.Protonvpn,
providers.Surfshark,
providers.Windscribe,
}

View File

@ -62,6 +62,7 @@ func (w Wireguard) validate(vpnProvider string, ipv6Supported bool) (err error)
providers.Ivpn,
providers.Mullvad,
providers.Nordvpn,
providers.Protonvpn,
providers.Surfshark,
providers.Windscribe,
) {
@ -173,10 +174,15 @@ func (w *Wireguard) overrideWith(other Wireguard) {
func (w *Wireguard) setDefaults(vpnProvider string) {
w.PrivateKey = gosettings.DefaultPointer(w.PrivateKey, "")
w.PreSharedKey = gosettings.DefaultPointer(w.PreSharedKey, "")
if vpnProvider == providers.Nordvpn {
switch vpnProvider {
case providers.Nordvpn:
defaultNordVPNAddress := netip.AddrFrom4([4]byte{10, 5, 0, 2})
defaultNordVPNPrefix := netip.PrefixFrom(defaultNordVPNAddress, defaultNordVPNAddress.BitLen())
w.Addresses = gosettings.DefaultSlice(w.Addresses, []netip.Prefix{defaultNordVPNPrefix})
case providers.Protonvpn:
defaultAddress := netip.AddrFrom4([4]byte{10, 2, 0, 2})
defaultPrefix := netip.PrefixFrom(defaultAddress, defaultAddress.BitLen())
w.Addresses = gosettings.DefaultSlice(w.Addresses, []netip.Prefix{defaultPrefix})
}
defaultAllowedIPs := []netip.Prefix{
netip.PrefixFrom(netip.IPv4Unspecified(), 0),

View File

@ -39,8 +39,8 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) {
// Validate EndpointIP
switch vpnProvider {
case providers.Airvpn, providers.Fastestvpn, providers.Ivpn,
providers.Mullvad, providers.Nordvpn, providers.Surfshark,
providers.Windscribe:
providers.Mullvad, providers.Nordvpn, providers.Protonvpn,
providers.Surfshark, providers.Windscribe:
// endpoint IP addresses are baked in
case providers.Custom:
if !w.EndpointIP.IsValid() || w.EndpointIP.IsUnspecified() {
@ -57,7 +57,8 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) {
return fmt.Errorf("%w", ErrWireguardEndpointPortNotSet)
}
// EndpointPort cannot be set
case providers.Fastestvpn, providers.Surfshark, providers.Nordvpn:
case providers.Fastestvpn, providers.Nordvpn,
providers.Protonvpn, providers.Surfshark:
if *w.EndpointPort != 0 {
return fmt.Errorf("%w", ErrWireguardEndpointPortSet)
}

View File

@ -21,7 +21,7 @@ type Connection struct {
PubKey string `json:"pubkey"`
// ServerName is used for PIA for port forwarding
ServerName string `json:"server_name,omitempty"`
// PortForward is used for PIA for port forwarding
// PortForward is used for PIA and ProtonVPN for port forwarding
PortForward bool `json:"port_forward"`
}

View File

@ -135,7 +135,7 @@ func getMarkdownHeaders(vpnProvider string) (headers []string) {
case providers.Privatevpn:
return []string{countryHeader, cityHeader, hostnameHeader}
case providers.Protonvpn:
return []string{countryHeader, regionHeader, cityHeader, hostnameHeader,
return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, vpnHeader,
freeHeader, portForwardHeader, secureHeader, torHeader}
case providers.Purevpn:
return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, tcpHeader, udpHeader}

View File

@ -8,7 +8,7 @@ import (
func (p *Provider) GetConnection(selection settings.ServerSelection, ipv6Supported bool) (
connection models.Connection, err error) {
defaults := utils.NewConnectionDefaults(443, 1194, 0) //nolint:gomnd
defaults := utils.NewConnectionDefaults(443, 1194, 51820) //nolint:gomnd
return utils.GetConnection(p.Name(),
p.storage, selection, defaults, ipv6Supported, p.randSource)
}

View File

@ -28,10 +28,11 @@ type logicalServer struct {
}
type physicalServer struct {
EntryIP netip.Addr `json:"EntryIP"`
ExitIP netip.Addr `json:"ExitIP"`
Domain string `json:"Domain"`
Status uint8 `json:"Status"`
EntryIP netip.Addr `json:"EntryIP"`
ExitIP netip.Addr `json:"ExitIP"`
Domain string `json:"Domain"`
Status uint8 `json:"Status"`
X25519PublicKey string `json:"X25519PublicKey"`
}
func fetchAPI(ctx context.Context, client *http.Client) (

View File

@ -7,7 +7,7 @@ import (
"github.com/qdm12/gluetun/internal/models"
)
type ipToServer map[string]models.Server
type ipToServers map[string][2]models.Server // first server is OpenVPN, second is Wireguard.
type features struct {
secureCore bool
@ -16,36 +16,50 @@ type features struct {
stream bool
}
func (its ipToServer) add(country, region, city, name, hostname string,
func (its ipToServers) add(country, region, city, name, hostname, wgPubKey string,
free bool, entryIP netip.Addr, features features) {
key := entryIP.String()
server, ok := its[key]
servers, ok := its[key]
if ok {
return
}
server.VPN = vpn.OpenVPN
server.Country = country
server.Region = region
server.City = city
server.ServerName = name
server.Hostname = hostname
server.Free = free
server.SecureCore = features.secureCore
server.Tor = features.tor
server.PortForward = features.p2p
server.Stream = features.stream
server.UDP = true
server.TCP = true
server.IPs = []netip.Addr{entryIP}
its[key] = server
baseServer := models.Server{
Country: country,
Region: region,
City: city,
ServerName: name,
Hostname: hostname,
Free: free,
SecureCore: features.secureCore,
Tor: features.tor,
PortForward: features.p2p,
Stream: features.stream,
IPs: []netip.Addr{entryIP},
}
openvpnServer := baseServer
openvpnServer.VPN = vpn.OpenVPN
openvpnServer.UDP = true
openvpnServer.TCP = true
servers[0] = openvpnServer
wireguardServer := baseServer
wireguardServer.VPN = vpn.Wireguard
wireguardServer.WgPubKey = wgPubKey
servers[1] = wireguardServer
its[key] = servers
}
func (its ipToServer) toServersSlice() (servers []models.Server) {
servers = make([]models.Server, 0, len(its))
for _, server := range its {
servers = append(servers, server)
func (its ipToServers) toServersSlice() (serversSlice []models.Server) {
const vpnProtocols = 2
serversSlice = make([]models.Server, 0, vpnProtocols*len(its))
for _, servers := range its {
serversSlice = append(serversSlice, servers[0], servers[1])
}
return servers
return serversSlice
}
func (its ipToServers) numberOfServers() int {
const serversPerIP = 2
return len(its) * serversPerIP
}

View File

@ -29,7 +29,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
common.ErrNotEnoughServers, count, minServers)
}
ipToServer := make(ipToServer, count)
ipToServer := make(ipToServers, count)
for _, logicalServer := range data.LogicalServers {
region := getStringValue(logicalServer.Region)
city := getStringValue(logicalServer.City)
@ -65,6 +65,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
hostname := physicalServer.Domain
entryIP := physicalServer.EntryIP
wgPubKey := physicalServer.X25519PublicKey
// Note: for multi-hop use the server name or hostname
// instead of the country
@ -74,11 +75,11 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
u.warner.Warn(warning)
}
ipToServer.add(country, region, city, name, hostname, free, entryIP, features)
ipToServer.add(country, region, city, name, hostname, wgPubKey, free, entryIP, features)
}
}
if len(ipToServer) < minServers {
if ipToServer.numberOfServers() < minServers {
return nil, fmt.Errorf("%w: %d and expected at least %d",
common.ErrNotEnoughServers, len(ipToServer), minServers)
}

File diff suppressed because it is too large Load Diff