VPN Unlimited support (#499)
- Fixes #420 - Revert to docker/build-push-action@v2.4.0
This commit is contained in:
3
.github/labels.yml
vendored
3
.github/labels.yml
vendored
@@ -53,6 +53,9 @@
|
|||||||
- name: ":cloud: Torguard"
|
- name: ":cloud: Torguard"
|
||||||
color: "cfe8d4"
|
color: "cfe8d4"
|
||||||
description: ""
|
description: ""
|
||||||
|
- name: ":cloud: VPNUnlimited"
|
||||||
|
color: "cfe8d4"
|
||||||
|
description: ""
|
||||||
- name: ":cloud: Vyprvpn"
|
- name: ":cloud: Vyprvpn"
|
||||||
color: "cfe8d4"
|
color: "cfe8d4"
|
||||||
description: ""
|
description: ""
|
||||||
|
|||||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -86,7 +86,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Build and push final image
|
- name: Build and push final image
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2.4.0
|
||||||
with:
|
with:
|
||||||
platforms: ${{ steps.vars.outputs.platforms }}
|
platforms: ${{ steps.vars.outputs.platforms }}
|
||||||
build-args: |
|
build-args: |
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
*Lightweight swiss-knife-like VPN client to tunnel to Cyberghost, FastestVPN,
|
*Lightweight swiss-knife-like VPN client to tunnel to Cyberghost, FastestVPN,
|
||||||
HideMyAss, IVPN, Mullvad, NordVPN, Privado, Private Internet Access, PrivateVPN,
|
HideMyAss, IVPN, Mullvad, NordVPN, Privado, Private Internet Access, PrivateVPN,
|
||||||
ProtonVPN, PureVPN, Surfshark, TorGuard, VyprVPN and Windscribe VPN servers
|
ProtonVPN, PureVPN, Surfshark, TorGuard, VPNUnlimited, 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*
|
||||||
|
|
||||||
**ANNOUNCEMENT**:
|
**ANNOUNCEMENT**:
|
||||||
@@ -39,7 +39,7 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Based on Alpine 3.13 for a small Docker image of 54MB
|
- Based on Alpine 3.13 for a small Docker image of 54MB
|
||||||
- Supports: **Cyberghost**, **FastestVPN**, **HideMyAss**, **IVPN**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **Vyprvpn**, **Windscribe** servers
|
- Supports: **Cyberghost**, **FastestVPN**, **HideMyAss**, **IVPN**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **VPNUnlimited**, **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
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ func (c *cli) Update(ctx context.Context, args []string, os os.OS, logger loggin
|
|||||||
flagSet.BoolVar(&options.Purevpn, "purevpn", false, "Update Purevpn servers")
|
flagSet.BoolVar(&options.Purevpn, "purevpn", false, "Update Purevpn servers")
|
||||||
flagSet.BoolVar(&options.Surfshark, "surfshark", false, "Update Surfshark servers")
|
flagSet.BoolVar(&options.Surfshark, "surfshark", false, "Update Surfshark servers")
|
||||||
flagSet.BoolVar(&options.Torguard, "torguard", false, "Update Torguard servers")
|
flagSet.BoolVar(&options.Torguard, "torguard", false, "Update Torguard servers")
|
||||||
|
flagSet.BoolVar(&options.VPNUnlimited, "vpnunlimited", false, "Update VPN Unlimited servers")
|
||||||
flagSet.BoolVar(&options.Vyprvpn, "vyprvpn", false, "Update Vyprvpn servers")
|
flagSet.BoolVar(&options.Vyprvpn, "vyprvpn", false, "Update Vyprvpn servers")
|
||||||
flagSet.BoolVar(&options.Windscribe, "windscribe", false, "Update Windscribe servers")
|
flagSet.BoolVar(&options.Windscribe, "windscribe", false, "Update Windscribe servers")
|
||||||
if err := flagSet.Parse(args); err != nil {
|
if err := flagSet.Parse(args); err != nil {
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
package configuration
|
package configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/pem"
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
@@ -44,12 +40,12 @@ func (settings *Provider) readCyberghost(r reader) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ExtraConfigOptions.ClientKey, err = readCyberghostClientKey(r)
|
settings.ExtraConfigOptions.ClientKey, err = readClientKey(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ExtraConfigOptions.ClientCertificate, err = readCyberghostClientCertificate(r)
|
settings.ExtraConfigOptions.ClientCertificate, err = readClientCertificate(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -72,49 +68,3 @@ func (settings *Provider) readCyberghost(r reader) (err error) {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readCyberghostClientKey(r reader) (clientKey string, err error) {
|
|
||||||
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTKEY", constants.ClientKey)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return extractClientKey(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
var errDecodePEMBlockClientKey = errors.New("cannot decode PEM block from client key")
|
|
||||||
|
|
||||||
func extractClientKey(b []byte) (key string, err error) {
|
|
||||||
pemBlock, _ := pem.Decode(b)
|
|
||||||
if pemBlock == nil {
|
|
||||||
return "", errDecodePEMBlockClientKey
|
|
||||||
}
|
|
||||||
parsedBytes := pem.EncodeToMemory(pemBlock)
|
|
||||||
s := string(parsedBytes)
|
|
||||||
s = strings.ReplaceAll(s, "\n", "")
|
|
||||||
s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----")
|
|
||||||
s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----")
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readCyberghostClientCertificate(r reader) (clientCertificate string, err error) {
|
|
||||||
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTCRT", constants.ClientCertificate)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return extractClientCertificate(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
var errDecodePEMBlockClientCert = errors.New("cannot decode PEM block from client certificate")
|
|
||||||
|
|
||||||
func extractClientCertificate(b []byte) (certificate string, err error) {
|
|
||||||
pemBlock, _ := pem.Decode(b)
|
|
||||||
if pemBlock == nil {
|
|
||||||
return "", errDecodePEMBlockClientCert
|
|
||||||
}
|
|
||||||
parsedBytes := pem.EncodeToMemory(pemBlock)
|
|
||||||
s := string(parsedBytes)
|
|
||||||
s = strings.ReplaceAll(s, "\n", "")
|
|
||||||
s = strings.TrimPrefix(s, "-----BEGIN CERTIFICATE-----")
|
|
||||||
s = strings.TrimSuffix(s, "-----END CERTIFICATE-----")
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|||||||
55
internal/configuration/keys.go
Normal file
55
internal/configuration/keys.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readClientKey(r reader) (clientKey string, err error) {
|
||||||
|
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTKEY", constants.ClientKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return extractClientKey(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errDecodePEMBlockClientKey = errors.New("cannot decode PEM block from client key")
|
||||||
|
|
||||||
|
func extractClientKey(b []byte) (key string, err error) {
|
||||||
|
pemBlock, _ := pem.Decode(b)
|
||||||
|
if pemBlock == nil {
|
||||||
|
return "", errDecodePEMBlockClientKey
|
||||||
|
}
|
||||||
|
parsedBytes := pem.EncodeToMemory(pemBlock)
|
||||||
|
s := string(parsedBytes)
|
||||||
|
s = strings.ReplaceAll(s, "\n", "")
|
||||||
|
s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----")
|
||||||
|
s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----")
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readClientCertificate(r reader) (clientCertificate string, err error) {
|
||||||
|
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTCRT", constants.ClientCertificate)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return extractClientCertificate(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errDecodePEMBlockClientCert = errors.New("cannot decode PEM block from client certificate")
|
||||||
|
|
||||||
|
func extractClientCertificate(b []byte) (certificate string, err error) {
|
||||||
|
pemBlock, _ := pem.Decode(b)
|
||||||
|
if pemBlock == nil {
|
||||||
|
return "", errDecodePEMBlockClientCert
|
||||||
|
}
|
||||||
|
parsedBytes := pem.EncodeToMemory(pemBlock)
|
||||||
|
s := string(parsedBytes)
|
||||||
|
s = strings.ReplaceAll(s, "\n", "")
|
||||||
|
s = strings.TrimPrefix(s, "-----BEGIN CERTIFICATE-----")
|
||||||
|
s = strings.TrimSuffix(s, "-----END CERTIFICATE-----")
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
@@ -70,7 +70,7 @@ func (settings *OpenVPN) read(r reader) (err error) {
|
|||||||
vpnsp, err := r.env.Inside("VPNSP", []string{
|
vpnsp, err := r.env.Inside("VPNSP", []string{
|
||||||
"cyberghost", "fastestvpn", "hidemyass", "ivpn", "mullvad", "nordvpn",
|
"cyberghost", "fastestvpn", "hidemyass", "ivpn", "mullvad", "nordvpn",
|
||||||
"privado", "pia", "private internet access", "privatevpn", "protonvpn",
|
"privado", "pia", "private internet access", "privatevpn", "protonvpn",
|
||||||
"purevpn", "surfshark", "torguard", "vyprvpn", "windscribe"},
|
"purevpn", "surfshark", "torguard", constants.VPNUnlimited, "vyprvpn", "windscribe"},
|
||||||
params.Default("private internet access"))
|
params.Default("private internet access"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -86,12 +86,13 @@ func (settings *OpenVPN) read(r reader) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
customConfig := settings.Config != ""
|
customConfig := settings.Config != ""
|
||||||
credentialsRequired := true
|
|
||||||
if customConfig {
|
if customConfig {
|
||||||
credentialsRequired = false
|
|
||||||
settings.Provider.Name = ""
|
settings.Provider.Name = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
credentialsRequired := !customConfig && settings.Provider.Name != constants.VPNUnlimited
|
||||||
|
|
||||||
settings.User, err = r.getFromEnvOrSecretFile("OPENVPN_USER", credentialsRequired, []string{"USER"})
|
settings.User, err = r.getFromEnvOrSecretFile("OPENVPN_USER", credentialsRequired, []string{"USER"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -139,7 +140,10 @@ func (settings *OpenVPN) read(r reader) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
settings.MSSFix = uint16(mssFix)
|
settings.MSSFix = uint16(mssFix)
|
||||||
|
return settings.readProvider(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPN) readProvider(r reader) error {
|
||||||
var readProvider func(r reader) error
|
var readProvider func(r reader) error
|
||||||
switch settings.Provider.Name {
|
switch settings.Provider.Name {
|
||||||
case "": // custom config
|
case "": // custom config
|
||||||
@@ -170,6 +174,8 @@ func (settings *OpenVPN) read(r reader) (err error) {
|
|||||||
readProvider = settings.Provider.readSurfshark
|
readProvider = settings.Provider.readSurfshark
|
||||||
case constants.Torguard:
|
case constants.Torguard:
|
||||||
readProvider = settings.Provider.readTorguard
|
readProvider = settings.Provider.readTorguard
|
||||||
|
case constants.VPNUnlimited:
|
||||||
|
readProvider = settings.Provider.readVPNUnlimited
|
||||||
case constants.Vyprvpn:
|
case constants.Vyprvpn:
|
||||||
readProvider = settings.Provider.readVyprvpn
|
readProvider = settings.Provider.readVyprvpn
|
||||||
case constants.Windscribe:
|
case constants.Windscribe:
|
||||||
@@ -177,6 +183,5 @@ func (settings *OpenVPN) read(r reader) (err error) {
|
|||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: %s", ErrInvalidVPNProvider, settings.Provider.Name)
|
return fmt.Errorf("%w: %s", ErrInvalidVPNProvider, settings.Provider.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return readProvider(r)
|
return readProvider(r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ func Test_OpenVPN_JSON(t *testing.T) {
|
|||||||
"custom_port": 0,
|
"custom_port": 0,
|
||||||
"numbers": null,
|
"numbers": null,
|
||||||
"encryption_preset": "",
|
"encryption_preset": "",
|
||||||
"free_only": false
|
"free_only": false,
|
||||||
|
"stream_only": false
|
||||||
},
|
},
|
||||||
"extra_config": {
|
"extra_config": {
|
||||||
"encryption_preset": "",
|
"encryption_preset": "",
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ func (settings *Provider) lines() (lines []string) {
|
|||||||
providerLines = settings.surfsharkLines()
|
providerLines = settings.surfsharkLines()
|
||||||
case "torguard":
|
case "torguard":
|
||||||
providerLines = settings.torguardLines()
|
providerLines = settings.torguardLines()
|
||||||
|
case strings.ToLower(constants.VPNUnlimited):
|
||||||
|
providerLines = settings.vpnUnlimitedLines()
|
||||||
case "vyprvpn":
|
case "vyprvpn":
|
||||||
providerLines = settings.vyprvpnLines()
|
providerLines = settings.vyprvpnLines()
|
||||||
case "windscribe":
|
case "windscribe":
|
||||||
|
|||||||
@@ -249,6 +249,31 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
" |--Hostnames: e",
|
" |--Hostnames: e",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
constants.VPNUnlimited: {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.VPNUnlimited,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Countries: []string{"a", "b"},
|
||||||
|
Cities: []string{"c", "d"},
|
||||||
|
Hostnames: []string{"e", "f"},
|
||||||
|
FreeOnly: true,
|
||||||
|
StreamOnly: true,
|
||||||
|
},
|
||||||
|
ExtraConfigOptions: ExtraConfigOptions{
|
||||||
|
ClientKey: "a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Vpn Unlimited settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Countries: a, b",
|
||||||
|
" |--Cities: c, d",
|
||||||
|
" |--Hostnames: e, f",
|
||||||
|
" |--Free servers only",
|
||||||
|
" |--Stream servers only",
|
||||||
|
" |--Client key is set",
|
||||||
|
},
|
||||||
|
},
|
||||||
"vyprvpn": {
|
"vyprvpn": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Vyprvpn,
|
Name: constants.Vyprvpn,
|
||||||
|
|||||||
@@ -15,10 +15,13 @@ type ServerSelection struct { //nolint:maligned
|
|||||||
// Cyberghost
|
// Cyberghost
|
||||||
Group string `json:"group"`
|
Group string `json:"group"`
|
||||||
|
|
||||||
Countries []string `json:"countries"` // Fastestvpn, HideMyAss, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN
|
// Fastestvpn, HideMyAss, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, VPNUnlimited
|
||||||
Cities []string `json:"cities"` // HideMyAss, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, Windscribe
|
Countries []string `json:"countries"`
|
||||||
Hostnames []string `json:"hostnames"` // Fastestvpn, HideMyAss, IVPN, PrivateVPN, Windscribe, Privado, Protonvpn
|
// HideMyAss, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, VPNUnlimited, Windscribe
|
||||||
Names []string `json:"names"` // Protonvpn
|
Cities []string `json:"cities"`
|
||||||
|
// Fastestvpn, HideMyAss, IVPN, PrivateVPN, Windscribe, Privado, Protonvpn, VPNUnlimited
|
||||||
|
Hostnames []string `json:"hostnames"`
|
||||||
|
Names []string `json:"names"` // Protonvpn
|
||||||
|
|
||||||
// Mullvad
|
// Mullvad
|
||||||
ISPs []string `json:"isps"`
|
ISPs []string `json:"isps"`
|
||||||
@@ -35,11 +38,14 @@ type ServerSelection struct { //nolint:maligned
|
|||||||
|
|
||||||
// ProtonVPN
|
// ProtonVPN
|
||||||
FreeOnly bool `json:"free_only"`
|
FreeOnly bool `json:"free_only"`
|
||||||
|
|
||||||
|
// VPNUnlimited
|
||||||
|
StreamOnly bool `json:"stream_only"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExtraConfigOptions struct {
|
type ExtraConfigOptions struct {
|
||||||
ClientCertificate string `json:"-"` // Cyberghost
|
ClientCertificate string `json:"-"` // Cyberghost
|
||||||
ClientKey string `json:"-"` // Cyberghost
|
ClientKey string `json:"-"` // Cyberghost, VPNUnlimited
|
||||||
EncryptionPreset string `json:"encryption_preset"` // PIA
|
EncryptionPreset string `json:"encryption_preset"` // PIA
|
||||||
OpenVPNIPv6 bool `json:"openvpn_ipv6"` // Mullvad
|
OpenVPNIPv6 bool `json:"openvpn_ipv6"` // Mullvad
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func (settings *Provider) readTorguard(r reader) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.TorguardHostnamesChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.TorguardHostnameChoices())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,23 +8,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Updater struct {
|
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"`
|
Fastestvpn bool `json:"fastestvpn"`
|
||||||
HideMyAss bool `json:"hidemyass"`
|
HideMyAss bool `json:"hidemyass"`
|
||||||
Ivpn bool `json:"ivpn"`
|
Ivpn bool `json:"ivpn"`
|
||||||
Mullvad bool `json:"mullvad"`
|
Mullvad bool `json:"mullvad"`
|
||||||
Nordvpn bool `json:"nordvpn"`
|
Nordvpn bool `json:"nordvpn"`
|
||||||
PIA bool `json:"pia"`
|
PIA bool `json:"pia"`
|
||||||
Privado bool `json:"privado"`
|
Privado bool `json:"privado"`
|
||||||
Privatevpn bool `json:"privatevpn"`
|
Privatevpn bool `json:"privatevpn"`
|
||||||
Protonvpn bool `json:"protonvpn"`
|
Protonvpn bool `json:"protonvpn"`
|
||||||
Purevpn bool `json:"purevpn"`
|
Purevpn bool `json:"purevpn"`
|
||||||
Surfshark bool `json:"surfshark"`
|
Surfshark bool `json:"surfshark"`
|
||||||
Torguard bool `json:"torguard"`
|
Torguard bool `json:"torguard"`
|
||||||
Vyprvpn bool `json:"vyprvpn"`
|
VPNUnlimited bool `json:"vpnunlimited"`
|
||||||
Windscribe bool `json:"windscribe"`
|
Vyprvpn bool `json:"vyprvpn"`
|
||||||
|
Windscribe bool `json:"windscribe"`
|
||||||
// The two below should be used in CLI mode only
|
// The two below should be used in CLI mode only
|
||||||
Stdout bool `json:"-"` // in order to update constants file (maintainer side)
|
Stdout bool `json:"-"` // in order to update constants file (maintainer side)
|
||||||
CLI bool `json:"-"`
|
CLI bool `json:"-"`
|
||||||
@@ -60,6 +61,7 @@ func (settings *Updater) read(r reader) (err error) {
|
|||||||
settings.Purevpn = true
|
settings.Purevpn = true
|
||||||
settings.Surfshark = true
|
settings.Surfshark = true
|
||||||
settings.Torguard = true
|
settings.Torguard = true
|
||||||
|
settings.VPNUnlimited = true
|
||||||
settings.Vyprvpn = true
|
settings.Vyprvpn = true
|
||||||
settings.Windscribe = true
|
settings.Windscribe = true
|
||||||
settings.Stdout = false
|
settings.Stdout = false
|
||||||
|
|||||||
85
internal/configuration/vpnunlimited.go
Normal file
85
internal/configuration/vpnunlimited.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) vpnUnlimitedLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Countries) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.Cities) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.Hostnames) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.ServerSelection.FreeOnly {
|
||||||
|
lines = append(lines, lastIndent+"Free servers only")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.ServerSelection.StreamOnly {
|
||||||
|
lines = append(lines, lastIndent+"Stream servers only")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.ExtraConfigOptions.ClientKey != "" {
|
||||||
|
lines = append(lines, lastIndent+"Client key is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readVPNUnlimited(r reader) (err error) {
|
||||||
|
settings.Name = constants.VPNUnlimited
|
||||||
|
|
||||||
|
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ExtraConfigOptions.ClientKey, err = readClientKey(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ExtraConfigOptions.ClientCertificate, err = readClientCertificate(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IvpnCountryChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IvpnCityChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.FreeOnly, err = r.env.YesNo("FREE_ONLY", params.Default("no"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.StreamOnly, err = r.env.YesNo("STREAM_ONLY", params.Default("no"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
42
internal/configuration/vpnunlimited_test.go
Normal file
42
internal/configuration/vpnunlimited_test.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Provider_vpnUnlimitedLines(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
settings Provider
|
||||||
|
lines []string
|
||||||
|
}{
|
||||||
|
"empty settings": {},
|
||||||
|
"full settings": {
|
||||||
|
settings: Provider{
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Countries: []string{"A", "B"},
|
||||||
|
Cities: []string{"C", "D"},
|
||||||
|
Hostnames: []string{"E", "F"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Countries: A, B",
|
||||||
|
"|--Cities: C, D",
|
||||||
|
"|--Hostnames: E, F",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
lines := testCase.settings.vpnUnlimitedLines()
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.lines, lines)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,254 +2,255 @@ package constants
|
|||||||
|
|
||||||
func CountryCodes() map[string]string {
|
func CountryCodes() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
"af": "Afghanistan",
|
"af": "Afghanistan",
|
||||||
"ax": "Aland Islands",
|
"ax": "Aland Islands",
|
||||||
"al": "Albania",
|
"al": "Albania",
|
||||||
"dz": "Algeria",
|
"dz": "Algeria",
|
||||||
"as": "American Samoa",
|
"as": "American Samoa",
|
||||||
"ad": "Andorra",
|
"ad": "Andorra",
|
||||||
"ao": "Angola",
|
"ao": "Angola",
|
||||||
"ai": "Anguilla",
|
"ai": "Anguilla",
|
||||||
"aq": "Antarctica",
|
"aq": "Antarctica",
|
||||||
"ag": "Antigua and Barbuda",
|
"ag": "Antigua and Barbuda",
|
||||||
"ar": "Argentina",
|
"ar": "Argentina",
|
||||||
"am": "Armenia",
|
"am": "Armenia",
|
||||||
"aw": "Aruba",
|
"aw": "Aruba",
|
||||||
"au": "Australia",
|
"au": "Australia",
|
||||||
"at": "Austria",
|
"at": "Austria",
|
||||||
"az": "Azerbaijan",
|
"az": "Azerbaijan",
|
||||||
"bs": "Bahamas",
|
"bs": "Bahamas",
|
||||||
"bh": "Bahrain",
|
"bh": "Bahrain",
|
||||||
"bd": "Bangladesh",
|
"bd": "Bangladesh",
|
||||||
"bb": "Barbados",
|
"bb": "Barbados",
|
||||||
"by": "Belarus",
|
"by": "Belarus",
|
||||||
"be": "Belgium",
|
"be": "Belgium",
|
||||||
"bz": "Belize",
|
"bz": "Belize",
|
||||||
"bj": "Benin",
|
"bj": "Benin",
|
||||||
"bm": "Bermuda",
|
"bm": "Bermuda",
|
||||||
"bt": "Bhutan",
|
"bt": "Bhutan",
|
||||||
"bo": "Bolivia",
|
"bo": "Bolivia",
|
||||||
"bq": "Bonaire",
|
"bq": "Bonaire",
|
||||||
"ba": "Bosnia and Herzegovina",
|
"ba": "Bosnia and Herzegovina",
|
||||||
"bw": "Botswana",
|
"bw": "Botswana",
|
||||||
"bv": "Bouvet Island",
|
"bv": "Bouvet Island",
|
||||||
"br": "Brazil",
|
"br": "Brazil",
|
||||||
"io": "British Indian Ocean Territory",
|
"io": "British Indian Ocean Territory",
|
||||||
"vg": "British Virgin Islands",
|
"vg": "British Virgin Islands",
|
||||||
"bn": "Brunei Darussalam",
|
"bn": "Brunei Darussalam",
|
||||||
"bg": "Bulgaria",
|
"bg": "Bulgaria",
|
||||||
"bf": "Burkina Faso",
|
"bf": "Burkina Faso",
|
||||||
"bi": "Burundi",
|
"bi": "Burundi",
|
||||||
"kh": "Cambodia",
|
"kh": "Cambodia",
|
||||||
"cm": "Cameroon",
|
"cm": "Cameroon",
|
||||||
"ca": "Canada",
|
"ca": "Canada",
|
||||||
"cv": "Cape Verde",
|
"cv": "Cape Verde",
|
||||||
"ky": "Cayman Islands",
|
"ky": "Cayman Islands",
|
||||||
"cf": "Central African Republic",
|
"cf": "Central African Republic",
|
||||||
"td": "Chad",
|
"td": "Chad",
|
||||||
"cl": "Chile",
|
"cl": "Chile",
|
||||||
"cn": "China",
|
"cn": "China",
|
||||||
"cx": "Christmas Island",
|
"cx": "Christmas Island",
|
||||||
"cc": "Cocos Islands",
|
"cc": "Cocos Islands",
|
||||||
"co": "Colombia",
|
"co": "Colombia",
|
||||||
"km": "Comoros",
|
"km": "Comoros",
|
||||||
"cg": "Congo",
|
"cg": "Congo",
|
||||||
"ck": "Cook Islands",
|
"ck": "Cook Islands",
|
||||||
"cr": "Costa Rica",
|
"cr": "Costa Rica",
|
||||||
"ci": "Cote d'Ivoire",
|
"ci": "Cote d'Ivoire",
|
||||||
"hr": "Croatia",
|
"hr": "Croatia",
|
||||||
"cu": "Cuba",
|
"cu": "Cuba",
|
||||||
"cw": "Curacao",
|
"cw": "Curacao",
|
||||||
"cy": "Cyprus",
|
"cy": "Cyprus",
|
||||||
"cz": "Czech Republic",
|
"cz": "Czech Republic",
|
||||||
"cd": "Democratic Republic of the Congo",
|
"cd": "Democratic Republic of the Congo",
|
||||||
"dk": "Denmark",
|
"dk": "Denmark",
|
||||||
"dj": "Djibouti",
|
"dj": "Djibouti",
|
||||||
"dm": "Dominica",
|
"dm": "Dominica",
|
||||||
"do": "Dominican Republic",
|
"do": "Dominican Republic",
|
||||||
"ec": "Ecuador",
|
"ec": "Ecuador",
|
||||||
"eg": "Egypt",
|
"eg": "Egypt",
|
||||||
"sv": "El Salvador",
|
"sv": "El Salvador",
|
||||||
"gq": "Equatorial Guinea",
|
"gq": "Equatorial Guinea",
|
||||||
"er": "Eritrea",
|
"er": "Eritrea",
|
||||||
"ee": "Estonia",
|
"ee": "Estonia",
|
||||||
"et": "Ethiopia",
|
"et": "Ethiopia",
|
||||||
"fk": "Falkland Islands",
|
"fk": "Falkland Islands",
|
||||||
"fo": "Faroe Islands",
|
"fo": "Faroe Islands",
|
||||||
"fj": "Fiji",
|
"fj": "Fiji",
|
||||||
"fi": "Finland",
|
"fi": "Finland",
|
||||||
"fr": "France",
|
"fr": "France",
|
||||||
"gf": "French Guiana",
|
"gf": "French Guiana",
|
||||||
"pf": "French Polynesia",
|
"pf": "French Polynesia",
|
||||||
"tf": "French Southern Territories",
|
"tf": "French Southern Territories",
|
||||||
"ga": "Gabon",
|
"ga": "Gabon",
|
||||||
"gm": "Gambia",
|
"gm": "Gambia",
|
||||||
"ge": "Georgia",
|
"ge": "Georgia",
|
||||||
"de": "Germany",
|
"de": "Germany",
|
||||||
"gh": "Ghana",
|
"gh": "Ghana",
|
||||||
"gi": "Gibraltar",
|
"gi": "Gibraltar",
|
||||||
"gr": "Greece",
|
"gr": "Greece",
|
||||||
"gl": "Greenland",
|
"gl": "Greenland",
|
||||||
"gd": "Grenada",
|
"gd": "Grenada",
|
||||||
"gp": "Guadeloupe",
|
"gp": "Guadeloupe",
|
||||||
"gu": "Guam",
|
"gu": "Guam",
|
||||||
"gt": "Guatemala",
|
"gt": "Guatemala",
|
||||||
"gg": "Guernsey",
|
"gg": "Guernsey",
|
||||||
"gw": "Guinea-Bissau",
|
"gw": "Guinea-Bissau",
|
||||||
"gn": "Guinea",
|
"gn": "Guinea",
|
||||||
"gy": "Guyana",
|
"gy": "Guyana",
|
||||||
"ht": "Haiti",
|
"ht": "Haiti",
|
||||||
"hm": "Heard Island and McDonald Islands",
|
"hm": "Heard Island and McDonald Islands",
|
||||||
"hn": "Honduras",
|
"hn": "Honduras",
|
||||||
"hk": "Hong Kong",
|
"hk": "Hong Kong",
|
||||||
"hu": "Hungary",
|
"hu": "Hungary",
|
||||||
"is": "Iceland",
|
"is": "Iceland",
|
||||||
"in": "India",
|
"in": "India",
|
||||||
"id": "Indonesia",
|
"id": "Indonesia",
|
||||||
"ir": "Iran",
|
"ir": "Iran",
|
||||||
"iq": "Iraq",
|
"iq": "Iraq",
|
||||||
"ie": "Ireland",
|
"ie": "Ireland",
|
||||||
"im": "Isle of Man",
|
"im": "Isle of Man",
|
||||||
"il": "Israel",
|
"il": "Israel",
|
||||||
"it": "Italy",
|
"it": "Italy",
|
||||||
"jm": "Jamaica",
|
"jm": "Jamaica",
|
||||||
"jp": "Japan",
|
"jp": "Japan",
|
||||||
"je": "Jersey",
|
"je": "Jersey",
|
||||||
"jo": "Jordan",
|
"jo": "Jordan",
|
||||||
"kz": "Kazakhstan",
|
"kz": "Kazakhstan",
|
||||||
"ke": "Kenya",
|
"ke": "Kenya",
|
||||||
"ki": "Kiribati",
|
"ki": "Kiribati",
|
||||||
"kr": "Korea",
|
"kr": "Korea",
|
||||||
"kw": "Kuwait",
|
"kw": "Kuwait",
|
||||||
"kg": "Kyrgyzstan",
|
"kg": "Kyrgyzstan",
|
||||||
"la": "Lao People's Democratic Republic",
|
"la": "Lao People's Democratic Republic",
|
||||||
"lv": "Latvia",
|
"lv": "Latvia",
|
||||||
"lb": "Lebanon",
|
"lb": "Lebanon",
|
||||||
"ls": "Lesotho",
|
"ls": "Lesotho",
|
||||||
"lr": "Liberia",
|
"lr": "Liberia",
|
||||||
"ly": "Libya",
|
"ly": "Libya",
|
||||||
"li": "Liechtenstein",
|
"li": "Liechtenstein",
|
||||||
"lt": "Lithuania",
|
"lt": "Lithuania",
|
||||||
"lu": "Luxembourg",
|
"lu": "Luxembourg",
|
||||||
"mo": "Macao",
|
"mo": "Macao",
|
||||||
"mk": "Macedonia",
|
"mk": "Macedonia",
|
||||||
"mg": "Madagascar",
|
"mg": "Madagascar",
|
||||||
"mw": "Malawi",
|
"mw": "Malawi",
|
||||||
"my": "Malaysia",
|
"my": "Malaysia",
|
||||||
"mv": "Maldives",
|
"mys": "Kuala Lumpur",
|
||||||
"ml": "Mali",
|
"mv": "Maldives",
|
||||||
"mt": "Malta",
|
"ml": "Mali",
|
||||||
"mh": "Marshall Islands",
|
"mt": "Malta",
|
||||||
"mq": "Martinique",
|
"mh": "Marshall Islands",
|
||||||
"mr": "Mauritania",
|
"mq": "Martinique",
|
||||||
"mu": "Mauritius",
|
"mr": "Mauritania",
|
||||||
"yt": "Mayotte",
|
"mu": "Mauritius",
|
||||||
"mx": "Mexico",
|
"yt": "Mayotte",
|
||||||
"fm": "Micronesia",
|
"mx": "Mexico",
|
||||||
"md": "Moldova",
|
"fm": "Micronesia",
|
||||||
"mc": "Monaco",
|
"md": "Moldova",
|
||||||
"mn": "Mongolia",
|
"mc": "Monaco",
|
||||||
"me": "Montenegro",
|
"mn": "Mongolia",
|
||||||
"ms": "Montserrat",
|
"me": "Montenegro",
|
||||||
"ma": "Morocco",
|
"ms": "Montserrat",
|
||||||
"mz": "Mozambique",
|
"ma": "Morocco",
|
||||||
"mm": "Myanmar",
|
"mz": "Mozambique",
|
||||||
"na": "Namibia",
|
"mm": "Myanmar",
|
||||||
"nr": "Nauru",
|
"na": "Namibia",
|
||||||
"np": "Nepal",
|
"nr": "Nauru",
|
||||||
"nl": "Netherlands",
|
"np": "Nepal",
|
||||||
"nc": "New Caledonia",
|
"nl": "Netherlands",
|
||||||
"nz": "New Zealand",
|
"nc": "New Caledonia",
|
||||||
"ni": "Nicaragua",
|
"nz": "New Zealand",
|
||||||
"ne": "Niger",
|
"ni": "Nicaragua",
|
||||||
"ng": "Nigeria",
|
"ne": "Niger",
|
||||||
"nu": "Niue",
|
"ng": "Nigeria",
|
||||||
"nf": "Norfolk Island",
|
"nu": "Niue",
|
||||||
"mp": "Northern Mariana Islands",
|
"nf": "Norfolk Island",
|
||||||
"no": "Norway",
|
"mp": "Northern Mariana Islands",
|
||||||
"om": "Oman",
|
"no": "Norway",
|
||||||
"pk": "Pakistan",
|
"om": "Oman",
|
||||||
"pw": "Palau",
|
"pk": "Pakistan",
|
||||||
"ps": "Palestine, State of",
|
"pw": "Palau",
|
||||||
"pa": "Panama",
|
"ps": "Palestine, State of",
|
||||||
"pg": "Papua New Guinea",
|
"pa": "Panama",
|
||||||
"py": "Paraguay",
|
"pg": "Papua New Guinea",
|
||||||
"pe": "Peru",
|
"py": "Paraguay",
|
||||||
"ph": "Philippines",
|
"pe": "Peru",
|
||||||
"pn": "Pitcairn",
|
"ph": "Philippines",
|
||||||
"pl": "Poland",
|
"pn": "Pitcairn",
|
||||||
"pt": "Portugal",
|
"pl": "Poland",
|
||||||
"pr": "Puerto Rico",
|
"pt": "Portugal",
|
||||||
"qa": "Qatar",
|
"pr": "Puerto Rico",
|
||||||
"re": "Reunion",
|
"qa": "Qatar",
|
||||||
"ro": "Romania",
|
"re": "Reunion",
|
||||||
"ru": "Russian Federation",
|
"ro": "Romania",
|
||||||
"rw": "Rwanda",
|
"ru": "Russian Federation",
|
||||||
"bl": "Saint Barthelemy",
|
"rw": "Rwanda",
|
||||||
"sh": "Saint Helena",
|
"bl": "Saint Barthelemy",
|
||||||
"kn": "Saint Kitts and Nevis",
|
"sh": "Saint Helena",
|
||||||
"lc": "Saint Lucia",
|
"kn": "Saint Kitts and Nevis",
|
||||||
"mf": "Saint Martin",
|
"lc": "Saint Lucia",
|
||||||
"pm": "Saint Pierre and Miquelon",
|
"mf": "Saint Martin",
|
||||||
"vc": "Saint Vincent and the Grenadines",
|
"pm": "Saint Pierre and Miquelon",
|
||||||
"ws": "Samoa",
|
"vc": "Saint Vincent and the Grenadines",
|
||||||
"sm": "San Marino",
|
"ws": "Samoa",
|
||||||
"st": "Sao Tome and Principe",
|
"sm": "San Marino",
|
||||||
"sa": "Saudi Arabia",
|
"st": "Sao Tome and Principe",
|
||||||
"sn": "Senegal",
|
"sa": "Saudi Arabia",
|
||||||
"rs": "Serbia",
|
"sn": "Senegal",
|
||||||
"sc": "Seychelles",
|
"rs": "Serbia",
|
||||||
"sl": "Sierra Leone",
|
"sc": "Seychelles",
|
||||||
"sg": "Singapore",
|
"sl": "Sierra Leone",
|
||||||
"sx": "Sint Maarten",
|
"sg": "Singapore",
|
||||||
"sk": "Slovakia",
|
"sx": "Sint Maarten",
|
||||||
"si": "Slovenia",
|
"sk": "Slovakia",
|
||||||
"sb": "Solomon Islands",
|
"si": "Slovenia",
|
||||||
"so": "Somalia",
|
"sb": "Solomon Islands",
|
||||||
"za": "South Africa",
|
"so": "Somalia",
|
||||||
"gs": "South Georgia and the South Sandwich Islands",
|
"za": "South Africa",
|
||||||
"ss": "South Sudan",
|
"gs": "South Georgia and the South Sandwich Islands",
|
||||||
"es": "Spain",
|
"ss": "South Sudan",
|
||||||
"lk": "Sri Lanka",
|
"es": "Spain",
|
||||||
"sd": "Sudan",
|
"lk": "Sri Lanka",
|
||||||
"sr": "Suriname",
|
"sd": "Sudan",
|
||||||
"sj": "Svalbard and Jan Mayen",
|
"sr": "Suriname",
|
||||||
"sz": "Swaziland",
|
"sj": "Svalbard and Jan Mayen",
|
||||||
"se": "Sweden",
|
"sz": "Swaziland",
|
||||||
"ch": "Switzerland",
|
"se": "Sweden",
|
||||||
"sy": "Syrian Arab Republic",
|
"ch": "Switzerland",
|
||||||
"tw": "Taiwan",
|
"sy": "Syrian Arab Republic",
|
||||||
"tj": "Tajikistan",
|
"tw": "Taiwan",
|
||||||
"tz": "Tanzania",
|
"tj": "Tajikistan",
|
||||||
"th": "Thailand",
|
"tz": "Tanzania",
|
||||||
"tl": "Timor-Leste",
|
"th": "Thailand",
|
||||||
"tg": "Togo",
|
"tl": "Timor-Leste",
|
||||||
"tk": "Tokelau",
|
"tg": "Togo",
|
||||||
"to": "Tonga",
|
"tk": "Tokelau",
|
||||||
"tt": "Trinidad and Tobago",
|
"to": "Tonga",
|
||||||
"tn": "Tunisia",
|
"tt": "Trinidad and Tobago",
|
||||||
"tr": "Turkey",
|
"tn": "Tunisia",
|
||||||
"tm": "Turkmenistan",
|
"tr": "Turkey",
|
||||||
"tc": "Turks and Caicos Islands",
|
"tm": "Turkmenistan",
|
||||||
"tv": "Tuvalu",
|
"tc": "Turks and Caicos Islands",
|
||||||
"ug": "Uganda",
|
"tv": "Tuvalu",
|
||||||
"ua": "Ukraine",
|
"ug": "Uganda",
|
||||||
"ae": "United Arab Emirates",
|
"ua": "Ukraine",
|
||||||
"gb": "United Kingdom",
|
"ae": "United Arab Emirates",
|
||||||
"uk": "United Kingdom",
|
"gb": "United Kingdom",
|
||||||
"um": "United States Minor Outlying Islands",
|
"uk": "United Kingdom",
|
||||||
"us": "United States",
|
"um": "United States Minor Outlying Islands",
|
||||||
"uy": "Uruguay",
|
"us": "United States",
|
||||||
"vi": "US Virgin Islands",
|
"uy": "Uruguay",
|
||||||
"uz": "Uzbekistan",
|
"vi": "US Virgin Islands",
|
||||||
"vu": "Vanuatu",
|
"uz": "Uzbekistan",
|
||||||
"va": "Vatican City State",
|
"vu": "Vanuatu",
|
||||||
"ve": "Venezuela",
|
"va": "Vatican City State",
|
||||||
"vn": "Vietnam",
|
"ve": "Venezuela",
|
||||||
"wf": "Wallis and Futuna",
|
"vn": "Vietnam",
|
||||||
"eh": "Western Sahara",
|
"wf": "Wallis and Futuna",
|
||||||
"ye": "Yemen",
|
"eh": "Western Sahara",
|
||||||
"zm": "Zambia",
|
"ye": "Yemen",
|
||||||
"zw": "Zimbabwe",
|
"zm": "Zambia",
|
||||||
|
"zw": "Zimbabwe",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,11 @@ func GetAllServers() (allServers models.AllServers) {
|
|||||||
Timestamp: 1620611129,
|
Timestamp: 1620611129,
|
||||||
Servers: TorguardServers(),
|
Servers: TorguardServers(),
|
||||||
},
|
},
|
||||||
|
VPNUnlimited: models.VPNUnlimitedServers{
|
||||||
|
Version: 1,
|
||||||
|
Timestamp: 1623950304,
|
||||||
|
Servers: VPNUnlimitedServers(),
|
||||||
|
},
|
||||||
Vyprvpn: models.VyprvpnServers{
|
Vyprvpn: models.VyprvpnServers{
|
||||||
Version: 2,
|
Version: 2,
|
||||||
Timestamp: 1620612506,
|
Timestamp: 1620612506,
|
||||||
|
|||||||
@@ -100,6 +100,11 @@ func Test_versions(t *testing.T) {
|
|||||||
version: allServers.Torguard.Version,
|
version: allServers.Torguard.Version,
|
||||||
digest: "6eb9028e",
|
digest: "6eb9028e",
|
||||||
},
|
},
|
||||||
|
"VPN Unlimited": {
|
||||||
|
model: models.VPNUnlimitedServer{},
|
||||||
|
version: allServers.VPNUnlimited.Version,
|
||||||
|
digest: "5cb51319",
|
||||||
|
},
|
||||||
"Vyprvpn": {
|
"Vyprvpn": {
|
||||||
model: models.VyprvpnServer{},
|
model: models.VyprvpnServer{},
|
||||||
version: allServers.Vyprvpn.Version,
|
version: allServers.Vyprvpn.Version,
|
||||||
@@ -212,6 +217,11 @@ func Test_timestamps(t *testing.T) {
|
|||||||
timestamp: allServers.Torguard.Timestamp,
|
timestamp: allServers.Torguard.Timestamp,
|
||||||
digest: "af54b9e8",
|
digest: "af54b9e8",
|
||||||
},
|
},
|
||||||
|
"VPN Unlimited": {
|
||||||
|
servers: allServers.VPNUnlimited.Servers,
|
||||||
|
timestamp: allServers.VPNUnlimited.Timestamp,
|
||||||
|
digest: "f6ddb84c",
|
||||||
|
},
|
||||||
"Vyprvpn": {
|
"Vyprvpn": {
|
||||||
servers: allServers.Vyprvpn.Servers,
|
servers: allServers.Vyprvpn.Servers,
|
||||||
timestamp: allServers.Vyprvpn.Timestamp,
|
timestamp: allServers.Vyprvpn.Timestamp,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func TorguardCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TorguardHostnamesChoices() (choices []string) {
|
func TorguardHostnameChoices() (choices []string) {
|
||||||
servers := TorguardServers()
|
servers := TorguardServers()
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ const (
|
|||||||
Surfshark = "surfshark"
|
Surfshark = "surfshark"
|
||||||
// Torguard is a VPN provider.
|
// Torguard is a VPN provider.
|
||||||
Torguard = "torguard"
|
Torguard = "torguard"
|
||||||
|
// VPNUnlimited is a VPN provider.
|
||||||
|
VPNUnlimited = "vpn unlimited"
|
||||||
// Vyprvpn is a VPN provider.
|
// Vyprvpn is a VPN provider.
|
||||||
Vyprvpn = "vyprvpn"
|
Vyprvpn = "vyprvpn"
|
||||||
// Windscribe is a VPN provider.
|
// Windscribe is a VPN provider.
|
||||||
|
|||||||
124
internal/constants/vpnunlimited.go
Normal file
124
internal/constants/vpnunlimited.go
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package constants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
|
const (
|
||||||
|
VPNUnlimitedCertificateAuthority = "MIIEjjCCA/egAwIBAgIJAKsVbHBdakXuMA0GCSqGSIb3DQEBBQUAMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb20wHhcNMTMxMjE2MTM1OTQ0WhcNMjMxMjE0MTM1OTQ0WjCB4DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5ZMREwDwYDVQQHEwhOZXcgWW9yazEfMB0GA1UEChMWU2ltcGxleCBTb2x1dGlvbnMgSW5jLjEWMBQGA1UECxMNVnBuIFVubGltaXRlZDEjMCEGA1UEAxMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xIzAhBgNVBCkTGnNlcnZlci52cG51bmxpbWl0ZWRhcHAuY29tMS4wLAYJKoZIhvcNAQkBFh9zdXBwb3J0QHNpbXBsZXhzb2x1dGlvbnNpbmMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDADUzS8QWGvdhLFKsEzAiq5+b0ukKjBza0k6/dmCeYTvCVqGKg/h1IAtQdVVLAkmEp0zvGH7PuOhXm7zZrCouBr/RiG4tEcoRHwc6AJmowkYERlY7+xGx3OuNrD00QceNTsan0bn78jwt0zhFNmHdoTtFjgK3oqmQYSAtbEVWYgwIDAQABo4IBTDCCAUgwHQYDVR0OBBYEFKClmYP+tMNgWagUJCCHjtaui2k+MIIBFwYDVR0jBIIBDjCCAQqAFKClmYP+tMNgWagUJCCHjtaui2k+oYHmpIHjMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb22CCQCrFWxwXWpF7jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBALkWhfw7SSV7it+ZYZmT+cQbExjlYgQ40zae2J2CqIYACRcfsDHvh7Q+fiwSocevv2NE0dWi6WB2H6SiudYjvDvubAX/QbzfBxtbxCCoAIlfPCm8xOnWFN7TUJAzWwHJkKgEnu29GZHu2x8J+7VeDbKH5RTMHHe8FkSxh6Zz/BMN"
|
||||||
|
)
|
||||||
|
|
||||||
|
func VPNUnlimitedCountryChoices() (choices []string) {
|
||||||
|
servers := VPNUnlimitedServers()
|
||||||
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].Country
|
||||||
|
}
|
||||||
|
return makeUnique(choices)
|
||||||
|
}
|
||||||
|
|
||||||
|
func VPNUnlimitedCityChoices() (choices []string) {
|
||||||
|
servers := VPNUnlimitedServers()
|
||||||
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].City
|
||||||
|
}
|
||||||
|
return makeUnique(choices)
|
||||||
|
}
|
||||||
|
|
||||||
|
func VPNUnlimitedHostnameChoices() (choices []string) {
|
||||||
|
servers := VPNUnlimitedServers()
|
||||||
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].Hostname
|
||||||
|
}
|
||||||
|
return makeUnique(choices)
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
|
// VPNUnlimitedServers returns a slice of all the server information for VPNUnlimited.
|
||||||
|
func VPNUnlimitedServers() []models.VPNUnlimitedServer {
|
||||||
|
return []models.VPNUnlimitedServer{
|
||||||
|
{Country: "Argentina", City: "", Hostname: "ar.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{131, 255, 4, 187}, {131, 255, 4, 235}}},
|
||||||
|
{Country: "Australia", City: "Sydney", Hostname: "au-syd.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{139, 99, 131, 38}, {139, 99, 130, 220}}},
|
||||||
|
{Country: "Austria", City: "", Hostname: "at.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{50, 7, 115, 19}, {185, 210, 219, 194}, {185, 210, 219, 198}}},
|
||||||
|
{Country: "Belarus", City: "", Hostname: "by.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 66, 68, 23}, {185, 66, 71, 108}, {185, 66, 71, 115}, {185, 66, 68, 84}, {185, 66, 71, 22}, {185, 66, 71, 122}, {185, 66, 71, 8}, {185, 66, 68, 18}}},
|
||||||
|
{Country: "Belgium", City: "", Hostname: "be.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 120, 143, 178}, {82, 102, 19, 110}}},
|
||||||
|
{Country: "Bosnia and Herzegovina", City: "", Hostname: "ba.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 164, 35, 37}}},
|
||||||
|
{Country: "Brazil", City: "", Hostname: "br.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{66, 90, 70, 7}, {177, 67, 82, 222}, {177, 67, 82, 218}, {177, 67, 82, 228}, {177, 67, 82, 221}, {177, 67, 82, 219}, {177, 67, 82, 210}, {177, 67, 82, 223}}},
|
||||||
|
{Country: "Bulgaria", City: "", Hostname: "bg.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 120, 152, 26}}},
|
||||||
|
{Country: "Canada", City: "", Hostname: "ca.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{192, 99, 7, 170}, {192, 99, 6, 164}, {192, 99, 14, 158}, {192, 99, 37, 199}, {192, 99, 6, 166}}},
|
||||||
|
{Country: "Canada", City: "Toronto", Hostname: "ca-tr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{184, 75, 213, 154}, {162, 253, 131, 106}, {162, 219, 176, 163}, {104, 254, 90, 58}, {104, 254, 92, 42}, {184, 75, 213, 194}, {204, 187, 100, 82}, {104, 254, 90, 34}}},
|
||||||
|
{Country: "Canada", City: "Vancouver", Hostname: "ca-vn.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{162, 221, 202, 138}, {162, 221, 202, 134}, {162, 221, 202, 17}}},
|
||||||
|
{Country: "Costa Rica", City: "", Hostname: "cr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{138, 59, 19, 8}}},
|
||||||
|
{Country: "Croatia", City: "", Hostname: "hr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{85, 10, 56, 3}, {85, 10, 56, 100}, {85, 10, 51, 3}, {85, 10, 56, 4}}},
|
||||||
|
{Country: "Cyprus", City: "", Hostname: "cy.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{194, 30, 136, 123}, {194, 30, 136, 102}}},
|
||||||
|
{Country: "Czech Republic", City: "", Hostname: "cz.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 216, 35, 46}}},
|
||||||
|
{Country: "Denmark", City: "", Hostname: "dk.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 120, 194, 174}, {89, 45, 7, 90}}},
|
||||||
|
{Country: "Estonia", City: "", Hostname: "ee.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 155, 96, 132}}},
|
||||||
|
{Country: "Finland", City: "", Hostname: "fi.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 112, 82, 26}, {91, 233, 116, 44}}},
|
||||||
|
{Country: "France", City: "", Hostname: "fr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{195, 154, 189, 85}, {195, 154, 204, 36}, {195, 154, 211, 84}, {62, 210, 38, 83}, {195, 154, 169, 66}, {195, 154, 166, 20}, {62, 210, 204, 161}, {62, 210, 205, 16}, {62, 210, 139, 124}, {195, 154, 221, 54}, {195, 154, 199, 175}, {195, 154, 189, 212}, {195, 154, 180, 96}, {195, 154, 199, 155}, {195, 154, 209, 149}, {195, 154, 222, 168}}},
|
||||||
|
{Country: "France", City: "Roubaix", Hostname: "fr-rbx.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{151, 80, 27, 199}, {51, 255, 71, 16}, {147, 135, 137, 107}}},
|
||||||
|
{Country: "Germany", City: "", Hostname: "de.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{84, 16, 236, 168}, {178, 162, 205, 77}, {178, 162, 205, 115}, {178, 162, 205, 82}, {84, 16, 238, 220}}},
|
||||||
|
{Country: "Germany", City: "Düsseldorf", Hostname: "de-dus.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{146, 0, 42, 77}, {146, 0, 32, 121}, {85, 14, 243, 42}}},
|
||||||
|
{Country: "Greece", City: "", Hostname: "gr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{154, 57, 3, 36}}},
|
||||||
|
{Country: "Hungary", City: "", Hostname: "hu.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{91, 219, 238, 174}}},
|
||||||
|
{Country: "Iceland", City: "", Hostname: "is.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 235, 49, 75}, {151, 236, 24, 114}, {37, 235, 49, 42}, {37, 235, 49, 244}, {37, 235, 49, 70}, {37, 235, 49, 15}, {151, 236, 24, 142}}},
|
||||||
|
{Country: "India", City: "", Hostname: "in.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{103, 26, 204, 46}, {103, 26, 204, 84}}},
|
||||||
|
{Country: "India", City: "Karnataka", Hostname: "in-ka.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{139, 59, 67, 224}, {139, 59, 65, 136}, {139, 59, 24, 197}, {139, 59, 24, 198}, {139, 59, 24, 199}, {139, 59, 24, 191}, {139, 59, 16, 78}}},
|
||||||
|
{Country: "Ireland", City: "Dublin", Hostname: "ie-dub.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{188, 241, 178, 118}}},
|
||||||
|
{Country: "Isle of Man", City: "", Hostname: "im.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{192, 71, 211, 15}, {37, 235, 55, 62}, {37, 235, 55, 68}, {37, 235, 55, 14}, {37, 235, 55, 45}}},
|
||||||
|
{Country: "Israel", City: "", Hostname: "il.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{193, 182, 144, 170}, {193, 182, 144, 151}, {193, 182, 144, 23}}},
|
||||||
|
{Country: "Italy", City: "Milan", Hostname: "it-mil.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{91, 193, 5, 50}}},
|
||||||
|
{Country: "Japan", City: "", Hostname: "jp.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{172, 104, 67, 80}, {172, 104, 75, 121}, {161, 202, 97, 109}, {172, 104, 71, 35}, {172, 104, 126, 64}, {172, 104, 64, 213}, {85, 208, 110, 122}, {172, 104, 78, 67}, {172, 104, 83, 34}, {172, 104, 99, 172}, {161, 202, 97, 101}, {172, 104, 83, 13}, {172, 104, 87, 163}, {172, 104, 99, 14}}},
|
||||||
|
{Country: "Korea", City: "", Hostname: "kr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{160, 202, 162, 60}, {160, 202, 163, 122}}},
|
||||||
|
{Country: "Kuala Lumpur", City: "", Hostname: "mys.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{111, 90, 141, 34}, {111, 90, 158, 159}}},
|
||||||
|
{Country: "Latvia", City: "", Hostname: "lv.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{195, 123, 213, 172}, {195, 123, 209, 168}}},
|
||||||
|
{Country: "Libya", City: "", Hostname: "ly.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{41, 208, 71, 39}}},
|
||||||
|
{Country: "Lithuania", City: "", Hostname: "lt.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 64, 105, 93}, {185, 64, 104, 142}, {185, 25, 48, 81}}},
|
||||||
|
{Country: "Luxembourg", City: "", Hostname: "lu.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{94, 242, 246, 45}, {94, 242, 246, 46}, {94, 242, 246, 77}, {94, 242, 246, 38}, {94, 242, 246, 47}}},
|
||||||
|
{Country: "Mexico", City: "", Hostname: "mx.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{169, 57, 35, 104}}},
|
||||||
|
{Country: "Moldova", City: "", Hostname: "md.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 163, 46, 141}}},
|
||||||
|
{Country: "Netherlands", City: "", Hostname: "nl.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{190, 2, 132, 115}, {190, 2, 132, 16}, {190, 2, 132, 52}}},
|
||||||
|
{Country: "New Zealand", City: "", Hostname: "nz.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{103, 75, 119, 109}, {103, 75, 119, 107}, {103, 75, 119, 105}, {103, 75, 119, 102}, {103, 75, 119, 103}, {103, 75, 119, 104}, {103, 75, 119, 106}, {103, 75, 119, 108}, {103, 75, 119, 101}, {103, 75, 119, 11}}},
|
||||||
|
{Country: "Norway", City: "", Hostname: "no.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 90, 61, 21}, {185, 90, 61, 74}}},
|
||||||
|
{Country: "Oman", City: "", Hostname: "om.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 226, 124, 110}}},
|
||||||
|
{Country: "Poland", City: "", Hostname: "pl.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 120, 156, 234}}},
|
||||||
|
{Country: "Portugal", City: "", Hostname: "pt.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 31, 159, 110}}},
|
||||||
|
{Country: "Romania", City: "", Hostname: "ro.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 144, 83, 11}, {93, 115, 92, 207}, {185, 144, 83, 13}, {77, 81, 98, 70}, {93, 115, 92, 208}}},
|
||||||
|
{Country: "Serbia", City: "", Hostname: "rs.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{152, 89, 160, 142}}},
|
||||||
|
{Country: "Singapore", City: "", Hostname: "sg-free.vpnunlimitedapp.com", Free: true, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{178, 128, 48, 177}, {188, 166, 177, 236}, {206, 189, 80, 158}, {178, 128, 117, 139}}},
|
||||||
|
{Country: "Singapore", City: "", Hostname: "sg.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{50, 7, 60, 52}, {117, 20, 41, 9}, {117, 20, 41, 10}, {139, 99, 62, 61}}},
|
||||||
|
{Country: "Slovakia", City: "", Hostname: "sk.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{46, 29, 2, 131}}},
|
||||||
|
{Country: "Slovenia", City: "", Hostname: "si.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{192, 71, 244, 38}, {192, 71, 244, 28}}},
|
||||||
|
{Country: "South Africa", City: "", Hostname: "za.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{129, 232, 130, 187}, {129, 232, 219, 196}, {129, 232, 133, 41}, {129, 232, 129, 157}, {129, 232, 219, 195}, {129, 232, 134, 122}, {129, 232, 130, 186}, {129, 232, 130, 179}}},
|
||||||
|
{Country: "Spain", City: "", Hostname: "es.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{194, 99, 104, 58}, {195, 206, 107, 134}}},
|
||||||
|
{Country: "Sweden", City: "", Hostname: "se.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{91, 132, 138, 174}}},
|
||||||
|
{Country: "Switzerland", City: "", Hostname: "ch.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{152, 89, 162, 90}, {152, 89, 162, 86}}},
|
||||||
|
{Country: "Thailand", City: "", Hostname: "th.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{103, 159, 3, 121}}},
|
||||||
|
{Country: "Turkey", City: "", Hostname: "tr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 17, 115, 62}, {185, 73, 202, 218}}},
|
||||||
|
{Country: "United Arab Emirates", City: "", Hostname: "ae.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{45, 9, 249, 201}, {45, 9, 249, 209}, {45, 9, 250, 147}, {45, 9, 250, 249}, {45, 9, 250, 138}, {45, 9, 249, 211}, {45, 9, 250, 144}, {45, 9, 249, 216}, {45, 9, 250, 145}, {45, 9, 250, 143}, {45, 9, 250, 134}, {45, 9, 250, 146}, {45, 9, 249, 202}}},
|
||||||
|
{Country: "United Kingdom", City: "", Hostname: "uk.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{176, 227, 198, 122}, {77, 245, 65, 2}, {109, 73, 77, 18}, {5, 152, 213, 186}, {88, 150, 224, 74}, {88, 150, 180, 82}}},
|
||||||
|
{Country: "United Kingdom", City: "London", Hostname: "uk-cv.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{5, 101, 169, 146}, {5, 101, 143, 66}, {178, 159, 10, 78}}},
|
||||||
|
{Country: "United Kingdom", City: "London", Hostname: "uk-lon.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{78, 110, 160, 6}, {50, 7, 114, 220}, {5, 101, 136, 154}, {23, 106, 33, 89}}},
|
||||||
|
{Country: "United States", City: "", Hostname: "us-stream.vpnunlimitedapp.com", Free: false, Stream: true, TCP: false, UDP: true, IPs: []net.IP{{167, 99, 96, 113}, {198, 199, 114, 155}, {192, 241, 194, 208}, {165, 227, 49, 171}, {159, 89, 128, 183}, {138, 197, 203, 142}, {64, 227, 111, 143}, {143, 110, 225, 79}, {164, 90, 144, 44}, {198, 199, 103, 243}, {198, 199, 96, 52}, {128, 199, 9, 51}, {143, 110, 156, 9}, {178, 128, 79, 75}, {198, 199, 97, 247}, {198, 199, 105, 87}, {198, 199, 103, 88}, {206, 189, 211, 205}, {206, 189, 165, 44}, {161, 35, 236, 242}}},
|
||||||
|
{Country: "United States", City: "", Hostname: "us.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{199, 115, 117, 81}, {199, 115, 115, 139}, {207, 244, 72, 212}, {199, 115, 115, 160}, {199, 115, 117, 73}}},
|
||||||
|
{Country: "United States", City: "Chicago", Hostname: "us-chi.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{66, 23, 205, 226}, {108, 62, 202, 211}, {173, 234, 41, 130}, {174, 34, 184, 130}}},
|
||||||
|
{Country: "United States", City: "Dallas", Hostname: "us-dal.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{172, 241, 115, 99}, {172, 241, 113, 19}, {172, 241, 112, 92}}},
|
||||||
|
{Country: "United States", City: "Denver", Hostname: "us-den.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{23, 237, 26, 131}, {23, 237, 26, 67}}},
|
||||||
|
{Country: "United States", City: "Houston", Hostname: "us-hou.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{162, 218, 228, 194}, {162, 218, 228, 196}, {66, 187, 75, 122}, {162, 218, 229, 106}}},
|
||||||
|
{Country: "United States", City: "Las Vegas", Hostname: "us-lv.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 242, 5, 18}, {185, 242, 5, 22}}},
|
||||||
|
{Country: "United States", City: "Los Angeles", Hostname: "us-la.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{64, 31, 33, 154}, {192, 184, 48, 10}, {23, 83, 37, 209}, {23, 83, 37, 213}, {45, 136, 131, 40}, {69, 162, 99, 70}}},
|
||||||
|
{Country: "United States", City: "Miami", Hostname: "us-mia.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{186, 233, 185, 29}, {186, 233, 185, 79}, {186, 233, 185, 80}, {186, 233, 184, 187}, {186, 233, 184, 188}, {186, 233, 184, 37}, {186, 233, 184, 31}}},
|
||||||
|
{Country: "United States", City: "New York", Hostname: "us-ny-free.vpnunlimitedapp.com", Free: true, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{64, 94, 215, 66}, {64, 94, 215, 162}, {64, 94, 215, 170}}},
|
||||||
|
{Country: "United States", City: "New York", Hostname: "us-ny.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{64, 42, 178, 202}, {23, 105, 134, 162}, {64, 42, 178, 226}, {23, 237, 58, 112}, {23, 108, 31, 122}}},
|
||||||
|
{Country: "United States", City: "Saint Louis", Hostname: "us-sl.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{69, 64, 58, 110}, {69, 64, 58, 255}, {209, 239, 123, 77}, {209, 239, 123, 107}}},
|
||||||
|
{Country: "United States", City: "Salt Lake City", Hostname: "us-slc.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{209, 95, 53, 223}, {209, 95, 53, 225}}},
|
||||||
|
{Country: "United States", City: "San Francisco", Hostname: "us-sf.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{209, 58, 139, 34}, {209, 58, 135, 72}, {209, 58, 130, 210}, {209, 58, 135, 106}, {209, 58, 135, 108}, {209, 58, 135, 74}, {209, 58, 139, 35}, {209, 58, 137, 94}, {172, 241, 251, 164}, {209, 58, 135, 120}}},
|
||||||
|
{Country: "United States", City: "Seattle", Hostname: "us-sea.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{216, 244, 82, 50}, {23, 81, 209, 137}, {216, 244, 82, 210}}},
|
||||||
|
{Country: "Vietnam", City: "", Hostname: "vn.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{103, 9, 78, 84}, {146, 196, 67, 7}}},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -188,6 +188,22 @@ func (s *TorguardServer) String() string {
|
|||||||
s.Country, s.City, s.Hostname, s.TCP, s.UDP, goStringifyIPs(s.IPs))
|
s.Country, s.City, s.Hostname, s.TCP, s.UDP, goStringifyIPs(s.IPs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VPNUnlimitedServer struct {
|
||||||
|
Country string `json:"country"`
|
||||||
|
City string `json:"city"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
Free bool `json:"free"`
|
||||||
|
Stream bool `json:"stream"`
|
||||||
|
TCP bool `json:"tcp"`
|
||||||
|
UDP bool `json:"udp"`
|
||||||
|
IPs []net.IP `json:"ips"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VPNUnlimitedServer) String() string {
|
||||||
|
return fmt.Sprintf("{Country: %q, City: %q, Hostname: %q, Free: %t, Stream: %t, TCP: %t, UDP: %t, IPs: %s}",
|
||||||
|
s.Country, s.City, s.Hostname, s.Free, s.Stream, s.TCP, s.UDP, goStringifyIPs(s.IPs))
|
||||||
|
}
|
||||||
|
|
||||||
type VyprvpnServer struct {
|
type VyprvpnServer struct {
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
Hostname string `json:"hostname"`
|
Hostname string `json:"hostname"`
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
package models
|
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"`
|
Fastestvpn FastestvpnServers `json:"fastestvpn"`
|
||||||
HideMyAss HideMyAssServers `json:"hidemyass"`
|
HideMyAss HideMyAssServers `json:"hidemyass"`
|
||||||
Ivpn IvpnServers `json:"ivpn"`
|
Ivpn IvpnServers `json:"ivpn"`
|
||||||
Mullvad MullvadServers `json:"mullvad"`
|
Mullvad MullvadServers `json:"mullvad"`
|
||||||
Nordvpn NordvpnServers `json:"nordvpn"`
|
Nordvpn NordvpnServers `json:"nordvpn"`
|
||||||
Privado PrivadoServers `json:"privado"`
|
Privado PrivadoServers `json:"privado"`
|
||||||
Pia PiaServers `json:"pia"`
|
Pia PiaServers `json:"pia"`
|
||||||
Privatevpn PrivatevpnServers `json:"privatevpn"`
|
Privatevpn PrivatevpnServers `json:"privatevpn"`
|
||||||
Protonvpn ProtonvpnServers `json:"protonvpn"`
|
Protonvpn ProtonvpnServers `json:"protonvpn"`
|
||||||
Purevpn PurevpnServers `json:"purevpn"`
|
Purevpn PurevpnServers `json:"purevpn"`
|
||||||
Surfshark SurfsharkServers `json:"surfshark"`
|
Surfshark SurfsharkServers `json:"surfshark"`
|
||||||
Torguard TorguardServers `json:"torguard"`
|
Torguard TorguardServers `json:"torguard"`
|
||||||
Vyprvpn VyprvpnServers `json:"vyprvpn"`
|
VPNUnlimited VPNUnlimitedServers `json:"vpnunlimited"`
|
||||||
Windscribe WindscribeServers `json:"windscribe"`
|
Vyprvpn VyprvpnServers `json:"vyprvpn"`
|
||||||
|
Windscribe WindscribeServers `json:"windscribe"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AllServers) Count() int {
|
func (a *AllServers) Count() int {
|
||||||
@@ -33,6 +34,7 @@ func (a *AllServers) Count() int {
|
|||||||
len(a.Purevpn.Servers) +
|
len(a.Purevpn.Servers) +
|
||||||
len(a.Surfshark.Servers) +
|
len(a.Surfshark.Servers) +
|
||||||
len(a.Torguard.Servers) +
|
len(a.Torguard.Servers) +
|
||||||
|
len(a.VPNUnlimited.Servers) +
|
||||||
len(a.Vyprvpn.Servers) +
|
len(a.Vyprvpn.Servers) +
|
||||||
len(a.Windscribe.Servers)
|
len(a.Windscribe.Servers)
|
||||||
}
|
}
|
||||||
@@ -102,6 +104,11 @@ type TorguardServers struct {
|
|||||||
Timestamp int64 `json:"timestamp"`
|
Timestamp int64 `json:"timestamp"`
|
||||||
Servers []TorguardServer `json:"servers"`
|
Servers []TorguardServer `json:"servers"`
|
||||||
}
|
}
|
||||||
|
type VPNUnlimitedServers struct {
|
||||||
|
Version uint16 `json:"version"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
Servers []VPNUnlimitedServer `json:"servers"`
|
||||||
|
}
|
||||||
type VyprvpnServers struct {
|
type VyprvpnServers struct {
|
||||||
Version uint16 `json:"version"`
|
Version uint16 `json:"version"`
|
||||||
Timestamp int64 `json:"timestamp"`
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/provider/purevpn"
|
"github.com/qdm12/gluetun/internal/provider/purevpn"
|
||||||
"github.com/qdm12/gluetun/internal/provider/surfshark"
|
"github.com/qdm12/gluetun/internal/provider/surfshark"
|
||||||
"github.com/qdm12/gluetun/internal/provider/torguard"
|
"github.com/qdm12/gluetun/internal/provider/torguard"
|
||||||
|
"github.com/qdm12/gluetun/internal/provider/vpnunlimited"
|
||||||
"github.com/qdm12/gluetun/internal/provider/vyprvpn"
|
"github.com/qdm12/gluetun/internal/provider/vyprvpn"
|
||||||
"github.com/qdm12/gluetun/internal/provider/windscribe"
|
"github.com/qdm12/gluetun/internal/provider/windscribe"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
@@ -69,6 +70,8 @@ func New(provider string, allServers models.AllServers, timeNow func() time.Time
|
|||||||
return surfshark.New(allServers.Surfshark.Servers, randSource)
|
return surfshark.New(allServers.Surfshark.Servers, randSource)
|
||||||
case constants.Torguard:
|
case constants.Torguard:
|
||||||
return torguard.New(allServers.Torguard.Servers, randSource)
|
return torguard.New(allServers.Torguard.Servers, randSource)
|
||||||
|
case constants.VPNUnlimited:
|
||||||
|
return vpnunlimited.New(allServers.VPNUnlimited.Servers, randSource)
|
||||||
case constants.Vyprvpn:
|
case constants.Vyprvpn:
|
||||||
return vyprvpn.New(allServers.Vyprvpn.Servers, randSource)
|
return vyprvpn.New(allServers.Vyprvpn.Servers, randSource)
|
||||||
case constants.Windscribe:
|
case constants.Windscribe:
|
||||||
|
|||||||
44
internal/provider/vpnunlimited/connection.go
Normal file
44
internal/provider/vpnunlimited/connection.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrProtocolUnsupported = errors.New("network protocol is not supported")
|
||||||
|
|
||||||
|
func (p *Provider) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
|
const port = 1194
|
||||||
|
const protocol = constants.UDP
|
||||||
|
if selection.TCP {
|
||||||
|
return connection, ErrProtocolUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
servers, err := p.filterServers(selection)
|
||||||
|
if err != nil {
|
||||||
|
return connection, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var connections []models.OpenVPNConnection
|
||||||
|
for _, server := range servers {
|
||||||
|
for _, IP := range server.IPs {
|
||||||
|
connection := models.OpenVPNConnection{
|
||||||
|
IP: IP,
|
||||||
|
Port: port,
|
||||||
|
Protocol: protocol,
|
||||||
|
}
|
||||||
|
connections = append(connections, connection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.PickRandomConnection(connections, p.randSource), nil
|
||||||
|
}
|
||||||
31
internal/provider/vpnunlimited/filter.go
Normal file
31
internal/provider/vpnunlimited/filter.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Provider) filterServers(selection configuration.ServerSelection) (
|
||||||
|
servers []models.VPNUnlimitedServer, err error) {
|
||||||
|
for _, server := range p.servers {
|
||||||
|
switch {
|
||||||
|
case
|
||||||
|
utils.FilterByPossibilities(server.Country, selection.Countries),
|
||||||
|
utils.FilterByPossibilities(server.City, selection.Cities),
|
||||||
|
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||||
|
selection.FreeOnly && !server.Free,
|
||||||
|
selection.StreamOnly && !server.Stream,
|
||||||
|
selection.TCP && !server.TCP,
|
||||||
|
!selection.TCP && !server.UDP:
|
||||||
|
default:
|
||||||
|
servers = append(servers, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(servers) == 0 {
|
||||||
|
return nil, utils.NoServerFoundError(selection)
|
||||||
|
}
|
||||||
|
|
||||||
|
return servers, nil
|
||||||
|
}
|
||||||
69
internal/provider/vpnunlimited/openvpnconf.go
Normal file
69
internal/provider/vpnunlimited/openvpnconf.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Provider) BuildConf(connection models.OpenVPNConnection,
|
||||||
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
|
lines = []string{
|
||||||
|
"client",
|
||||||
|
"dev tun",
|
||||||
|
"nobind",
|
||||||
|
"persist-key",
|
||||||
|
"tls-exit",
|
||||||
|
"remote-cert-tls server",
|
||||||
|
|
||||||
|
// VPNUnlimited specific
|
||||||
|
"reneg-sec 0",
|
||||||
|
"ping 5",
|
||||||
|
"ping-exit 30",
|
||||||
|
"comp-lzo no",
|
||||||
|
"route-metric 1",
|
||||||
|
|
||||||
|
// Added constant values
|
||||||
|
"auth-nocache",
|
||||||
|
"mute-replay-warnings",
|
||||||
|
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
|
||||||
|
"auth-retry nointeract",
|
||||||
|
"suppress-timestamps",
|
||||||
|
|
||||||
|
// Modified variables
|
||||||
|
"verb " + strconv.Itoa(settings.Verbosity),
|
||||||
|
// "auth-user-pass " + constants.OpenVPNAuthConf,
|
||||||
|
connection.ProtoLine(),
|
||||||
|
connection.RemoteLine(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.Cipher != "" {
|
||||||
|
lines = append(lines, utils.CipherLines(settings.Cipher, settings.Version)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.Auth != "" {
|
||||||
|
lines = append(lines, "auth "+settings.Auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.MSSFix > 0 {
|
||||||
|
lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !settings.Root {
|
||||||
|
lines = append(lines, "user "+username)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, utils.WrapOpenvpnCA(
|
||||||
|
constants.VPNUnlimitedCertificateAuthority)...)
|
||||||
|
lines = append(lines, utils.WrapOpenvpnCert(
|
||||||
|
settings.Provider.ExtraConfigOptions.ClientCertificate)...)
|
||||||
|
lines = append(lines, utils.WrapOpenvpnKey(
|
||||||
|
settings.Provider.ExtraConfigOptions.ClientKey)...)
|
||||||
|
|
||||||
|
lines = append(lines, "")
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
17
internal/provider/vpnunlimited/portforward.go
Normal file
17
internal/provider/vpnunlimited/portforward.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
"github.com/qdm12/golibs/os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Provider) 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 VPN Unlimited")
|
||||||
|
}
|
||||||
19
internal/provider/vpnunlimited/provider.go
Normal file
19
internal/provider/vpnunlimited/provider.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Provider struct {
|
||||||
|
servers []models.VPNUnlimitedServer
|
||||||
|
randSource rand.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(servers []models.VPNUnlimitedServer, randSource rand.Source) *Provider {
|
||||||
|
return &Provider{
|
||||||
|
servers: servers,
|
||||||
|
randSource: randSource,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,22 +32,23 @@ func (s *storage) logTimeDiff(provider string, persistedUnix, hardcodedUnix int6
|
|||||||
|
|
||||||
func (s *storage) mergeServers(hardcoded, persisted models.AllServers) models.AllServers {
|
func (s *storage) mergeServers(hardcoded, persisted models.AllServers) models.AllServers {
|
||||||
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),
|
Fastestvpn: s.mergeFastestvpn(hardcoded.Fastestvpn, persisted.Fastestvpn),
|
||||||
HideMyAss: s.mergeHideMyAss(hardcoded.HideMyAss, persisted.HideMyAss),
|
HideMyAss: s.mergeHideMyAss(hardcoded.HideMyAss, persisted.HideMyAss),
|
||||||
Ivpn: s.mergeIvpn(hardcoded.Ivpn, persisted.Ivpn),
|
Ivpn: s.mergeIvpn(hardcoded.Ivpn, persisted.Ivpn),
|
||||||
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),
|
||||||
Privado: s.mergePrivado(hardcoded.Privado, persisted.Privado),
|
Privado: s.mergePrivado(hardcoded.Privado, persisted.Privado),
|
||||||
Pia: s.mergePIA(hardcoded.Pia, persisted.Pia),
|
Pia: s.mergePIA(hardcoded.Pia, persisted.Pia),
|
||||||
Privatevpn: s.mergePrivatevpn(hardcoded.Privatevpn, persisted.Privatevpn),
|
Privatevpn: s.mergePrivatevpn(hardcoded.Privatevpn, persisted.Privatevpn),
|
||||||
Protonvpn: s.mergeProtonvpn(hardcoded.Protonvpn, persisted.Protonvpn),
|
Protonvpn: s.mergeProtonvpn(hardcoded.Protonvpn, persisted.Protonvpn),
|
||||||
Purevpn: s.mergePureVPN(hardcoded.Purevpn, persisted.Purevpn),
|
Purevpn: s.mergePureVPN(hardcoded.Purevpn, persisted.Purevpn),
|
||||||
Surfshark: s.mergeSurfshark(hardcoded.Surfshark, persisted.Surfshark),
|
Surfshark: s.mergeSurfshark(hardcoded.Surfshark, persisted.Surfshark),
|
||||||
Torguard: s.mergeTorguard(hardcoded.Torguard, persisted.Torguard),
|
Torguard: s.mergeTorguard(hardcoded.Torguard, persisted.Torguard),
|
||||||
Vyprvpn: s.mergeVyprvpn(hardcoded.Vyprvpn, persisted.Vyprvpn),
|
VPNUnlimited: s.mergeVPNUnlimited(hardcoded.VPNUnlimited, persisted.VPNUnlimited),
|
||||||
Windscribe: s.mergeWindscribe(hardcoded.Windscribe, persisted.Windscribe),
|
Vyprvpn: s.mergeVyprvpn(hardcoded.Vyprvpn, persisted.Vyprvpn),
|
||||||
|
Windscribe: s.mergeWindscribe(hardcoded.Windscribe, persisted.Windscribe),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,6 +236,20 @@ func (s *storage) mergeTorguard(hardcoded, persisted models.TorguardServers) mod
|
|||||||
return persisted
|
return persisted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *storage) mergeVPNUnlimited(hardcoded, persisted models.VPNUnlimitedServers) models.VPNUnlimitedServers {
|
||||||
|
if persisted.Timestamp <= hardcoded.Timestamp {
|
||||||
|
return hardcoded
|
||||||
|
}
|
||||||
|
versionDiff := hardcoded.Version - persisted.Version
|
||||||
|
if versionDiff > 0 {
|
||||||
|
s.logVersionDiff(constants.VPNUnlimited, versionDiff)
|
||||||
|
return hardcoded
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logTimeDiff(constants.VPNUnlimited, persisted.Timestamp, hardcoded.Timestamp)
|
||||||
|
return persisted
|
||||||
|
}
|
||||||
|
|
||||||
func (s *storage) mergeVyprvpn(hardcoded, persisted models.VyprvpnServers) models.VyprvpnServers {
|
func (s *storage) mergeVyprvpn(hardcoded, persisted models.VyprvpnServers) models.VyprvpnServers {
|
||||||
if persisted.Timestamp <= hardcoded.Timestamp {
|
if persisted.Timestamp <= hardcoded.Timestamp {
|
||||||
return hardcoded
|
return hardcoded
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ func countServers(allServers models.AllServers) int {
|
|||||||
len(allServers.Purevpn.Servers) +
|
len(allServers.Purevpn.Servers) +
|
||||||
len(allServers.Surfshark.Servers) +
|
len(allServers.Surfshark.Servers) +
|
||||||
len(allServers.Torguard.Servers) +
|
len(allServers.Torguard.Servers) +
|
||||||
|
len(allServers.VPNUnlimited.Servers) +
|
||||||
len(allServers.Vyprvpn.Servers) +
|
len(allServers.Vyprvpn.Servers) +
|
||||||
len(allServers.Windscribe.Servers)
|
len(allServers.Windscribe.Servers)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/updater/providers/cyberghost"
|
"github.com/qdm12/gluetun/internal/updater/providers/cyberghost"
|
||||||
"github.com/qdm12/gluetun/internal/updater/providers/fastestvpn"
|
"github.com/qdm12/gluetun/internal/updater/providers/fastestvpn"
|
||||||
"github.com/qdm12/gluetun/internal/updater/providers/hidemyass"
|
"github.com/qdm12/gluetun/internal/updater/providers/hidemyass"
|
||||||
@@ -17,6 +18,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/updater/providers/purevpn"
|
"github.com/qdm12/gluetun/internal/updater/providers/purevpn"
|
||||||
"github.com/qdm12/gluetun/internal/updater/providers/surfshark"
|
"github.com/qdm12/gluetun/internal/updater/providers/surfshark"
|
||||||
"github.com/qdm12/gluetun/internal/updater/providers/torguard"
|
"github.com/qdm12/gluetun/internal/updater/providers/torguard"
|
||||||
|
"github.com/qdm12/gluetun/internal/updater/providers/vpnunlimited"
|
||||||
"github.com/qdm12/gluetun/internal/updater/providers/vyprvpn"
|
"github.com/qdm12/gluetun/internal/updater/providers/vyprvpn"
|
||||||
"github.com/qdm12/gluetun/internal/updater/providers/windscribe"
|
"github.com/qdm12/gluetun/internal/updater/providers/windscribe"
|
||||||
)
|
)
|
||||||
@@ -261,6 +263,26 @@ func (u *updater) updateTorguard(ctx context.Context) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *updater) updateVPNUnlimited(ctx context.Context) (err error) {
|
||||||
|
minServers := getMinServers(len(u.servers.VPNUnlimited.Servers))
|
||||||
|
servers, warnings, err := vpnunlimited.GetServers(
|
||||||
|
ctx, u.unzipper, u.presolver, minServers)
|
||||||
|
if u.options.CLI {
|
||||||
|
for _, warning := range warnings {
|
||||||
|
u.logger.Warn(constants.VPNUnlimited + ": " + warning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if u.options.Stdout {
|
||||||
|
u.println(vpnunlimited.Stringify(servers))
|
||||||
|
}
|
||||||
|
u.servers.VPNUnlimited.Timestamp = u.timeNow().Unix()
|
||||||
|
u.servers.VPNUnlimited.Servers = servers
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *updater) updateVyprvpn(ctx context.Context) (err error) {
|
func (u *updater) updateVyprvpn(ctx context.Context) (err error) {
|
||||||
minServers := getMinServers(len(u.servers.Vyprvpn.Servers))
|
minServers := getMinServers(len(u.servers.Vyprvpn.Servers))
|
||||||
servers, warnings, err := vyprvpn.GetServers(
|
servers, warnings, err := vyprvpn.GetServers(
|
||||||
|
|||||||
160
internal/updater/providers/vpnunlimited/constants.go
Normal file
160
internal/updater/providers/vpnunlimited/constants.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getHostToServer() (hts hostToServer, warnings []string) {
|
||||||
|
shortHTS := map[string]models.VPNUnlimitedServer{
|
||||||
|
"ae": {},
|
||||||
|
"ar": {},
|
||||||
|
"at": {},
|
||||||
|
"au-syd": {
|
||||||
|
City: "Sydney",
|
||||||
|
},
|
||||||
|
"ba": {},
|
||||||
|
"be": {},
|
||||||
|
"bg": {},
|
||||||
|
"br": {},
|
||||||
|
"by": {},
|
||||||
|
"ca-tr": {
|
||||||
|
City: "Toronto",
|
||||||
|
},
|
||||||
|
"ca-vn": {
|
||||||
|
City: "Vancouver",
|
||||||
|
},
|
||||||
|
"ca": {},
|
||||||
|
"ch": {},
|
||||||
|
"cr": {},
|
||||||
|
"cy": {},
|
||||||
|
"cz": {},
|
||||||
|
"de-dus": {
|
||||||
|
City: "Düsseldorf",
|
||||||
|
},
|
||||||
|
"de": {},
|
||||||
|
"dk": {},
|
||||||
|
"ee": {},
|
||||||
|
"es": {},
|
||||||
|
"fi": {},
|
||||||
|
"fr-rbx": {
|
||||||
|
City: "Roubaix",
|
||||||
|
},
|
||||||
|
"fr": {},
|
||||||
|
"gr": {},
|
||||||
|
"hr": {},
|
||||||
|
"hu": {},
|
||||||
|
"ie-dub": {
|
||||||
|
City: "Dublin",
|
||||||
|
},
|
||||||
|
"il": {},
|
||||||
|
"im": {},
|
||||||
|
"in-ka": {
|
||||||
|
City: "Karnataka",
|
||||||
|
},
|
||||||
|
"in": {},
|
||||||
|
"is": {},
|
||||||
|
"it-mil": {
|
||||||
|
City: "Milan",
|
||||||
|
},
|
||||||
|
"jp": {},
|
||||||
|
"kr": {},
|
||||||
|
"lt": {},
|
||||||
|
"lu": {},
|
||||||
|
"lv": {},
|
||||||
|
"ly": {},
|
||||||
|
"md": {},
|
||||||
|
"mx": {},
|
||||||
|
"mys": {},
|
||||||
|
"nl": {},
|
||||||
|
"no": {},
|
||||||
|
"nz": {},
|
||||||
|
"om": {},
|
||||||
|
"pl": {},
|
||||||
|
"pt": {},
|
||||||
|
"ro": {},
|
||||||
|
"rs": {},
|
||||||
|
"se": {},
|
||||||
|
"sg-free": {
|
||||||
|
Free: true,
|
||||||
|
},
|
||||||
|
"sg": {},
|
||||||
|
"si": {},
|
||||||
|
"sk": {},
|
||||||
|
"th": {},
|
||||||
|
"tr": {},
|
||||||
|
"uk-cv": {
|
||||||
|
City: "London",
|
||||||
|
},
|
||||||
|
"uk-lon": {
|
||||||
|
City: "London",
|
||||||
|
},
|
||||||
|
"uk": {},
|
||||||
|
"us-chi": {
|
||||||
|
City: "Chicago",
|
||||||
|
},
|
||||||
|
"us-dal": {
|
||||||
|
City: "Dallas",
|
||||||
|
},
|
||||||
|
"us-den": {
|
||||||
|
City: "Denver",
|
||||||
|
},
|
||||||
|
"us-hou": {
|
||||||
|
City: "Houston",
|
||||||
|
},
|
||||||
|
"us-la": {
|
||||||
|
City: "Los Angeles",
|
||||||
|
},
|
||||||
|
"us-lv": {
|
||||||
|
City: "Las Vegas",
|
||||||
|
},
|
||||||
|
"us-mia": {
|
||||||
|
City: "Miami",
|
||||||
|
},
|
||||||
|
"us-ny-free": {
|
||||||
|
City: "New York",
|
||||||
|
Free: true,
|
||||||
|
},
|
||||||
|
"us-ny": {
|
||||||
|
City: "New York",
|
||||||
|
},
|
||||||
|
"us-sea": {
|
||||||
|
City: "Seattle",
|
||||||
|
},
|
||||||
|
"us-sf": {
|
||||||
|
City: "San Francisco",
|
||||||
|
},
|
||||||
|
"us-sl": {
|
||||||
|
City: "Saint Louis",
|
||||||
|
},
|
||||||
|
"us-slc": {
|
||||||
|
City: "Salt Lake City",
|
||||||
|
},
|
||||||
|
"us-stream": {
|
||||||
|
Stream: true,
|
||||||
|
},
|
||||||
|
"us": {},
|
||||||
|
"vn": {},
|
||||||
|
"za": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
hts = make(hostToServer, len(shortHTS))
|
||||||
|
|
||||||
|
countryCodesMap := constants.CountryCodes()
|
||||||
|
for shortHost, server := range shortHTS {
|
||||||
|
server.UDP = true
|
||||||
|
server.Hostname = shortHost + ".vpnunlimitedapp.com"
|
||||||
|
countryCode := strings.Split(shortHost, "-")[0]
|
||||||
|
country, ok := countryCodesMap[countryCode]
|
||||||
|
if !ok {
|
||||||
|
warnings = append(warnings, "country code not found: "+countryCode)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
server.Country = country
|
||||||
|
hts[server.Hostname] = server
|
||||||
|
}
|
||||||
|
|
||||||
|
return hts, warnings
|
||||||
|
}
|
||||||
38
internal/updater/providers/vpnunlimited/hosttoserver.go
Normal file
38
internal/updater/providers/vpnunlimited/hosttoserver.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type hostToServer map[string]models.VPNUnlimitedServer
|
||||||
|
|
||||||
|
func (hts hostToServer) toHostsSlice() (hosts []string) {
|
||||||
|
hosts = make([]string, 0, len(hts))
|
||||||
|
for host := range hts {
|
||||||
|
hosts = append(hosts, host)
|
||||||
|
}
|
||||||
|
return hosts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) {
|
||||||
|
for host, IPs := range hostToIPs {
|
||||||
|
server := hts[host]
|
||||||
|
server.IPs = IPs
|
||||||
|
hts[host] = server
|
||||||
|
}
|
||||||
|
for host, server := range hts {
|
||||||
|
if len(server.IPs) == 0 {
|
||||||
|
delete(hts, host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts hostToServer) toServersSlice() (servers []models.VPNUnlimitedServer) {
|
||||||
|
servers = make([]models.VPNUnlimitedServer, 0, len(hts))
|
||||||
|
for _, server := range hts {
|
||||||
|
servers = append(servers, server)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
32
internal/updater/providers/vpnunlimited/resolve.go
Normal file
32
internal/updater/providers/vpnunlimited/resolve.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/updater/resolver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
|
||||||
|
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
|
||||||
|
warnings []string, err error) {
|
||||||
|
const (
|
||||||
|
maxFailRatio = 0.1
|
||||||
|
maxDuration = 20 * time.Second
|
||||||
|
betweenDuration = time.Second
|
||||||
|
maxNoNew = 2
|
||||||
|
maxFails = 2
|
||||||
|
)
|
||||||
|
settings := resolver.ParallelSettings{
|
||||||
|
MaxFailRatio: maxFailRatio,
|
||||||
|
MinFound: minServers,
|
||||||
|
Repeat: resolver.RepeatSettings{
|
||||||
|
MaxDuration: maxDuration,
|
||||||
|
BetweenDuration: betweenDuration,
|
||||||
|
MaxNoNew: maxNoNew,
|
||||||
|
MaxFails: maxFails,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return presolver.Resolve(ctx, hosts, settings)
|
||||||
|
}
|
||||||
42
internal/updater/providers/vpnunlimited/servers.go
Normal file
42
internal/updater/providers/vpnunlimited/servers.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Package vpnunlimited contains code to obtain the server information
|
||||||
|
// for the VPNUnlimited provider.
|
||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/gluetun/internal/updater/resolver"
|
||||||
|
"github.com/qdm12/gluetun/internal/updater/unzip"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrNotEnoughServers = errors.New("not enough servers found")
|
||||||
|
|
||||||
|
func GetServers(ctx context.Context, unzipper unzip.Unzipper,
|
||||||
|
presolver resolver.Parallel, minServers int) (
|
||||||
|
servers []models.VPNUnlimitedServer, warnings []string, err error) {
|
||||||
|
// Hardcoded data from a user provided ZIP file since it's behind a login wall
|
||||||
|
hts, warnings := getHostToServer()
|
||||||
|
|
||||||
|
hosts := hts.toHostsSlice()
|
||||||
|
hostToIPs, newWarnings, err := resolveHosts(ctx, presolver, hosts, minServers)
|
||||||
|
warnings = append(warnings, newWarnings...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, warnings, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hts.adaptWithIPs(hostToIPs)
|
||||||
|
|
||||||
|
servers = hts.toServersSlice()
|
||||||
|
|
||||||
|
if len(servers) < minServers {
|
||||||
|
return nil, warnings, fmt.Errorf("%w: %d and expected at least %d",
|
||||||
|
ErrNotEnoughServers, len(servers), minServers)
|
||||||
|
}
|
||||||
|
|
||||||
|
sortServers(servers)
|
||||||
|
|
||||||
|
return servers, warnings, nil
|
||||||
|
}
|
||||||
19
internal/updater/providers/vpnunlimited/sort.go
Normal file
19
internal/updater/providers/vpnunlimited/sort.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sortServers(servers []models.VPNUnlimitedServer) {
|
||||||
|
sort.Slice(servers, func(i, j int) bool {
|
||||||
|
if servers[i].Country == servers[j].Country {
|
||||||
|
if servers[i].City == servers[j].City {
|
||||||
|
return servers[i].Hostname < servers[j].Hostname
|
||||||
|
}
|
||||||
|
return servers[i].City < servers[j].City
|
||||||
|
}
|
||||||
|
return servers[i].Country < servers[j].Country
|
||||||
|
})
|
||||||
|
}
|
||||||
14
internal/updater/providers/vpnunlimited/string.go
Normal file
14
internal/updater/providers/vpnunlimited/string.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package vpnunlimited
|
||||||
|
|
||||||
|
import "github.com/qdm12/gluetun/internal/models"
|
||||||
|
|
||||||
|
func Stringify(servers []models.VPNUnlimitedServer) (s string) {
|
||||||
|
s = "func VPNUnlimitedServers() []models.VPNUnlimitedServer {\n"
|
||||||
|
s += " return []models.VPNUnlimitedServer{\n"
|
||||||
|
for _, server := range servers {
|
||||||
|
s += " " + server.String() + ",\n"
|
||||||
|
}
|
||||||
|
s += " }\n"
|
||||||
|
s += "}"
|
||||||
|
return s
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/configuration"
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/updater/resolver"
|
"github.com/qdm12/gluetun/internal/updater/resolver"
|
||||||
"github.com/qdm12/gluetun/internal/updater/unzip"
|
"github.com/qdm12/gluetun/internal/updater/unzip"
|
||||||
@@ -186,6 +187,16 @@ func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u.options.VPNUnlimited {
|
||||||
|
u.logger.Info("updating " + constants.VPNUnlimited + " servers...")
|
||||||
|
if err := u.updateVPNUnlimited(ctx); err != nil {
|
||||||
|
if ctxErr := ctx.Err(); ctxErr != nil {
|
||||||
|
return allServers, ctxErr
|
||||||
|
}
|
||||||
|
u.logger.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if u.options.Vyprvpn {
|
if u.options.Vyprvpn {
|
||||||
u.logger.Info("updating Vyprvpn servers...")
|
u.logger.Info("updating Vyprvpn servers...")
|
||||||
if err := u.updateVyprvpn(ctx); err != nil {
|
if err := u.updateVyprvpn(ctx); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user