Feature: FastestVPN support (#383)
This commit is contained in:
3
.github/labels.yml
vendored
3
.github/labels.yml
vendored
@@ -21,6 +21,9 @@
|
|||||||
- name: ":cloud: HideMyAss"
|
- name: ":cloud: HideMyAss"
|
||||||
color: "cfe8d4"
|
color: "cfe8d4"
|
||||||
description: ""
|
description: ""
|
||||||
|
- name: ":cloud: FastestVPN"
|
||||||
|
color: "cfe8d4"
|
||||||
|
description: ""
|
||||||
- name: ":cloud: Mullvad"
|
- name: ":cloud: Mullvad"
|
||||||
color: "cfe8d4"
|
color: "cfe8d4"
|
||||||
description: ""
|
description: ""
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Gluetun VPN client
|
# Gluetun VPN client
|
||||||
|
|
||||||
*Lightweight swiss-knife-like VPN client to tunnel to Cyberghost,
|
*Lightweight swiss-knife-like VPN client to tunnel to Cyberghost, FastestVPN,
|
||||||
HideMyAss, Mullvad, NordVPN, Privado, Private Internet Access, PrivateVPN,
|
HideMyAss, Mullvad, NordVPN, Privado, Private Internet Access, PrivateVPN,
|
||||||
PureVPN, Surfshark, TorGuard, VyprVPN and Windscribe VPN servers
|
PureVPN, Surfshark, TorGuard, VyprVPN and Windscribe VPN servers
|
||||||
using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
||||||
@@ -39,7 +39,7 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Based on Alpine 3.12 for a small Docker image of 52MB
|
- Based on Alpine 3.12 for a small Docker image of 52MB
|
||||||
- Supports: **Cyberghost**, **HideMyAss**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **Vyprvpn**, **Windscribe**, servers
|
- Supports: **Cyberghost**, **FastestVPN**, **HideMyAss**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **Vyprvpn**, **Windscribe**, servers
|
||||||
- Supports Openvpn only for now
|
- Supports Openvpn only for now
|
||||||
- DNS over TLS baked in with service provider(s) of your choice
|
- DNS over TLS baked in with service provider(s) of your choice
|
||||||
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
|
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ func (c *cli) Update(ctx context.Context, args []string, os os.OS) error {
|
|||||||
flagSet.BoolVar(&options.Stdout, "stdout", false, "Write results to console to modify the program (for maintainers)")
|
flagSet.BoolVar(&options.Stdout, "stdout", false, "Write results to console to modify the program (for maintainers)")
|
||||||
flagSet.StringVar(&options.DNSAddress, "dns", "8.8.8.8", "DNS resolver address to use")
|
flagSet.StringVar(&options.DNSAddress, "dns", "8.8.8.8", "DNS resolver address to use")
|
||||||
flagSet.BoolVar(&options.Cyberghost, "cyberghost", false, "Update Cyberghost servers")
|
flagSet.BoolVar(&options.Cyberghost, "cyberghost", false, "Update Cyberghost servers")
|
||||||
|
flagSet.BoolVar(&options.Fastestvpn, "fastestvpn", false, "Update FastestVPN servers")
|
||||||
flagSet.BoolVar(&options.HideMyAss, "hidemyass", false, "Update HideMyAss servers")
|
flagSet.BoolVar(&options.HideMyAss, "hidemyass", false, "Update HideMyAss servers")
|
||||||
flagSet.BoolVar(&options.Mullvad, "mullvad", false, "Update Mullvad servers")
|
flagSet.BoolVar(&options.Mullvad, "mullvad", false, "Update Mullvad servers")
|
||||||
flagSet.BoolVar(&options.Nordvpn, "nordvpn", false, "Update Nordvpn servers")
|
flagSet.BoolVar(&options.Nordvpn, "nordvpn", false, "Update Nordvpn servers")
|
||||||
|
|||||||
43
internal/configuration/fastestvpn.go
Normal file
43
internal/configuration/fastestvpn.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) fastestvpnLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Hostnames) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.Countries) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readFastestvpn(r reader) (err error) {
|
||||||
|
settings.Name = constants.Fastestvpn
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.FastestvpnHostnameChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.FastestvpnCountriesChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -56,8 +56,8 @@ var (
|
|||||||
|
|
||||||
func (settings *OpenVPN) read(r reader) (err error) {
|
func (settings *OpenVPN) read(r reader) (err error) {
|
||||||
vpnsp, err := r.env.Inside("VPNSP", []string{
|
vpnsp, err := r.env.Inside("VPNSP", []string{
|
||||||
"cyberghost", "hidemyass", "mullvad", "nordvpn", "privado",
|
"cyberghost", "fastestvpn", "hidemyass", "mullvad", "nordvpn",
|
||||||
"pia", "private internet access", "privatevpn",
|
"privado", "pia", "private internet access", "privatevpn",
|
||||||
"purevpn", "surfshark", "torguard", "vyprvpn", "windscribe"},
|
"purevpn", "surfshark", "torguard", "vyprvpn", "windscribe"},
|
||||||
params.Default("private internet access"))
|
params.Default("private internet access"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -115,6 +115,8 @@ func (settings *OpenVPN) read(r reader) (err error) {
|
|||||||
switch settings.Provider.Name {
|
switch settings.Provider.Name {
|
||||||
case constants.Cyberghost:
|
case constants.Cyberghost:
|
||||||
readProvider = settings.Provider.readCyberghost
|
readProvider = settings.Provider.readCyberghost
|
||||||
|
case constants.Fastestvpn:
|
||||||
|
readProvider = settings.Provider.readFastestvpn
|
||||||
case constants.HideMyAss:
|
case constants.HideMyAss:
|
||||||
readProvider = settings.Provider.readHideMyAss
|
readProvider = settings.Provider.readHideMyAss
|
||||||
case constants.Mullvad:
|
case constants.Mullvad:
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ func (settings *Provider) lines() (lines []string) {
|
|||||||
switch strings.ToLower(settings.Name) {
|
switch strings.ToLower(settings.Name) {
|
||||||
case "cyberghost":
|
case "cyberghost":
|
||||||
providerLines = settings.cyberghostLines()
|
providerLines = settings.cyberghostLines()
|
||||||
|
case "fastestvpn":
|
||||||
|
providerLines = settings.fastestvpnLines()
|
||||||
case "hidemyass":
|
case "hidemyass":
|
||||||
providerLines = settings.hideMyAssLines()
|
providerLines = settings.hideMyAssLines()
|
||||||
case "mullvad":
|
case "mullvad":
|
||||||
|
|||||||
@@ -42,6 +42,22 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
" |--Client certificate is set",
|
" |--Client certificate is set",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"fastestvpn": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Fastestvpn,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Hostnames: []string{"a", "b"},
|
||||||
|
Countries: []string{"c", "d"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Fastestvpn settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Hostnames: a, b",
|
||||||
|
" |--Countries: c, d",
|
||||||
|
},
|
||||||
|
},
|
||||||
"hidemyass": {
|
"hidemyass": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.HideMyAss,
|
Name: constants.HideMyAss,
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ type ServerSelection struct {
|
|||||||
// Cyberghost
|
// Cyberghost
|
||||||
Group string `json:"group"`
|
Group string `json:"group"`
|
||||||
|
|
||||||
Countries []string `json:"countries"` // HideMyAss, Mullvad, PrivateVPN, PureVPN
|
Countries []string `json:"countries"` // Fastestvpn, HideMyAss, Mullvad, PrivateVPN, PureVPN
|
||||||
Cities []string `json:"cities"` // HideMyAss, Mullvad, PrivateVPN, PureVPN, Windscribe
|
Cities []string `json:"cities"` // HideMyAss, Mullvad, PrivateVPN, PureVPN, Windscribe
|
||||||
Hostnames []string `json:"hostnames"` // HideMyAss, PrivateVPN, Windscribe, Privado
|
Hostnames []string `json:"hostnames"` // Fastestvpn, HideMyAss, PrivateVPN, Windscribe, Privado
|
||||||
|
|
||||||
// Mullvad
|
// Mullvad
|
||||||
ISPs []string `json:"isps"`
|
ISPs []string `json:"isps"`
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ type Updater struct {
|
|||||||
Period time.Duration `json:"period"`
|
Period time.Duration `json:"period"`
|
||||||
DNSAddress string `json:"dns_address"`
|
DNSAddress string `json:"dns_address"`
|
||||||
Cyberghost bool `json:"cyberghost"`
|
Cyberghost bool `json:"cyberghost"`
|
||||||
|
Fastestvpn bool `json:"fastestvpn"`
|
||||||
HideMyAss bool `json:"hidemyass"`
|
HideMyAss bool `json:"hidemyass"`
|
||||||
Mullvad bool `json:"mullvad"`
|
Mullvad bool `json:"mullvad"`
|
||||||
Nordvpn bool `json:"nordvpn"`
|
Nordvpn bool `json:"nordvpn"`
|
||||||
|
|||||||
117
internal/constants/fastestvpn.go
Normal file
117
internal/constants/fastestvpn.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package constants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
|
const (
|
||||||
|
FastestvpnCertificate = "MIIFQjCCAyqgAwIBAgIIUfxepT+rr8owDQYJKoZIhvcNAQEMBQAwPzELMAkGA1UEBhMCS1kxEzARBgNVBAoTCkZhc3Rlc3RWUE4xGzAZBgNVBAMTEkZhc3Rlc3RWUE4gUm9vdCBDQTAeFw0xNzA5MTYwMDAxNDZaFw0yNzA5MTQwMDAxNDZaMD8xCzAJBgNVBAYTAktZMRMwEQYDVQQKEwpGYXN0ZXN0VlBOMRswGQYDVQQDExJGYXN0ZXN0VlBOIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC1Xj+WfPTozFynFqc+c3CVrggIllaXEl5bY5VgFynXkqCTM6lSrfC4pNjGXUbqWe6RnGJbM4/6kUn+lQDjFSQV1rzP2eDS8+r5+X2WXh4AoeNRUWhvSG+HiHD/B2EFK+Nd5BRSdUjpKWAtsCmT2bBt7nT0jN1OdeNrLJeyF8siAqv/oQzKznF9aIe/N01b2M8ZOFTzoXi2fZAckgGWui8NB/lzkVIJqSkAPRL8qiJLuRCPVOX1PFD8vV//R8/QumtfbcYBMo6vCk2HmWdrh5OQHPxb3KJtbtG+Z1j8x6HGEAe17djYepBiRMyCEQvYgfD6tvFylc4IquhqE9yaP60PJod5TxpWnRQ6HIGSeBm+S+rYSMalTZ8+pUqOOA+IQCYpfpx6EKIJL/VsW2C7cXdvudxDhXPI5lR/QidCb9Ohq3WkfxXaYwzrngdg2avmNqId9R4KESuM9GoHW0dszfyBCh5wYfeaffMElfDam3B92NUwyhZwtIiv623WVXY9PPz+EDjSJsIAu2Vi1vdJyA4nD4k9Lwmx/1zTc/UaYVLsiBqL2WdfvFTeoWoV+dNxQXSEPhB8gwi8x4O4lZW0cwVy/6fa8KMY8gZbcbSTr7U5bRERfW8l+jY+mYKQ/M/ccgpxaHiw1/+4LWfbJQ7VhJJrTyN0C36FQzY1URkSXg+53wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmVEL4x6xdCqiqu2OBLs27EA8xGYwDQYJKoZIhvcNAQEMBQADggIBABCpITvO1+R4T9v2+onHiFxU5JjtCZ0zkXqRCMp/Z0UIYbeo1p07pZCPAUjBfGPCkAaR++OiG9sysALdJf8Y6HQKcyuAcWUqQnaIhoZ2JcAP7EKq7uCqsMhcYZD/j3O/3RPtSW5UOx6ItDU+Ua0t9Edho9whNw0VQXmo1JjYoP3FzPjuKoDWTSO1q5eYlZfwcTcs55O2shNkFafPg/6cCm5j6v9nyHrM3sk4LjkrBPUXVx2m/aoz219t8O9Ha9/CdMKXsPO/8gTUzpgnzSgPnGnBmi5xr1nspVN8X4E2f3D+DKqBim3YgslD68NcuFQvJ0/BxZzWVbrr+QXoyzaiCgXuogpIDc2bB6oRXqFnHNz36d4QJmJdWdSaijiS/peQ6EOPgOZ1GuObLWlDCBZLNeQ+N6QaiJxVO4XUj/s22i1IRtwdz84TRHrbWiIpEymsqmb/Ep5r4xV5d6+791axclfOTH7tQrY/SbPtTJI4OEgNekI8YfadQifpelF82MsFFEZuaQn0lj+fvLGtE/zKh3OdLTxRc5TAgBB+0T81+JQosygNr2aFFG0hxar1eyw/gLeG8H+7Ie50pyPvXO4OgB6Key8rSExpilQXlvAT1qX0qS3/K1i/9QkSE9ftIPT6vtwLV2sVQzfyanI4IZgWC6ryhvNLsRn0NFnQclor0+aq"
|
||||||
|
FastestvpnOpenvpnStaticKeyV1 = "697fe793b32cb5091d30f2326d5d124a9412e93d0a44ef7361395d76528fcbfc82c3859dccea70a93cfa8fae409709bff75f844cf5ff0c237f426d0c20969233db0e706edb6bdf195ec3dc11b3f76bc807a77e74662d9a800c8cd1144ebb67b7f0d3f1281d1baf522bfe03b7c3f963b1364fc0769400e413b61ca7b43ab19fac9e0f77e41efd4bda7fd77b1de2d7d7855cbbe3e620cecceac72c21a825b243e651f44d90e290e09c3ad650de8fca99c858bc7caad584bc69b11e5c9fd9381c69c505ec487a65912c672d83ed0113b5a74ddfbd3ab33b3683cec593557520a72c4d6cce46111f56f3396cc3ce7183edce553c68ea0796cf6c4375fad00aaa2a42"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FastestvpnCountriesChoices() (choices []string) {
|
||||||
|
servers := FastestvpnServers()
|
||||||
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].Country
|
||||||
|
}
|
||||||
|
return choices
|
||||||
|
}
|
||||||
|
|
||||||
|
func FastestvpnHostnameChoices() (choices []string) {
|
||||||
|
servers := FastestvpnServers()
|
||||||
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].Hostname
|
||||||
|
}
|
||||||
|
return choices
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastestvpnServers returns the list of all VPN servers for FastestVPN.
|
||||||
|
//nolint:lll
|
||||||
|
func FastestvpnServers() []models.FastestvpnServer {
|
||||||
|
return []models.FastestvpnServer{
|
||||||
|
{Country: "Australia", Hostname: "au-sd-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{139, 99, 149, 10}}},
|
||||||
|
{Country: "Australia", Hostname: "au-sd-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{139, 99, 149, 10}}},
|
||||||
|
{Country: "Australia", Hostname: "au2-sd-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{139, 99, 131, 126}}},
|
||||||
|
{Country: "Australia", Hostname: "au2-sd-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{139, 99, 131, 126}}},
|
||||||
|
{Country: "Austria", Hostname: "at.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{86, 107, 21, 146}}},
|
||||||
|
{Country: "Belgium", Hostname: "bel1.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{217, 138, 211, 67}}},
|
||||||
|
{Country: "Belgium", Hostname: "bel2.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{217, 138, 211, 68}}},
|
||||||
|
{Country: "Belgium", Hostname: "bel3.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{217, 138, 211, 69}}},
|
||||||
|
{Country: "Brazil", Hostname: "br-jp-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{45, 179, 88, 31}}},
|
||||||
|
{Country: "Brazil", Hostname: "br-jp-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{45, 179, 88, 31}}},
|
||||||
|
{Country: "Bulgaria", Hostname: "bg.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{37, 46, 114, 46}}},
|
||||||
|
{Country: "Canada", Hostname: "canada.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{158, 69, 26, 75}}},
|
||||||
|
{Country: "Czechia", Hostname: "cz-pr-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{185, 216, 35, 218}}},
|
||||||
|
{Country: "Czechia", Hostname: "cz-pr-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{185, 216, 35, 218}}},
|
||||||
|
{Country: "Denmark", Hostname: "dk.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{185, 245, 84, 70}}},
|
||||||
|
{Country: "Finland", Hostname: "fi-hs-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{194, 34, 132, 19}}},
|
||||||
|
{Country: "Finland", Hostname: "fi-hs-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{194, 34, 132, 19}}},
|
||||||
|
{Country: "France", Hostname: "fr-rb-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{37, 59, 172, 213}}},
|
||||||
|
{Country: "France", Hostname: "fr-rb-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{37, 59, 172, 213}}},
|
||||||
|
{Country: "Germany", Hostname: "de1.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{83, 143, 245, 254}}},
|
||||||
|
{Country: "Hong.Kong", Hostname: "hk-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{64, 120, 88, 115}}},
|
||||||
|
{Country: "Hong.Kong", Hostname: "hk-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{64, 120, 88, 115}}},
|
||||||
|
{Country: "India", Hostname: "in50.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{103, 104, 74, 32}}},
|
||||||
|
{Country: "India-Stream", Hostname: "in-stream.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{103, 104, 74, 30}}},
|
||||||
|
{Country: "Italy", Hostname: "it.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{37, 120, 207, 90}}},
|
||||||
|
{Country: "Japan", Hostname: "jp-tk-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{202, 239, 38, 147}}},
|
||||||
|
{Country: "Japan", Hostname: "jp-tk-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{202, 239, 38, 147}}},
|
||||||
|
{Country: "Luxembourg", Hostname: "lux1.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{94, 242, 195, 147}}},
|
||||||
|
{Country: "Netherlands", Hostname: "nl.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{213, 5, 64, 22}}},
|
||||||
|
{Country: "Netherlands", Hostname: "nl2.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{89, 46, 223, 251}}},
|
||||||
|
{Country: "Netherlands", Hostname: "nl3.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{89, 46, 223, 252}}},
|
||||||
|
{Country: "Norway", Hostname: "nr-ol-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{185, 90, 61, 20}}},
|
||||||
|
{Country: "Norway", Hostname: "nr-ol-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{185, 90, 61, 20}}},
|
||||||
|
{Country: "Poland", Hostname: "pl2.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{194, 15, 196, 117}}},
|
||||||
|
{Country: "Portugal", Hostname: "pt.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{185, 90, 57, 146}}},
|
||||||
|
{Country: "Romania", Hostname: "ro.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{91, 199, 50, 131}}},
|
||||||
|
{Country: "Russia", Hostname: "russia.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{95, 213, 193, 52}}},
|
||||||
|
{Country: "Serbia", Hostname: "rs.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{37, 46, 115, 246}}},
|
||||||
|
{Country: "Singapore", Hostname: "sg-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{209, 58, 174, 195}}},
|
||||||
|
{Country: "Singapore", Hostname: "sg-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{209, 58, 174, 195}}},
|
||||||
|
{Country: "South.Korea", Hostname: "kr-so-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{103, 249, 31, 36}}},
|
||||||
|
{Country: "South.Korea", Hostname: "kr-so-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{103, 249, 31, 36}}},
|
||||||
|
{Country: "Spain", Hostname: "es-bl-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{193, 148, 19, 155}}},
|
||||||
|
{Country: "Spain", Hostname: "es-bl-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{193, 148, 19, 155}}},
|
||||||
|
{Country: "Sweden", Hostname: "se-st-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{128, 127, 104, 200}}},
|
||||||
|
{Country: "Sweden", Hostname: "se-st-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{128, 127, 104, 201}}},
|
||||||
|
{Country: "Sweden", Hostname: "se2.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{79, 142, 76, 142}}},
|
||||||
|
{Country: "Switzerland", Hostname: "ch-zr-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{82, 102, 24, 254}}},
|
||||||
|
{Country: "Switzerland", Hostname: "ch-zr-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{82, 102, 24, 254}}},
|
||||||
|
{Country: "Turkey", Hostname: "tr-iz-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{185, 123, 102, 57}}},
|
||||||
|
{Country: "Turkey", Hostname: "tr.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{185, 123, 102, 57}}},
|
||||||
|
{Country: "UAE-Dubai", Hostname: "ue-db-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{45, 9, 249, 110}}},
|
||||||
|
{Country: "UAE-Dubai", Hostname: "ue-db-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{45, 9, 249, 110}}},
|
||||||
|
{Country: "UK", Hostname: "uk.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{5, 226, 139, 143}}},
|
||||||
|
{Country: "UK", Hostname: "uk6.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{5, 226, 139, 148}}},
|
||||||
|
{Country: "UK-Stream", Hostname: "uk-stream.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{195, 206, 169, 171}}},
|
||||||
|
{Country: "US-Atlanta", Hostname: "us-at-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{23, 82, 10, 205}}},
|
||||||
|
{Country: "US-Atlanta", Hostname: "us-at-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{23, 82, 10, 205}}},
|
||||||
|
{Country: "US-Charlotte", Hostname: "us-cf-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{192, 154, 253, 6}}},
|
||||||
|
{Country: "US-Charlotte", Hostname: "us-cf-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{192, 154, 253, 6}}},
|
||||||
|
{Country: "US-Chicago", Hostname: "us-ch1.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{174, 34, 154, 209}}},
|
||||||
|
{Country: "US-Chicago", Hostname: "us-ch2.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{174, 34, 154, 207}}},
|
||||||
|
{Country: "US-Dallas", Hostname: "us-dl-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{74, 63, 219, 202}}},
|
||||||
|
{Country: "US-Dallas", Hostname: "us-dl-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{74, 63, 219, 202}}},
|
||||||
|
{Country: "US-Denver", Hostname: "us-dv1.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{173, 248, 157, 107}}},
|
||||||
|
{Country: "US-Los.Angeles", Hostname: "us-la-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{64, 31, 35, 222}}},
|
||||||
|
{Country: "US-Los.Angeles", Hostname: "us-la-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{64, 31, 35, 222}}},
|
||||||
|
{Country: "US-Miami", Hostname: "us-mi-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{162, 255, 138, 231}}},
|
||||||
|
{Country: "US-Miami", Hostname: "us-mi-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{162, 255, 138, 232}}},
|
||||||
|
{Country: "US-Netflix", Hostname: "netflix.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{37, 59, 172, 215}}},
|
||||||
|
{Country: "US-New.York", Hostname: "us-ny-ovtcp-01.jumptoserver.com", UDP: false, TCP: true, IPs: []net.IP{{38, 132, 102, 107}}},
|
||||||
|
{Country: "US-New.York", Hostname: "us-ny-ovudp-01.jumptoserver.com", UDP: true, TCP: false, IPs: []net.IP{{38, 132, 102, 107}}},
|
||||||
|
{Country: "US-Phoenix", Hostname: "us-ph1.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{23, 83, 184, 71}}},
|
||||||
|
{Country: "US-Seattle", Hostname: "us-se1.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{23, 82, 33, 99}}},
|
||||||
|
{Country: "US-St.Louis", Hostname: "us-st1.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{148, 72, 173, 28}}},
|
||||||
|
{Country: "US-St.Louis", Hostname: "us-st3.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{148, 72, 173, 30}}},
|
||||||
|
{Country: "US-St.Louis", Hostname: "us-st4.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{148, 72, 173, 31}}},
|
||||||
|
{Country: "US-St.Louis", Hostname: "us-st5.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{148, 72, 173, 32}}},
|
||||||
|
{Country: "US-Washington", Hostname: "us-wt.jumptoserver.com", UDP: true, TCP: true, IPs: []net.IP{{23, 82, 15, 90}}},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,11 @@ func GetAllServers() (allServers models.AllServers) {
|
|||||||
Timestamp: 1612031135, // latest takes precedence
|
Timestamp: 1612031135, // latest takes precedence
|
||||||
Servers: CyberghostServers(),
|
Servers: CyberghostServers(),
|
||||||
},
|
},
|
||||||
|
Fastestvpn: models.FastestvpnServers{
|
||||||
|
Version: 1,
|
||||||
|
Timestamp: 1613323814,
|
||||||
|
Servers: FastestvpnServers(),
|
||||||
|
},
|
||||||
HideMyAss: models.HideMyAssServers{
|
HideMyAss: models.HideMyAssServers{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Timestamp: 1614562368,
|
Timestamp: 1614562368,
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ func Test_versions(t *testing.T) {
|
|||||||
version: allServers.Cyberghost.Version,
|
version: allServers.Cyberghost.Version,
|
||||||
digest: "fd6242bb",
|
digest: "fd6242bb",
|
||||||
},
|
},
|
||||||
|
"Fastestvpn": {
|
||||||
|
model: models.FastestvpnServer{},
|
||||||
|
version: allServers.Fastestvpn.Version,
|
||||||
|
digest: "8825919b",
|
||||||
|
},
|
||||||
"HideMyAss": {
|
"HideMyAss": {
|
||||||
model: models.HideMyAssServer{},
|
model: models.HideMyAssServer{},
|
||||||
version: allServers.HideMyAss.Version,
|
version: allServers.HideMyAss.Version,
|
||||||
@@ -135,6 +140,11 @@ func Test_timestamps(t *testing.T) {
|
|||||||
timestamp: allServers.Cyberghost.Timestamp,
|
timestamp: allServers.Cyberghost.Timestamp,
|
||||||
digest: "5d3a8cbf",
|
digest: "5d3a8cbf",
|
||||||
},
|
},
|
||||||
|
"Fastestvpn": {
|
||||||
|
servers: allServers.Fastestvpn.Version,
|
||||||
|
timestamp: allServers.Fastestvpn.Timestamp,
|
||||||
|
digest: "da65734a",
|
||||||
|
},
|
||||||
"HideMyAss": {
|
"HideMyAss": {
|
||||||
servers: allServers.HideMyAss.Servers,
|
servers: allServers.HideMyAss.Servers,
|
||||||
timestamp: allServers.HideMyAss.Timestamp,
|
timestamp: allServers.HideMyAss.Timestamp,
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package constants
|
|||||||
const (
|
const (
|
||||||
// Cyberghost is a VPN provider.
|
// Cyberghost is a VPN provider.
|
||||||
Cyberghost = "cyberghost"
|
Cyberghost = "cyberghost"
|
||||||
|
// Fastestvpn is a VPN provider.
|
||||||
|
Fastestvpn = "fastestvpn"
|
||||||
// HideMyAss is a VPN provider.
|
// HideMyAss is a VPN provider.
|
||||||
HideMyAss = "hidemyass"
|
HideMyAss = "hidemyass"
|
||||||
// Mullvad is a VPN provider.
|
// Mullvad is a VPN provider.
|
||||||
|
|||||||
@@ -17,6 +17,19 @@ func (s *CyberghostServer) String() string {
|
|||||||
return fmt.Sprintf("{Region: %q, Group: %q, IPs: %s}", s.Region, s.Group, goStringifyIPs(s.IPs))
|
return fmt.Sprintf("{Region: %q, Group: %q, IPs: %s}", s.Region, s.Group, goStringifyIPs(s.IPs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FastestvpnServer struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
TCP bool `json:"tcp"`
|
||||||
|
UDP bool `json:"udp"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
IPs []net.IP `json:"ips"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FastestvpnServer) String() string {
|
||||||
|
return fmt.Sprintf("{Country: %q, Hostname: %q, UDP: %t, TCP: %t, IPs: %s}",
|
||||||
|
s.Country, s.Hostname, s.UDP, s.TCP, goStringifyIPs(s.IPs))
|
||||||
|
}
|
||||||
|
|
||||||
type HideMyAssServer struct {
|
type HideMyAssServer struct {
|
||||||
Country string `json:"country"`
|
Country string `json:"country"`
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
@@ -83,6 +96,18 @@ func (p *PIAServer) String() string {
|
|||||||
p.Region, p.ServerName, p.TCP, p.UDP, p.PortForward, goStringifyIP(p.IP))
|
p.Region, p.ServerName, p.TCP, p.UDP, p.PortForward, goStringifyIP(p.IP))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PrivatevpnServer struct {
|
||||||
|
Country string `json:"country"`
|
||||||
|
City string `json:"city"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
IPs []net.IP `json:"ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PrivatevpnServer) String() string {
|
||||||
|
return fmt.Sprintf("{Country: %q, City: %q, Hostname: %q, IPs: %s}",
|
||||||
|
s.Country, s.City, s.Hostname, goStringifyIPs(s.IPs))
|
||||||
|
}
|
||||||
|
|
||||||
type PurevpnServer struct {
|
type PurevpnServer struct {
|
||||||
Country string `json:"country"`
|
Country string `json:"country"`
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
@@ -137,18 +162,6 @@ func (s *WindscribeServer) String() string {
|
|||||||
s.Region, s.City, s.Hostname, goStringifyIP(s.IP))
|
s.Region, s.City, s.Hostname, goStringifyIP(s.IP))
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrivatevpnServer struct {
|
|
||||||
Country string `json:"country"`
|
|
||||||
City string `json:"city"`
|
|
||||||
Hostname string `json:"hostname"`
|
|
||||||
IPs []net.IP `json:"ip"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PrivatevpnServer) String() string {
|
|
||||||
return fmt.Sprintf("{Country: %q, City: %q, Hostname: %q, IPs: %s}",
|
|
||||||
s.Country, s.City, s.Hostname, goStringifyIPs(s.IPs))
|
|
||||||
}
|
|
||||||
|
|
||||||
func goStringifyIP(ip net.IP) string {
|
func goStringifyIP(ip net.IP) string {
|
||||||
s := fmt.Sprintf("%#v", ip)
|
s := fmt.Sprintf("%#v", ip)
|
||||||
s = strings.TrimSuffix(strings.TrimPrefix(s, "net.IP{"), "}")
|
s = strings.TrimSuffix(strings.TrimPrefix(s, "net.IP{"), "}")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package models
|
|||||||
type AllServers struct {
|
type AllServers struct {
|
||||||
Version uint16 `json:"version"`
|
Version uint16 `json:"version"`
|
||||||
Cyberghost CyberghostServers `json:"cyberghost"`
|
Cyberghost CyberghostServers `json:"cyberghost"`
|
||||||
|
Fastestvpn FastestvpnServers `json:"fastestvpn"`
|
||||||
HideMyAss HideMyAssServers `json:"hidemyass"`
|
HideMyAss HideMyAssServers `json:"hidemyass"`
|
||||||
Mullvad MullvadServers `json:"mullvad"`
|
Mullvad MullvadServers `json:"mullvad"`
|
||||||
Nordvpn NordvpnServers `json:"nordvpn"`
|
Nordvpn NordvpnServers `json:"nordvpn"`
|
||||||
@@ -18,6 +19,7 @@ type AllServers struct {
|
|||||||
|
|
||||||
func (a *AllServers) Count() int {
|
func (a *AllServers) Count() int {
|
||||||
return len(a.Cyberghost.Servers) +
|
return len(a.Cyberghost.Servers) +
|
||||||
|
len(a.Fastestvpn.Servers) +
|
||||||
len(a.HideMyAss.Servers) +
|
len(a.HideMyAss.Servers) +
|
||||||
len(a.Mullvad.Servers) +
|
len(a.Mullvad.Servers) +
|
||||||
len(a.Nordvpn.Servers) +
|
len(a.Nordvpn.Servers) +
|
||||||
@@ -36,6 +38,11 @@ type CyberghostServers struct {
|
|||||||
Timestamp int64 `json:"timestamp"`
|
Timestamp int64 `json:"timestamp"`
|
||||||
Servers []CyberghostServer `json:"servers"`
|
Servers []CyberghostServer `json:"servers"`
|
||||||
}
|
}
|
||||||
|
type FastestvpnServers struct {
|
||||||
|
Version uint16 `json:"version"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
Servers []FastestvpnServer `json:"servers"`
|
||||||
|
}
|
||||||
type HideMyAssServers struct {
|
type HideMyAssServers struct {
|
||||||
Version uint16 `json:"version"`
|
Version uint16 `json:"version"`
|
||||||
Timestamp int64 `json:"timestamp"`
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
|||||||
170
internal/provider/fastestvpn.go
Normal file
170
internal/provider/fastestvpn.go
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
"github.com/qdm12/golibs/os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fastestvpn struct {
|
||||||
|
servers []models.FastestvpnServer
|
||||||
|
randSource rand.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFastestvpn(servers []models.FastestvpnServer, timeNow timeNowFunc) *fastestvpn {
|
||||||
|
return &fastestvpn{
|
||||||
|
servers: servers,
|
||||||
|
randSource: rand.NewSource(timeNow().UnixNano()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fastestvpn) filterServers(countries, hostnames []string, protocol string) (servers []models.FastestvpnServer) {
|
||||||
|
var tcp, udp bool
|
||||||
|
if protocol == "tcp" {
|
||||||
|
tcp = true
|
||||||
|
} else {
|
||||||
|
udp = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, server := range f.servers {
|
||||||
|
switch {
|
||||||
|
case filterByPossibilities(server.Country, countries):
|
||||||
|
case filterByPossibilities(server.Hostname, hostnames):
|
||||||
|
case tcp && !server.TCP:
|
||||||
|
case udp && !server.UDP:
|
||||||
|
default:
|
||||||
|
servers = append(servers, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fastestvpn) notFoundErr(selection configuration.ServerSelection) error {
|
||||||
|
message := "no server found for protocol " + selection.Protocol
|
||||||
|
|
||||||
|
if len(selection.Hostnames) > 0 {
|
||||||
|
message += " + hostnames " + commaJoin(selection.Hostnames)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selection.Countries) > 0 {
|
||||||
|
message += " + countries " + commaJoin(selection.Countries)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fastestvpn) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
|
var port uint16 = 4443
|
||||||
|
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
return models.OpenVPNConnection{IP: selection.TargetIP, Port: port, Protocol: selection.Protocol}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
servers := f.filterServers(selection.Countries, selection.Hostnames, selection.Protocol)
|
||||||
|
if len(servers) == 0 {
|
||||||
|
return connection, f.notFoundErr(selection)
|
||||||
|
}
|
||||||
|
|
||||||
|
var connections []models.OpenVPNConnection
|
||||||
|
for _, server := range servers {
|
||||||
|
for _, IP := range server.IPs {
|
||||||
|
connection := models.OpenVPNConnection{
|
||||||
|
IP: IP,
|
||||||
|
Port: port,
|
||||||
|
Protocol: selection.Protocol,
|
||||||
|
}
|
||||||
|
connections = append(connections, connection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pickRandomConnection(connections, f.randSource), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fastestvpn) BuildConf(connection models.OpenVPNConnection,
|
||||||
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
|
if len(settings.Cipher) == 0 {
|
||||||
|
settings.Cipher = aes256cbc
|
||||||
|
}
|
||||||
|
if len(settings.Auth) == 0 {
|
||||||
|
settings.Auth = sha256
|
||||||
|
}
|
||||||
|
if settings.MSSFix == 0 {
|
||||||
|
settings.MSSFix = 1450
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = []string{
|
||||||
|
"client",
|
||||||
|
"dev tun",
|
||||||
|
"nobind",
|
||||||
|
"persist-key",
|
||||||
|
"ping 15",
|
||||||
|
"ping-exit 60",
|
||||||
|
"ping-timer-rem",
|
||||||
|
"tls-exit",
|
||||||
|
|
||||||
|
// Fastestvpn specific
|
||||||
|
"ping-restart 0",
|
||||||
|
"tls-client",
|
||||||
|
"tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA", //nolint:lll
|
||||||
|
"comp-lzo",
|
||||||
|
"key-direction 1",
|
||||||
|
"tun-mtu 1500",
|
||||||
|
"tun-mtu-extra 32",
|
||||||
|
"mssfix " + strconv.Itoa(int(settings.MSSFix)), // defaults to 1450
|
||||||
|
|
||||||
|
// Added constant values
|
||||||
|
"auth-nocache",
|
||||||
|
"mute-replay-warnings",
|
||||||
|
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
|
||||||
|
`pull-filter ignore "ping-restart"`,
|
||||||
|
"auth-retry nointeract",
|
||||||
|
"suppress-timestamps",
|
||||||
|
|
||||||
|
// Modified variables
|
||||||
|
"verb " + strconv.Itoa(settings.Verbosity),
|
||||||
|
"auth-user-pass " + constants.OpenVPNAuthConf,
|
||||||
|
"proto " + connection.Protocol,
|
||||||
|
"remote " + connection.IP.String() + " " + strconv.Itoa(int(connection.Port)),
|
||||||
|
"cipher " + settings.Cipher,
|
||||||
|
"auth " + settings.Auth,
|
||||||
|
}
|
||||||
|
if !settings.Root {
|
||||||
|
lines = append(lines, "user "+username)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, []string{
|
||||||
|
"<ca>",
|
||||||
|
"-----BEGIN CERTIFICATE-----",
|
||||||
|
constants.FastestvpnCertificate,
|
||||||
|
"-----END CERTIFICATE-----",
|
||||||
|
"</ca>",
|
||||||
|
}...)
|
||||||
|
|
||||||
|
lines = append(lines, []string{
|
||||||
|
"<tls-auth>",
|
||||||
|
"-----BEGIN OpenVPN Static key V1-----",
|
||||||
|
constants.FastestvpnOpenvpnStaticKeyV1,
|
||||||
|
"-----END OpenVPN Static key V1-----",
|
||||||
|
"</tls-auth>",
|
||||||
|
"",
|
||||||
|
}...)
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fastestvpn) PortForward(ctx context.Context, client *http.Client,
|
||||||
|
openFile os.OpenFileFunc, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,
|
||||||
|
syncState func(port uint16) (pfFilepath string)) {
|
||||||
|
panic("port forwarding is not supported for fastestvpn")
|
||||||
|
}
|
||||||
@@ -27,6 +27,8 @@ func New(provider string, allServers models.AllServers, timeNow timeNowFunc) Pro
|
|||||||
switch provider {
|
switch provider {
|
||||||
case constants.Cyberghost:
|
case constants.Cyberghost:
|
||||||
return newCyberghost(allServers.Cyberghost.Servers, timeNow)
|
return newCyberghost(allServers.Cyberghost.Servers, timeNow)
|
||||||
|
case constants.Fastestvpn:
|
||||||
|
return newFastestvpn(allServers.Fastestvpn.Servers, timeNow)
|
||||||
case constants.HideMyAss:
|
case constants.HideMyAss:
|
||||||
return newHideMyAss(allServers.HideMyAss.Servers, timeNow)
|
return newHideMyAss(allServers.HideMyAss.Servers, timeNow)
|
||||||
case constants.Mullvad:
|
case constants.Mullvad:
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ func (s *storage) mergeServers(hardcoded, persisted models.AllServers) models.Al
|
|||||||
return models.AllServers{
|
return models.AllServers{
|
||||||
Version: hardcoded.Version,
|
Version: hardcoded.Version,
|
||||||
Cyberghost: s.mergeCyberghost(hardcoded.Cyberghost, persisted.Cyberghost),
|
Cyberghost: s.mergeCyberghost(hardcoded.Cyberghost, persisted.Cyberghost),
|
||||||
|
Fastestvpn: s.mergeFastestvpn(hardcoded.Fastestvpn, persisted.Fastestvpn),
|
||||||
HideMyAss: s.mergeHideMyAss(hardcoded.HideMyAss, persisted.HideMyAss),
|
HideMyAss: s.mergeHideMyAss(hardcoded.HideMyAss, persisted.HideMyAss),
|
||||||
Mullvad: s.mergeMullvad(hardcoded.Mullvad, persisted.Mullvad),
|
Mullvad: s.mergeMullvad(hardcoded.Mullvad, persisted.Mullvad),
|
||||||
Nordvpn: s.mergeNordVPN(hardcoded.Nordvpn, persisted.Nordvpn),
|
Nordvpn: s.mergeNordVPN(hardcoded.Nordvpn, persisted.Nordvpn),
|
||||||
@@ -41,6 +42,22 @@ func (s *storage) mergeCyberghost(hardcoded, persisted models.CyberghostServers)
|
|||||||
return persisted
|
return persisted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *storage) mergeFastestvpn(hardcoded, persisted models.FastestvpnServers) models.FastestvpnServers {
|
||||||
|
if persisted.Timestamp <= hardcoded.Timestamp {
|
||||||
|
return hardcoded
|
||||||
|
}
|
||||||
|
versionDiff := hardcoded.Version - persisted.Version
|
||||||
|
if versionDiff > 0 {
|
||||||
|
s.logger.Info(
|
||||||
|
"Fastestvpn servers from file discarded because they are %d versions behind",
|
||||||
|
versionDiff)
|
||||||
|
return hardcoded
|
||||||
|
}
|
||||||
|
s.logger.Info("Using Fastestvpn servers from file (%s more recent)",
|
||||||
|
getUnixTimeDifference(persisted.Timestamp, hardcoded.Timestamp))
|
||||||
|
return persisted
|
||||||
|
}
|
||||||
|
|
||||||
func (s *storage) mergeHideMyAss(hardcoded, persisted models.HideMyAssServers) models.HideMyAssServers {
|
func (s *storage) mergeHideMyAss(hardcoded, persisted models.HideMyAssServers) models.HideMyAssServers {
|
||||||
if persisted.Timestamp <= hardcoded.Timestamp {
|
if persisted.Timestamp <= hardcoded.Timestamp {
|
||||||
return hardcoded
|
return hardcoded
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ var (
|
|||||||
|
|
||||||
func countServers(allServers models.AllServers) int {
|
func countServers(allServers models.AllServers) int {
|
||||||
return len(allServers.Cyberghost.Servers) +
|
return len(allServers.Cyberghost.Servers) +
|
||||||
|
len(allServers.Fastestvpn.Servers) +
|
||||||
len(allServers.HideMyAss.Servers) +
|
len(allServers.HideMyAss.Servers) +
|
||||||
len(allServers.Mullvad.Servers) +
|
len(allServers.Mullvad.Servers) +
|
||||||
len(allServers.Nordvpn.Servers) +
|
len(allServers.Nordvpn.Servers) +
|
||||||
|
|||||||
147
internal/updater/fastestvpn.go
Normal file
147
internal/updater/fastestvpn.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package updater
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (u *updater) updateFastestvpn(ctx context.Context) (err error) {
|
||||||
|
servers, warnings, err := findFastestvpnServersFromZip(ctx, u.client, u.lookupIP)
|
||||||
|
if u.options.CLI {
|
||||||
|
for _, warning := range warnings {
|
||||||
|
u.logger.Warn("FastestVPN: %s", warning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot update FastestVPN servers: %w", err)
|
||||||
|
}
|
||||||
|
if u.options.Stdout {
|
||||||
|
u.println(stringifyFastestVPNServers(servers))
|
||||||
|
}
|
||||||
|
u.servers.Fastestvpn.Timestamp = u.timeNow().Unix()
|
||||||
|
u.servers.Fastestvpn.Servers = servers
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findFastestvpnServersFromZip(ctx context.Context, client *http.Client, lookupIP lookupIPFunc) (
|
||||||
|
servers []models.FastestvpnServer, warnings []string, err error) {
|
||||||
|
const zipURL = "https://support.fastestvpn.com/download/openvpn-tcp-udp-config-files"
|
||||||
|
contents, err := fetchAndExtractFiles(ctx, client, zipURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
trailNumberExp := regexp.MustCompile(`[0-9]+$`)
|
||||||
|
|
||||||
|
type Data struct {
|
||||||
|
TCP bool
|
||||||
|
UDP bool
|
||||||
|
Country string
|
||||||
|
}
|
||||||
|
hostToData := make(map[string]Data)
|
||||||
|
|
||||||
|
for fileName, content := range contents {
|
||||||
|
const (
|
||||||
|
tcpSuffix = "-TCP.ovpn"
|
||||||
|
udpSuffix = "-UDP.ovpn"
|
||||||
|
)
|
||||||
|
var tcp, udp bool
|
||||||
|
var suffix string
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(fileName, tcpSuffix):
|
||||||
|
suffix = tcpSuffix
|
||||||
|
tcp = true
|
||||||
|
case strings.HasSuffix(fileName, udpSuffix):
|
||||||
|
suffix = udpSuffix
|
||||||
|
udp = true
|
||||||
|
default:
|
||||||
|
warning := `filename "` + fileName + `" does not have a protocol suffix`
|
||||||
|
warnings = append(warnings, warning)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
countryWithNumber := strings.TrimSuffix(fileName, suffix)
|
||||||
|
number := trailNumberExp.FindString(countryWithNumber)
|
||||||
|
country := countryWithNumber[:len(countryWithNumber)-len(number)]
|
||||||
|
|
||||||
|
host, warning, err := extractHostFromOVPN(content)
|
||||||
|
if len(warning) > 0 {
|
||||||
|
warnings = append(warnings, warning)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// treat error as warning and go to next file
|
||||||
|
warnings = append(warnings, err.Error()+" in "+fileName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
data := hostToData[host]
|
||||||
|
data.Country = country
|
||||||
|
if tcp {
|
||||||
|
data.TCP = true
|
||||||
|
}
|
||||||
|
if udp {
|
||||||
|
data.UDP = true
|
||||||
|
}
|
||||||
|
hostToData[host] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
hosts := make([]string, len(hostToData))
|
||||||
|
i := 0
|
||||||
|
for host := range hostToData {
|
||||||
|
hosts[i] = host
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
const repetition = 1
|
||||||
|
const timeBetween = 0
|
||||||
|
const failOnErr = true
|
||||||
|
hostToIPs, _, err := parallelResolve(ctx, lookupIP, hosts, repetition, timeBetween, failOnErr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, warnings, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for host, IPs := range hostToIPs {
|
||||||
|
if len(IPs) == 0 {
|
||||||
|
warning := fmt.Sprintf("no IP address found for host %q", host)
|
||||||
|
warnings = append(warnings, warning)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
data := hostToData[host]
|
||||||
|
|
||||||
|
server := models.FastestvpnServer{
|
||||||
|
Hostname: host,
|
||||||
|
TCP: data.TCP,
|
||||||
|
UDP: data.UDP,
|
||||||
|
Country: data.Country,
|
||||||
|
IPs: uniqueSortedIPs(IPs),
|
||||||
|
}
|
||||||
|
servers = append(servers, server)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(servers, func(i, j int) bool {
|
||||||
|
if servers[i].Country == servers[j].Country {
|
||||||
|
return servers[i].Hostname < servers[j].Hostname
|
||||||
|
}
|
||||||
|
return servers[i].Country < servers[j].Country
|
||||||
|
})
|
||||||
|
|
||||||
|
return servers, warnings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringifyFastestVPNServers(servers []models.FastestvpnServer) (s string) {
|
||||||
|
s = "func FastestvpnServers() []models.FastestvpnServer {\n"
|
||||||
|
s += " return []models.FastestvpnServer{\n"
|
||||||
|
for _, server := range servers {
|
||||||
|
s += " " + server.String() + ",\n"
|
||||||
|
}
|
||||||
|
s += " }\n"
|
||||||
|
s += "}"
|
||||||
|
return s
|
||||||
|
}
|
||||||
@@ -60,6 +60,16 @@ func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u.options.Fastestvpn {
|
||||||
|
u.logger.Info("updating Fastestvpn servers...")
|
||||||
|
if err := u.updateFastestvpn(ctx); err != nil {
|
||||||
|
u.logger.Error(err)
|
||||||
|
}
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return allServers, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if u.options.HideMyAss {
|
if u.options.HideMyAss {
|
||||||
u.logger.Info("updating HideMyAss servers...")
|
u.logger.Info("updating HideMyAss servers...")
|
||||||
if err := u.updateHideMyAss(ctx); err != nil {
|
if err := u.updateHideMyAss(ctx); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user