Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b6caa435f | ||
|
|
f9cb71027c | ||
|
|
82ac568ee3 | ||
|
|
61afdce788 | ||
|
|
119cac5a67 | ||
|
|
c6fedd9214 | ||
|
|
da525e039d | ||
|
|
29d92fd307 | ||
|
|
3863cc439e | ||
|
|
b1cfc03fc5 | ||
|
|
f706071048 | ||
|
|
501ae2741b | ||
|
|
5b75635386 | ||
|
|
2901db3cf3 | ||
|
|
6c2a3e36b5 | ||
|
|
8b125e6e95 | ||
|
|
e1cc14e055 | ||
|
|
d6659552df | ||
|
|
67001fa958 | ||
|
|
ffeeae91ab | ||
|
|
04fad1b781 | ||
|
|
dcaf952986 | ||
|
|
ca3b9e892d | ||
|
|
9f12ffc069 | ||
|
|
0d6800a515 | ||
|
|
b3d8b78205 | ||
|
|
ee82a85543 | ||
|
|
7907146aaf | ||
|
|
1a677ce4f7 | ||
|
|
f1a6594474 | ||
|
|
f1a82d9d9c | ||
|
|
8b52af0d03 | ||
|
|
dbf5c569ea | ||
|
|
06a2d79cb4 | ||
|
|
eb6238ee52 | ||
|
|
f41fec57ed | ||
|
|
c348343b22 | ||
|
|
b69dcb62e3 |
@@ -68,6 +68,7 @@ LABEL \
|
||||
org.opencontainers.image.description="VPN swiss-knife like client to tunnel to multiple VPN servers using OpenVPN, IPtables, DNS over TLS, Shadowsocks, an HTTP proxy and Alpine Linux"
|
||||
ENV VPNSP=pia \
|
||||
VERSION_INFORMATION=on \
|
||||
LOG_LEVEL=info \
|
||||
VPN_TYPE=openvpn \
|
||||
PROTOCOL=udp \
|
||||
OPENVPN_VERSION=2.5 \
|
||||
|
||||
@@ -58,7 +58,7 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
||||
- Based on Alpine 3.14 for a small Docker image of 31MB
|
||||
- Supports: **Cyberghost**, **FastestVPN**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **VPNUnlimited**, **Vyprvpn**, **Windscribe** servers
|
||||
- Supports OpenVPN
|
||||
- Supports Wireguard for **Mullvad** and **Windscribe** (more in progress, see #134)
|
||||
- Supports Wireguard for **Mullvad**, **Ivpn** and **Windscribe** (more in progress, see #134)
|
||||
- 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
|
||||
- Choose the vpn network protocol, `udp` or `tcp`
|
||||
|
||||
@@ -135,12 +135,21 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO run this in a loop or in openvpn to reload from file without restarting
|
||||
storageLogger := logger.NewChild(logging.Settings{Prefix: "storage: "})
|
||||
storage, err := storage.New(storageLogger, constants.ServersData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allServers := storage.GetServers()
|
||||
|
||||
var allSettings configuration.Settings
|
||||
err := allSettings.Read(env,
|
||||
err = allSettings.Read(env, allServers,
|
||||
logger.NewChild(logging.Settings{Prefix: "configuration: "}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.PatchLevel(allSettings.Log.Level)
|
||||
|
||||
puid, pgid := allSettings.System.PUID, allSettings.System.PGID
|
||||
|
||||
@@ -167,7 +176,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
Version: buildInfo.Version,
|
||||
Commit: buildInfo.Commit,
|
||||
BuildDate: buildInfo.Created,
|
||||
Announcement: "Wireguard is now supported!",
|
||||
Announcement: "Wireguard is now supported for Mullvad, IVPN and Windscribe!",
|
||||
AnnounceExp: announcementExp,
|
||||
// Sponsor information
|
||||
PaypalUser: "qmcgaw",
|
||||
@@ -199,15 +208,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO run this in a loop or in openvpn to reload from file without restarting
|
||||
storage := storage.New(
|
||||
logger.NewChild(logging.Settings{Prefix: "storage: "}),
|
||||
constants.ServersData)
|
||||
allServers, err := storage.SyncServers(constants.GetAllServers())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const defaultUsername = "nonrootuser"
|
||||
nonRootUsername, err := alpineConf.CreateUser(defaultUsername, puid)
|
||||
if err != nil {
|
||||
@@ -225,7 +225,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
return err
|
||||
}
|
||||
|
||||
firewallLogLevel := logging.LevelInfo
|
||||
firewallLogLevel := allSettings.Log.Level
|
||||
if allSettings.Firewall.Debug {
|
||||
firewallLogLevel = logging.LevelDebug
|
||||
}
|
||||
@@ -233,7 +233,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
Prefix: "routing: ",
|
||||
Level: firewallLogLevel,
|
||||
})
|
||||
routingConf := routing.NewRouting(routingLogger)
|
||||
routingConf := routing.New(netLinker, routingLogger)
|
||||
|
||||
defaultInterface, defaultGateway, err := routingConf.DefaultRoute()
|
||||
if err != nil {
|
||||
@@ -293,7 +293,8 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
}
|
||||
|
||||
for _, vpnPort := range allSettings.Firewall.VPNInputPorts {
|
||||
err = firewallConf.SetAllowedPort(ctx, vpnPort, allSettings.VPN.OpenVPN.Interface)
|
||||
vpnIntf := allSettings.VPN.VPNInterface()
|
||||
err = firewallConf.SetAllowedPort(ctx, vpnPort, vpnIntf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -18,13 +18,14 @@ type OpenvpnConfigMaker interface {
|
||||
}
|
||||
|
||||
func (c *CLI) OpenvpnConfig(logger logging.Logger, env params.Interface) error {
|
||||
var allSettings configuration.Settings
|
||||
err := allSettings.Read(env, logger)
|
||||
storage, err := storage.New(logger, constants.ServersData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allServers, err := storage.New(logger, constants.ServersData).
|
||||
SyncServers(constants.GetAllServers())
|
||||
allServers := storage.GetServers()
|
||||
|
||||
var allSettings configuration.Settings
|
||||
err = allSettings.Read(env, allServers, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
var (
|
||||
ErrModeUnspecified = errors.New("at least one of -enduser or -maintainers must be specified")
|
||||
ErrSyncServers = errors.New("cannot sync hardcoded and persisted servers")
|
||||
ErrNewStorage = errors.New("cannot create storage")
|
||||
ErrUpdateServerInformation = errors.New("cannot update server information")
|
||||
ErrWriteToFile = errors.New("cannot write updated information to file")
|
||||
)
|
||||
@@ -68,11 +68,13 @@ func (c *CLI) Update(ctx context.Context, args []string, logger logging.Logger)
|
||||
|
||||
const clientTimeout = 10 * time.Second
|
||||
httpClient := &http.Client{Timeout: clientTimeout}
|
||||
storage := storage.New(logger, constants.ServersData)
|
||||
currentServers, err := storage.SyncServers(constants.GetAllServers())
|
||||
|
||||
storage, err := storage.New(logger, constants.ServersData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrSyncServers, err)
|
||||
return fmt.Errorf("%w: %s", ErrNewStorage, err)
|
||||
}
|
||||
currentServers := storage.GetServers()
|
||||
|
||||
updater := updater.New(options, httpClient, currentServers, logger)
|
||||
allServers, err := updater.UpdateServers(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
func (settings *Provider) readCyberghost(r reader) (err error) {
|
||||
settings.Name = constants.Cyberghost
|
||||
servers := r.servers.GetCyberghost()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
@@ -15,17 +16,18 @@ func (settings *Provider) readCyberghost(r reader) (err error) {
|
||||
}
|
||||
|
||||
settings.ServerSelection.Groups, err = r.env.CSVInside("CYBERGHOST_GROUP",
|
||||
constants.CyberghostGroupChoices())
|
||||
constants.CyberghostGroupChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CYBERGHOST_GROUP: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.CyberghostRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.CyberghostRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.CyberghostHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.CyberghostHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -8,18 +8,20 @@ import (
|
||||
|
||||
func (settings *Provider) readFastestvpn(r reader) (err error) {
|
||||
settings.Name = constants.Fastestvpn
|
||||
servers := r.servers.GetFastestvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.FastestvpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.FastestvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.FastestvpnCountriesChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.FastestvpnCountriesChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
@@ -33,7 +34,7 @@ func (settings *Health) lines() (lines []string) {
|
||||
|
||||
// Read is to be used for the healthcheck query mode.
|
||||
func (settings *Health) Read(env params.Interface, logger logging.Logger) (err error) {
|
||||
reader := newReader(env, logger)
|
||||
reader := newReader(env, models.AllServers{}, logger) // note: no need for servers data
|
||||
return settings.read(reader)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,28 +8,30 @@ import (
|
||||
|
||||
func (settings *Provider) readHideMyAss(r reader) (err error) {
|
||||
settings.Name = constants.HideMyAss
|
||||
servers := r.servers.GetHideMyAss()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.HideMyAssCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.HideMyAssCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.HideMyAssCountryChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.HideMyAssCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.HideMyAssCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.HideMyAssCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.HideMyAssHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.HideMyAssHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -8,23 +8,25 @@ import (
|
||||
|
||||
func (settings *Provider) readIpvanish(r reader) (err error) {
|
||||
settings.Name = constants.Ipvanish
|
||||
servers := r.servers.GetIpvanish()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IpvanishCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IpvanishCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IpvanishCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IpvanishCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.IpvanishHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params/mock_params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -119,21 +120,28 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
servers := []models.IpvanishServer{{Hostname: "a"}}
|
||||
allServers := models.AllServers{
|
||||
Ipvanish: models.IpvanishServers{
|
||||
Servers: servers,
|
||||
},
|
||||
}
|
||||
|
||||
env := mock_params.NewMockInterface(ctrl)
|
||||
if testCase.targetIP.call {
|
||||
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
||||
Return(testCase.targetIP.value, testCase.targetIP.err)
|
||||
}
|
||||
if testCase.countries.call {
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.IpvanishCountryChoices()).
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.IpvanishCountryChoices(servers)).
|
||||
Return(testCase.countries.values, testCase.countries.err)
|
||||
}
|
||||
if testCase.cities.call {
|
||||
env.EXPECT().CSVInside("CITY", constants.IpvanishCityChoices()).
|
||||
env.EXPECT().CSVInside("CITY", constants.IpvanishCityChoices(servers)).
|
||||
Return(testCase.cities.values, testCase.cities.err)
|
||||
}
|
||||
if testCase.hostnames.call {
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices()).
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices(servers)).
|
||||
Return(testCase.hostnames.values, testCase.hostnames.err)
|
||||
}
|
||||
if testCase.protocol.call {
|
||||
@@ -141,7 +149,10 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
||||
Return(testCase.protocol.value, testCase.protocol.err)
|
||||
}
|
||||
|
||||
r := reader{env: env}
|
||||
r := reader{
|
||||
servers: allServers,
|
||||
env: env,
|
||||
}
|
||||
|
||||
var settings Provider
|
||||
err := settings.readIpvanish(r)
|
||||
|
||||
@@ -4,30 +4,67 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
func (settings *Provider) readIvpn(r reader) (err error) {
|
||||
settings.Name = constants.Ivpn
|
||||
servers := r.servers.GetIvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IvpnCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IvpnCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IvpnCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IvpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices())
|
||||
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.IvpnISPChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable ISP: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||
err = settings.ServerSelection.OpenVPN.readIVPN(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return settings.ServerSelection.Wireguard.readIVPN(r.env)
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readIVPN(env params.Interface) (err error) {
|
||||
settings.TCP, err = readProtocol(env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.CustomPort, err = readOpenVPNCustomPort(env, settings.TCP,
|
||||
[]uint16{80, 443, 1443}, []uint16{53, 1194, 2049, 2050})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *WireguardSelection) readIVPN(env params.Interface) (err error) {
|
||||
settings.CustomPort, err = readWireguardCustomPort(env,
|
||||
[]uint16{2049, 2050, 53, 30587, 41893, 48574, 58237})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@ import (
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params/mock_params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_Provider_readIvpn(t *testing.T) {
|
||||
func Test_Provider_readIvpn(t *testing.T) { //nolint:gocognit
|
||||
t.Parallel()
|
||||
|
||||
var errDummy = errors.New("dummy test error")
|
||||
@@ -23,6 +24,15 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
err error
|
||||
}
|
||||
|
||||
type portCall struct {
|
||||
getCall bool
|
||||
getValue string // "" or "0"
|
||||
getErr error
|
||||
portCall bool
|
||||
portValue uint16
|
||||
portErr error
|
||||
}
|
||||
|
||||
type sliceStringCall struct {
|
||||
call bool
|
||||
values []string
|
||||
@@ -30,11 +40,14 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
protocol singleStringCall
|
||||
targetIP singleStringCall
|
||||
countries sliceStringCall
|
||||
cities sliceStringCall
|
||||
isps sliceStringCall
|
||||
hostnames sliceStringCall
|
||||
protocol singleStringCall
|
||||
ovpnPort portCall
|
||||
wgPort portCall
|
||||
settings Provider
|
||||
err error
|
||||
}{
|
||||
@@ -62,20 +75,32 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
},
|
||||
err: errors.New("environment variable CITY: dummy test error"),
|
||||
},
|
||||
"isps error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
err: errors.New("environment variable ISP: dummy test error"),
|
||||
},
|
||||
"hostnames error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"),
|
||||
},
|
||||
"protocol error": {
|
||||
"openvpn protocol error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: singleStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
@@ -83,12 +108,42 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
},
|
||||
err: errors.New("environment variable PROTOCOL: dummy test error"),
|
||||
},
|
||||
"openvpn custom port error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: singleStringCall{call: true},
|
||||
ovpnPort: portCall{getCall: true, getErr: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
err: errors.New("environment variable PORT: dummy test error"),
|
||||
},
|
||||
"wireguard custom port error": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: singleStringCall{call: true},
|
||||
ovpnPort: portCall{getCall: true, getValue: "0"},
|
||||
wgPort: portCall{getCall: true, getErr: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
err: errors.New("environment variable WIREGUARD_PORT: dummy test error"),
|
||||
},
|
||||
"default settings": {
|
||||
targetIP: singleStringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
isps: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: singleStringCall{call: true},
|
||||
ovpnPort: portCall{getCall: true, getValue: "0"},
|
||||
wgPort: portCall{getCall: true, getValue: "0"},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
},
|
||||
@@ -97,17 +152,25 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
targetIP: singleStringCall{call: true, value: "1.2.3.4"},
|
||||
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
|
||||
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
|
||||
isps: sliceStringCall{call: true, values: []string{"ISP 1"}},
|
||||
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
|
||||
protocol: singleStringCall{call: true, value: constants.TCP},
|
||||
ovpnPort: portCall{getCall: true, portCall: true, portValue: 443},
|
||||
wgPort: portCall{getCall: true, portCall: true, portValue: 2049},
|
||||
settings: Provider{
|
||||
Name: constants.Ivpn,
|
||||
ServerSelection: ServerSelection{
|
||||
OpenVPN: OpenVPNSelection{
|
||||
TCP: true,
|
||||
CustomPort: 443,
|
||||
},
|
||||
Wireguard: WireguardSelection{
|
||||
CustomPort: 2049,
|
||||
},
|
||||
TargetIP: net.IPv4(1, 2, 3, 4),
|
||||
Countries: []string{"A", "B"},
|
||||
Cities: []string{"C", "D"},
|
||||
ISPs: []string{"ISP 1"},
|
||||
Hostnames: []string{"E", "F"},
|
||||
},
|
||||
},
|
||||
@@ -120,28 +183,59 @@ func Test_Provider_readIvpn(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
env := mock_params.NewMockInterface(ctrl)
|
||||
if testCase.protocol.call {
|
||||
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||
Return(testCase.protocol.value, testCase.protocol.err)
|
||||
|
||||
servers := []models.IvpnServer{{Hostname: "a"}}
|
||||
allServers := models.AllServers{
|
||||
Ivpn: models.IvpnServers{
|
||||
Servers: servers,
|
||||
},
|
||||
}
|
||||
|
||||
if testCase.targetIP.call {
|
||||
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
||||
Return(testCase.targetIP.value, testCase.targetIP.err)
|
||||
}
|
||||
if testCase.countries.call {
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.IvpnCountryChoices()).
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.IvpnCountryChoices(servers)).
|
||||
Return(testCase.countries.values, testCase.countries.err)
|
||||
}
|
||||
if testCase.cities.call {
|
||||
env.EXPECT().CSVInside("CITY", constants.IvpnCityChoices()).
|
||||
env.EXPECT().CSVInside("CITY", constants.IvpnCityChoices(servers)).
|
||||
Return(testCase.cities.values, testCase.cities.err)
|
||||
}
|
||||
if testCase.isps.call {
|
||||
env.EXPECT().CSVInside("ISP", constants.IvpnISPChoices(servers)).
|
||||
Return(testCase.isps.values, testCase.isps.err)
|
||||
}
|
||||
if testCase.hostnames.call {
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices()).
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices(servers)).
|
||||
Return(testCase.hostnames.values, testCase.hostnames.err)
|
||||
}
|
||||
if testCase.protocol.call {
|
||||
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||
Return(testCase.protocol.value, testCase.protocol.err)
|
||||
}
|
||||
if testCase.ovpnPort.getCall {
|
||||
env.EXPECT().Get("PORT", gomock.Any()).
|
||||
Return(testCase.ovpnPort.getValue, testCase.ovpnPort.getErr)
|
||||
}
|
||||
if testCase.ovpnPort.portCall {
|
||||
env.EXPECT().Port("PORT").
|
||||
Return(testCase.ovpnPort.portValue, testCase.ovpnPort.portErr)
|
||||
}
|
||||
if testCase.wgPort.getCall {
|
||||
env.EXPECT().Get("WIREGUARD_PORT", gomock.Any()).
|
||||
Return(testCase.wgPort.getValue, testCase.wgPort.getErr)
|
||||
}
|
||||
if testCase.wgPort.portCall {
|
||||
env.EXPECT().Port("WIREGUARD_PORT").
|
||||
Return(testCase.wgPort.portValue, testCase.wgPort.portErr)
|
||||
}
|
||||
|
||||
r := reader{env: env}
|
||||
r := reader{
|
||||
servers: allServers,
|
||||
env: env,
|
||||
}
|
||||
|
||||
var settings Provider
|
||||
err := settings.readIvpn(r)
|
||||
|
||||
30
internal/configuration/log.go
Normal file
30
internal/configuration/log.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
type Log struct {
|
||||
Level logging.Level `json:"level"`
|
||||
}
|
||||
|
||||
func (settings *Log) lines() (lines []string) {
|
||||
lines = append(lines, lastIndent+"Log:")
|
||||
|
||||
lines = append(lines, indent+lastIndent+"Level: "+settings.Level.String())
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
func (settings *Log) read(env params.Interface) (err error) {
|
||||
defaultLevel := logging.LevelInfo.String()
|
||||
settings.Level, err = env.LogLevel("LOG_LEVEL", params.Default(defaultLevel))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable LOG_LEVEL: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -9,28 +9,29 @@ import (
|
||||
|
||||
func (settings *Provider) readMullvad(r reader) (err error) {
|
||||
settings.Name = constants.Mullvad
|
||||
servers := r.servers.GetMullvad()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.MullvadCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.MullvadCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.MullvadCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.MullvadCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.MullvadHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.MullvadHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.MullvadISPChoices())
|
||||
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.MullvadISPChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable ISP: %w", err)
|
||||
}
|
||||
@@ -40,7 +41,12 @@ func (settings *Provider) readMullvad(r reader) (err error) {
|
||||
return fmt.Errorf("environment variable OWNED: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readMullvad(r.env)
|
||||
err = settings.ServerSelection.OpenVPN.readMullvad(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return settings.ServerSelection.Wireguard.readMullvad(r.env)
|
||||
}
|
||||
|
||||
func (settings *OpenVPNSelection) readMullvad(env params.Interface) (err error) {
|
||||
@@ -57,3 +63,12 @@ func (settings *OpenVPNSelection) readMullvad(env params.Interface) (err error)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *WireguardSelection) readMullvad(env params.Interface) (err error) {
|
||||
settings.CustomPort, err = readWireguardCustomPort(env, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,23 +10,24 @@ import (
|
||||
|
||||
func (settings *Provider) readNordvpn(r reader) (err error) {
|
||||
settings.Name = constants.Nordvpn
|
||||
servers := r.servers.GetNordvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.NordvpnRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.NordvpnRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.NordvpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.NordvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.NordvpnHostnameChoices())
|
||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.NordvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -8,28 +8,29 @@ import (
|
||||
|
||||
func (settings *Provider) readPrivado(r reader) (err error) {
|
||||
settings.Name = constants.Privado
|
||||
servers := r.servers.GetPrivado()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivadoCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivadoCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PrivadoRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PrivadoRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivadoCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivadoCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PrivadoHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PrivadoHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -9,23 +9,24 @@ import (
|
||||
|
||||
func (settings *Provider) readPrivateInternetAccess(r reader) (err error) {
|
||||
settings.Name = constants.PrivateInternetAccess
|
||||
servers := r.servers.GetPia()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PIAGeoChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PIAGeoChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PIAHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PIAHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_NAME", constants.PIANameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_NAME", constants.PIANameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -8,23 +8,25 @@ import (
|
||||
|
||||
func (settings *Provider) readPrivatevpn(r reader) (err error) {
|
||||
settings.Name = constants.Privatevpn
|
||||
servers := r.servers.GetPrivatevpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivatevpnCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivatevpnCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivatevpnCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivatevpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PrivatevpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.PrivatevpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -9,33 +9,35 @@ import (
|
||||
|
||||
func (settings *Provider) readProtonvpn(r reader) (err error) {
|
||||
settings.Name = constants.Protonvpn
|
||||
servers := r.servers.GetProtonvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.ProtonvpnCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.ProtonvpnCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.ProtonvpnRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.ProtonvpnRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.ProtonvpnCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.ProtonvpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.ProtonvpnNameChoices())
|
||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.ProtonvpnNameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.ProtonvpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.ProtonvpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -103,7 +103,8 @@ func (settings *Provider) readVPNServiceProvider(r reader, vpnType string) (err
|
||||
"privado", "pia", "private internet access", "privatevpn", "protonvpn",
|
||||
"purevpn", "surfshark", "torguard", constants.VPNUnlimited, "vyprvpn", "windscribe"}
|
||||
case constants.Wireguard:
|
||||
allowedVPNServiceProviders = []string{constants.Mullvad, constants.Windscribe}
|
||||
allowedVPNServiceProviders = []string{constants.Mullvad, constants.Windscribe,
|
||||
constants.Ivpn}
|
||||
}
|
||||
|
||||
vpnsp, err := r.env.Inside("VPNSP", allowedVPNServiceProviders,
|
||||
@@ -167,6 +168,7 @@ func readOpenVPNCustomPort(env params.Interface, tcp bool,
|
||||
ErrInvalidPort, port, portsToString(allowedUDP))
|
||||
}
|
||||
|
||||
// note: set allowed to an empty slice to allow all valid ports
|
||||
func readWireguardCustomPort(env params.Interface, allowed []uint16) (port uint16, err error) {
|
||||
port, err = readPortOrZero(env, "WIREGUARD_PORT")
|
||||
if err != nil {
|
||||
@@ -175,11 +177,16 @@ func readWireguardCustomPort(env params.Interface, allowed []uint16) (port uint1
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if len(allowed) == 0 {
|
||||
return port, nil
|
||||
}
|
||||
|
||||
for i := range allowed {
|
||||
if allowed[i] == port {
|
||||
return port, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf(
|
||||
"environment variable WIREGUARD_PORT: %w: port %d, can only be one of %s",
|
||||
ErrInvalidPort, port, portsToString(allowed))
|
||||
|
||||
@@ -8,28 +8,29 @@ import (
|
||||
|
||||
func (settings *Provider) readPurevpn(r reader) (err error) {
|
||||
settings.Name = constants.Purevpn
|
||||
servers := r.servers.GetPurevpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PurevpnRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PurevpnRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PurevpnCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PurevpnCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PurevpnCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PurevpnCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PurevpnHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PurevpnHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -7,19 +7,23 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/golibs/verification"
|
||||
)
|
||||
|
||||
type reader struct {
|
||||
servers models.AllServers
|
||||
env params.Interface
|
||||
logger logging.Logger
|
||||
regex verification.Regex
|
||||
}
|
||||
|
||||
func newReader(env params.Interface, logger logging.Logger) reader {
|
||||
func newReader(env params.Interface,
|
||||
servers models.AllServers, logger logging.Logger) reader {
|
||||
return reader{
|
||||
servers: servers,
|
||||
env: env,
|
||||
logger: logger,
|
||||
regex: verification.NewRegex(),
|
||||
|
||||
@@ -40,6 +40,9 @@ type ServerSelection struct { //nolint:maligned
|
||||
// VPNUnlimited
|
||||
StreamOnly bool `json:"stream_only"`
|
||||
|
||||
// Surfshark
|
||||
MultiHopOnly bool `json:"multihop_only"`
|
||||
|
||||
OpenVPN OpenVPNSelection `json:"openvpn"`
|
||||
Wireguard WireguardSelection `json:"wireguard"`
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
@@ -22,6 +23,7 @@ type Settings struct {
|
||||
VersionInformation bool
|
||||
ControlServer ControlServer
|
||||
Health Health
|
||||
Log Log
|
||||
}
|
||||
|
||||
func (settings *Settings) String() string {
|
||||
@@ -33,6 +35,7 @@ func (settings *Settings) lines() (lines []string) {
|
||||
lines = append(lines, settings.VPN.lines()...)
|
||||
lines = append(lines, settings.DNS.lines()...)
|
||||
lines = append(lines, settings.Firewall.lines()...)
|
||||
lines = append(lines, settings.Log.lines()...)
|
||||
lines = append(lines, settings.System.lines()...)
|
||||
lines = append(lines, settings.HTTPProxy.lines()...)
|
||||
lines = append(lines, settings.ShadowSocks.lines()...)
|
||||
@@ -57,12 +60,14 @@ var (
|
||||
ErrUpdater = errors.New("cannot read Updater settings")
|
||||
ErrPublicIP = errors.New("cannot read Public IP getter settings")
|
||||
ErrHealth = errors.New("cannot read health settings")
|
||||
ErrLog = errors.New("cannot read log settings")
|
||||
)
|
||||
|
||||
// Read obtains all configuration options for the program and returns an error as soon
|
||||
// as an error is encountered reading them.
|
||||
func (settings *Settings) Read(env params.Interface, logger logging.Logger) (err error) {
|
||||
r := newReader(env, logger)
|
||||
func (settings *Settings) Read(env params.Interface, servers models.AllServers,
|
||||
logger logging.Logger) (err error) {
|
||||
r := newReader(env, servers, logger)
|
||||
|
||||
settings.VersionInformation, err = r.env.OnOff("VERSION_INFORMATION", params.Default("on"))
|
||||
if err != nil {
|
||||
@@ -113,5 +118,9 @@ func (settings *Settings) Read(env params.Interface, logger logging.Logger) (err
|
||||
return fmt.Errorf("%w: %s", ErrHealth, err)
|
||||
}
|
||||
|
||||
if err := settings.Log.read(r.env); err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrLog, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ func Test_Settings_lines(t *testing.T) {
|
||||
" |--Protocol: udp",
|
||||
"|--DNS:",
|
||||
"|--Firewall: disabled ⚠️",
|
||||
"|--Log:",
|
||||
" |--Level: DEBUG",
|
||||
"|--System:",
|
||||
" |--Process user ID: 0",
|
||||
" |--Process group ID: 0",
|
||||
|
||||
@@ -2,27 +2,101 @@ package configuration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
func (settings *Provider) readSurfshark(r reader) (err error) {
|
||||
settings.Name = constants.Surfshark
|
||||
servers := r.servers.GetSurfshark()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.SurfsharkRegionChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.SurfsharkCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.SurfsharkHostnameChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.SurfsharkCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.SurfsharkHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
regionChoices := constants.SurfsharkRegionChoices(servers)
|
||||
regionChoices = append(regionChoices, constants.SurfsharkRetroLocChoices(servers)...)
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", regionChoices)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
// Retro compatibility
|
||||
// TODO remove in v4
|
||||
settings.ServerSelection = surfsharkRetroRegion(settings.ServerSelection)
|
||||
|
||||
settings.ServerSelection.MultiHopOnly, err = r.env.YesNo("MULTIHOP_ONLY", params.Default("no"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable MULTIHOP_ONLY: %w", err)
|
||||
}
|
||||
|
||||
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||
}
|
||||
|
||||
func surfsharkRetroRegion(selection ServerSelection) (
|
||||
updatedSelection ServerSelection) {
|
||||
locationData := constants.SurfsharkLocationData()
|
||||
|
||||
retroToLocation := make(map[string]models.SurfsharkLocationData, len(locationData))
|
||||
for _, data := range locationData {
|
||||
if data.RetroLoc == "" {
|
||||
continue
|
||||
}
|
||||
retroToLocation[strings.ToLower(data.RetroLoc)] = data
|
||||
}
|
||||
|
||||
for i, region := range selection.Regions {
|
||||
location, ok := retroToLocation[region]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
selection.Regions[i] = strings.ToLower(location.Region)
|
||||
selection.Countries = append(selection.Countries, strings.ToLower(location.Country))
|
||||
selection.Cities = append(selection.Cities, strings.ToLower(location.City)) // even empty string
|
||||
selection.Hostnames = append(selection.Hostnames, location.Hostname)
|
||||
}
|
||||
|
||||
selection.Regions = dedupSlice(selection.Regions)
|
||||
selection.Countries = dedupSlice(selection.Countries)
|
||||
selection.Cities = dedupSlice(selection.Cities)
|
||||
selection.Hostnames = dedupSlice(selection.Hostnames)
|
||||
|
||||
return selection
|
||||
}
|
||||
|
||||
func dedupSlice(slice []string) (deduped []string) {
|
||||
if slice == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
deduped = make([]string, 0, len(slice))
|
||||
seen := make(map[string]struct{}, len(slice))
|
||||
for _, s := range slice {
|
||||
if _, ok := seen[s]; !ok {
|
||||
seen[s] = struct{}{}
|
||||
deduped = append(deduped, s)
|
||||
}
|
||||
}
|
||||
|
||||
return deduped
|
||||
}
|
||||
|
||||
305
internal/configuration/surfshark_test.go
Normal file
305
internal/configuration/surfshark_test.go
Normal file
@@ -0,0 +1,305 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/params/mock_params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_Provider_readSurfshark(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var errDummy = errors.New("dummy test error")
|
||||
|
||||
type stringCall struct {
|
||||
call bool
|
||||
value string
|
||||
err error
|
||||
}
|
||||
|
||||
type boolCall struct {
|
||||
call bool
|
||||
value bool
|
||||
err error
|
||||
}
|
||||
|
||||
type sliceStringCall struct {
|
||||
call bool
|
||||
values []string
|
||||
err error
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
targetIP stringCall
|
||||
countries sliceStringCall
|
||||
cities sliceStringCall
|
||||
hostnames sliceStringCall
|
||||
regions sliceStringCall
|
||||
multiHop boolCall
|
||||
protocol stringCall
|
||||
settings Provider
|
||||
err error
|
||||
}{
|
||||
"target IP error": {
|
||||
targetIP: stringCall{call: true, value: "something", err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable OPENVPN_TARGET_IP: dummy test error"),
|
||||
},
|
||||
"countries error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable COUNTRY: dummy test error"),
|
||||
},
|
||||
"cities error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable CITY: dummy test error"),
|
||||
},
|
||||
"hostnames error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"),
|
||||
},
|
||||
"regions error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable REGION: dummy test error"),
|
||||
},
|
||||
"multi hop error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true},
|
||||
multiHop: boolCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable MULTIHOP_ONLY: dummy test error"),
|
||||
},
|
||||
"openvpn protocol error": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true},
|
||||
multiHop: boolCall{call: true},
|
||||
protocol: stringCall{call: true, err: errDummy},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
err: errors.New("environment variable PROTOCOL: dummy test error"),
|
||||
},
|
||||
"default settings": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true},
|
||||
multiHop: boolCall{call: true},
|
||||
protocol: stringCall{call: true},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
},
|
||||
},
|
||||
"set settings": {
|
||||
targetIP: stringCall{call: true, value: "1.2.3.4"},
|
||||
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
|
||||
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
|
||||
regions: sliceStringCall{call: true, values: []string{
|
||||
"E", "F", "netherlands amsterdam",
|
||||
}}, // Netherlands Amsterdam is for retro compatibility test
|
||||
multiHop: boolCall{call: true},
|
||||
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
|
||||
protocol: stringCall{call: true, value: constants.TCP},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
ServerSelection: ServerSelection{
|
||||
OpenVPN: OpenVPNSelection{
|
||||
TCP: true,
|
||||
},
|
||||
TargetIP: net.IPv4(1, 2, 3, 4),
|
||||
Regions: []string{"E", "F", "europe"},
|
||||
Countries: []string{"A", "B", "netherlands"},
|
||||
Cities: []string{"C", "D", "amsterdam"},
|
||||
Hostnames: []string{"E", "F", "nl-ams.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"Netherlands Amsterdam": {
|
||||
targetIP: stringCall{call: true},
|
||||
countries: sliceStringCall{call: true},
|
||||
cities: sliceStringCall{call: true},
|
||||
regions: sliceStringCall{call: true, values: []string{"netherlands amsterdam"}},
|
||||
multiHop: boolCall{call: true},
|
||||
hostnames: sliceStringCall{call: true},
|
||||
protocol: stringCall{call: true},
|
||||
settings: Provider{
|
||||
Name: constants.Surfshark,
|
||||
ServerSelection: ServerSelection{
|
||||
Regions: []string{"europe"},
|
||||
Countries: []string{"netherlands"},
|
||||
Cities: []string{"amsterdam"},
|
||||
Hostnames: []string{"nl-ams.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
env := mock_params.NewMockInterface(ctrl)
|
||||
|
||||
servers := []models.SurfsharkServer{{Hostname: "a"}}
|
||||
allServers := models.AllServers{
|
||||
Surfshark: models.SurfsharkServers{
|
||||
Servers: servers,
|
||||
},
|
||||
}
|
||||
|
||||
if testCase.targetIP.call {
|
||||
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
||||
Return(testCase.targetIP.value, testCase.targetIP.err)
|
||||
}
|
||||
if testCase.countries.call {
|
||||
env.EXPECT().CSVInside("COUNTRY", constants.SurfsharkCountryChoices(servers)).
|
||||
Return(testCase.countries.values, testCase.countries.err)
|
||||
}
|
||||
if testCase.cities.call {
|
||||
env.EXPECT().CSVInside("CITY", constants.SurfsharkCityChoices(servers)).
|
||||
Return(testCase.cities.values, testCase.cities.err)
|
||||
}
|
||||
if testCase.hostnames.call {
|
||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.SurfsharkHostnameChoices(servers)).
|
||||
Return(testCase.hostnames.values, testCase.hostnames.err)
|
||||
}
|
||||
if testCase.regions.call {
|
||||
regionChoices := constants.SurfsharkRegionChoices(servers)
|
||||
regionChoices = append(regionChoices, constants.SurfsharkRetroLocChoices(servers)...)
|
||||
env.EXPECT().CSVInside("REGION", regionChoices).
|
||||
Return(testCase.regions.values, testCase.regions.err)
|
||||
}
|
||||
if testCase.multiHop.call {
|
||||
env.EXPECT().YesNo("MULTIHOP_ONLY", gomock.Any()).
|
||||
Return(testCase.multiHop.value, testCase.multiHop.err)
|
||||
}
|
||||
if testCase.protocol.call {
|
||||
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||
Return(testCase.protocol.value, testCase.protocol.err)
|
||||
}
|
||||
|
||||
r := reader{
|
||||
servers: allServers,
|
||||
env: env,
|
||||
}
|
||||
|
||||
var settings Provider
|
||||
err := settings.readSurfshark(r)
|
||||
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.Equal(t, testCase.settings, settings)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_surfsharkRetroRegion(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
original ServerSelection
|
||||
modified ServerSelection
|
||||
}{
|
||||
"empty": {},
|
||||
"1 retro region": {
|
||||
original: ServerSelection{
|
||||
Regions: []string{"australia adelaide"},
|
||||
},
|
||||
modified: ServerSelection{
|
||||
Regions: []string{"asia pacific"},
|
||||
Countries: []string{"australia"},
|
||||
Cities: []string{"adelaide"},
|
||||
Hostnames: []string{"au-adl.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
"2 overlapping retro regions": {
|
||||
original: ServerSelection{
|
||||
Regions: []string{"australia adelaide", "australia melbourne"},
|
||||
},
|
||||
modified: ServerSelection{
|
||||
Regions: []string{"asia pacific"},
|
||||
Countries: []string{"australia"},
|
||||
Cities: []string{"adelaide", "melbourne"},
|
||||
Hostnames: []string{"au-adl.prod.surfshark.com", "au-mel.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
"2 distinct retro regions": {
|
||||
original: ServerSelection{
|
||||
Regions: []string{"australia adelaide", "netherlands amsterdam"},
|
||||
},
|
||||
modified: ServerSelection{
|
||||
Regions: []string{"asia pacific", "europe"},
|
||||
Countries: []string{"australia", "netherlands"},
|
||||
Cities: []string{"adelaide", "amsterdam"},
|
||||
Hostnames: []string{"au-adl.prod.surfshark.com", "nl-ams.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
"retro region with existing region": {
|
||||
// note TestRegion will be ignored in the filters downstream
|
||||
original: ServerSelection{
|
||||
Regions: []string{"TestRegion", "australia adelaide"},
|
||||
},
|
||||
modified: ServerSelection{
|
||||
Regions: []string{"TestRegion", "asia pacific"},
|
||||
Countries: []string{"australia"},
|
||||
Cities: []string{"adelaide"},
|
||||
Hostnames: []string{"au-adl.prod.surfshark.com"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
selection := surfsharkRetroRegion(testCase.original)
|
||||
|
||||
assert.Equal(t, testCase.modified, selection)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -8,23 +8,25 @@ import (
|
||||
|
||||
func (settings *Provider) readTorguard(r reader) (err error) {
|
||||
settings.Name = constants.Torguard
|
||||
servers := r.servers.GetTorguard()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.TorguardCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.TorguardCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.TorguardCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.TorguardCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.TorguardHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.TorguardHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -87,3 +87,11 @@ func (settings VPN) isOpenVPNCustomConfig(env params.Interface) (ok bool) {
|
||||
s, err := env.Get("OPENVPN_CUSTOM_CONFIG")
|
||||
return err == nil && s != ""
|
||||
}
|
||||
|
||||
func (settings VPN) VPNInterface() (intf string) {
|
||||
if settings.Type == constants.Wireguard {
|
||||
return settings.Wireguard.Interface
|
||||
}
|
||||
// OpenVPN
|
||||
return settings.OpenVPN.Interface
|
||||
}
|
||||
|
||||
@@ -9,23 +9,25 @@ import (
|
||||
|
||||
func (settings *Provider) readVPNUnlimited(r reader) (err error) {
|
||||
settings.Name = constants.VPNUnlimited
|
||||
servers := r.servers.GetVPNUnlimited()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.VPNUnlimitedCountryChoices())
|
||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.VPNUnlimitedCountryChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.VPNUnlimitedCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.VPNUnlimitedCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.VPNUnlimitedHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.VPNUnlimitedHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@ import (
|
||||
|
||||
func (settings *Provider) readVyprvpn(r reader) (err error) {
|
||||
settings.Name = constants.Vyprvpn
|
||||
servers := r.servers.GetVyprvpn()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.VyprvpnRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.VyprvpnRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
@@ -9,23 +9,25 @@ import (
|
||||
|
||||
func (settings *Provider) readWindscribe(r reader) (err error) {
|
||||
settings.Name = constants.Windscribe
|
||||
servers := r.servers.GetWindscribe()
|
||||
|
||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.WindscribeRegionChoices())
|
||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.WindscribeRegionChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable REGION: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.WindscribeCityChoices())
|
||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.WindscribeCityChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable CITY: %w", err)
|
||||
}
|
||||
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.WindscribeHostnameChoices())
|
||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||
constants.WindscribeHostnameChoices(servers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
type Wireguard struct {
|
||||
PrivateKey string `json:"privatekey"`
|
||||
PreSharedKey string `json:"presharedkey"`
|
||||
Address *net.IPNet `json:"address"`
|
||||
Addresses []*net.IPNet `json:"addresses"`
|
||||
Interface string `json:"interface"`
|
||||
}
|
||||
|
||||
@@ -33,8 +33,11 @@ func (settings *Wireguard) lines() (lines []string) {
|
||||
lines = append(lines, indent+lastIndent+"Pre-shared key is set")
|
||||
}
|
||||
|
||||
if settings.Address != nil {
|
||||
lines = append(lines, indent+lastIndent+"Address: "+settings.Address.String())
|
||||
if len(settings.Addresses) > 0 {
|
||||
lines = append(lines, indent+lastIndent+"Addresses: ")
|
||||
for _, address := range settings.Addresses {
|
||||
lines = append(lines, indent+indent+lastIndent+address.String())
|
||||
}
|
||||
}
|
||||
|
||||
return lines
|
||||
@@ -53,16 +56,10 @@ func (settings *Wireguard) read(r reader) (err error) {
|
||||
return fmt.Errorf("environment variable WIREGUARD_PRESHARED_KEY: %w", err)
|
||||
}
|
||||
|
||||
addressString, err := r.env.Get("WIREGUARD_ADDRESS", params.Compulsory())
|
||||
err = settings.readAddresses(r.env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: %w", err)
|
||||
return err
|
||||
}
|
||||
ip, ipNet, err := net.ParseCIDR(addressString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: %w", err)
|
||||
}
|
||||
ipNet.IP = ip
|
||||
settings.Address = ipNet
|
||||
|
||||
settings.Interface, err = r.env.Get("WIREGUARD_INTERFACE", params.Default("wg0"))
|
||||
if err != nil {
|
||||
@@ -71,3 +68,21 @@ func (settings *Wireguard) read(r reader) (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *Wireguard) readAddresses(env params.Interface) (err error) {
|
||||
addressStrings, err := env.CSV("WIREGUARD_ADDRESS", params.Compulsory())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: %w", err)
|
||||
}
|
||||
|
||||
for _, addressString := range addressStrings {
|
||||
ip, ipNet, err := net.ParseCIDR(addressString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: address %s: %w", addressString, err)
|
||||
}
|
||||
ipNet.IP = ip
|
||||
settings.Addresses = append(settings.Addresses, ipNet)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ const (
|
||||
CyberghostCertificate = "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"
|
||||
)
|
||||
|
||||
func CyberghostRegionChoices() (choices []string) {
|
||||
servers := CyberghostServers()
|
||||
func CyberghostRegionChoices(servers []models.CyberghostServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -20,8 +19,7 @@ func CyberghostRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func CyberghostGroupChoices() (choices []string) {
|
||||
servers := CyberghostServers()
|
||||
func CyberghostGroupChoices(servers []models.CyberghostServer) (choices []string) {
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range servers {
|
||||
uniqueChoices[server.Group] = struct{}{}
|
||||
@@ -38,19 +36,10 @@ func CyberghostGroupChoices() (choices []string) {
|
||||
return sortable
|
||||
}
|
||||
|
||||
func CyberghostHostnameChoices() (choices []string) {
|
||||
servers := CyberghostServers()
|
||||
func CyberghostHostnameChoices(servers []models.CyberghostServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// CyberghostServers returns a slice with the server information for each
|
||||
// of the Cyberghost server.
|
||||
func CyberghostServers() (servers []models.CyberghostServer) {
|
||||
servers = make([]models.CyberghostServer, len(allServers.Cyberghost.Servers))
|
||||
copy(servers, allServers.Cyberghost.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -3,16 +3,29 @@ package constants
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/storage"
|
||||
"github.com/qdm12/golibs/logging/mock_logging"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_CyberghostGroupChoices(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
logger := mock_logging.NewMockLogger(ctrl)
|
||||
logger.EXPECT().Info(gomock.Any())
|
||||
|
||||
storage, err := storage.New(logger, "")
|
||||
require.NoError(t, err)
|
||||
|
||||
servers := storage.GetServers()
|
||||
|
||||
expected := []string{"Premium TCP Asia", "Premium TCP Europe",
|
||||
"Premium TCP USA", "Premium UDP Asia", "Premium UDP Europe",
|
||||
"Premium UDP USA"}
|
||||
choices := CyberghostGroupChoices()
|
||||
choices := CyberghostGroupChoices(servers.GetCyberghost())
|
||||
|
||||
assert.Equal(t, expected, choices)
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ const (
|
||||
FastestvpnOpenvpnStaticKeyV1 = "697fe793b32cb5091d30f2326d5d124a9412e93d0a44ef7361395d76528fcbfc82c3859dccea70a93cfa8fae409709bff75f844cf5ff0c237f426d0c20969233db0e706edb6bdf195ec3dc11b3f76bc807a77e74662d9a800c8cd1144ebb67b7f0d3f1281d1baf522bfe03b7c3f963b1364fc0769400e413b61ca7b43ab19fac9e0f77e41efd4bda7fd77b1de2d7d7855cbbe3e620cecceac72c21a825b243e651f44d90e290e09c3ad650de8fca99c858bc7caad584bc69b11e5c9fd9381c69c505ec487a65912c672d83ed0113b5a74ddfbd3ab33b3683cec593557520a72c4d6cce46111f56f3396cc3ce7183edce553c68ea0796cf6c4375fad00aaa2a42"
|
||||
)
|
||||
|
||||
func FastestvpnCountriesChoices() (choices []string) {
|
||||
servers := FastestvpnServers()
|
||||
func FastestvpnCountriesChoices(servers []models.FastestvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -19,18 +18,10 @@ func FastestvpnCountriesChoices() (choices []string) {
|
||||
return choices
|
||||
}
|
||||
|
||||
func FastestvpnHostnameChoices() (choices []string) {
|
||||
servers := FastestvpnServers()
|
||||
func FastestvpnHostnameChoices(servers []models.FastestvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return choices
|
||||
}
|
||||
|
||||
// FastestvpnServers returns the list of all VPN servers for FastestVPN.
|
||||
func FastestvpnServers() (servers []models.FastestvpnServer) {
|
||||
servers = make([]models.FastestvpnServer, len(allServers.Fastestvpn.Servers))
|
||||
copy(servers, allServers.Fastestvpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ const (
|
||||
HideMyAssRSAPrivateKey = "MIIEpAIBAAKCAQEA5XY3ERJYWs/YIeBoybivNlu+M32rJs+CAZsh7BnnetTxytI4ngsMRoqXETuis8udp2hsqEHsglLR9tlk9C8yCuKhxbkpdrXFWdISmUq5sa7/wqg/zJF1AZm5Jy0oHNyTHfG6XW61I/h9IN5dmcR9YLir8DVDBNllbtt0z+DnvOhYJOqC30ENahWkTmNKl1cT7EBrR5slddiBJleAb08z77pwsD310e6jWTBySsBcPy+xu/Jj2QgVil/3mstZZDI+noFzs3SkTFBkha/lNTP7NODBQ6m39iaJxz6ZR1xE3v7XU0H5WnpZIcQ2+kmu5Krk2y1GYMKL+9oaotXFPz9v+QIDAQABAoIBAQCcMcssOMOiFWc3MC3EWo4SP4MKQ9n0Uj5Z34LI151FdJyehlj54+VYQ1Cv71tCbjED2sZUBoP69mtsT/EzcsjqtfiOwgrifrs2+BOm+0HKHKiGlcbP9peiHkT10PxEITWXpYtJvGlbcfOjIxqt6B28cBjCK09ShrVQL9ylAKBearRRUacszppntMNTMtN/uG48ZR9Wm+xAczImdG6CrG5sLI/++JwM5PDChLvn5JgMGyOfQZdjNe1oSOVLmqFeG5uu/FS4oMon9+HtfjHJr4ZgA1yQ2wQh3GvEjlP8zwHxEpRJYbxpj6ZbjHZJ2HLX/Gcd9/cXiN8+fQ2zPIYQyG9dAoGBAPUUmt2nJNvl7gj0GbZZ3XR9o+hvj7bJ74W2NhMrw6kjrrzHTAUQd1sBQS8szAQCLqf2ou1aw9AMMBdsLAHydXxvbH7IBAla7rKr23iethtSfjhTNSgQLJHVZlNHfp3hzNtCQZ7j0qVjrteNotrdVF7kKPHDXAK00ICy6SPNjvrXAoGBAO+vdnO15jLeZbbi3lQNS4r8oCadyqyX7ouKE6MtKNhiPsNPGqHKiGcKs/+QylVgYvSmm7TgpsCAiEYeLSPT+Yq3y7HtwVpULlpfAhEJXmvn/6hGpOizx1WNGWhw7nHPWPDzf+jqCGzHdhK0aEZR3MZZQ+U+uKfGiJ8vrvgB7eGvAoGAWxxp5nU48rcsIw/8bxpBhgkfYk33M5EnBqKSv9XJS5wEXhIJZOiWNrLktNEGl4boKXE7aNoRacreJhcE1UR6AOS7hPZ+6atwiePyF4mJUeb9HZtxa493wk9/Vv6BR9il++1Jz/QKX4oLef8hyBP4Rb60qgxirG7kBLR+j9zfhskCgYEAzA5y5xIeuIIU0H4XUDG9dcebxSSjbwsuYIgeLdb9pjMGQhsvjjyyoh8/nT20tLkJpkXN3FFCRjNnUWLRhWYrVkkh1wqWiYOPrwqh5MU4KN/sDWSPcznTY+drkTpMFoKzsvdrl2zf3VR3FneXKv742bkXj601Ykko+XWMHcLutisCgYBSq8IrsjzfaTQiTGI9a7WWsvzK92bq7Abnfq7swAXWcJd/bnjTQKLrrvt2bmwNvlWKAb3c69BFMn0X4t4PuN0iJQ39D6aQAEaM7HwWAmjf5TbodbmgbGxdsUB4xcCIQQ1mvTkigXWrCg0YAD2GZSoaslXAAVv6nR5qWEIa0Hx9GA=="
|
||||
)
|
||||
|
||||
func HideMyAssCountryChoices() (choices []string) {
|
||||
servers := HideMyAssServers()
|
||||
func HideMyAssCountryChoices(servers []models.HideMyAssServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -20,8 +19,7 @@ func HideMyAssCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func HideMyAssCityChoices() (choices []string) {
|
||||
servers := HideMyAssServers()
|
||||
func HideMyAssCityChoices(servers []models.HideMyAssServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -29,18 +27,10 @@ func HideMyAssCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func HideMyAssHostnameChoices() (choices []string) {
|
||||
servers := HideMyAssServers()
|
||||
func HideMyAssHostnameChoices(servers []models.HideMyAssServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// HideMyAssServers returns a slice of all the server information for HideMyAss.
|
||||
func HideMyAssServers() (servers []models.HideMyAssServer) {
|
||||
servers = make([]models.HideMyAssServer, len(allServers.HideMyAss.Servers))
|
||||
copy(servers, allServers.HideMyAss.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ const (
|
||||
IpvanishCA = "MIIErTCCA5WgAwIBAgIJAMYKzSS8uPKDMA0GCSqGSIb3DQEBDQUAMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCRkwxFDASBgNVBAcTC1dpbnRlciBQYXJrMREwDwYDVQQKEwhJUFZhbmlzaDEVMBMGA1UECxMMSVBWYW5pc2ggVlBOMRQwEgYDVQQDEwtJUFZhbmlzaCBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBpcHZhbmlzaC5jb20wHhcNMTIwMTExMTkzMjIwWhcNMjgxMTAyMTkzMjIwWjCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkZMMRQwEgYDVQQHEwtXaW50ZXIgUGFyazERMA8GA1UEChMISVBWYW5pc2gxFTATBgNVBAsTDElQVmFuaXNoIFZQTjEUMBIGA1UEAxMLSVBWYW5pc2ggQ0ExIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAaXB2YW5pc2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt9DBWNr/IKOuY3TmDP5x7vYZR0DGxLbXU8TyAzBbjUtFFMbhxlHiXVQrZHmgzih94x7BgXM7tWpmMKYVb+gNaqMdWE680Qm3nOwmhy/dulXDkEHAwD05i/iTx4ZaUdtV2vsKBxRg1vdC4AEiwD7bqV4HOi13xcG971aQ55Mj1KeCdA0aNvpat1LWx2jjWxsfI8s2Lv5Fkoi1HO1+vTnnaEsJZrBgAkLXpItqP29Lik3/OBIvkBIxlKrhiVPixE5qNiD+eSPirsmROvsyIonoJtuY4Dw5K6pcNlKyYiwo1IOFYU3YxffwFJk+bSW4WVBhsdf5dGxq/uOHmuz5gdwxCwIDAQABo4H9MIH6MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFEv9FCWJHefBcIPX9p8RHCVOGe6uMIHKBgNVHSMEgcIwgb+AFEv9FCWJHefBcIPX9p8RHCVOGe6uoYGbpIGYMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCRkwxFDASBgNVBAcTC1dpbnRlciBQYXJrMREwDwYDVQQKEwhJUFZhbmlzaDEVMBMGA1UECxMMSVBWYW5pc2ggVlBOMRQwEgYDVQQDEwtJUFZhbmlzaCBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBpcHZhbmlzaC5jb22CCQDGCs0kvLjygzANBgkqhkiG9w0BAQ0FAAOCAQEAI2dkh/43ksV2fdYpVGhYaFZPVqCJoToCez0IvOmLeLGzow+EOSrY508oyjYeNP4VJEjApqo0NrMbKl8g/8bpLBcotOCF1c1HZ+y9v7648uumh01SMjsbBeHOuQcLb+7gX6c0pEmxWv8qj5JiW3/1L1bktnjW5Yp5oFkFSMXjOnIoYKHyKLjN2jtwH6XowUNYpg4qVtKU0CXPdOznWcd9/zSfa393HwJPeeVLbKYaFMC4IEbIUmKYtWyoJ9pJ58smU3pWsHZUg9Zc0LZZNjkNlBdQSLmUHAJ33Bd7pJS0JQeiWviC+4UTmzEWRKa7pDGnYRYNu2cUo0/voStphv8EVA=="
|
||||
)
|
||||
|
||||
func IpvanishCountryChoices() (choices []string) {
|
||||
servers := IpvanishServers()
|
||||
func IpvanishCountryChoices(servers []models.IpvanishServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -18,8 +17,7 @@ func IpvanishCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IpvanishCityChoices() (choices []string) {
|
||||
servers := IpvanishServers()
|
||||
func IpvanishCityChoices(servers []models.IpvanishServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -27,18 +25,10 @@ func IpvanishCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IpvanishHostnameChoices() (choices []string) {
|
||||
servers := IpvanishServers()
|
||||
func IpvanishHostnameChoices(servers []models.IpvanishServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// IpvanishServers returns a slice of all the server information for Ipvanish.
|
||||
func IpvanishServers() (servers []models.IpvanishServer) {
|
||||
servers = make([]models.IpvanishServer, len(allServers.Ipvanish.Servers))
|
||||
copy(servers, allServers.Ipvanish.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ const (
|
||||
IvpnOpenvpnStaticKeyV1 = "ac470c93ff9f5602a8aab37dee84a52814d10f20490ad23c47d5d82120c1bf859e93d0696b455d4a1b8d55d40c2685c41ca1d0aef29a3efd27274c4ef09020a3978fe45784b335da6df2d12db97bbb838416515f2a96f04715fd28949c6fe296a925cfada3f8b8928ed7fc963c1563272f5cf46e5e1d9c845d7703ca881497b7e6564a9d1dea9358adffd435295479f47d5298fabf5359613ff5992cb57ff081a04dfb81a26513a6b44a9b5490ad265f8a02384832a59cc3e075ad545461060b7bcab49bac815163cb80983dd51d5b1fd76170ffd904d8291071e96efc3fb777856c717b148d08a510f5687b8a8285dcffe737b98916dd15ef6235dee4266d3b"
|
||||
)
|
||||
|
||||
func IvpnCountryChoices() (choices []string) {
|
||||
servers := IvpnServers()
|
||||
func IvpnCountryChoices(servers []models.IvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -19,8 +18,7 @@ func IvpnCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IvpnCityChoices() (choices []string) {
|
||||
servers := IvpnServers()
|
||||
func IvpnCityChoices(servers []models.IvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -28,18 +26,18 @@ func IvpnCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IvpnHostnameChoices() (choices []string) {
|
||||
servers := IvpnServers()
|
||||
func IvpnISPChoices(servers []models.IvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].ISP
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func IvpnHostnameChoices(servers []models.IvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// IvpnServers returns a slice of all the server information for Ivpn.
|
||||
func IvpnServers() (servers []models.IvpnServer) {
|
||||
servers = make([]models.IvpnServer, len(allServers.Ivpn.Servers))
|
||||
copy(servers, allServers.Ivpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ const (
|
||||
MullvadCertificate = "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"
|
||||
)
|
||||
|
||||
func MullvadCountryChoices() (choices []string) {
|
||||
servers := MullvadServers()
|
||||
func MullvadCountryChoices(servers []models.MullvadServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -18,8 +17,7 @@ func MullvadCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func MullvadCityChoices() (choices []string) {
|
||||
servers := MullvadServers()
|
||||
func MullvadCityChoices(servers []models.MullvadServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -27,8 +25,7 @@ func MullvadCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func MullvadHostnameChoices() (choices []string) {
|
||||
servers := MullvadServers()
|
||||
func MullvadHostnameChoices(servers []models.MullvadServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
@@ -36,18 +33,10 @@ func MullvadHostnameChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func MullvadISPChoices() (choices []string) {
|
||||
servers := MullvadServers()
|
||||
func MullvadISPChoices(servers []models.MullvadServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].ISP
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// MullvadServers returns a slice of all the server information for Mullvad.
|
||||
func MullvadServers() (servers []models.MullvadServer) {
|
||||
servers = make([]models.MullvadServer, len(allServers.Mullvad.Servers))
|
||||
copy(servers, allServers.Mullvad.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ const (
|
||||
NordvpnOpenvpnStaticKeyV1 = "e685bdaf659a25a200e2b9e39e51ff030fc72cf1ce07232bd8b2be5e6c670143f51e937e670eee09d4f2ea5a6e4e69965db852c275351b86fc4ca892d78ae002d6f70d029bd79c4d1c26cf14e9588033cf639f8a74809f29f72b9d58f9b8f5fefc7938eade40e9fed6cb92184abb2cc10eb1a296df243b251df0643d53724cdb5a92a1d6cb817804c4a9319b57d53be580815bcfcb2df55018cc83fc43bc7ff82d51f9b88364776ee9d12fc85cc7ea5b9741c4f598c485316db066d52db4540e212e1518a9bd4828219e24b20d88f598a196c9de96012090e333519ae18d35099427e7b372d348d352dc4c85e18cd4b93f8a56ddb2e64eb67adfc9b337157ff4"
|
||||
)
|
||||
|
||||
func NordvpnRegionChoices() (choices []string) {
|
||||
servers := NordvpnServers()
|
||||
func NordvpnRegionChoices(servers []models.NordvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -19,8 +18,7 @@ func NordvpnRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func NordvpnHostnameChoices() (choices []string) {
|
||||
servers := NordvpnServers()
|
||||
func NordvpnHostnameChoices(servers []models.NordvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
@@ -28,18 +26,10 @@ func NordvpnHostnameChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func NordvpnNameChoices() (choices []string) {
|
||||
servers := NordvpnServers()
|
||||
func NordvpnNameChoices(servers []models.NordvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Name
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// NordvpnServers returns a slice of all the server information for Nordvpn.
|
||||
func NordvpnServers() (servers []models.NordvpnServer) {
|
||||
servers = make([]models.NordvpnServer, len(allServers.Nordvpn.Servers))
|
||||
copy(servers, allServers.Nordvpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ const (
|
||||
PIACertificateStrong = "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"
|
||||
)
|
||||
|
||||
func PIAGeoChoices() (choices []string) {
|
||||
servers := PIAServers()
|
||||
func PIAGeoChoices(servers []models.PIAServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -24,8 +23,7 @@ func PIAGeoChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PIAHostnameChoices() (choices []string) {
|
||||
servers := PIAServers()
|
||||
func PIAHostnameChoices(servers []models.PIAServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
@@ -33,8 +31,7 @@ func PIAHostnameChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PIANameChoices() (choices []string) {
|
||||
servers := PIAServers()
|
||||
func PIANameChoices(servers []models.PIAServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].ServerName
|
||||
@@ -42,15 +39,8 @@ func PIANameChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// PIAServers returns a slice of all the server information for PIA.
|
||||
func PIAServers() (servers []models.PIAServer) {
|
||||
servers = make([]models.PIAServer, len(allServers.Pia.Servers))
|
||||
copy(servers, allServers.Pia.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
func PIAServerWhereName(serverName string) (server models.PIAServer) {
|
||||
for _, server := range PIAServers() {
|
||||
func PIAServerWhereName(servers []models.PIAServer, serverName string) (server models.PIAServer) {
|
||||
for _, server := range servers {
|
||||
if server.ServerName == serverName {
|
||||
return server
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
PrivadoCertificate = "MIIFKDCCAxCgAwIBAgIJAMtrmqZxIV/OMA0GCSqGSIb3DQEBDQUAMBIxEDAOBgNVBAMMB1ByaXZhZG8wHhcNMjAwMTA4MjEyODQ1WhcNMzUwMTA5MjEyODQ1WjASMRAwDgYDVQQDDAdQcml2YWRvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxPwOgiwNJzZTnKIXwAB0TSu/Lu2qt2U2I8obtQjwhi/7OrfmbmYykSdro70al2XPhnwAGGdCxW6LDnp0UN/IOhD11mgBPo14f5CLkBQjSJ6VN5miPbvK746LsNZl9H8rQGvDuPo4CG9BfPZMiDRGlsMxij/jztzgT1gmuxQ7WHfFRcNzBas1dHa9hV/d3TU6/t47x4SE/ljdcCtJiu7Zn6ODKQoys3mB7Luz2ngqUJWvkqsg+E4+3eJ0M8Hlbn5TPaRJBID7DAdYo6Vs6xGCYr981ThFcmoIQ10js10yANrrfGAzd03b3TnLAgko0uQMHjliMZL6L8sWOPHxyxJI0us88SFh4UgcFyRHKHPKux7w24SxAlZUYoUcTHp9VjG5XvDKYxzgV2RdM4ulBGbQRQ3y3/CyddsyQYMvA55Ets0LfPaBvDIcct70iXijGsdvlX1du3ArGpG7Vaje/RU4nbbGT6HYRdt5YyZfof288ukMOSj20nVcmS+c/4tqsxSerRb1aq5LOi1IemSkTMeC5gCbexk+L1vl7NT/58sxjGmu5bXwnvev/lIItfi2AlITrfUSEv19iDMKkeshwn/+sFJBMWYyluP+yJ56yR+MWoXvLlSWphLDTqq19yx3BZn0P1tgbXoR0g8PTdJFcz8z3RIb7myVLYulV1oGG/3rka0CAwEAAaOBgDB+MB0GA1UdDgQWBBTFtJkZCVDuDAD6k5bJzefjJdO3DTBCBgNVHSMEOzA5gBTFtJkZCVDuDAD6k5bJzefjJdO3DaEWpBQwEjEQMA4GA1UEAwwHUHJpdmFkb4IJAMtrmqZxIV/OMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQB7MUSXMeBb9wlSv4sUaT1JHEwE26nlBw+TKmezfuPU5pBlY0LYr6qQZY95DHqsRJ7ByUzGUrGo17dNGXlcuNc6TAaQQEDRPo6y+LVh2TWMk15TUMI+MkqryJtCret7xGvDigKYMJgBy58HN3RAVr1B7cL9youwzLgc2Y/NcFKvnQJKeiIYAJ7g0CcnJiQvgZTS7xdwkEBXfsngmUCIG320DLPEL+Ze0HiUrxwWljMRya6i40AeH3Zu2i532xX1wV5+cjA4RJWIKg6ri/Q54iFGtZrA9/nc6y9uoQHkmz8cGyVUmJxFzMrrIICVqUtVRxLhkTMe4UzwRWTBeGgtW4tS0yq1QonAKfOyjgRw/CeY55D2UGvnAFZdTadtYXS4Alu2P9zdwoEk3fzHiVmDjqfJVr5wz9383aABUFrPI3nz6ed/Z6LZflKh1k+DUDEp8NxU4klUULWsSOKoa5zGX51G8cdHxwQLImXvtGuN5eSR8jCTgxFZhdps/xes4KkyfIz9FMYG748M+uOTgKITf4zdJ9BAyiQaOufVQZ8WjhWzWk9YHec9VqPkzpWNGkVjiRI5ewuXwZzZ164tMv2hikBXSuUCnFz37/ZNwGlDi0oBdDszCk2GxccdFHHaCSmpjU5MrdJ+5IhtTKGeTx+US2hTIVHQFIO99DmacxSYvLNcSQ=="
|
||||
)
|
||||
|
||||
func PrivadoCountryChoices() (choices []string) {
|
||||
servers := PrivadoServers()
|
||||
func PrivadoCountryChoices(servers []models.PrivadoServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -18,8 +15,7 @@ func PrivadoCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PrivadoRegionChoices() (choices []string) {
|
||||
servers := PrivadoServers()
|
||||
func PrivadoRegionChoices(servers []models.PrivadoServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -27,8 +23,7 @@ func PrivadoRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PrivadoCityChoices() (choices []string) {
|
||||
servers := PrivadoServers()
|
||||
func PrivadoCityChoices(servers []models.PrivadoServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -36,18 +31,10 @@ func PrivadoCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PrivadoHostnameChoices() (choices []string) {
|
||||
servers := PrivadoServers()
|
||||
func PrivadoHostnameChoices(servers []models.PrivadoServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// PrivadoServers returns a slice of all the Privado servers.
|
||||
func PrivadoServers() (servers []models.PrivadoServer) {
|
||||
servers = make([]models.PrivadoServer, len(allServers.Privado.Servers))
|
||||
copy(servers, allServers.Privado.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
@@ -10,8 +8,7 @@ const (
|
||||
PrivatevpnOpenvpnStaticKeyV1 = "a49082f082ca89d6a6bb4ecc7c047c6d428a1d3c8254a95206d38a61d7fbe65984214cd7d56eacc5a60803bffd677fa7294d4bfe555036339312de2dfb1335bd9d5fd94b04bba3a15fc5192aeb02fb6d8dd2ca831fad7509be5eefa8d1eaa689dc586c831a23b589c512662652ecf1bb3a4a673816aba434a04f6857b8c2f8bb265bfe48a7b8112539729d2f7d9734a720e1035188118c73fef1824d0237d5579ca382d703b4bb252acaedc753b12199f00154d3769efbcf85ef5ad6ee755cbeaa944cb98e7654286df54c793a8443f5363078e3da548ba0beed079df633283cefb256f6a4bcfc4ab2c4affc24955c1864d5458e84a7c210d0d186269e55dcf6"
|
||||
)
|
||||
|
||||
func PrivatevpnCountryChoices() (choices []string) {
|
||||
servers := PrivatevpnServers()
|
||||
func PrivatevpnCountryChoices(servers []models.PrivatevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -19,8 +16,7 @@ func PrivatevpnCountryChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func PrivatevpnCityChoices() (choices []string) {
|
||||
servers := PrivatevpnServers()
|
||||
func PrivatevpnCityChoices(servers []models.PrivatevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -28,17 +24,10 @@ func PrivatevpnCityChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func PrivatevpnHostnameChoices() (choices []string) {
|
||||
servers := PrivatevpnServers()
|
||||
func PrivatevpnHostnameChoices(servers []models.PrivatevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func PrivatevpnServers() (servers []models.PrivatevpnServer) {
|
||||
servers = make([]models.PrivatevpnServer, len(allServers.Privatevpn.Servers))
|
||||
copy(servers, allServers.Privatevpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
@@ -10,8 +8,7 @@ const (
|
||||
ProtonvpnOpenvpnStaticKeyV1 = "6acef03f62675b4b1bbd03e53b187727423cea742242106cb2916a8a4c8297563d22c7e5cef430b1103c6f66eb1fc5b375a672f158e2e2e936c3faa48b035a6de17beaac23b5f03b10b868d53d03521d8ba115059da777a60cbfd7b2c9c5747278a15b8f6e68a3ef7fd583ec9f398c8bd4735dab40cbd1e3c62a822e97489186c30a0b48c7c38ea32ceb056d3fa5a710e10ccc7a0ddb363b08c3d2777a3395e10c0b6080f56309192ab5aacd4b45f55da61fc77af39bd81a19218a79762c33862df55785075f37d8c71dc8a42097ee43344739a0dd48d03025b0450cf1fb5e8caeb893d9a96d1f15519bb3c4dcb40ee316672ea16c012664f8a9f11255518deb"
|
||||
)
|
||||
|
||||
func ProtonvpnCountryChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnCountryChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -19,8 +16,7 @@ func ProtonvpnCountryChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func ProtonvpnRegionChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnRegionChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -28,8 +24,7 @@ func ProtonvpnRegionChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func ProtonvpnCityChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnCityChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -37,8 +32,7 @@ func ProtonvpnCityChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func ProtonvpnNameChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnNameChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Name
|
||||
@@ -46,18 +40,10 @@ func ProtonvpnNameChoices() (choices []string) {
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
func ProtonvpnHostnameChoices() (choices []string) {
|
||||
servers := ProtonvpnServers()
|
||||
func ProtonvpnHostnameChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeChoicesUnique(choices)
|
||||
}
|
||||
|
||||
// ProtonvpnServers returns a slice of all the server information for Protonvpn.
|
||||
func ProtonvpnServers() (servers []models.ProtonvpnServer) {
|
||||
servers = make([]models.ProtonvpnServer, len(allServers.Protonvpn.Servers))
|
||||
copy(servers, allServers.Protonvpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
@@ -12,8 +10,7 @@ const (
|
||||
PurevpnOpenvpnStaticKeyV1 = "e30af995f56d07426d9ba1f824730521d4283db4b4d0cdda9c6e8759a3799dcb7939b6a5989160c9660de0f6125cbb1f585b41c074b2fe88ecfcf17eab9a33be1352379cdf74952b588fb161a93e13df9135b2b29038231e02d657a6225705e6868ccb0c384ed11614690a1894bfbeb274cebf1fe9c2329bdd5c8a40fe8820624d2ea7540cd79ab76892db51fc371a3ac5fc9573afecb3fffe3281e61d72e91579d9b03d8cbf7909b3aebf4d90850321ee6b7d0a7846d15c27d8290e031e951e19438a4654663cad975e138f5bc5af89c737ad822f27e19057731f41e1e254cc9c95b7175c622422cde9f1f2cfd3510add94498b4d7133d3729dd214a16b27fb"
|
||||
)
|
||||
|
||||
func PurevpnRegionChoices() (choices []string) {
|
||||
servers := PurevpnServers()
|
||||
func PurevpnRegionChoices(servers []models.PurevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -21,8 +18,7 @@ func PurevpnRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PurevpnCountryChoices() (choices []string) {
|
||||
servers := PurevpnServers()
|
||||
func PurevpnCountryChoices(servers []models.PurevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -30,8 +26,7 @@ func PurevpnCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PurevpnCityChoices() (choices []string) {
|
||||
servers := PurevpnServers()
|
||||
func PurevpnCityChoices(servers []models.PurevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -39,18 +34,10 @@ func PurevpnCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func PurevpnHostnameChoices() (choices []string) {
|
||||
servers := PurevpnServers()
|
||||
func PurevpnHostnameChoices(servers []models.PurevpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// PurevpnServers returns a slice of all the server information for Purevpn.
|
||||
func PurevpnServers() (servers []models.PurevpnServer) {
|
||||
servers = make([]models.PurevpnServer, len(allServers.Purevpn.Servers))
|
||||
copy(servers, allServers.Purevpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
//go:embed servers.json
|
||||
var allServersEmbedFS embed.FS //nolint:gochecknoglobals
|
||||
var allServers models.AllServers //nolint:gochecknoglobals
|
||||
var parseOnce sync.Once //nolint:gochecknoglobals
|
||||
|
||||
func init() { //nolint:gochecknoinits
|
||||
// error returned covered by unit test
|
||||
parseOnce.Do(func() { allServers, _ = parseAllServers() })
|
||||
}
|
||||
|
||||
func parseAllServers() (allServers models.AllServers, err error) {
|
||||
f, err := allServersEmbedFS.Open("servers.json")
|
||||
if err != nil {
|
||||
return allServers, err
|
||||
}
|
||||
decoder := json.NewDecoder(f)
|
||||
err = decoder.Decode(&allServers)
|
||||
return allServers, err
|
||||
}
|
||||
|
||||
func GetAllServers() models.AllServers {
|
||||
parseOnce.Do(func() { allServers, _ = parseAllServers() }) // init did not execute, used in tests
|
||||
return allServers
|
||||
}
|
||||
@@ -10,8 +10,7 @@ const (
|
||||
SurfsharkOpenvpnStaticKeyV1 = "b02cb1d7c6fee5d4f89b8de72b51a8d0c7b282631d6fc19be1df6ebae9e2779e6d9f097058a31c97f57f0c35526a44ae09a01d1284b50b954d9246725a1ead1ff224a102ed9ab3da0152a15525643b2eee226c37041dc55539d475183b889a10e18bb94f079a4a49888da566b99783460ece01daaf93548beea6c827d9674897e7279ff1a19cb092659e8c1860fbad0db4ad0ad5732f1af4655dbd66214e552f04ed8fd0104e1d4bf99c249ac229ce169d9ba22068c6c0ab742424760911d4636aafb4b85f0c952a9ce4275bc821391aa65fcd0d2394f006e3fba0fd34c4bc4ab260f4b45dec3285875589c97d3087c9134d3a3aa2f904512e85aa2dc2202498"
|
||||
)
|
||||
|
||||
func SurfsharkRegionChoices() (choices []string) {
|
||||
servers := SurfsharkServers()
|
||||
func SurfsharkRegionChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -19,18 +18,211 @@ func SurfsharkRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func SurfsharkHostnameChoices() (choices []string) {
|
||||
servers := SurfsharkServers()
|
||||
func SurfsharkCountryChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func SurfsharkCityChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// TODO remove in v4.
|
||||
func SurfsharkRetroLocChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
locationData := SurfsharkLocationData()
|
||||
choices = make([]string, len(locationData))
|
||||
for i := range locationData {
|
||||
choices[i] = locationData[i].RetroLoc
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func SurfsharkHostToLocation() (hostToLocation map[string]models.SurfsharkLocationData) {
|
||||
locationData := SurfsharkLocationData()
|
||||
hostToLocation = make(map[string]models.SurfsharkLocationData, len(locationData))
|
||||
for _, data := range locationData {
|
||||
hostToLocation[data.Hostname] = data
|
||||
}
|
||||
return hostToLocation
|
||||
}
|
||||
|
||||
// TODO remove retroRegion and servers from API in v4.
|
||||
func SurfsharkLocationData() (data []models.SurfsharkLocationData) {
|
||||
//nolint:lll
|
||||
return []models.SurfsharkLocationData{
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Adelaide", RetroLoc: "Australia Adelaide", Hostname: "au-adl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Brisbane", RetroLoc: "Australia Brisbane", Hostname: "au-bne.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Melbourne", RetroLoc: "Australia Melbourne", Hostname: "au-mel.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Perth", RetroLoc: "Australia Perth", Hostname: "au-per.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Australia", City: "Sydney", RetroLoc: "Australia Sydney", Hostname: "au-syd.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Azerbaijan", City: "Baku", RetroLoc: "Azerbaijan", Hostname: "az-bak.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Hong Kong", City: "Hong Kong", RetroLoc: "Hong Kong", Hostname: "hk-hkg.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "India", City: "Chennai", RetroLoc: "India Chennai", Hostname: "in-chn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "India", City: "Indore", RetroLoc: "India Indore", Hostname: "in-idr.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "India", City: "Mumbai", RetroLoc: "India Mumbai", Hostname: "in-mum.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Indonesia", City: "Jakarta", RetroLoc: "Indonesia", Hostname: "id-jak.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st001", Hostname: "jp-tok-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st002", Hostname: "jp-tok-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st003", Hostname: "jp-tok-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st004", Hostname: "jp-tok-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st005", Hostname: "jp-tok-st005.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st006", Hostname: "jp-tok-st006.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st007", Hostname: "jp-tok-st007.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st008", Hostname: "jp-tok-st008.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st009", Hostname: "jp-tok-st009.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st010", Hostname: "jp-tok-st010.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st011", Hostname: "jp-tok-st011.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st012", Hostname: "jp-tok-st012.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st013", Hostname: "jp-tok-st013.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo", Hostname: "jp-tok.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Kazakhstan", City: "Oral", RetroLoc: "Kazakhstan", Hostname: "kz-ura.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Malaysia", City: "Kuala Lumpur", RetroLoc: "Malaysia", Hostname: "my-kul.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "New Zealand", City: "Auckland", RetroLoc: "New Zealand", Hostname: "nz-akl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Philippines", City: "Manila", RetroLoc: "Philippines", Hostname: "ph-mnl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore Hong Kong", City: "Hong Kong", RetroLoc: "Singapore Hong Kong", Hostname: "sg-hk.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Asia Pacific", Country: "Singapore in", City: "", RetroLoc: "Singapore in", Hostname: "sg-in.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore mp001", Hostname: "sg-sng-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st001", Hostname: "sg-sng-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st002", Hostname: "sg-sng-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st003", Hostname: "sg-sng-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st004", Hostname: "sg-sng-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore", Hostname: "sg-sng.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "South Korea", City: "Seoul", RetroLoc: "Korea", Hostname: "kr-seo.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Taiwan", City: "Taichung City", RetroLoc: "Taiwan", Hostname: "tw-tai.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Thailand", City: "Bangkok", RetroLoc: "Thailand", Hostname: "th-bkk.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Asia Pacific", Country: "Vietnam", City: "Ho Chi Minh City", RetroLoc: "Vietnam", Hostname: "vn-hcm.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Albania", City: "Tirana", RetroLoc: "Albania", Hostname: "al-tia.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Austria", City: "Vienna", RetroLoc: "Austria", Hostname: "at-vie.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Belgium", City: "Brussels", RetroLoc: "Belgium", Hostname: "be-bru.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Bosnia and Herzegovina", City: "Sarajevo", RetroLoc: "Bosnia and Herzegovina", Hostname: "ba-sjj.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Bulgaria", City: "Sofia", RetroLoc: "Bulgaria", Hostname: "bg-sof.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Croatia", City: "Zagreb", RetroLoc: "Croatia", Hostname: "hr-zag.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Cyprus", City: "Nicosia", RetroLoc: "Cyprus", Hostname: "cy-nic.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Czech Republic", City: "Prague", RetroLoc: "Czech Republic", Hostname: "cz-prg.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Denmark", City: "Copenhagen", RetroLoc: "Denmark", Hostname: "dk-cph.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Estonia", City: "Tallinn", RetroLoc: "Estonia", Hostname: "ee-tll.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Finland", City: "Helsinki", RetroLoc: "Finland", Hostname: "fi-hel.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "France Sweden", City: "", RetroLoc: "France Sweden", Hostname: "fr-se.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "France", City: "Bordeaux", RetroLoc: "France Bordeaux", Hostname: "fr-bod.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "France", City: "Marseille", RetroLoc: "France Marseilles", Hostname: "fr-mrs.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "France", City: "Paris", RetroLoc: "France Paris", Hostname: "fr-par.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany Singapour", City: "", RetroLoc: "Germany Singapour", Hostname: "de-sg.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Germany UK", City: "", RetroLoc: "Germany UK", Hostname: "de-uk.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Germany", City: "Berlin", RetroLoc: "Germany Berlin", Hostname: "de-ber.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st001", Hostname: "de-fra-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st002", Hostname: "de-fra-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st003", Hostname: "de-fra-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st004", Hostname: "de-fra-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st005", Hostname: "de-fra-st005.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main", Hostname: "de-fra.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt mp001", Hostname: "de-fra-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Greece", City: "Athens", RetroLoc: "Greece", Hostname: "gr-ath.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Hungary", City: "Budapest", RetroLoc: "Hungary", Hostname: "hu-bud.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Iceland", City: "Reykjavik", RetroLoc: "Iceland", Hostname: "is-rkv.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "India UK", City: "", RetroLoc: "India UK", Hostname: "in-uk.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Ireland", City: "Dublin", RetroLoc: "Ireland", Hostname: "ie-dub.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Italy", City: "Milan", RetroLoc: "Italy Milan", Hostname: "it-mil.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Italy", City: "Rome", RetroLoc: "Italy Rome", Hostname: "it-rom.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Latvia", City: "Riga", RetroLoc: "Latvia", Hostname: "lv-rig.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Luxembourg", City: "Luxembourg", RetroLoc: "Luxembourg", Hostname: "lu-ste.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Moldova", City: "Chisinau", RetroLoc: "Moldova", Hostname: "md-chi.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", RetroLoc: "Netherlands Amsterdam mp001", Hostname: "nl-ams-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", RetroLoc: "Netherlands Amsterdam st001", Hostname: "nl-ams-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", RetroLoc: "Netherlands Amsterdam", Hostname: "nl-ams.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "North Macedonia", City: "Skopje", RetroLoc: "North Macedonia", Hostname: "mk-skp.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Norway", City: "Oslo", RetroLoc: "Norway", Hostname: "no-osl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Poland", City: "Gdansk", RetroLoc: "Poland Gdansk", Hostname: "pl-gdn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Poland", City: "Warsaw", RetroLoc: "Poland Warsaw", Hostname: "pl-waw.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Portugal", City: "Lisbon", RetroLoc: "Portugal Lisbon", Hostname: "pt-lis.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Portugal", City: "Porto", RetroLoc: "Portugal Porto", Hostname: "pt-opo.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Romania", City: "Bucharest", RetroLoc: "Romania", Hostname: "ro-buc.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Russia", City: "Moscow", RetroLoc: "Russia Moscow", Hostname: "ru-mos.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Serbia", City: "Belgrade", RetroLoc: "Serbia", Hostname: "rs-beg.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Singapore Netherlands", City: "", RetroLoc: "Singapore Netherlands", Hostname: "sg-nl.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Slovakia", City: "Bratislava", RetroLoc: "Slovekia", Hostname: "sk-bts.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Slovenia", City: "Ljubljana", RetroLoc: "Slovenia", Hostname: "si-lju.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Spain", City: "Barcelona", RetroLoc: "Spain Barcelona", Hostname: "es-bcn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Spain", City: "Madrid", RetroLoc: "Spain Madrid", Hostname: "es-mad.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Spain", City: "Valencia", RetroLoc: "Spain Valencia", Hostname: "es-vlc.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Sweden", City: "Stockholm", RetroLoc: "Sweden", Hostname: "se-sto.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Switzerland", City: "Zurich", RetroLoc: "Switzerland", Hostname: "ch-zur.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "Turkey", City: "Istanbul", RetroLoc: "Turkey Istanbul", Hostname: "tr-ist.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "UK France", City: "", RetroLoc: "UK France", Hostname: "uk-fr.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "UK Germany", City: "", RetroLoc: "UK Germany", Hostname: "uk-de.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Europe", Country: "Ukraine", City: "Kyiv", RetroLoc: "Ukraine", Hostname: "ua-iev.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "Glasgow", RetroLoc: "UK Glasgow", Hostname: "uk-gla.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London mp001", Hostname: "uk-lon-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st001", Hostname: "uk-lon-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st002", Hostname: "uk-lon-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st003", Hostname: "uk-lon-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st004", Hostname: "uk-lon-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st005", Hostname: "uk-lon-st005.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London", Hostname: "uk-lon.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "United Kingdom", City: "Manchester", RetroLoc: "UK Manchester", Hostname: "uk-man.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "US Netherlands", City: "", RetroLoc: "US Netherlands", Hostname: "us-nl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Europe", Country: "US Portugal", City: "", RetroLoc: "US Portugal", Hostname: "us-pt.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "Middle East and Africa", Country: "Israel", City: "Tel Aviv", RetroLoc: "Israel", Hostname: "il-tlv.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Middle East and Africa", Country: "Nigeria", City: "Lagos", RetroLoc: "Nigeria", Hostname: "ng-lag.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Middle East and Africa", Country: "South Africa", City: "Johannesburg", RetroLoc: "South Africa", Hostname: "za-jnb.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "Middle East and Africa", Country: "United Arab Emirates", City: "Dubai", RetroLoc: "United Arab Emirates", Hostname: "ae-dub.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Argentina", City: "Buenos Aires", RetroLoc: "Argentina Buenos Aires", Hostname: "ar-bua.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Australia US", City: "", RetroLoc: "Australia US", Hostname: "au-us.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "The Americas", Country: "Brazil", City: "Sao Paulo", RetroLoc: "Brazil", Hostname: "br-sao.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Canada US", City: "", RetroLoc: "Canada US", Hostname: "ca-us.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "The Americas", Country: "Canada", City: "Montreal", RetroLoc: "Canada Montreal", Hostname: "ca-mon.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Canada", City: "Toronto", RetroLoc: "Canada Toronto mp001", Hostname: "ca-tor-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Canada", City: "Toronto", RetroLoc: "Canada Toronto", Hostname: "ca-tor.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Canada", City: "Vancouver", RetroLoc: "Canada Vancouver", Hostname: "ca-van.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Chile", City: "Santiago", RetroLoc: "Chile", Hostname: "cl-san.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Colombia", City: "Bogota", RetroLoc: "Colombia", Hostname: "co-bog.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Costa Rica", City: "San Jose", RetroLoc: "Costa Rica", Hostname: "cr-sjn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Mexico", City: "Mexico City", RetroLoc: "Mexico City Mexico", Hostname: "mx-mex.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "Netherlands US", City: "", RetroLoc: "Netherlands US", Hostname: "nl-us.prod.surfshark.com", MultiHop: true},
|
||||
{Region: "The Americas", Country: "United States", City: "Atlanta", RetroLoc: "US Atlanta", Hostname: "us-atl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Bend", RetroLoc: "US Bend", Hostname: "us-bdn.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Boston", RetroLoc: "US Boston", Hostname: "us-bos.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Buffalo", RetroLoc: "US Buffalo", Hostname: "us-buf.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Charlotte", RetroLoc: "US Charlotte", Hostname: "us-clt.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Chicago", RetroLoc: "US Chicago", Hostname: "us-chi.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Dallas", RetroLoc: "US Dallas", Hostname: "us-dal.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Denver", RetroLoc: "US Denver", Hostname: "us-den.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Detroit", RetroLoc: "US Gahanna", Hostname: "us-dtw.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Houston", RetroLoc: "US Houston", Hostname: "us-hou.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Kansas City", RetroLoc: "US Kansas City", Hostname: "us-kan.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Las Vegas", RetroLoc: "US Las Vegas", Hostname: "us-las.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Latham", RetroLoc: "US Latham", Hostname: "us-ltm.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Los Angeles", RetroLoc: "US Los Angeles", Hostname: "us-lax.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Manassas", RetroLoc: "US Maryland", Hostname: "us-mnz.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Miami", RetroLoc: "US Miami", Hostname: "us-mia.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City mp001", Hostname: "us-nyc-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st001", Hostname: "us-nyc-st001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st002", Hostname: "us-nyc-st002.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st003", Hostname: "us-nyc-st003.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st004", Hostname: "us-nyc-st004.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st005", Hostname: "us-nyc-st005.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City", Hostname: "us-nyc.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Orlando", RetroLoc: "US Orlando", Hostname: "us-orl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Phoenix", RetroLoc: "US Phoenix", Hostname: "us-phx.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Salt Lake City", RetroLoc: "US Salt Lake City", Hostname: "us-slc.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "San Francisco", RetroLoc: "US San Francisco mp001", Hostname: "us-sfo-mp001.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "San Francisco", RetroLoc: "US San Francisco", Hostname: "us-sfo.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Seattle", RetroLoc: "US Seatle", Hostname: "us-sea.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "St. Louis", RetroLoc: "US Saint Louis", Hostname: "us-stl.prod.surfshark.com", MultiHop: false},
|
||||
{Region: "The Americas", Country: "United States", City: "Tampa", RetroLoc: "US Tampa", Hostname: "us-tpa.prod.surfshark.com", MultiHop: false},
|
||||
}
|
||||
}
|
||||
|
||||
func SurfsharkHostnameChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// SurfsharkServers returns a slice of all the server information for Surfshark.
|
||||
func SurfsharkServers() (servers []models.SurfsharkServer) {
|
||||
servers = make([]models.SurfsharkServer, len(allServers.Surfshark.Servers))
|
||||
copy(servers, allServers.Surfshark.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ const (
|
||||
TorguardOpenvpnStaticKeyV1 = "770e8de5fc56e0248cc7b5aab56be80d0e19cbf003c1b3ed68efbaf08613c3a1a019dac6a4b84f13a6198f73229ffc21fa512394e288f82aa2cf0180f01fb3eb1a71e00a077a20f6d7a83633f5b4f47f27e30617eaf8485dd8c722a8606d56b3c183f65da5d3c9001a8cbdb96c793d936251098b24fe52a6dd2472e98cfccbc466e63520d63ade7a0eacc36208c3142a1068236a52142fbb7b3ed83d785e12a28261bccfb3bcb62a8d2f6d18f5df5f3652e59c5627d8d9c8f7877c4d7b08e19a5c363556ba68d392be78b75152dd55ba0f74d45089e84f77f4492d886524ea6c82b9f4dd83d46528d4f5c3b51cfeaf2838d938bd0597c426b0e440434f2c451f"
|
||||
)
|
||||
|
||||
func TorguardCountryChoices() (choices []string) {
|
||||
servers := TorguardServers()
|
||||
func TorguardCountryChoices(servers []models.TorguardServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -19,8 +18,7 @@ func TorguardCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func TorguardCityChoices() (choices []string) {
|
||||
servers := TorguardServers()
|
||||
func TorguardCityChoices(servers []models.TorguardServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -28,18 +26,10 @@ func TorguardCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func TorguardHostnameChoices() (choices []string) {
|
||||
servers := TorguardServers()
|
||||
func TorguardHostnameChoices(servers []models.TorguardServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// TorguardServers returns a slice of all the server information for Torguard.
|
||||
func TorguardServers() (servers []models.TorguardServer) {
|
||||
servers = make([]models.TorguardServer, len(allServers.Torguard.Servers))
|
||||
copy(servers, allServers.Torguard.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ 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()
|
||||
func VPNUnlimitedCountryChoices(servers []models.VPNUnlimitedServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Country
|
||||
@@ -18,8 +17,7 @@ func VPNUnlimitedCountryChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func VPNUnlimitedCityChoices() (choices []string) {
|
||||
servers := VPNUnlimitedServers()
|
||||
func VPNUnlimitedCityChoices(servers []models.VPNUnlimitedServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -27,18 +25,10 @@ func VPNUnlimitedCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func VPNUnlimitedHostnameChoices() (choices []string) {
|
||||
servers := VPNUnlimitedServers()
|
||||
func VPNUnlimitedHostnameChoices(servers []models.VPNUnlimitedServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// VPNUnlimitedServers returns a slice of all the server information for VPNUnlimited.
|
||||
func VPNUnlimitedServers() (servers []models.VPNUnlimitedServer) {
|
||||
servers = make([]models.VPNUnlimitedServer, len(allServers.VPNUnlimited.Servers))
|
||||
copy(servers, allServers.VPNUnlimited.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -9,18 +9,10 @@ const (
|
||||
VyprvpnCertificate = "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"
|
||||
)
|
||||
|
||||
func VyprvpnRegionChoices() (choices []string) {
|
||||
servers := VyprvpnServers()
|
||||
func VyprvpnRegionChoices(servers []models.VyprvpnServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// VyprvpnServers returns a slice of all the VyprVPN servers.
|
||||
func VyprvpnServers() (servers []models.VyprvpnServer) {
|
||||
servers = make([]models.VyprvpnServer, len(allServers.Vyprvpn.Servers))
|
||||
copy(servers, allServers.Vyprvpn.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
import "github.com/qdm12/gluetun/internal/models"
|
||||
|
||||
//nolint:lll
|
||||
const (
|
||||
@@ -10,8 +8,7 @@ const (
|
||||
WindscribeOpenvpnStaticKeyV1 = "5801926a57ac2ce27e3dfd1dd6ef82042d82bd4f3f0021296f57734f6f1ea714a6623845541c4b0c3dea0a050fe6746cb66dfab14cda27e5ae09d7c155aa554f399fa4a863f0e8c1af787e5c602a801d3a2ec41e395a978d56729457fe6102d7d9e9119aa83643210b33c678f9d4109e3154ac9c759e490cb309b319cf708cae83ddadc3060a7a26564d1a24411cd552fe6620ea16b755697a4fc5e6e9d0cfc0c5c4a1874685429046a424c026db672e4c2c492898052ba59128d46200b40f880027a8b6610a4d559bdc9346d33a0a6b08e75c7fd43192b162bfd0aef0c716b31584827693f676f9a5047123466f0654eade34972586b31c6ce7e395f4b478cb"
|
||||
)
|
||||
|
||||
func WindscribeRegionChoices() (choices []string) {
|
||||
servers := WindscribeServers()
|
||||
func WindscribeRegionChoices(servers []models.WindscribeServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
@@ -19,8 +16,7 @@ func WindscribeRegionChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func WindscribeCityChoices() (choices []string) {
|
||||
servers := WindscribeServers()
|
||||
func WindscribeCityChoices(servers []models.WindscribeServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].City
|
||||
@@ -28,18 +24,10 @@ func WindscribeCityChoices() (choices []string) {
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
func WindscribeHostnameChoices() (choices []string) {
|
||||
servers := WindscribeServers()
|
||||
func WindscribeHostnameChoices(servers []models.WindscribeServer) (choices []string) {
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Hostname
|
||||
}
|
||||
return makeUnique(choices)
|
||||
}
|
||||
|
||||
// WindscribeServers returns a slice of all the Windscribe servers.
|
||||
func WindscribeServers() (servers []models.WindscribeServer) {
|
||||
servers = make([]models.WindscribeServer, len(allServers.Windscribe.Servers))
|
||||
copy(servers, allServers.Windscribe.Servers)
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/subnet"
|
||||
)
|
||||
|
||||
type OutboundSubnetsSetter interface {
|
||||
@@ -23,8 +25,7 @@ func (c *Config) SetOutboundSubnets(ctx context.Context, subnets []net.IPNet) (e
|
||||
|
||||
c.logger.Info("setting allowed subnets through firewall...")
|
||||
|
||||
subnetsToAdd := findSubnetsToAdd(c.outboundSubnets, subnets)
|
||||
subnetsToRemove := findSubnetsToRemove(c.outboundSubnets, subnets)
|
||||
subnetsToAdd, subnetsToRemove := subnet.FindSubnetsToChange(c.outboundSubnets, subnets)
|
||||
if len(subnetsToAdd) == 0 && len(subnetsToRemove) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -39,12 +40,12 @@ func (c *Config) SetOutboundSubnets(ctx context.Context, subnets []net.IPNet) (e
|
||||
|
||||
func (c *Config) removeOutboundSubnets(ctx context.Context, subnets []net.IPNet) {
|
||||
const remove = true
|
||||
for _, subnet := range subnets {
|
||||
if err := c.acceptOutputFromIPToSubnet(ctx, c.defaultInterface, c.localIP, subnet, remove); err != nil {
|
||||
for _, subNet := range subnets {
|
||||
if err := c.acceptOutputFromIPToSubnet(ctx, c.defaultInterface, c.localIP, subNet, remove); err != nil {
|
||||
c.logger.Error("cannot remove outdated outbound subnet through firewall: " + err.Error())
|
||||
continue
|
||||
}
|
||||
c.outboundSubnets = removeSubnetFromSubnets(c.outboundSubnets, subnet)
|
||||
c.outboundSubnets = subnet.RemoveSubnetFromSubnets(c.outboundSubnets, subNet)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package httpproxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func (h *handler) handleHTTPS(responseWriter http.ResponseWriter, request *http.Request) {
|
||||
@@ -38,27 +36,30 @@ func (h *handler) handleHTTPS(responseWriter http.ResponseWriter, request *http.
|
||||
}
|
||||
|
||||
h.wg.Add(1)
|
||||
ctx, cancel := context.WithCancel(h.ctx)
|
||||
const transferGoroutines = 2
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(transferGoroutines)
|
||||
go func() { // trigger cleanup when done
|
||||
wg.Wait()
|
||||
cancel()
|
||||
}()
|
||||
go func() { // cleanup
|
||||
<-ctx.Done()
|
||||
|
||||
serverToClientDone := make(chan struct{})
|
||||
clientToServerClientDone := make(chan struct{})
|
||||
go transfer(destinationConn, clientConnection, clientToServerClientDone)
|
||||
go transfer(clientConnection, destinationConn, serverToClientDone)
|
||||
|
||||
select {
|
||||
case <-h.ctx.Done():
|
||||
destinationConn.Close()
|
||||
clientConnection.Close()
|
||||
h.wg.Done()
|
||||
}()
|
||||
go transfer(destinationConn, clientConnection, wg)
|
||||
go transfer(clientConnection, destinationConn, wg)
|
||||
<-serverToClientDone
|
||||
<-clientToServerClientDone
|
||||
case <-serverToClientDone:
|
||||
<-clientToServerClientDone
|
||||
case <-clientToServerClientDone: // happens more rarely, when a connection is closed on the client side
|
||||
<-serverToClientDone
|
||||
}
|
||||
|
||||
func transfer(destination io.WriteCloser, source io.ReadCloser, wg *sync.WaitGroup) {
|
||||
h.wg.Done()
|
||||
}
|
||||
|
||||
func transfer(destination io.WriteCloser, source io.ReadCloser, done chan<- struct{}) {
|
||||
_, _ = io.Copy(destination, source)
|
||||
_ = source.Close()
|
||||
_ = destination.Close()
|
||||
wg.Done()
|
||||
close(done)
|
||||
}
|
||||
|
||||
@@ -9,11 +9,7 @@ import (
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
type Server interface {
|
||||
Run(ctx context.Context, errorCh chan<- error)
|
||||
}
|
||||
|
||||
type server struct {
|
||||
type Server struct {
|
||||
address string
|
||||
handler http.Handler
|
||||
logger logging.Logger
|
||||
@@ -21,9 +17,9 @@ type server struct {
|
||||
}
|
||||
|
||||
func New(ctx context.Context, address string, logger logging.Logger,
|
||||
stealth, verbose bool, username, password string) Server {
|
||||
stealth, verbose bool, username, password string) *Server {
|
||||
wg := &sync.WaitGroup{}
|
||||
return &server{
|
||||
return &Server{
|
||||
address: address,
|
||||
handler: newHandler(ctx, wg, logger, stealth, verbose, username, password),
|
||||
logger: logger,
|
||||
@@ -31,7 +27,7 @@ func New(ctx context.Context, address string, logger logging.Logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) Run(ctx context.Context, errorCh chan<- error) {
|
||||
func (s *Server) Run(ctx context.Context, errorCh chan<- error) {
|
||||
server := http.Server{Addr: s.address, Handler: s.handler}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
|
||||
252
internal/models/getservers.go
Normal file
252
internal/models/getservers.go
Normal file
@@ -0,0 +1,252 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (a AllServers) GetCopy() (servers AllServers) {
|
||||
servers = a // copy versions and timestamps
|
||||
servers.Cyberghost.Servers = a.GetCyberghost()
|
||||
servers.Fastestvpn.Servers = a.GetFastestvpn()
|
||||
servers.HideMyAss.Servers = a.GetHideMyAss()
|
||||
servers.Ipvanish.Servers = a.GetIpvanish()
|
||||
servers.Ivpn.Servers = a.GetIvpn()
|
||||
servers.Mullvad.Servers = a.GetMullvad()
|
||||
servers.Nordvpn.Servers = a.GetNordvpn()
|
||||
servers.Privado.Servers = a.GetPrivado()
|
||||
servers.Pia.Servers = a.GetPia()
|
||||
servers.Privatevpn.Servers = a.GetPrivatevpn()
|
||||
servers.Protonvpn.Servers = a.GetProtonvpn()
|
||||
servers.Purevpn.Servers = a.GetPurevpn()
|
||||
servers.Surfshark.Servers = a.GetSurfshark()
|
||||
servers.Torguard.Servers = a.GetTorguard()
|
||||
servers.VPNUnlimited.Servers = a.GetVPNUnlimited()
|
||||
servers.Vyprvpn.Servers = a.GetVyprvpn()
|
||||
servers.Windscribe.Servers = a.GetWindscribe()
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetCyberghost() (servers []CyberghostServer) {
|
||||
if a.Cyberghost.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]CyberghostServer, len(a.Cyberghost.Servers))
|
||||
for i, serverToCopy := range a.Cyberghost.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetFastestvpn() (servers []FastestvpnServer) {
|
||||
if a.Fastestvpn.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]FastestvpnServer, len(a.Fastestvpn.Servers))
|
||||
for i, serverToCopy := range a.Fastestvpn.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetHideMyAss() (servers []HideMyAssServer) {
|
||||
if a.HideMyAss.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]HideMyAssServer, len(a.HideMyAss.Servers))
|
||||
for i, serverToCopy := range a.HideMyAss.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetIpvanish() (servers []IpvanishServer) {
|
||||
if a.Ipvanish.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]IpvanishServer, len(a.Ipvanish.Servers))
|
||||
for i, serverToCopy := range a.Ipvanish.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetIvpn() (servers []IvpnServer) {
|
||||
if a.Ivpn.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]IvpnServer, len(a.Ivpn.Servers))
|
||||
for i, serverToCopy := range a.Ivpn.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetMullvad() (servers []MullvadServer) {
|
||||
if a.Mullvad.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]MullvadServer, len(a.Mullvad.Servers))
|
||||
for i, serverToCopy := range a.Mullvad.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
servers[i].IPsV6 = copyIPs(serverToCopy.IPsV6)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetNordvpn() (servers []NordvpnServer) {
|
||||
if a.Nordvpn.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]NordvpnServer, len(a.Nordvpn.Servers))
|
||||
for i, serverToCopy := range a.Nordvpn.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IP = copyIP(serverToCopy.IP)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetPia() (servers []PIAServer) {
|
||||
if a.Pia.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]PIAServer, len(a.Pia.Servers))
|
||||
for i, serverToCopy := range a.Pia.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetPrivado() (servers []PrivadoServer) {
|
||||
if a.Privado.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]PrivadoServer, len(a.Privado.Servers))
|
||||
for i, serverToCopy := range a.Privado.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IP = copyIP(serverToCopy.IP)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetPrivatevpn() (servers []PrivatevpnServer) {
|
||||
if a.Privatevpn.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]PrivatevpnServer, len(a.Privatevpn.Servers))
|
||||
for i, serverToCopy := range a.Privatevpn.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetProtonvpn() (servers []ProtonvpnServer) {
|
||||
if a.Protonvpn.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]ProtonvpnServer, len(a.Protonvpn.Servers))
|
||||
for i, serverToCopy := range a.Protonvpn.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].EntryIP = copyIP(serverToCopy.EntryIP)
|
||||
servers[i].ExitIP = copyIP(serverToCopy.ExitIP)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetPurevpn() (servers []PurevpnServer) {
|
||||
if a.Purevpn.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]PurevpnServer, len(a.Purevpn.Servers))
|
||||
for i, serverToCopy := range a.Purevpn.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetSurfshark() (servers []SurfsharkServer) {
|
||||
if a.Surfshark.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]SurfsharkServer, len(a.Surfshark.Servers))
|
||||
for i, serverToCopy := range a.Surfshark.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetTorguard() (servers []TorguardServer) {
|
||||
if a.Torguard.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]TorguardServer, len(a.Torguard.Servers))
|
||||
for i, serverToCopy := range a.Torguard.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetVPNUnlimited() (servers []VPNUnlimitedServer) {
|
||||
if a.VPNUnlimited.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]VPNUnlimitedServer, len(a.VPNUnlimited.Servers))
|
||||
for i, serverToCopy := range a.VPNUnlimited.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetVyprvpn() (servers []VyprvpnServer) {
|
||||
if a.Vyprvpn.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]VyprvpnServer, len(a.Vyprvpn.Servers))
|
||||
for i, serverToCopy := range a.Vyprvpn.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func (a *AllServers) GetWindscribe() (servers []WindscribeServer) {
|
||||
if a.Windscribe.Servers == nil {
|
||||
return nil
|
||||
}
|
||||
servers = make([]WindscribeServer, len(a.Windscribe.Servers))
|
||||
for i, serverToCopy := range a.Windscribe.Servers {
|
||||
servers[i] = serverToCopy
|
||||
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func copyIPs(toCopy []net.IP) (copied []net.IP) {
|
||||
if toCopy == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
copied = make([]net.IP, len(toCopy))
|
||||
for i := range toCopy {
|
||||
copied[i] = copyIP(toCopy[i])
|
||||
}
|
||||
|
||||
return copied
|
||||
}
|
||||
|
||||
func copyIP(toCopy net.IP) (copied net.IP) {
|
||||
copied = make(net.IP, len(toCopy))
|
||||
copy(copied, toCopy)
|
||||
return copied
|
||||
}
|
||||
181
internal/models/getservers_test.go
Normal file
181
internal/models/getservers_test.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_AllServers_GetCopy(t *testing.T) {
|
||||
allServers := AllServers{
|
||||
Cyberghost: CyberghostServers{
|
||||
Version: 2,
|
||||
Servers: []CyberghostServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Fastestvpn: FastestvpnServers{
|
||||
Servers: []FastestvpnServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
HideMyAss: HideMyAssServers{
|
||||
Servers: []HideMyAssServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Ipvanish: IpvanishServers{
|
||||
Servers: []IpvanishServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Ivpn: IvpnServers{
|
||||
Servers: []IvpnServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Mullvad: MullvadServers{
|
||||
Servers: []MullvadServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Nordvpn: NordvpnServers{
|
||||
Servers: []NordvpnServer{{
|
||||
IP: net.IP{1, 2, 3, 4},
|
||||
}},
|
||||
},
|
||||
Privado: PrivadoServers{
|
||||
Servers: []PrivadoServer{{
|
||||
IP: net.IP{1, 2, 3, 4},
|
||||
}},
|
||||
},
|
||||
Pia: PiaServers{
|
||||
Servers: []PIAServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Privatevpn: PrivatevpnServers{
|
||||
Servers: []PrivatevpnServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Protonvpn: ProtonvpnServers{
|
||||
Servers: []ProtonvpnServer{{
|
||||
EntryIP: net.IP{1, 2, 3, 4},
|
||||
ExitIP: net.IP{1, 2, 3, 4},
|
||||
}},
|
||||
},
|
||||
Purevpn: PurevpnServers{
|
||||
Version: 1,
|
||||
Servers: []PurevpnServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Surfshark: SurfsharkServers{
|
||||
Servers: []SurfsharkServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Torguard: TorguardServers{
|
||||
Servers: []TorguardServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
VPNUnlimited: VPNUnlimitedServers{
|
||||
Servers: []VPNUnlimitedServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Vyprvpn: VyprvpnServers{
|
||||
Servers: []VyprvpnServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
Windscribe: WindscribeServers{
|
||||
Servers: []WindscribeServer{{
|
||||
IPs: []net.IP{{1, 2, 3, 4}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
servers := allServers.GetCopy()
|
||||
|
||||
assert.Equal(t, allServers, servers)
|
||||
}
|
||||
|
||||
func Test_AllServers_GetVyprvpn(t *testing.T) {
|
||||
allServers := AllServers{
|
||||
Vyprvpn: VyprvpnServers{
|
||||
Servers: []VyprvpnServer{
|
||||
{Hostname: "a", IPs: []net.IP{{1, 1, 1, 1}}},
|
||||
{Hostname: "b", IPs: []net.IP{{2, 2, 2, 2}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
servers := allServers.GetVyprvpn()
|
||||
|
||||
expectedServers := []VyprvpnServer{
|
||||
{Hostname: "a", IPs: []net.IP{{1, 1, 1, 1}}},
|
||||
{Hostname: "b", IPs: []net.IP{{2, 2, 2, 2}}},
|
||||
}
|
||||
assert.Equal(t, expectedServers, servers)
|
||||
|
||||
allServers.Vyprvpn.Servers[0].IPs[0][0] = 9
|
||||
assert.NotEqual(t, 9, servers[0].IPs[0][0])
|
||||
|
||||
allServers.Vyprvpn.Servers[0].IPs[0][0] = 1
|
||||
servers[0].IPs[0][0] = 9
|
||||
assert.NotEqual(t, 9, allServers.Vyprvpn.Servers[0].IPs[0][0])
|
||||
}
|
||||
|
||||
func Test_copyIPs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
toCopy []net.IP
|
||||
copied []net.IP
|
||||
}{
|
||||
"nil": {},
|
||||
"empty": {
|
||||
toCopy: []net.IP{},
|
||||
copied: []net.IP{},
|
||||
},
|
||||
"single IP": {
|
||||
toCopy: []net.IP{{1, 1, 1, 1}},
|
||||
copied: []net.IP{{1, 1, 1, 1}},
|
||||
},
|
||||
"two IPs": {
|
||||
toCopy: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}},
|
||||
copied: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Reserver leading 9 for copy modifications below
|
||||
for _, ipToCopy := range testCase.toCopy {
|
||||
require.NotEqual(t, 9, ipToCopy[0])
|
||||
}
|
||||
|
||||
copied := copyIPs(testCase.toCopy)
|
||||
|
||||
assert.Equal(t, testCase.copied, copied)
|
||||
|
||||
if len(copied) > 0 {
|
||||
original := testCase.toCopy[0][0]
|
||||
testCase.toCopy[0][0] = 9
|
||||
assert.NotEqual(t, 9, copied[0][0])
|
||||
testCase.toCopy[0][0] = original
|
||||
|
||||
copied[0][0] = 9
|
||||
assert.NotEqual(t, 9, testCase.toCopy[0][0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
12
internal/models/location.go
Normal file
12
internal/models/location.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package models
|
||||
|
||||
// SurfsharkLocationData is required to keep location data on Surfshark
|
||||
// servers that are not obtained through their API.
|
||||
type SurfsharkLocationData struct {
|
||||
Region string
|
||||
Country string
|
||||
City string
|
||||
RetroLoc string // TODO remove in v4
|
||||
Hostname string
|
||||
MultiHop bool
|
||||
}
|
||||
@@ -39,9 +39,12 @@ type IpvanishServer struct {
|
||||
}
|
||||
|
||||
type IvpnServer struct {
|
||||
VPN string `json:"vpn"`
|
||||
Country string `json:"country"`
|
||||
City string `json:"city"`
|
||||
ISP string `json:"isp"`
|
||||
Hostname string `json:"hostname"`
|
||||
WgPubKey string `json:"wgpubkey,omitempty"`
|
||||
TCP bool `json:"tcp"`
|
||||
UDP bool `json:"udp"`
|
||||
IPs []net.IP `json:"ips"`
|
||||
@@ -116,7 +119,11 @@ type PurevpnServer struct {
|
||||
|
||||
type SurfsharkServer struct {
|
||||
Region string `json:"region"`
|
||||
Country string `json:"country"` // Country is also used for multi-hop
|
||||
City string `json:"city"`
|
||||
RetroLoc string `json:"retroloc"` // TODO remove in v4
|
||||
Hostname string `json:"hostname"`
|
||||
MultiHop bool `json:"multihop"`
|
||||
TCP bool `json:"tcp"`
|
||||
UDP bool `json:"udp"`
|
||||
IPs []net.IP `json:"ips"`
|
||||
|
||||
@@ -2,6 +2,21 @@ package netlink
|
||||
|
||||
import "github.com/vishvananda/netlink"
|
||||
|
||||
type Addr = netlink.Addr
|
||||
|
||||
var _ Addresser = (*NetLink)(nil)
|
||||
|
||||
type Addresser interface {
|
||||
AddrList(link netlink.Link, family int) (
|
||||
addresses []netlink.Addr, err error)
|
||||
AddrAdd(link netlink.Link, addr *netlink.Addr) error
|
||||
}
|
||||
|
||||
func (n *NetLink) AddrList(link netlink.Link, family int) (
|
||||
addresses []netlink.Addr, err error) {
|
||||
return netlink.AddrList(link, family)
|
||||
}
|
||||
|
||||
func (n *NetLink) AddrAdd(link netlink.Link, addr *netlink.Addr) error {
|
||||
return netlink.AddrAdd(link, addr)
|
||||
}
|
||||
|
||||
9
internal/netlink/family.go
Normal file
9
internal/netlink/family.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package netlink
|
||||
|
||||
import "github.com/vishvananda/netlink"
|
||||
|
||||
//nolint:revive
|
||||
const (
|
||||
FAMILY_ALL = netlink.FAMILY_ALL
|
||||
FAMILY_V4 = netlink.FAMILY_V4
|
||||
)
|
||||
@@ -1,14 +1,12 @@
|
||||
package netlink
|
||||
|
||||
import "github.com/vishvananda/netlink"
|
||||
|
||||
//go:generate mockgen -destination=mock_$GOPACKAGE/$GOFILE . NetLinker
|
||||
|
||||
var _ NetLinker = (*NetLink)(nil)
|
||||
|
||||
type NetLinker interface {
|
||||
AddrAdd(link netlink.Link, addr *netlink.Addr) error
|
||||
RouteAdd(route *netlink.Route) error
|
||||
RuleAdd(rule *netlink.Rule) error
|
||||
RuleDel(rule *netlink.Rule) error
|
||||
Addresser
|
||||
Linker
|
||||
Router
|
||||
Ruler
|
||||
}
|
||||
|
||||
11
internal/netlink/ipnet.go
Normal file
11
internal/netlink/ipnet.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func NewIPNet(ip net.IP) *net.IPNet {
|
||||
return netlink.NewIPNet(ip)
|
||||
}
|
||||
48
internal/netlink/link.go
Normal file
48
internal/netlink/link.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package netlink
|
||||
|
||||
import "github.com/vishvananda/netlink"
|
||||
|
||||
type (
|
||||
Link = netlink.Link
|
||||
Bridge = netlink.Bridge
|
||||
)
|
||||
|
||||
var _ Linker = (*NetLink)(nil)
|
||||
|
||||
type Linker interface {
|
||||
LinkList() (links []netlink.Link, err error)
|
||||
LinkByName(name string) (link netlink.Link, err error)
|
||||
LinkByIndex(index int) (link netlink.Link, err error)
|
||||
LinkAdd(link netlink.Link) (err error)
|
||||
LinkDel(link netlink.Link) (err error)
|
||||
LinkSetUp(link netlink.Link) (err error)
|
||||
LinkSetDown(link netlink.Link) (err error)
|
||||
}
|
||||
|
||||
func (n *NetLink) LinkList() (links []netlink.Link, err error) {
|
||||
return netlink.LinkList()
|
||||
}
|
||||
|
||||
func (n *NetLink) LinkByName(name string) (link netlink.Link, err error) {
|
||||
return netlink.LinkByName(name)
|
||||
}
|
||||
|
||||
func (n *NetLink) LinkByIndex(index int) (link netlink.Link, err error) {
|
||||
return netlink.LinkByIndex(index)
|
||||
}
|
||||
|
||||
func (n *NetLink) LinkAdd(link netlink.Link) (err error) {
|
||||
return netlink.LinkAdd(link)
|
||||
}
|
||||
|
||||
func (n *NetLink) LinkDel(link netlink.Link) (err error) {
|
||||
return netlink.LinkDel(link)
|
||||
}
|
||||
|
||||
func (n *NetLink) LinkSetUp(link netlink.Link) (err error) {
|
||||
return netlink.LinkSetUp(link)
|
||||
}
|
||||
|
||||
func (n *NetLink) LinkSetDown(link netlink.Link) (err error) {
|
||||
return netlink.LinkSetDown(link)
|
||||
}
|
||||
9
internal/netlink/linkattrs.go
Normal file
9
internal/netlink/linkattrs.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package netlink
|
||||
|
||||
import "github.com/vishvananda/netlink"
|
||||
|
||||
type LinkAttrs = netlink.LinkAttrs
|
||||
|
||||
func NewLinkAttrs() LinkAttrs {
|
||||
return netlink.NewLinkAttrs()
|
||||
}
|
||||
265
internal/netlink/mock_netlink/interface.go
Normal file
265
internal/netlink/mock_netlink/interface.go
Normal file
@@ -0,0 +1,265 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/qdm12/gluetun/internal/netlink (interfaces: NetLinker)
|
||||
|
||||
// Package mock_netlink is a generated GoMock package.
|
||||
package mock_netlink
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
netlink "github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// MockNetLinker is a mock of NetLinker interface.
|
||||
type MockNetLinker struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockNetLinkerMockRecorder
|
||||
}
|
||||
|
||||
// MockNetLinkerMockRecorder is the mock recorder for MockNetLinker.
|
||||
type MockNetLinkerMockRecorder struct {
|
||||
mock *MockNetLinker
|
||||
}
|
||||
|
||||
// NewMockNetLinker creates a new mock instance.
|
||||
func NewMockNetLinker(ctrl *gomock.Controller) *MockNetLinker {
|
||||
mock := &MockNetLinker{ctrl: ctrl}
|
||||
mock.recorder = &MockNetLinkerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockNetLinker) EXPECT() *MockNetLinkerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AddrAdd mocks base method.
|
||||
func (m *MockNetLinker) AddrAdd(arg0 netlink.Link, arg1 *netlink.Addr) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddrAdd", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddrAdd indicates an expected call of AddrAdd.
|
||||
func (mr *MockNetLinkerMockRecorder) AddrAdd(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrAdd", reflect.TypeOf((*MockNetLinker)(nil).AddrAdd), arg0, arg1)
|
||||
}
|
||||
|
||||
// AddrList mocks base method.
|
||||
func (m *MockNetLinker) AddrList(arg0 netlink.Link, arg1 int) ([]netlink.Addr, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddrList", arg0, arg1)
|
||||
ret0, _ := ret[0].([]netlink.Addr)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// AddrList indicates an expected call of AddrList.
|
||||
func (mr *MockNetLinkerMockRecorder) AddrList(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrList", reflect.TypeOf((*MockNetLinker)(nil).AddrList), arg0, arg1)
|
||||
}
|
||||
|
||||
// LinkAdd mocks base method.
|
||||
func (m *MockNetLinker) LinkAdd(arg0 netlink.Link) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LinkAdd", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// LinkAdd indicates an expected call of LinkAdd.
|
||||
func (mr *MockNetLinkerMockRecorder) LinkAdd(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkAdd", reflect.TypeOf((*MockNetLinker)(nil).LinkAdd), arg0)
|
||||
}
|
||||
|
||||
// LinkByIndex mocks base method.
|
||||
func (m *MockNetLinker) LinkByIndex(arg0 int) (netlink.Link, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LinkByIndex", arg0)
|
||||
ret0, _ := ret[0].(netlink.Link)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// LinkByIndex indicates an expected call of LinkByIndex.
|
||||
func (mr *MockNetLinkerMockRecorder) LinkByIndex(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkByIndex", reflect.TypeOf((*MockNetLinker)(nil).LinkByIndex), arg0)
|
||||
}
|
||||
|
||||
// LinkByName mocks base method.
|
||||
func (m *MockNetLinker) LinkByName(arg0 string) (netlink.Link, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LinkByName", arg0)
|
||||
ret0, _ := ret[0].(netlink.Link)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// LinkByName indicates an expected call of LinkByName.
|
||||
func (mr *MockNetLinkerMockRecorder) LinkByName(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkByName", reflect.TypeOf((*MockNetLinker)(nil).LinkByName), arg0)
|
||||
}
|
||||
|
||||
// LinkDel mocks base method.
|
||||
func (m *MockNetLinker) LinkDel(arg0 netlink.Link) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LinkDel", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// LinkDel indicates an expected call of LinkDel.
|
||||
func (mr *MockNetLinkerMockRecorder) LinkDel(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkDel", reflect.TypeOf((*MockNetLinker)(nil).LinkDel), arg0)
|
||||
}
|
||||
|
||||
// LinkList mocks base method.
|
||||
func (m *MockNetLinker) LinkList() ([]netlink.Link, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LinkList")
|
||||
ret0, _ := ret[0].([]netlink.Link)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// LinkList indicates an expected call of LinkList.
|
||||
func (mr *MockNetLinkerMockRecorder) LinkList() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkList", reflect.TypeOf((*MockNetLinker)(nil).LinkList))
|
||||
}
|
||||
|
||||
// LinkSetDown mocks base method.
|
||||
func (m *MockNetLinker) LinkSetDown(arg0 netlink.Link) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LinkSetDown", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// LinkSetDown indicates an expected call of LinkSetDown.
|
||||
func (mr *MockNetLinkerMockRecorder) LinkSetDown(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetDown", reflect.TypeOf((*MockNetLinker)(nil).LinkSetDown), arg0)
|
||||
}
|
||||
|
||||
// LinkSetUp mocks base method.
|
||||
func (m *MockNetLinker) LinkSetUp(arg0 netlink.Link) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LinkSetUp", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// LinkSetUp indicates an expected call of LinkSetUp.
|
||||
func (mr *MockNetLinkerMockRecorder) LinkSetUp(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetUp", reflect.TypeOf((*MockNetLinker)(nil).LinkSetUp), arg0)
|
||||
}
|
||||
|
||||
// RouteAdd mocks base method.
|
||||
func (m *MockNetLinker) RouteAdd(arg0 *netlink.Route) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RouteAdd", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RouteAdd indicates an expected call of RouteAdd.
|
||||
func (mr *MockNetLinkerMockRecorder) RouteAdd(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteAdd", reflect.TypeOf((*MockNetLinker)(nil).RouteAdd), arg0)
|
||||
}
|
||||
|
||||
// RouteDel mocks base method.
|
||||
func (m *MockNetLinker) RouteDel(arg0 *netlink.Route) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RouteDel", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RouteDel indicates an expected call of RouteDel.
|
||||
func (mr *MockNetLinkerMockRecorder) RouteDel(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteDel", reflect.TypeOf((*MockNetLinker)(nil).RouteDel), arg0)
|
||||
}
|
||||
|
||||
// RouteList mocks base method.
|
||||
func (m *MockNetLinker) RouteList(arg0 netlink.Link, arg1 int) ([]netlink.Route, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RouteList", arg0, arg1)
|
||||
ret0, _ := ret[0].([]netlink.Route)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// RouteList indicates an expected call of RouteList.
|
||||
func (mr *MockNetLinkerMockRecorder) RouteList(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteList", reflect.TypeOf((*MockNetLinker)(nil).RouteList), arg0, arg1)
|
||||
}
|
||||
|
||||
// RouteReplace mocks base method.
|
||||
func (m *MockNetLinker) RouteReplace(arg0 *netlink.Route) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RouteReplace", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RouteReplace indicates an expected call of RouteReplace.
|
||||
func (mr *MockNetLinkerMockRecorder) RouteReplace(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteReplace", reflect.TypeOf((*MockNetLinker)(nil).RouteReplace), arg0)
|
||||
}
|
||||
|
||||
// RuleAdd mocks base method.
|
||||
func (m *MockNetLinker) RuleAdd(arg0 *netlink.Rule) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RuleAdd", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RuleAdd indicates an expected call of RuleAdd.
|
||||
func (mr *MockNetLinkerMockRecorder) RuleAdd(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleAdd", reflect.TypeOf((*MockNetLinker)(nil).RuleAdd), arg0)
|
||||
}
|
||||
|
||||
// RuleDel mocks base method.
|
||||
func (m *MockNetLinker) RuleDel(arg0 *netlink.Rule) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RuleDel", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RuleDel indicates an expected call of RuleDel.
|
||||
func (mr *MockNetLinkerMockRecorder) RuleDel(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleDel", reflect.TypeOf((*MockNetLinker)(nil).RuleDel), arg0)
|
||||
}
|
||||
|
||||
// RuleList mocks base method.
|
||||
func (m *MockNetLinker) RuleList(arg0 int) ([]netlink.Rule, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RuleList", arg0)
|
||||
ret0, _ := ret[0].([]netlink.Rule)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// RuleList indicates an expected call of RuleList.
|
||||
func (mr *MockNetLinkerMockRecorder) RuleList(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleList", reflect.TypeOf((*MockNetLinker)(nil).RuleList), arg0)
|
||||
}
|
||||
@@ -2,6 +2,31 @@ package netlink
|
||||
|
||||
import "github.com/vishvananda/netlink"
|
||||
|
||||
type Route = netlink.Route
|
||||
|
||||
var _ Router = (*NetLink)(nil)
|
||||
|
||||
type Router interface {
|
||||
RouteList(link netlink.Link, family int) (
|
||||
routes []netlink.Route, err error)
|
||||
RouteAdd(route *netlink.Route) error
|
||||
RouteDel(route *netlink.Route) error
|
||||
RouteReplace(route *netlink.Route) error
|
||||
}
|
||||
|
||||
func (n *NetLink) RouteList(link netlink.Link, family int) (
|
||||
routes []netlink.Route, err error) {
|
||||
return netlink.RouteList(link, family)
|
||||
}
|
||||
|
||||
func (n *NetLink) RouteAdd(route *netlink.Route) error {
|
||||
return netlink.RouteAdd(route)
|
||||
}
|
||||
|
||||
func (n *NetLink) RouteDel(route *netlink.Route) error {
|
||||
return netlink.RouteDel(route)
|
||||
}
|
||||
|
||||
func (n *NetLink) RouteReplace(route *netlink.Route) error {
|
||||
return netlink.RouteReplace(route)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,24 @@ package netlink
|
||||
|
||||
import "github.com/vishvananda/netlink"
|
||||
|
||||
type Rule = netlink.Rule
|
||||
|
||||
func NewRule() *Rule {
|
||||
return netlink.NewRule()
|
||||
}
|
||||
|
||||
var _ Ruler = (*NetLink)(nil)
|
||||
|
||||
type Ruler interface {
|
||||
RuleList(family int) (rules []netlink.Rule, err error)
|
||||
RuleAdd(rule *netlink.Rule) error
|
||||
RuleDel(rule *netlink.Rule) error
|
||||
}
|
||||
|
||||
func (n *NetLink) RuleList(family int) (rules []netlink.Rule, err error) {
|
||||
return netlink.RuleList(family)
|
||||
}
|
||||
|
||||
func (n *NetLink) RuleAdd(rule *netlink.Rule) error {
|
||||
return netlink.RuleAdd(rule)
|
||||
}
|
||||
|
||||
@@ -33,9 +33,5 @@ func (c *Cyberghost) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, c.randSource), nil
|
||||
return utils.PickConnection(connections, selection, c.randSource)
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ func (c *Cyberghost) filterServers(selection configuration.ServerSelection) (
|
||||
servers []models.CyberghostServer, err error) {
|
||||
if len(selection.Groups) == 0 {
|
||||
if selection.OpenVPN.TCP {
|
||||
selection.Groups = tcpGroupChoices()
|
||||
selection.Groups = tcpGroupChoices(c.servers)
|
||||
} else {
|
||||
selection.Groups = udpGroupChoices()
|
||||
selection.Groups = udpGroupChoices(c.servers)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,18 +50,18 @@ func (c *Cyberghost) filterServers(selection configuration.ServerSelection) (
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func tcpGroupChoices() (choices []string) {
|
||||
func tcpGroupChoices(servers []models.CyberghostServer) (choices []string) {
|
||||
const tcp = true
|
||||
return groupsForTCP(tcp)
|
||||
return groupsForTCP(servers, tcp)
|
||||
}
|
||||
|
||||
func udpGroupChoices() (choices []string) {
|
||||
func udpGroupChoices(servers []models.CyberghostServer) (choices []string) {
|
||||
const tcp = false
|
||||
return groupsForTCP(tcp)
|
||||
return groupsForTCP(servers, tcp)
|
||||
}
|
||||
|
||||
func groupsForTCP(tcp bool) (choices []string) {
|
||||
allGroups := constants.CyberghostGroupChoices()
|
||||
func groupsForTCP(servers []models.CyberghostServer, tcp bool) (choices []string) {
|
||||
allGroups := constants.CyberghostGroupChoices(servers)
|
||||
choices = make([]string, 0, len(allGroups))
|
||||
for _, group := range allGroups {
|
||||
switch {
|
||||
|
||||
@@ -19,7 +19,7 @@ func Test_Cyberghost_filterServers(t *testing.T) {
|
||||
filteredServers []models.CyberghostServer
|
||||
err error
|
||||
}{
|
||||
"no servers": {
|
||||
"no server": {
|
||||
selection: configuration.ServerSelection{VPN: constants.OpenVPN},
|
||||
err: errors.New("no server found: for VPN openvpn; protocol udp"),
|
||||
},
|
||||
@@ -146,10 +146,18 @@ func Test_Cyberghost_filterServers(t *testing.T) {
|
||||
func Test_tcpGroupChoices(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
servers := []models.CyberghostServer{
|
||||
{Group: "Premium TCP Asia"},
|
||||
{Group: "Premium TCP Europe"},
|
||||
{Group: "Premium TCP USA"},
|
||||
{Group: "Premium UDP Asia"},
|
||||
{Group: "Premium UDP Europe"},
|
||||
{Group: "Premium UDP USA"},
|
||||
}
|
||||
expected := []string{
|
||||
"Premium TCP Asia", "Premium TCP Europe", "Premium TCP USA",
|
||||
}
|
||||
choices := tcpGroupChoices()
|
||||
choices := tcpGroupChoices(servers)
|
||||
|
||||
assert.Equal(t, expected, choices)
|
||||
}
|
||||
@@ -157,10 +165,18 @@ func Test_tcpGroupChoices(t *testing.T) {
|
||||
func Test_udpGroupChoices(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
servers := []models.CyberghostServer{
|
||||
{Group: "Premium TCP Asia"},
|
||||
{Group: "Premium TCP Europe"},
|
||||
{Group: "Premium TCP USA"},
|
||||
{Group: "Premium UDP Asia"},
|
||||
{Group: "Premium UDP Europe"},
|
||||
{Group: "Premium UDP USA"},
|
||||
}
|
||||
expected := []string{
|
||||
"Premium UDP Asia", "Premium UDP Europe", "Premium UDP USA",
|
||||
}
|
||||
choices := udpGroupChoices()
|
||||
choices := udpGroupChoices(servers)
|
||||
|
||||
assert.Equal(t, expected, choices)
|
||||
}
|
||||
|
||||
@@ -33,9 +33,5 @@ func (f *Fastestvpn) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, f.randSource), nil
|
||||
return utils.PickConnection(connections, selection, f.randSource)
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@ func (f *Fastestvpn) filterServers(selection configuration.ServerSelection) (
|
||||
case
|
||||
utils.FilterByPossibilities(server.Country, selection.Countries),
|
||||
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||
selection.OpenVPN.TCP && !server.TCP,
|
||||
!selection.OpenVPN.TCP && !server.UDP:
|
||||
utils.FilterByProtocol(selection, server.TCP, server.UDP):
|
||||
default:
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
@@ -38,9 +38,5 @@ func (h *HideMyAss) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, h.randSource), nil
|
||||
return utils.PickConnection(connections, selection, h.randSource)
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@ func (h *HideMyAss) filterServers(selection configuration.ServerSelection) (
|
||||
utils.FilterByPossibilities(server.Country, selection.Countries),
|
||||
utils.FilterByPossibilities(server.City, selection.Cities),
|
||||
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||
selection.OpenVPN.TCP && !server.TCP,
|
||||
!selection.OpenVPN.TCP && !server.UDP:
|
||||
utils.FilterByProtocol(selection, server.TCP, server.UDP):
|
||||
default:
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
@@ -38,9 +38,5 @@ func (i *Ipvanish) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, i.randSource), nil
|
||||
return utils.PickConnection(connections, selection, i.randSource)
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@ func (i *Ipvanish) filterServers(selection configuration.ServerSelection) (
|
||||
utils.FilterByPossibilities(server.Country, selection.Countries),
|
||||
utils.FilterByPossibilities(server.City, selection.Cities),
|
||||
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||
selection.OpenVPN.TCP && !server.TCP,
|
||||
!selection.OpenVPN.TCP && !server.UDP:
|
||||
utils.FilterByProtocol(selection, server.TCP, server.UDP):
|
||||
default:
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
package ivpn
|
||||
|
||||
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 (i *Ivpn) GetConnection(selection configuration.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
const port = 2049
|
||||
const protocol = constants.UDP
|
||||
if selection.OpenVPN.TCP {
|
||||
return connection, ErrProtocolUnsupported
|
||||
}
|
||||
port := getPort(selection)
|
||||
protocol := utils.GetProtocol(selection)
|
||||
|
||||
servers, err := i.filterServers(selection)
|
||||
if err != nil {
|
||||
@@ -33,14 +25,21 @@ func (i *Ivpn) GetConnection(selection configuration.ServerSelection) (
|
||||
Port: port,
|
||||
Protocol: protocol,
|
||||
Hostname: server.Hostname,
|
||||
PubKey: server.WgPubKey, // Wireguard only
|
||||
}
|
||||
connections = append(connections, connection)
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
return utils.PickConnection(connections, selection, i.randSource)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, i.randSource), nil
|
||||
func getPort(selection configuration.ServerSelection) (port uint16) {
|
||||
const (
|
||||
defaultOpenVPNTCP = 443
|
||||
defaultOpenVPNUDP = 1194
|
||||
defaultWireguard = 58237
|
||||
)
|
||||
return utils.GetPort(selection, defaultOpenVPNTCP,
|
||||
defaultOpenVPNUDP, defaultWireguard)
|
||||
}
|
||||
|
||||
97
internal/provider/ivpn/connection_test.go
Normal file
97
internal/provider/ivpn/connection_test.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package ivpn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_Ivpn_GetConnection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
servers []models.IvpnServer
|
||||
selection configuration.ServerSelection
|
||||
connection models.Connection
|
||||
err error
|
||||
}{
|
||||
"no server available": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
},
|
||||
err: errors.New("no server found: for VPN openvpn; protocol udp"),
|
||||
},
|
||||
"no filter": {
|
||||
servers: []models.IvpnServer{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, UDP: true},
|
||||
},
|
||||
connection: models.Connection{
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
Port: 1194,
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"target IP": {
|
||||
selection: configuration.ServerSelection{
|
||||
TargetIP: net.IPv4(2, 2, 2, 2),
|
||||
},
|
||||
servers: []models.IvpnServer{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, UDP: true},
|
||||
},
|
||||
connection: models.Connection{
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1194,
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"with filter": {
|
||||
selection: configuration.ServerSelection{
|
||||
Hostnames: []string{"b"},
|
||||
},
|
||||
servers: []models.IvpnServer{
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, UDP: true},
|
||||
{Hostname: "b", IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, UDP: true},
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, UDP: true},
|
||||
},
|
||||
connection: models.Connection{
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1194,
|
||||
Protocol: constants.UDP,
|
||||
Hostname: "b",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
randSource := rand.NewSource(0)
|
||||
|
||||
m := New(testCase.servers, randSource)
|
||||
|
||||
connection, err := m.GetConnection(testCase.selection)
|
||||
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.Equal(t, testCase.connection, connection)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,12 @@ func (i *Ivpn) filterServers(selection configuration.ServerSelection) (
|
||||
for _, server := range i.servers {
|
||||
switch {
|
||||
case
|
||||
server.VPN != selection.VPN,
|
||||
utils.FilterByPossibilities(server.ISP, selection.ISPs),
|
||||
utils.FilterByPossibilities(server.Country, selection.Countries),
|
||||
utils.FilterByPossibilities(server.City, selection.Cities),
|
||||
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||
selection.OpenVPN.TCP && !server.TCP,
|
||||
!selection.OpenVPN.TCP && !server.UDP:
|
||||
utils.FilterByProtocol(selection, server.TCP, server.UDP):
|
||||
default:
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
132
internal/provider/ivpn/filter_test.go
Normal file
132
internal/provider/ivpn/filter_test.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package ivpn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_Ivpn_filterServers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
servers []models.IvpnServer
|
||||
selection configuration.ServerSelection
|
||||
filtered []models.IvpnServer
|
||||
err error
|
||||
}{
|
||||
"no server available": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
},
|
||||
err: errors.New("no server found: for VPN openvpn; protocol udp"),
|
||||
},
|
||||
"no filter": {
|
||||
servers: []models.IvpnServer{
|
||||
{Hostname: "a", UDP: true},
|
||||
{Hostname: "b", UDP: true},
|
||||
{Hostname: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.IvpnServer{
|
||||
{Hostname: "a", UDP: true},
|
||||
{Hostname: "b", UDP: true},
|
||||
{Hostname: "c", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by country": {
|
||||
selection: configuration.ServerSelection{
|
||||
Countries: []string{"b"},
|
||||
},
|
||||
servers: []models.IvpnServer{
|
||||
{Country: "a", UDP: true},
|
||||
{Country: "b", UDP: true},
|
||||
{Country: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.IvpnServer{
|
||||
{Country: "b", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by city": {
|
||||
selection: configuration.ServerSelection{
|
||||
Cities: []string{"b"},
|
||||
},
|
||||
servers: []models.IvpnServer{
|
||||
{City: "a", UDP: true},
|
||||
{City: "b", UDP: true},
|
||||
{City: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.IvpnServer{
|
||||
{City: "b", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by ISP": {
|
||||
selection: configuration.ServerSelection{
|
||||
ISPs: []string{"b"},
|
||||
},
|
||||
servers: []models.IvpnServer{
|
||||
{ISP: "a", UDP: true},
|
||||
{ISP: "b", UDP: true},
|
||||
{ISP: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.IvpnServer{
|
||||
{ISP: "b", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by hostname": {
|
||||
selection: configuration.ServerSelection{
|
||||
Hostnames: []string{"b"},
|
||||
},
|
||||
servers: []models.IvpnServer{
|
||||
{Hostname: "a", UDP: true},
|
||||
{Hostname: "b", UDP: true},
|
||||
{Hostname: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.IvpnServer{
|
||||
{Hostname: "b", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by protocol": {
|
||||
selection: configuration.ServerSelection{
|
||||
OpenVPN: configuration.OpenVPNSelection{
|
||||
TCP: true,
|
||||
},
|
||||
},
|
||||
servers: []models.IvpnServer{
|
||||
{Hostname: "a", UDP: true},
|
||||
{Hostname: "b", UDP: true, TCP: true},
|
||||
{Hostname: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.IvpnServer{
|
||||
{Hostname: "b", UDP: true, TCP: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
randSource := rand.NewSource(0)
|
||||
|
||||
m := New(testCase.servers, randSource)
|
||||
|
||||
servers, err := m.filterServers(testCase.selection)
|
||||
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.Equal(t, testCase.filtered, servers)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package mullvad
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
@@ -10,7 +9,7 @@ import (
|
||||
func (m *Mullvad) GetConnection(selection configuration.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
port := getPort(selection)
|
||||
protocol := getProtocol(selection)
|
||||
protocol := utils.GetProtocol(selection)
|
||||
|
||||
servers, err := m.filterServers(selection)
|
||||
if err != nil {
|
||||
@@ -31,39 +30,15 @@ func (m *Mullvad) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, m.randSource), nil
|
||||
return utils.PickConnection(connections, selection, m.randSource)
|
||||
}
|
||||
|
||||
func getPort(selection configuration.ServerSelection) (port uint16) {
|
||||
switch selection.VPN {
|
||||
case constants.Wireguard:
|
||||
customPort := selection.Wireguard.CustomPort
|
||||
if customPort > 0 {
|
||||
return customPort
|
||||
}
|
||||
const defaultPort = 51820
|
||||
return defaultPort
|
||||
default: // OpenVPN
|
||||
customPort := selection.OpenVPN.CustomPort
|
||||
if customPort > 0 {
|
||||
return customPort
|
||||
}
|
||||
port = 1194
|
||||
if selection.OpenVPN.TCP {
|
||||
port = 443
|
||||
}
|
||||
return port
|
||||
}
|
||||
}
|
||||
|
||||
func getProtocol(selection configuration.ServerSelection) (protocol string) {
|
||||
protocol = constants.UDP
|
||||
if selection.VPN == constants.OpenVPN && selection.OpenVPN.TCP {
|
||||
protocol = constants.TCP
|
||||
}
|
||||
return protocol
|
||||
const (
|
||||
defaultOpenVPNTCP = 443
|
||||
defaultOpenVPNUDP = 1194
|
||||
defaultWireguard = 51820
|
||||
)
|
||||
return utils.GetPort(selection, defaultOpenVPNTCP,
|
||||
defaultOpenVPNUDP, defaultWireguard)
|
||||
}
|
||||
|
||||
@@ -94,111 +94,3 @@ func Test_Mullvad_GetConnection(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getPort(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
selection configuration.ServerSelection
|
||||
port uint16
|
||||
}{
|
||||
"default": {
|
||||
port: 1194,
|
||||
},
|
||||
"OpenVPN UDP": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
},
|
||||
port: 1194,
|
||||
},
|
||||
"OpenVPN TCP": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
OpenVPN: configuration.OpenVPNSelection{
|
||||
TCP: true,
|
||||
},
|
||||
},
|
||||
port: 443,
|
||||
},
|
||||
"OpenVPN custom port": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
OpenVPN: configuration.OpenVPNSelection{
|
||||
CustomPort: 1234,
|
||||
},
|
||||
},
|
||||
port: 1234,
|
||||
},
|
||||
"Wireguard": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.Wireguard,
|
||||
},
|
||||
port: 51820,
|
||||
},
|
||||
"Wireguard custom port": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.Wireguard,
|
||||
Wireguard: configuration.WireguardSelection{
|
||||
CustomPort: 1234,
|
||||
},
|
||||
},
|
||||
port: 1234,
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
port := getPort(testCase.selection)
|
||||
|
||||
assert.Equal(t, testCase.port, port)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getProtocol(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
selection configuration.ServerSelection
|
||||
protocol string
|
||||
}{
|
||||
"default": {
|
||||
protocol: constants.UDP,
|
||||
},
|
||||
"OpenVPN UDP": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
},
|
||||
protocol: constants.UDP,
|
||||
},
|
||||
"OpenVPN TCP": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
OpenVPN: configuration.OpenVPNSelection{
|
||||
TCP: true,
|
||||
},
|
||||
},
|
||||
protocol: constants.TCP,
|
||||
},
|
||||
"Wireguard": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.Wireguard,
|
||||
},
|
||||
protocol: constants.UDP,
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
protocol := getProtocol(testCase.selection)
|
||||
|
||||
assert.Equal(t, testCase.protocol, protocol)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,5 @@ func (n *Nordvpn) GetConnection(selection configuration.ServerSelection) (
|
||||
connections[i] = connection
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, n.randSource), nil
|
||||
return utils.PickConnection(connections, selection, n.randSource)
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ func (n *Nordvpn) filterServers(selection configuration.ServerSelection) (
|
||||
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||
utils.FilterByPossibilities(server.Name, selection.Names),
|
||||
utils.FilterByPossibilities(serverNumber, selectedNumbers),
|
||||
selection.OpenVPN.TCP && !server.TCP,
|
||||
!selection.OpenVPN.TCP && !server.UDP:
|
||||
utils.FilterByProtocol(selection, server.TCP, server.UDP):
|
||||
default:
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
@@ -37,9 +37,5 @@ func (p *Privado) GetConnection(selection configuration.ServerSelection) (
|
||||
connections[i] = connection
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, p.randSource), nil
|
||||
return utils.PickConnection(connections, selection, p.randSource)
|
||||
}
|
||||
|
||||
@@ -38,15 +38,5 @@ func (p *PIA) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
connection, err = utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
} else {
|
||||
connection, err = utils.PickRandomConnection(connections, p.randSource), nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return connection, err
|
||||
}
|
||||
|
||||
return connection, nil
|
||||
return utils.PickConnection(connections, selection, p.randSource)
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@ func (p *PIA) filterServers(selection configuration.ServerSelection) (
|
||||
utils.FilterByPossibilities(server.Region, selection.Regions),
|
||||
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||
utils.FilterByPossibilities(server.ServerName, selection.Names),
|
||||
selection.OpenVPN.TCP && !server.TCP,
|
||||
!selection.OpenVPN.TCP && !server.UDP:
|
||||
utils.FilterByProtocol(selection, server.TCP, server.UDP):
|
||||
default:
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ var (
|
||||
func (p *PIA) PortForward(ctx context.Context, client *http.Client,
|
||||
logger logging.Logger, gateway net.IP, serverName string) (
|
||||
port uint16, err error) {
|
||||
server := constants.PIAServerWhereName(serverName)
|
||||
server := constants.PIAServerWhereName(p.servers, serverName)
|
||||
if !server.PortForward {
|
||||
logger.Error("The server " + serverName +
|
||||
" (region " + server.Region + ") does not support port forwarding")
|
||||
|
||||
@@ -34,9 +34,5 @@ func (p *Privatevpn) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, p.randSource), nil
|
||||
return utils.PickConnection(connections, selection, p.randSource)
|
||||
}
|
||||
|
||||
@@ -34,9 +34,5 @@ func (p *Protonvpn) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, p.randSource), nil
|
||||
return utils.PickConnection(connections, selection, p.randSource)
|
||||
}
|
||||
|
||||
@@ -34,9 +34,5 @@ func (p *Purevpn) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, p.randSource), nil
|
||||
return utils.PickConnection(connections, selection, p.randSource)
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ func (p *Purevpn) filterServers(selection configuration.ServerSelection) (
|
||||
utils.FilterByPossibilities(server.Country, selection.Countries),
|
||||
utils.FilterByPossibilities(server.City, selection.Cities),
|
||||
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||
selection.OpenVPN.TCP && !server.TCP,
|
||||
!selection.OpenVPN.TCP && !server.UDP:
|
||||
utils.FilterByProtocol(selection, server.TCP, server.UDP):
|
||||
default:
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
@@ -34,9 +34,5 @@ func (s *Surfshark) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, s.randSource), nil
|
||||
return utils.PickConnection(connections, selection, s.randSource)
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ func (s *Surfshark) filterServers(selection configuration.ServerSelection) (
|
||||
switch {
|
||||
case
|
||||
utils.FilterByPossibilities(server.Region, selection.Regions),
|
||||
utils.FilterByPossibilities(server.Country, selection.Countries),
|
||||
utils.FilterByPossibilities(server.City, selection.Cities),
|
||||
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||
selection.OpenVPN.TCP && !server.TCP,
|
||||
!selection.OpenVPN.TCP && !server.UDP:
|
||||
utils.FilterByProtocol(selection, server.TCP, server.UDP),
|
||||
selection.MultiHopOnly && !server.MultiHop:
|
||||
default:
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
145
internal/provider/surfshark/filter_test.go
Normal file
145
internal/provider/surfshark/filter_test.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package surfshark
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_Surfshark_filterServers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
servers []models.SurfsharkServer
|
||||
selection configuration.ServerSelection
|
||||
filtered []models.SurfsharkServer
|
||||
err error
|
||||
}{
|
||||
"no server available": {
|
||||
selection: configuration.ServerSelection{
|
||||
VPN: constants.OpenVPN,
|
||||
},
|
||||
err: errors.New("no server found: for VPN openvpn; protocol udp"),
|
||||
},
|
||||
"no filter": {
|
||||
servers: []models.SurfsharkServer{
|
||||
{Hostname: "a", UDP: true},
|
||||
{Hostname: "b", UDP: true},
|
||||
{Hostname: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.SurfsharkServer{
|
||||
{Hostname: "a", UDP: true},
|
||||
{Hostname: "b", UDP: true},
|
||||
{Hostname: "c", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by region": {
|
||||
selection: configuration.ServerSelection{
|
||||
Regions: []string{"b"},
|
||||
},
|
||||
servers: []models.SurfsharkServer{
|
||||
{Region: "a", UDP: true},
|
||||
{Region: "b", UDP: true},
|
||||
{Region: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.SurfsharkServer{
|
||||
{Region: "b", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by country": {
|
||||
selection: configuration.ServerSelection{
|
||||
Countries: []string{"b"},
|
||||
},
|
||||
servers: []models.SurfsharkServer{
|
||||
{Country: "a", UDP: true},
|
||||
{Country: "b", UDP: true},
|
||||
{Country: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.SurfsharkServer{
|
||||
{Country: "b", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by city": {
|
||||
selection: configuration.ServerSelection{
|
||||
Cities: []string{"b"},
|
||||
},
|
||||
servers: []models.SurfsharkServer{
|
||||
{City: "a", UDP: true},
|
||||
{City: "b", UDP: true},
|
||||
{City: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.SurfsharkServer{
|
||||
{City: "b", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by hostname": {
|
||||
selection: configuration.ServerSelection{
|
||||
Hostnames: []string{"b"},
|
||||
},
|
||||
servers: []models.SurfsharkServer{
|
||||
{Hostname: "a", UDP: true},
|
||||
{Hostname: "b", UDP: true},
|
||||
{Hostname: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.SurfsharkServer{
|
||||
{Hostname: "b", UDP: true},
|
||||
},
|
||||
},
|
||||
"filter by protocol": {
|
||||
selection: configuration.ServerSelection{
|
||||
OpenVPN: configuration.OpenVPNSelection{
|
||||
TCP: true,
|
||||
},
|
||||
},
|
||||
servers: []models.SurfsharkServer{
|
||||
{Hostname: "a", UDP: true},
|
||||
{Hostname: "b", UDP: true, TCP: true},
|
||||
{Hostname: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.SurfsharkServer{
|
||||
{Hostname: "b", UDP: true, TCP: true},
|
||||
},
|
||||
},
|
||||
"filter by multihop only": {
|
||||
selection: configuration.ServerSelection{
|
||||
MultiHopOnly: true,
|
||||
},
|
||||
servers: []models.SurfsharkServer{
|
||||
{Hostname: "a", UDP: true},
|
||||
{Hostname: "b", MultiHop: true, UDP: true},
|
||||
{Hostname: "c", UDP: true},
|
||||
},
|
||||
filtered: []models.SurfsharkServer{
|
||||
{Hostname: "b", MultiHop: true, UDP: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
randSource := rand.NewSource(0)
|
||||
|
||||
s := New(testCase.servers, randSource)
|
||||
|
||||
servers, err := s.filterServers(testCase.selection)
|
||||
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.Equal(t, testCase.filtered, servers)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -37,9 +37,5 @@ func (t *Torguard) GetConnection(selection configuration.ServerSelection) (
|
||||
}
|
||||
}
|
||||
|
||||
if selection.TargetIP != nil {
|
||||
return utils.GetTargetIPConnection(connections, selection.TargetIP)
|
||||
}
|
||||
|
||||
return utils.PickRandomConnection(connections, t.randSource), nil
|
||||
return utils.PickConnection(connections, selection, t.randSource)
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@ func (t *Torguard) filterServers(selection configuration.ServerSelection) (
|
||||
utils.FilterByPossibilities(server.Country, selection.Countries),
|
||||
utils.FilterByPossibilities(server.City, selection.Cities),
|
||||
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
|
||||
selection.OpenVPN.TCP && !server.TCP,
|
||||
!selection.OpenVPN.TCP && !server.UDP:
|
||||
utils.FilterByProtocol(selection, server.TCP, server.UDP):
|
||||
default:
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func NoServerFoundError(selection configuration.ServerSelection) (err error) {
|
||||
}
|
||||
messageParts = append(messageParts, "protocol "+protocol)
|
||||
|
||||
switch len(selection.Countries) {
|
||||
switch len(selection.Groups) {
|
||||
case 0:
|
||||
case 1:
|
||||
part := "group " + selection.Groups[0]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user