mirror of
https://github.com/qdm12/gluetun.git
synced 2026-05-07 04:20:12 +02:00
Add linters and fix lint issues
This commit is contained in:
@@ -7,30 +7,43 @@ linters-settings:
|
|||||||
linters:
|
linters:
|
||||||
disable-all: true
|
disable-all: true
|
||||||
enable:
|
enable:
|
||||||
|
- asciicheck
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- deadcode
|
- deadcode
|
||||||
- dogsled
|
- dogsled
|
||||||
- dupl
|
- dupl
|
||||||
- errcheck
|
- errcheck
|
||||||
|
- exhaustive
|
||||||
|
- exportloopref
|
||||||
|
- gci
|
||||||
- gochecknoglobals
|
- gochecknoglobals
|
||||||
- gochecknoinits
|
- gochecknoinits
|
||||||
- gocognit
|
- gocognit
|
||||||
- goconst
|
- goconst
|
||||||
- gocritic
|
- gocritic
|
||||||
- gocyclo
|
- gocyclo
|
||||||
|
- godot
|
||||||
|
- goheader
|
||||||
- goimports
|
- goimports
|
||||||
- golint
|
- golint
|
||||||
|
- gomnd
|
||||||
|
- goprintffuncname
|
||||||
- gosec
|
- gosec
|
||||||
- gosimple
|
- gosimple
|
||||||
- govet
|
- govet
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- interfacer
|
- interfacer
|
||||||
|
- lll
|
||||||
- maligned
|
- maligned
|
||||||
- misspell
|
- misspell
|
||||||
- nakedret
|
- nakedret
|
||||||
|
- nestif
|
||||||
|
- noctx
|
||||||
|
- nolintlint
|
||||||
- prealloc
|
- prealloc
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- scopelint
|
- scopelint
|
||||||
|
- sqlclosecheck
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- structcheck
|
- structcheck
|
||||||
- typecheck
|
- typecheck
|
||||||
|
|||||||
+21
-10
@@ -73,8 +73,9 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
logger := createLogger()
|
logger := createLogger()
|
||||||
|
|
||||||
httpClient := &http.Client{Timeout: 15 * time.Second}
|
const clientTimeout = 15 * time.Second
|
||||||
client := network.NewClient(15 * time.Second)
|
httpClient := &http.Client{Timeout: clientTimeout}
|
||||||
|
client := network.NewClient(clientTimeout)
|
||||||
// Create configurators
|
// Create configurators
|
||||||
fileManager := files.NewFileManager()
|
fileManager := files.NewFileManager()
|
||||||
alpineConf := alpine.NewConfigurator(fileManager)
|
alpineConf := alpine.NewConfigurator(fileManager)
|
||||||
@@ -205,7 +206,8 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
|
|||||||
go openvpnLooper.Run(ctx, wg)
|
go openvpnLooper.Run(ctx, wg)
|
||||||
|
|
||||||
updaterOptions := updater.NewOptions("127.0.0.1")
|
updaterOptions := updater.NewOptions("127.0.0.1")
|
||||||
updaterLooper := updater.NewLooper(updaterOptions, allSettings.UpdaterPeriod, allServers, storage, openvpnLooper.SetAllServers, httpClient, logger)
|
updaterLooper := updater.NewLooper(updaterOptions, allSettings.UpdaterPeriod,
|
||||||
|
allServers, storage, openvpnLooper.SetAllServers, httpClient, logger)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
// wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker
|
// wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker
|
||||||
go updaterLooper.Run(ctx, wg)
|
go updaterLooper.Run(ctx, wg)
|
||||||
@@ -215,14 +217,16 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
|
|||||||
// wait for unboundLooper.Restart or its ticker launched with RunRestartTicker
|
// wait for unboundLooper.Restart or its ticker launched with RunRestartTicker
|
||||||
go unboundLooper.Run(ctx, wg, signalDNSReady)
|
go unboundLooper.Run(ctx, wg, signalDNSReady)
|
||||||
|
|
||||||
publicIPLooper := publicip.NewLooper(client, logger, fileManager, allSettings.System.IPStatusFilepath, allSettings.PublicIPPeriod, uid, gid)
|
publicIPLooper := publicip.NewLooper(client, logger, fileManager,
|
||||||
|
allSettings.System.IPStatusFilepath, allSettings.PublicIPPeriod, uid, gid)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go publicIPLooper.Run(ctx, wg)
|
go publicIPLooper.Run(ctx, wg)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go publicIPLooper.RunRestartTicker(ctx, wg)
|
go publicIPLooper.RunRestartTicker(ctx, wg)
|
||||||
publicIPLooper.SetPeriod(allSettings.PublicIPPeriod) // call after RunRestartTicker
|
publicIPLooper.SetPeriod(allSettings.PublicIPPeriod) // call after RunRestartTicker
|
||||||
|
|
||||||
tinyproxyLooper := tinyproxy.NewLooper(tinyProxyConf, firewallConf, allSettings.TinyProxy, logger, streamMerger, uid, gid, defaultInterface)
|
tinyproxyLooper := tinyproxy.NewLooper(tinyProxyConf, firewallConf,
|
||||||
|
allSettings.TinyProxy, logger, streamMerger, uid, gid, defaultInterface)
|
||||||
restartTinyproxy := tinyproxyLooper.Restart
|
restartTinyproxy := tinyproxyLooper.Restart
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go tinyproxyLooper.Run(ctx, wg)
|
go tinyproxyLooper.Run(ctx, wg)
|
||||||
@@ -246,7 +250,8 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
|
|||||||
)
|
)
|
||||||
controlServerAddress := fmt.Sprintf("0.0.0.0:%d", allSettings.ControlServer.Port)
|
controlServerAddress := fmt.Sprintf("0.0.0.0:%d", allSettings.ControlServer.Port)
|
||||||
controlServerLogging := allSettings.ControlServer.Log
|
controlServerLogging := allSettings.ControlServer.Log
|
||||||
httpServer := server.New(controlServerAddress, controlServerLogging, logger, openvpnLooper, unboundLooper, updaterLooper)
|
httpServer := server.New(controlServerAddress, controlServerLogging,
|
||||||
|
logger, openvpnLooper, unboundLooper, updaterLooper)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go httpServer.Run(ctx, wg)
|
go httpServer.Run(ctx, wg)
|
||||||
|
|
||||||
@@ -309,8 +314,10 @@ func createLogger() logging.Logger {
|
|||||||
return logger
|
return logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func printVersions(ctx context.Context, logger logging.Logger, versionFunctions map[string]func(ctx context.Context) (string, error)) {
|
func printVersions(ctx context.Context, logger logging.Logger,
|
||||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
versionFunctions map[string]func(ctx context.Context) (string, error)) {
|
||||||
|
const timeout = 5 * time.Second
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
for name, f := range versionFunctions {
|
for name, f := range versionFunctions {
|
||||||
version, err := f(ctx)
|
version, err := f(ctx)
|
||||||
@@ -322,7 +329,9 @@ func printVersions(ctx context.Context, logger logging.Logger, versionFunctions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectStreamLines(ctx context.Context, streamMerger command.StreamMerger, logger logging.Logger, signalTunnelReady func()) {
|
//nolint:lll
|
||||||
|
func collectStreamLines(ctx context.Context, streamMerger command.StreamMerger,
|
||||||
|
logger logging.Logger, signalTunnelReady func()) {
|
||||||
// Blocking line merging paramsReader for all programs: openvpn, tinyproxy, unbound and shadowsocks
|
// Blocking line merging paramsReader for all programs: openvpn, tinyproxy, unbound and shadowsocks
|
||||||
logger.Info("Launching standard output merger")
|
logger.Info("Launching standard output merger")
|
||||||
streamMerger.CollectLines(ctx, func(line string) {
|
streamMerger.CollectLines(ctx, func(line string) {
|
||||||
@@ -331,6 +340,8 @@ func collectStreamLines(ctx context.Context, streamMerger command.StreamMerger,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch level {
|
switch level {
|
||||||
|
case logging.DebugLevel:
|
||||||
|
logger.Debug(line)
|
||||||
case logging.InfoLevel:
|
case logging.InfoLevel:
|
||||||
logger.Info(line)
|
logger.Info(line)
|
||||||
case logging.WarnLevel:
|
case logging.WarnLevel:
|
||||||
@@ -374,7 +385,7 @@ func routeReadyEvents(ctx context.Context, wg *sync.WaitGroup, tunnelReadyCh, dn
|
|||||||
restartTickerCancel() // stop previous restart tickers
|
restartTickerCancel() // stop previous restart tickers
|
||||||
tickerWg.Wait()
|
tickerWg.Wait()
|
||||||
restartTickerContext, restartTickerCancel = context.WithCancel(ctx)
|
restartTickerContext, restartTickerCancel = context.WithCancel(ctx)
|
||||||
tickerWg.Add(2)
|
tickerWg.Add(2) //nolint:gomnd
|
||||||
go unboundLooper.RunRestartTicker(restartTickerContext, tickerWg)
|
go unboundLooper.RunRestartTicker(restartTickerContext, tickerWg)
|
||||||
go updaterLooper.RunRestartTicker(restartTickerContext, tickerWg)
|
go updaterLooper.RunRestartTicker(restartTickerContext, tickerWg)
|
||||||
defaultInterface, _, err := routing.DefaultRoute()
|
defaultInterface, _, err := routing.DefaultRoute()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"os/user"
|
"os/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateUser creates a user in Alpine with the given UID
|
// CreateUser creates a user in Alpine with the given UID.
|
||||||
func (c *configurator) CreateUser(username string, uid int) error {
|
func (c *configurator) CreateUser(username string, uid int) error {
|
||||||
UIDStr := fmt.Sprintf("%d", uid)
|
UIDStr := fmt.Sprintf("%d", uid)
|
||||||
u, err := c.lookupUID(UIDStr)
|
u, err := c.lookupUID(UIDStr)
|
||||||
@@ -23,7 +23,8 @@ func (c *configurator) CreateUser(username string, uid int) error {
|
|||||||
if err != nil && !unknownUsername {
|
if err != nil && !unknownUsername {
|
||||||
return fmt.Errorf("cannot create user: %w", err)
|
return fmt.Errorf("cannot create user: %w", err)
|
||||||
} else if u != nil {
|
} else if u != nil {
|
||||||
return fmt.Errorf("cannot create user: user with name %s already exists for ID %s instead of %d", username, u.Uid, uid)
|
return fmt.Errorf("cannot create user: user with name %s already exists for ID %s instead of %d",
|
||||||
|
username, u.Uid, uid)
|
||||||
}
|
}
|
||||||
passwd, err := c.fileManager.ReadFile("/etc/passwd")
|
passwd, err := c.fileManager.ReadFile("/etc/passwd")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+2
-1
@@ -117,7 +117,8 @@ func Update(args []string) error {
|
|||||||
return fmt.Errorf("at least one of -file or -stdout must be specified")
|
return fmt.Errorf("at least one of -file or -stdout must be specified")
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
httpClient := &http.Client{Timeout: 10 * time.Second}
|
const clientTimeout = 10 * time.Second
|
||||||
|
httpClient := &http.Client{Timeout: clientTimeout}
|
||||||
storage := storage.New(logger)
|
storage := storage.New(logger)
|
||||||
const writeSync = false
|
const writeSync = false
|
||||||
currentServers, err := storage.SyncServers(constants.GetAllServers(), writeSync)
|
currentServers, err := storage.SyncServers(constants.GetAllServers(), writeSync)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
CyberghostCertificate = "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"
|
CyberghostCertificate = "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"
|
||||||
CyberghostClientCertificate = "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"
|
CyberghostClientCertificate = "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"
|
||||||
@@ -40,6 +41,7 @@ func CyberghostGroupChoices() (choices []string) {
|
|||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func CyberghostServers() []models.CyberghostServer {
|
func CyberghostServers() []models.CyberghostServer {
|
||||||
return []models.CyberghostServer{
|
return []models.CyberghostServer{
|
||||||
{Region: "Albania", Group: "Premium TCP Europe", IPs: []net.IP{{31, 171, 152, 99}, {31, 171, 152, 102}, {31, 171, 152, 104}, {31, 171, 152, 106}, {31, 171, 152, 107}, {31, 171, 152, 108}, {31, 171, 152, 109}, {31, 171, 152, 133}, {31, 171, 152, 139}, {31, 171, 152, 140}}},
|
{Region: "Albania", Group: "Premium TCP Europe", IPs: []net.IP{{31, 171, 152, 99}, {31, 171, 152, 102}, {31, 171, 152, 104}, {31, 171, 152, 106}, {31, 171, 152, 107}, {31, 171, 152, 108}, {31, 171, 152, 109}, {31, 171, 152, 133}, {31, 171, 152, 139}, {31, 171, 152, 140}}},
|
||||||
|
|||||||
+42
-15
@@ -7,19 +7,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Cloudflare is a DNS over TLS provider
|
// Cloudflare is a DNS over TLS provider.
|
||||||
Cloudflare models.DNSProvider = "cloudflare"
|
Cloudflare models.DNSProvider = "cloudflare"
|
||||||
// Google is a DNS over TLS provider
|
// Google is a DNS over TLS provider.
|
||||||
Google models.DNSProvider = "google"
|
Google models.DNSProvider = "google"
|
||||||
// Quad9 is a DNS over TLS provider
|
// Quad9 is a DNS over TLS provider.
|
||||||
Quad9 models.DNSProvider = "quad9"
|
Quad9 models.DNSProvider = "quad9"
|
||||||
// Quadrant is a DNS over TLS provider
|
// Quadrant is a DNS over TLS provider.
|
||||||
Quadrant models.DNSProvider = "quadrant"
|
Quadrant models.DNSProvider = "quadrant"
|
||||||
// CleanBrowsing is a DNS over TLS provider
|
// CleanBrowsing is a DNS over TLS provider.
|
||||||
CleanBrowsing models.DNSProvider = "cleanbrowsing"
|
CleanBrowsing models.DNSProvider = "cleanbrowsing"
|
||||||
// SecureDNS is a DNS over TLS provider
|
// SecureDNS is a DNS over TLS provider.
|
||||||
SecureDNS models.DNSProvider = "securedns"
|
SecureDNS models.DNSProvider = "securedns"
|
||||||
// LibreDNS is a DNS over TLS provider
|
// LibreDNS is a DNS over TLS provider.
|
||||||
LibreDNS models.DNSProvider = "libredns"
|
LibreDNS models.DNSProvider = "libredns"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,37 +28,63 @@ const (
|
|||||||
func DNSProviderMapping() map[models.DNSProvider]models.DNSProviderData {
|
func DNSProviderMapping() map[models.DNSProvider]models.DNSProviderData {
|
||||||
return map[models.DNSProvider]models.DNSProviderData{
|
return map[models.DNSProvider]models.DNSProviderData{
|
||||||
Cloudflare: {
|
Cloudflare: {
|
||||||
IPs: []net.IP{{1, 1, 1, 1}, {1, 0, 0, 1}, {0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11}, {0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x01}},
|
IPs: []net.IP{
|
||||||
|
{1, 1, 1, 1},
|
||||||
|
{1, 0, 0, 1},
|
||||||
|
{0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11},
|
||||||
|
{0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x01},
|
||||||
|
},
|
||||||
SupportsTLS: true,
|
SupportsTLS: true,
|
||||||
SupportsIPv6: true,
|
SupportsIPv6: true,
|
||||||
Host: models.DNSHost("cloudflare-dns.com"),
|
Host: models.DNSHost("cloudflare-dns.com"),
|
||||||
},
|
},
|
||||||
Google: {
|
Google: {
|
||||||
IPs: []net.IP{{8, 8, 8, 8}, {8, 8, 4, 4}, {0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x88}, {0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x44}},
|
IPs: []net.IP{
|
||||||
|
{8, 8, 8, 8},
|
||||||
|
{8, 8, 4, 4},
|
||||||
|
{0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x88},
|
||||||
|
{0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x44},
|
||||||
|
},
|
||||||
SupportsTLS: true,
|
SupportsTLS: true,
|
||||||
SupportsIPv6: true,
|
SupportsIPv6: true,
|
||||||
Host: models.DNSHost("dns.google"),
|
Host: models.DNSHost("dns.google"),
|
||||||
},
|
},
|
||||||
Quad9: {
|
Quad9: {
|
||||||
IPs: []net.IP{{9, 9, 9, 9}, {149, 112, 112, 112}, {0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe}, {0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9}},
|
IPs: []net.IP{
|
||||||
|
{9, 9, 9, 9},
|
||||||
|
{149, 112, 112, 112},
|
||||||
|
{0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe},
|
||||||
|
{0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9},
|
||||||
|
},
|
||||||
SupportsTLS: true,
|
SupportsTLS: true,
|
||||||
SupportsIPv6: true,
|
SupportsIPv6: true,
|
||||||
Host: models.DNSHost("dns.quad9.net"),
|
Host: models.DNSHost("dns.quad9.net"),
|
||||||
},
|
},
|
||||||
Quadrant: {
|
Quadrant: {
|
||||||
IPs: []net.IP{{12, 159, 2, 159}, {0x20, 0x1, 0x18, 0x90, 0x14, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x59}},
|
IPs: []net.IP{
|
||||||
|
{12, 159, 2, 159},
|
||||||
|
{0x20, 0x1, 0x18, 0x90, 0x14, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x59},
|
||||||
|
},
|
||||||
SupportsTLS: true,
|
SupportsTLS: true,
|
||||||
SupportsIPv6: true,
|
SupportsIPv6: true,
|
||||||
Host: models.DNSHost("dns-tls.qis.io"),
|
Host: models.DNSHost("dns-tls.qis.io"),
|
||||||
},
|
},
|
||||||
CleanBrowsing: {
|
CleanBrowsing: {
|
||||||
IPs: []net.IP{{185, 228, 168, 9}, {185, 228, 169, 9}, {0x2a, 0xd, 0x2a, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, {0x2a, 0xd, 0x2a, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}},
|
IPs: []net.IP{
|
||||||
|
{185, 228, 168, 9},
|
||||||
|
{185, 228, 169, 9},
|
||||||
|
{0x2a, 0xd, 0x2a, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
|
||||||
|
{0x2a, 0xd, 0x2a, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
|
||||||
|
},
|
||||||
SupportsTLS: true,
|
SupportsTLS: true,
|
||||||
SupportsIPv6: true,
|
SupportsIPv6: true,
|
||||||
Host: models.DNSHost("security-filter-dns.cleanbrowsing.org"),
|
Host: models.DNSHost("security-filter-dns.cleanbrowsing.org"),
|
||||||
},
|
},
|
||||||
SecureDNS: {
|
SecureDNS: {
|
||||||
IPs: []net.IP{{146, 185, 167, 43}, {0x2a, 0x3, 0xb0, 0xc0, 0x0, 0x0, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0xe, 0x9a, 0x30, 0x1}},
|
IPs: []net.IP{
|
||||||
|
{146, 185, 167, 43},
|
||||||
|
{0x2a, 0x3, 0xb0, 0xc0, 0x0, 0x0, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0xe, 0x9a, 0x30, 0x1},
|
||||||
|
},
|
||||||
SupportsTLS: true,
|
SupportsTLS: true,
|
||||||
SupportsIPv6: true,
|
SupportsIPv6: true,
|
||||||
Host: models.DNSHost("dot.securedns.eu"),
|
Host: models.DNSHost("dot.securedns.eu"),
|
||||||
@@ -72,6 +98,7 @@ func DNSProviderMapping() map[models.DNSProvider]models.DNSProviderData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Block lists URLs
|
// Block lists URLs
|
||||||
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
AdsBlockListHostnamesURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/ads-hostnames.updated"
|
AdsBlockListHostnamesURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/ads-hostnames.updated"
|
||||||
AdsBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/ads-ips.updated"
|
AdsBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/ads-ips.updated"
|
||||||
@@ -81,8 +108,8 @@ const (
|
|||||||
SurveillanceBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/surveillance-ips.updated"
|
SurveillanceBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/surveillance-ips.updated"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNS certificates to fetch
|
// DNS certificates to fetch.
|
||||||
// TODO obtain from source directly, see qdm12/updated)
|
// TODO obtain from source directly, see qdm12/updated).
|
||||||
const (
|
const (
|
||||||
NamedRootURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/named.root.updated"
|
NamedRootURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/named.root.updated"
|
||||||
RootKeyURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/root.key.updated"
|
RootKeyURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/root.key.updated"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
MullvadCertificate = "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"
|
MullvadCertificate = "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"
|
||||||
)
|
)
|
||||||
@@ -53,7 +54,7 @@ func MullvadISPChoices() (choices []string) {
|
|||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:dupl
|
//nolint:dupl,lll
|
||||||
func MullvadServers() []models.MullvadServer {
|
func MullvadServers() []models.MullvadServer {
|
||||||
return []models.MullvadServer{
|
return []models.MullvadServer{
|
||||||
{Country: "Albania", City: "Tirana", ISP: "iRegister", Owned: false, IPs: []net.IP{{31, 171, 154, 210}}, IPsV6: []net.IP{{0x2a, 0x4, 0x27, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f}}},
|
{Country: "Albania", City: "Tirana", ISP: "iRegister", Owned: false, IPs: []net.IP{{31, 171, 154, 210}}, IPsV6: []net.IP{{0x2a, 0x4, 0x27, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f}}},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
NordvpnCertificate = "MIIFCjCCAvKgAwIBAgIBATANBgkqhkiG9w0BAQ0FADA5MQswCQYDVQQGEwJQQTEQMA4GA1UEChMHTm9yZFZQTjEYMBYGA1UEAxMPTm9yZFZQTiBSb290IENBMB4XDTE2MDEwMTAwMDAwMFoXDTM1MTIzMTIzNTk1OVowOTELMAkGA1UEBhMCUEExEDAOBgNVBAoTB05vcmRWUE4xGDAWBgNVBAMTD05vcmRWUE4gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMkr/BYhyo0F2upsIMXwC6QvkZps3NN2/eQFkfQIS1gql0aejsKsEnmY0Kaon8uZCTXPsRH1gQNgg5D2gixdd1mJUvV3dE3y9FJrXMoDkXdCGBodvKJyU6lcfEVF6/UxHcbBguZK9UtRHS9eJYm3rpL/5huQMCppX7kUeQ8dpCwd3iKITqwd1ZudDqsWaU0vqzC2H55IyaZ/5/TnCk31Q1UP6BksbbuRcwOVskEDsm6YoWDnn/IIzGOYnFJRzQH5jTz3j1QBvRIuQuBuvUkfhx1FEwhwZigrcxXuMP+QgM54kezgziJUaZcOM2zF3lvrwMvXDMfNeIoJABv9ljw969xQ8czQCU5lMVmA37ltv5Ec9U5hZuwk/9QO1Z+d/r6Jx0mlurS8gnCAKJgwa3kyZw6e4FZ8mYL4vpRRhPdvRTWCMJkeB4yBHyhxUmTRgJHm6YR3D6hcFAc9cQcTEl/I60tMdz33G6m0O42sQt/+AR3YCY/RusWVBJB/qNS94EtNtj8iaebCQW1jHAhvGmFILVR9lzD0EzWKHkvyWEjmUVRgCDd6Ne3eFRNS73gdv/C3l5boYySeu4exkEYVxVRn8DhCxs0MnkMHWFK6MyzXCCn+JnWFDYPfDKHvpff/kLDobtPBf+Lbch5wQy9quY27xaj0XwLyjOltpiSTLWae/Q4vAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQC9fUL2sZPxIN2mD32VeNySTgZlCEdVmlq471o/bDMP4B8gnQesFRtXY2ZCjs50Jm73B2LViL9qlREmI6vE5IC8IsRBJSV4ce1WYxyXro5rmVg/k6a10rlsbK/eg//GHoJxDdXDOokLUSnxt7gk3QKpX6eCdh67p0PuWm/7WUJQxH2SDxsT9vB/iZriTIEe/ILoOQF0Aqp7AgNCcLcLAmbxXQkXYCCSB35Vp06u+eTWjG0/pyS5V14stGtw+fA0DJp5ZJV4eqJ5LqxMlYvEZ/qKTEdoCeaXv2QEmN6dVqjDoTAok0t5u4YRXzEVCfXAC3ocplNdtCA72wjFJcSbfif4BSC8bDACTXtnPC7nD0VndZLp+RiNLeiENhk0oTC+UVdSc+n2nJOzkCK0vYu0Ads4JGIB7g8IB3z2t9ICmsWrgnhdNdcOe15BincrGA8avQ1cWXsfIKEjbrnEuEk9b5jel6NfHtPKoHc9mDpRdNPISeVawDBM1mJChneHt59Nh8Gah74+TM1jBsw4fhJPvoc7Atcg740JErb904mZfkIEmojCVPhBHVQ9LHBAdM8qFI2kRK0IynOmAZhexlP/aT/kpEsEPyaZQlnBn3An1CRz8h0SPApL8PytggYKeQmRhl499+6jLxcZ2IegLfqq41dzIjwHwTMplg+1pKIOVojpWA=="
|
NordvpnCertificate = "MIIFCjCCAvKgAwIBAgIBATANBgkqhkiG9w0BAQ0FADA5MQswCQYDVQQGEwJQQTEQMA4GA1UEChMHTm9yZFZQTjEYMBYGA1UEAxMPTm9yZFZQTiBSb290IENBMB4XDTE2MDEwMTAwMDAwMFoXDTM1MTIzMTIzNTk1OVowOTELMAkGA1UEBhMCUEExEDAOBgNVBAoTB05vcmRWUE4xGDAWBgNVBAMTD05vcmRWUE4gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMkr/BYhyo0F2upsIMXwC6QvkZps3NN2/eQFkfQIS1gql0aejsKsEnmY0Kaon8uZCTXPsRH1gQNgg5D2gixdd1mJUvV3dE3y9FJrXMoDkXdCGBodvKJyU6lcfEVF6/UxHcbBguZK9UtRHS9eJYm3rpL/5huQMCppX7kUeQ8dpCwd3iKITqwd1ZudDqsWaU0vqzC2H55IyaZ/5/TnCk31Q1UP6BksbbuRcwOVskEDsm6YoWDnn/IIzGOYnFJRzQH5jTz3j1QBvRIuQuBuvUkfhx1FEwhwZigrcxXuMP+QgM54kezgziJUaZcOM2zF3lvrwMvXDMfNeIoJABv9ljw969xQ8czQCU5lMVmA37ltv5Ec9U5hZuwk/9QO1Z+d/r6Jx0mlurS8gnCAKJgwa3kyZw6e4FZ8mYL4vpRRhPdvRTWCMJkeB4yBHyhxUmTRgJHm6YR3D6hcFAc9cQcTEl/I60tMdz33G6m0O42sQt/+AR3YCY/RusWVBJB/qNS94EtNtj8iaebCQW1jHAhvGmFILVR9lzD0EzWKHkvyWEjmUVRgCDd6Ne3eFRNS73gdv/C3l5boYySeu4exkEYVxVRn8DhCxs0MnkMHWFK6MyzXCCn+JnWFDYPfDKHvpff/kLDobtPBf+Lbch5wQy9quY27xaj0XwLyjOltpiSTLWae/Q4vAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQC9fUL2sZPxIN2mD32VeNySTgZlCEdVmlq471o/bDMP4B8gnQesFRtXY2ZCjs50Jm73B2LViL9qlREmI6vE5IC8IsRBJSV4ce1WYxyXro5rmVg/k6a10rlsbK/eg//GHoJxDdXDOokLUSnxt7gk3QKpX6eCdh67p0PuWm/7WUJQxH2SDxsT9vB/iZriTIEe/ILoOQF0Aqp7AgNCcLcLAmbxXQkXYCCSB35Vp06u+eTWjG0/pyS5V14stGtw+fA0DJp5ZJV4eqJ5LqxMlYvEZ/qKTEdoCeaXv2QEmN6dVqjDoTAok0t5u4YRXzEVCfXAC3ocplNdtCA72wjFJcSbfif4BSC8bDACTXtnPC7nD0VndZLp+RiNLeiENhk0oTC+UVdSc+n2nJOzkCK0vYu0Ads4JGIB7g8IB3z2t9ICmsWrgnhdNdcOe15BincrGA8avQ1cWXsfIKEjbrnEuEk9b5jel6NfHtPKoHc9mDpRdNPISeVawDBM1mJChneHt59Nh8Gah74+TM1jBsw4fhJPvoc7Atcg740JErb904mZfkIEmojCVPhBHVQ9LHBAdM8qFI2kRK0IynOmAZhexlP/aT/kpEsEPyaZQlnBn3An1CRz8h0SPApL8PytggYKeQmRhl499+6jLxcZ2IegLfqq41dzIjwHwTMplg+1pKIOVojpWA=="
|
||||||
NordvpnOpenvpnStaticKeyV1 = "e685bdaf659a25a200e2b9e39e51ff030fc72cf1ce07232bd8b2be5e6c670143f51e937e670eee09d4f2ea5a6e4e69965db852c275351b86fc4ca892d78ae002d6f70d029bd79c4d1c26cf14e9588033cf639f8a74809f29f72b9d58f9b8f5fefc7938eade40e9fed6cb92184abb2cc10eb1a296df243b251df0643d53724cdb5a92a1d6cb817804c4a9319b57d53be580815bcfcb2df55018cc83fc43bc7ff82d51f9b88364776ee9d12fc85cc7ea5b9741c4f598c485316db066d52db4540e212e1518a9bd4828219e24b20d88f598a196c9de96012090e333519ae18d35099427e7b372d348d352dc4c85e18cd4b93f8a56ddb2e64eb67adfc9b337157ff4"
|
NordvpnOpenvpnStaticKeyV1 = "e685bdaf659a25a200e2b9e39e51ff030fc72cf1ce07232bd8b2be5e6c670143f51e937e670eee09d4f2ea5a6e4e69965db852c275351b86fc4ca892d78ae002d6f70d029bd79c4d1c26cf14e9588033cf639f8a74809f29f72b9d58f9b8f5fefc7938eade40e9fed6cb92184abb2cc10eb1a296df243b251df0643d53724cdb5a92a1d6cb817804c4a9319b57d53be580815bcfcb2df55018cc83fc43bc7ff82d51f9b88364776ee9d12fc85cc7ea5b9741c4f598c485316db066d52db4540e212e1518a9bd4828219e24b20d88f598a196c9de96012090e333519ae18d35099427e7b372d348d352dc4c85e18cd4b93f8a56ddb2e64eb67adfc9b337157ff4"
|
||||||
@@ -20,6 +21,7 @@ func NordvpnRegionChoices() (choices []string) {
|
|||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:gomnd
|
||||||
func NordvpnServers() []models.NordvpnServer {
|
func NordvpnServers() []models.NordvpnServer {
|
||||||
return []models.NordvpnServer{
|
return []models.NordvpnServer{
|
||||||
{Region: "Albania", Number: 18, TCP: true, UDP: true, IP: net.IP{31, 171, 152, 19}},
|
{Region: "Albania", Number: 18, TCP: true, UDP: true, IP: net.IP{31, 171, 152, 19}},
|
||||||
|
|||||||
+12
-12
@@ -5,28 +5,28 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// UnboundConf is the file path to the Unbound configuration file
|
// UnboundConf is the file path to the Unbound configuration file.
|
||||||
UnboundConf models.Filepath = "/etc/unbound/unbound.conf"
|
UnboundConf models.Filepath = "/etc/unbound/unbound.conf"
|
||||||
// ResolvConf is the file path to the system resolv.conf file
|
// ResolvConf is the file path to the system resolv.conf file.
|
||||||
ResolvConf models.Filepath = "/etc/resolv.conf"
|
ResolvConf models.Filepath = "/etc/resolv.conf"
|
||||||
// CACertificates is the file path to the CA certificates file
|
// CACertificates is the file path to the CA certificates file.
|
||||||
CACertificates models.Filepath = "/etc/ssl/certs/ca-certificates.crt"
|
CACertificates models.Filepath = "/etc/ssl/certs/ca-certificates.crt"
|
||||||
// OpenVPNAuthConf is the file path to the OpenVPN auth file
|
// OpenVPNAuthConf is the file path to the OpenVPN auth file.
|
||||||
OpenVPNAuthConf models.Filepath = "/etc/openvpn/auth.conf"
|
OpenVPNAuthConf models.Filepath = "/etc/openvpn/auth.conf"
|
||||||
// OpenVPNConf is the file path to the OpenVPN client configuration file
|
// OpenVPNConf is the file path to the OpenVPN client configuration file.
|
||||||
OpenVPNConf models.Filepath = "/etc/openvpn/target.ovpn"
|
OpenVPNConf models.Filepath = "/etc/openvpn/target.ovpn"
|
||||||
// PIAPortForward is the file path to the port forwarding JSON information for PIA v4 servers
|
// PIAPortForward is the file path to the port forwarding JSON information for PIA v4 servers.
|
||||||
PIAPortForward models.Filepath = "/gluetun/piaportforward.json"
|
PIAPortForward models.Filepath = "/gluetun/piaportforward.json"
|
||||||
// TunnelDevice is the file path to tun device
|
// TunnelDevice is the file path to tun device.
|
||||||
TunnelDevice models.Filepath = "/dev/net/tun"
|
TunnelDevice models.Filepath = "/dev/net/tun"
|
||||||
// NetRoute is the path to the file containing information on the network route
|
// NetRoute is the path to the file containing information on the network route.
|
||||||
NetRoute models.Filepath = "/proc/net/route"
|
NetRoute models.Filepath = "/proc/net/route"
|
||||||
// TinyProxyConf is the filepath to the tinyproxy configuration file
|
// TinyProxyConf is the filepath to the tinyproxy configuration file.
|
||||||
TinyProxyConf models.Filepath = "/etc/tinyproxy/tinyproxy.conf"
|
TinyProxyConf models.Filepath = "/etc/tinyproxy/tinyproxy.conf"
|
||||||
// ShadowsocksConf is the filepath to the shadowsocks configuration file
|
// ShadowsocksConf is the filepath to the shadowsocks configuration file.
|
||||||
ShadowsocksConf models.Filepath = "/etc/shadowsocks.json"
|
ShadowsocksConf models.Filepath = "/etc/shadowsocks.json"
|
||||||
// RootHints is the filepath to the root.hints file used by Unbound
|
// RootHints is the filepath to the root.hints file used by Unbound.
|
||||||
RootHints models.Filepath = "/etc/unbound/root.hints"
|
RootHints models.Filepath = "/etc/unbound/root.hints"
|
||||||
// RootKey is the filepath to the root.key file used by Unbound
|
// RootKey is the filepath to the root.key file used by Unbound.
|
||||||
RootKey models.Filepath = "/etc/unbound/root.key"
|
RootKey models.Filepath = "/etc/unbound/root.key"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package constants
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserReadPermission os.FileMode = 0400
|
||||||
|
AllReadWritePermissions os.FileMode = 0666
|
||||||
|
)
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
PIAEncryptionPresetNormal = "normal"
|
PIAEncryptionPresetNormal = "normal"
|
||||||
PIAEncryptionPresetStrong = "strong"
|
PIAEncryptionPresetStrong = "strong"
|
||||||
@@ -24,6 +25,7 @@ func PIAGeoChoices() (choices []string) {
|
|||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func PIAServers() []models.PIAServer {
|
func PIAServers() []models.PIAServer {
|
||||||
return []models.PIAServer{
|
return []models.PIAServer{
|
||||||
{Region: "AU Melbourne", PortForward: true, OpenvpnUDP: models.PIAServerOpenvpn{CN: "melbourne405", IPs: []net.IP{{103, 2, 198, 108}}}, OpenvpnTCP: models.PIAServerOpenvpn{CN: "melbourne405", IPs: []net.IP{{103, 2, 198, 103}}}},
|
{Region: "AU Melbourne", PortForward: true, OpenvpnUDP: models.PIAServerOpenvpn{CN: "melbourne405", IPs: []net.IP{{103, 2, 198, 108}}}, OpenvpnTCP: models.PIAServerOpenvpn{CN: "melbourne405", IPs: []net.IP{{103, 2, 198, 103}}}},
|
||||||
@@ -133,6 +135,7 @@ func PIAOldGeoChoices() (choices []string) {
|
|||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func PIAOldServers() []models.PIAOldServer {
|
func PIAOldServers() []models.PIAOldServer {
|
||||||
return []models.PIAOldServer{
|
return []models.PIAOldServer{
|
||||||
{Region: "AU Melbourne", IPs: []net.IP{{27, 50, 82, 131}, {43, 250, 204, 105}, {43, 250, 204, 107}, {43, 250, 204, 109}, {43, 250, 204, 111}, {43, 250, 204, 113}, {43, 250, 204, 115}, {43, 250, 204, 117}, {43, 250, 204, 119}, {43, 250, 204, 123}, {43, 250, 204, 125}}},
|
{Region: "AU Melbourne", IPs: []net.IP{{27, 50, 82, 131}, {43, 250, 204, 105}, {43, 250, 204, 107}, {43, 250, 204, 109}, {43, 250, 204, 111}, {43, 250, 204, 113}, {43, 250, 204, 115}, {43, 250, 204, 117}, {43, 250, 204, 119}, {43, 250, 204, 123}, {43, 250, 204, 125}}},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
PurevpnCertificateAuthority = "MIIE6DCCA9CgAwIBAgIJAMjXFoeo5uSlMA0GCSqGSIb3DQEBCwUAMIGoMQswCQYDVQQGEwJISzEQMA4GA1UECBMHQ2VudHJhbDELMAkGA1UEBxMCSEsxGDAWBgNVBAoTD1NlY3VyZS1TZXJ2ZXJDQTELMAkGA1UECxMCSVQxGDAWBgNVBAMTD1NlY3VyZS1TZXJ2ZXJDQTEYMBYGA1UEKRMPU2VjdXJlLVNlcnZlckNBMR8wHQYJKoZIhvcNAQkBFhBtYWlsQGhvc3QuZG9tYWluMB4XDTE2MDExNTE1MzQwOVoXDTI2MDExMjE1MzQwOVowgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDluufhyLlyvXzPUL16kAWAdivl1roQv3QHbuRshyKacf/1Er1JqEbtW3Mx9Fvr/u27qU2W8lQI6DaJhU2BfijPe/KHkib55mvHzIVvoexxya26nk79F2c+d9PnuuMdThWQO3El5a/i2AASnM7T7piIBT2WRZW2i8RbfJaTT7G7LP7OpMKIV1qyBg/cWoO7cIWQW4jmzqrNryIkF0AzStLN1DxvnQZwgXBGv0CwuAkfQuNSLu0PQgPp0PhdukNZFllv5D29IhPr0Z+kwPtrAgPQo+lHlOBHBMUpDT4XChTPeAvMaUSBsqmonAE8UUHEabWrqYN/kWNHCNkYXMkiVmK1AgMBAAGjggERMIIBDTAdBgNVHQ4EFgQU456ijsFrYnzHBShLAPpOUqQ+Z2cwgd0GA1UdIwSB1TCB0oAU456ijsFrYnzHBShLAPpOUqQ+Z2ehga6kgaswgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQDI1xaHqObkpTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCvga2HMwOtUxWH/inL2qk24KX2pxLg939JNhqoyNrUpbDHag5xPQYXUmUpKrNJZ0z+o/ZnNUPHydTSXE7Z7E45J0GDN5E7g4pakndKnDLSjp03NgGsCGW+cXnz6UBPM5FStFvGdDeModeSUyoS9fjk+mYROvmiy5EiVDP91sKGcPLR7Ym0M7zl2aaqV7bb98HmMoBOxpeZQinof67nKrCsgz/xjktWFgcmPl4/PQSsmqQD0fTtWxGuRX+FzwvF2OCMCAJgp1RqJNlk2g50/kBIoJVPPCfjDFeDU5zGaWGSQ9+z1L6/z7VXdjUiHL0ouOcHwbiS4ZjTr9nMn6WdAHU2"
|
PurevpnCertificateAuthority = "MIIE6DCCA9CgAwIBAgIJAMjXFoeo5uSlMA0GCSqGSIb3DQEBCwUAMIGoMQswCQYDVQQGEwJISzEQMA4GA1UECBMHQ2VudHJhbDELMAkGA1UEBxMCSEsxGDAWBgNVBAoTD1NlY3VyZS1TZXJ2ZXJDQTELMAkGA1UECxMCSVQxGDAWBgNVBAMTD1NlY3VyZS1TZXJ2ZXJDQTEYMBYGA1UEKRMPU2VjdXJlLVNlcnZlckNBMR8wHQYJKoZIhvcNAQkBFhBtYWlsQGhvc3QuZG9tYWluMB4XDTE2MDExNTE1MzQwOVoXDTI2MDExMjE1MzQwOVowgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDluufhyLlyvXzPUL16kAWAdivl1roQv3QHbuRshyKacf/1Er1JqEbtW3Mx9Fvr/u27qU2W8lQI6DaJhU2BfijPe/KHkib55mvHzIVvoexxya26nk79F2c+d9PnuuMdThWQO3El5a/i2AASnM7T7piIBT2WRZW2i8RbfJaTT7G7LP7OpMKIV1qyBg/cWoO7cIWQW4jmzqrNryIkF0AzStLN1DxvnQZwgXBGv0CwuAkfQuNSLu0PQgPp0PhdukNZFllv5D29IhPr0Z+kwPtrAgPQo+lHlOBHBMUpDT4XChTPeAvMaUSBsqmonAE8UUHEabWrqYN/kWNHCNkYXMkiVmK1AgMBAAGjggERMIIBDTAdBgNVHQ4EFgQU456ijsFrYnzHBShLAPpOUqQ+Z2cwgd0GA1UdIwSB1TCB0oAU456ijsFrYnzHBShLAPpOUqQ+Z2ehga6kgaswgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQDI1xaHqObkpTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCvga2HMwOtUxWH/inL2qk24KX2pxLg939JNhqoyNrUpbDHag5xPQYXUmUpKrNJZ0z+o/ZnNUPHydTSXE7Z7E45J0GDN5E7g4pakndKnDLSjp03NgGsCGW+cXnz6UBPM5FStFvGdDeModeSUyoS9fjk+mYROvmiy5EiVDP91sKGcPLR7Ym0M7zl2aaqV7bb98HmMoBOxpeZQinof67nKrCsgz/xjktWFgcmPl4/PQSsmqQD0fTtWxGuRX+FzwvF2OCMCAJgp1RqJNlk2g50/kBIoJVPPCfjDFeDU5zGaWGSQ9+z1L6/z7VXdjUiHL0ouOcHwbiS4ZjTr9nMn6WdAHU2"
|
||||||
PurevpnCertificate = "MIIEnzCCA4egAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBqDELMAkGA1UEBhMCSEsxEDAOBgNVBAgTB0NlbnRyYWwxCzAJBgNVBAcTAkhLMRgwFgYDVQQKEw9TZWN1cmUtU2VydmVyQ0ExCzAJBgNVBAsTAklUMRgwFgYDVQQDEw9TZWN1cmUtU2VydmVyQ0ExGDAWBgNVBCkTD1NlY3VyZS1TZXJ2ZXJDQTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRvbWFpbjAeFw0xNjAxMTUxNjE1MzhaFw0yNjAxMTIxNjE1MzhaMIGdMQswCQYDVQQGEwJISzEQMA4GA1UECBMHQ2VudHJhbDELMAkGA1UEBxMCSEsxFjAUBgNVBAoTDVNlY3VyZS1DbGllbnQxCzAJBgNVBAsTAklUMRYwFAYDVQQDEw1TZWN1cmUtQ2xpZW50MREwDwYDVQQpEwhjaGFuZ2VtZTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxsnyn4v6xxDPnuDaYS0b9M1N8nxgg7OBPBlK+FWRxdTQ8yxt5U5CZGm7riVp7fya2J2iPZIgmHQEv/KbxztsHAVlYSfYYlalrnhEL3bDP2tY+N43AwB1k5BrPq2s1pPLT2XG951drDKG4PUuFHUP1sHzW5oQlfVCmxgIMAP8OYkCAwEAAaOCAV8wggFbMAkGA1UdEwQCMAAwLQYJYIZIAYb4QgENBCAWHkVhc3ktUlNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU9MwUnUDbQKKZKjoeieD2OD5NlAEwgd0GA1UdIwSB1TCB0oAU456ijsFrYnzHBShLAPpOUqQ+Z2ehga6kgaswgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQDI1xaHqObkpTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADggEBAFyFo2VUX/UFixsdPdK9/Yt6mkCWc+XS1xbapGXXb9U1d+h1iBCIV9odUHgNCXWpz1hR5Uu/OCzaZ0asLE4IFMZlQmJs8sMT0c1tfPPGW45vxbL0lhqnQ8PNcBH7huNK7VFjUh4szXRKmaQPaM4S91R3L4CaNfVeHfAg7mN2m9Zn5Gto1Q1/CFMGKu2hxwGEw5p+X1czBWEvg/O09ckx/ggkkI1NcZsNiYQ+6Pz8DdGGX3+05YwLZu94+O6iIMrzxl/il0eK83g3YPbsOrASARvw6w/8sOnJCK5eOacl21oww875KisnYdWjHB1FiI+VzQ1/gyoDsL5kPTJVuu2CoG8="
|
PurevpnCertificate = "MIIEnzCCA4egAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBqDELMAkGA1UEBhMCSEsxEDAOBgNVBAgTB0NlbnRyYWwxCzAJBgNVBAcTAkhLMRgwFgYDVQQKEw9TZWN1cmUtU2VydmVyQ0ExCzAJBgNVBAsTAklUMRgwFgYDVQQDEw9TZWN1cmUtU2VydmVyQ0ExGDAWBgNVBCkTD1NlY3VyZS1TZXJ2ZXJDQTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRvbWFpbjAeFw0xNjAxMTUxNjE1MzhaFw0yNjAxMTIxNjE1MzhaMIGdMQswCQYDVQQGEwJISzEQMA4GA1UECBMHQ2VudHJhbDELMAkGA1UEBxMCSEsxFjAUBgNVBAoTDVNlY3VyZS1DbGllbnQxCzAJBgNVBAsTAklUMRYwFAYDVQQDEw1TZWN1cmUtQ2xpZW50MREwDwYDVQQpEwhjaGFuZ2VtZTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxsnyn4v6xxDPnuDaYS0b9M1N8nxgg7OBPBlK+FWRxdTQ8yxt5U5CZGm7riVp7fya2J2iPZIgmHQEv/KbxztsHAVlYSfYYlalrnhEL3bDP2tY+N43AwB1k5BrPq2s1pPLT2XG951drDKG4PUuFHUP1sHzW5oQlfVCmxgIMAP8OYkCAwEAAaOCAV8wggFbMAkGA1UdEwQCMAAwLQYJYIZIAYb4QgENBCAWHkVhc3ktUlNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU9MwUnUDbQKKZKjoeieD2OD5NlAEwgd0GA1UdIwSB1TCB0oAU456ijsFrYnzHBShLAPpOUqQ+Z2ehga6kgaswgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQDI1xaHqObkpTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADggEBAFyFo2VUX/UFixsdPdK9/Yt6mkCWc+XS1xbapGXXb9U1d+h1iBCIV9odUHgNCXWpz1hR5Uu/OCzaZ0asLE4IFMZlQmJs8sMT0c1tfPPGW45vxbL0lhqnQ8PNcBH7huNK7VFjUh4szXRKmaQPaM4S91R3L4CaNfVeHfAg7mN2m9Zn5Gto1Q1/CFMGKu2hxwGEw5p+X1czBWEvg/O09ckx/ggkkI1NcZsNiYQ+6Pz8DdGGX3+05YwLZu94+O6iIMrzxl/il0eK83g3YPbsOrASARvw6w/8sOnJCK5eOacl21oww875KisnYdWjHB1FiI+VzQ1/gyoDsL5kPTJVuu2CoG8="
|
||||||
@@ -40,6 +41,7 @@ func PurevpnCityChoices() (choices []string) {
|
|||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func PurevpnServers() []models.PurevpnServer {
|
func PurevpnServers() []models.PurevpnServer {
|
||||||
return []models.PurevpnServer{
|
return []models.PurevpnServer{
|
||||||
{Region: "Africa", Country: "Algeria", City: "Algiers", IPs: []net.IP{{172, 94, 64, 2}}},
|
{Region: "Africa", Country: "Algeria", City: "Algiers", IPs: []net.IP{{172, 94, 64, 2}}},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package constants
|
|||||||
import "github.com/qdm12/gluetun/internal/models"
|
import "github.com/qdm12/gluetun/internal/models"
|
||||||
|
|
||||||
func GetAllServers() (allServers models.AllServers) {
|
func GetAllServers() (allServers models.AllServers) {
|
||||||
|
//nolint:gomnd
|
||||||
return models.AllServers{
|
return models.AllServers{
|
||||||
Version: 1, // used for migration of the top level scheme
|
Version: 1, // used for migration of the top level scheme
|
||||||
Cyberghost: models.CyberghostServers{
|
Cyberghost: models.CyberghostServers{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5" //nolint:gosec
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -11,49 +11,164 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func digestServerModelVersion(t *testing.T, server interface{}, version uint16) string { //nolint:unparam
|
func digestServerModelVersion(t *testing.T, server interface{}, version uint16) string {
|
||||||
bytes, err := json.Marshal(server)
|
bytes, err := json.Marshal(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
bytes = append(bytes, []byte(fmt.Sprintf("%d", version))...)
|
bytes = append(bytes, []byte(fmt.Sprintf("%d", version))...)
|
||||||
arr := md5.Sum(bytes) //nolint:gosec
|
arr := sha256.Sum256(bytes)
|
||||||
return base64.RawStdEncoding.EncodeToString(arr[:])
|
hexString := hex.EncodeToString(arr[:])
|
||||||
|
if len(hexString) > 8 {
|
||||||
|
hexString = hexString[:8]
|
||||||
|
}
|
||||||
|
return hexString
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_versions(t *testing.T) {
|
func Test_versions(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
allServers := GetAllServers()
|
allServers := GetAllServers()
|
||||||
assert.Equal(t, "e8eLGRpb1sNX8mDNPOjA6g", digestServerModelVersion(t, models.CyberghostServer{}, allServers.Cyberghost.Version))
|
const format = "you forgot to update the version for %s"
|
||||||
assert.Equal(t, "4yL2lFcxXd/l1ByxBQ7d3g", digestServerModelVersion(t, models.MullvadServer{}, allServers.Mullvad.Version))
|
testCases := map[string]struct {
|
||||||
assert.Equal(t, "fjzfUqJH0KvetGRdZYEtOg", digestServerModelVersion(t, models.NordvpnServer{}, allServers.Nordvpn.Version))
|
model interface{}
|
||||||
assert.Equal(t, "1Ux7clCAJI6fwj0O61Dtpg", digestServerModelVersion(t, models.PIAServer{}, allServers.Pia.Version))
|
version uint16
|
||||||
assert.Equal(t, "EZ/SBXQOCS/iJU7A9yc7vg", digestServerModelVersion(t, models.PurevpnServer{}, allServers.Purevpn.Version))
|
digest string
|
||||||
assert.Equal(t, "7yfMpHwzRpEngA/6nYsNag", digestServerModelVersion(t, models.SurfsharkServer{}, allServers.Surfshark.Version))
|
}{
|
||||||
assert.Equal(t, "7yfMpHwzRpEngA/6nYsNag", digestServerModelVersion(t, models.VyprvpnServer{}, allServers.Vyprvpn.Version))
|
"Cyberghost": {
|
||||||
assert.Equal(t, "7yfMpHwzRpEngA/6nYsNag", digestServerModelVersion(t, models.WindscribeServer{}, allServers.Windscribe.Version))
|
model: models.CyberghostServer{},
|
||||||
|
version: allServers.Cyberghost.Version,
|
||||||
|
digest: "fd6242bb",
|
||||||
|
},
|
||||||
|
"Mullvad": {
|
||||||
|
model: models.MullvadServer{},
|
||||||
|
version: allServers.Mullvad.Version,
|
||||||
|
digest: "665e9dc1",
|
||||||
|
},
|
||||||
|
"Nordvpn": {
|
||||||
|
model: models.NordvpnServer{},
|
||||||
|
version: allServers.Nordvpn.Version,
|
||||||
|
digest: "040de8d0",
|
||||||
|
},
|
||||||
|
"Private Internet Access": {
|
||||||
|
model: models.PIAServer{},
|
||||||
|
version: allServers.Pia.Version,
|
||||||
|
digest: "f1e01afe",
|
||||||
|
},
|
||||||
|
"Private Internet Access Old": {
|
||||||
|
model: models.PIAOldServer{},
|
||||||
|
version: allServers.PiaOld.Version,
|
||||||
|
digest: "4e25ce4a",
|
||||||
|
},
|
||||||
|
"Purevpn": {
|
||||||
|
model: models.PurevpnServer{},
|
||||||
|
version: allServers.Purevpn.Version,
|
||||||
|
digest: "cc1a2219",
|
||||||
|
},
|
||||||
|
"Surfshark": {
|
||||||
|
model: models.SurfsharkServer{},
|
||||||
|
version: allServers.Surfshark.Version,
|
||||||
|
digest: "042bef64",
|
||||||
|
},
|
||||||
|
"Vyprvpn": {
|
||||||
|
model: models.VyprvpnServer{},
|
||||||
|
version: allServers.Vyprvpn.Version,
|
||||||
|
digest: "042bef64",
|
||||||
|
},
|
||||||
|
"Windscribe": {
|
||||||
|
model: models.WindscribeServer{},
|
||||||
|
version: allServers.Windscribe.Version,
|
||||||
|
digest: "042bef64",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
name := name
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
digest := digestServerModelVersion(t, testCase.model, testCase.version)
|
||||||
|
failureMessage := fmt.Sprintf(format, name)
|
||||||
|
assert.Equal(t, testCase.digest, digest, failureMessage)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func digestServersTimestamp(t *testing.T, servers interface{}, timestamp int64) string { //nolint:unparam
|
func digestServersTimestamp(t *testing.T, servers interface{}, timestamp int64) string {
|
||||||
bytes, err := json.Marshal(servers)
|
bytes, err := json.Marshal(servers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
bytes = append(bytes, []byte(fmt.Sprintf("%d", timestamp))...)
|
bytes = append(bytes, []byte(fmt.Sprintf("%d", timestamp))...)
|
||||||
arr := md5.Sum(bytes) //nolint:gosec
|
arr := sha256.Sum256(bytes)
|
||||||
return base64.RawStdEncoding.EncodeToString(arr[:])
|
hexString := hex.EncodeToString(arr[:])
|
||||||
|
if len(hexString) > 8 {
|
||||||
|
hexString = hexString[:8]
|
||||||
|
}
|
||||||
|
return hexString
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_timestamps(t *testing.T) {
|
func Test_timestamps(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
allServers := GetAllServers()
|
allServers := GetAllServers()
|
||||||
assert.Equal(t, "EFMpdq2b9COLevjXmje5zg", digestServersTimestamp(t, allServers.Cyberghost.Servers, allServers.Cyberghost.Timestamp))
|
const format = "you forgot to update the timestamp for %s"
|
||||||
assert.Equal(t, "EU4fTzD7jWC9N5kmN5bOEg", digestServersTimestamp(t, allServers.Mullvad.Servers, allServers.Mullvad.Timestamp))
|
testCases := map[string]struct {
|
||||||
assert.Equal(t, "OLI62FoTf2wis25Nw4FLpg", digestServersTimestamp(t, allServers.Nordvpn.Servers, allServers.Nordvpn.Timestamp))
|
servers interface{}
|
||||||
assert.Equal(t, "beZCOXNWxzrPsUWCyQM99A", digestServersTimestamp(t, allServers.Pia.Servers, allServers.Pia.Timestamp))
|
timestamp int64
|
||||||
assert.Equal(t, "e8mWsWynkSUGiJLvjALRvQ", digestServersTimestamp(t, allServers.PiaOld.Servers, allServers.PiaOld.Timestamp))
|
digest string
|
||||||
assert.Equal(t, "kwJdVWTiBOspfrRwZIA+Sg", digestServersTimestamp(t, allServers.Purevpn.Servers, allServers.Purevpn.Timestamp))
|
}{
|
||||||
assert.Equal(t, "q28ju2KJqLhrggJTTjXSiw", digestServersTimestamp(t, allServers.Surfshark.Servers, allServers.Surfshark.Timestamp))
|
"Cyberghost": {
|
||||||
assert.Equal(t, "KdIQWi2tYUM4aMXvWfVBEg", digestServersTimestamp(t, allServers.Vyprvpn.Servers, allServers.Vyprvpn.Timestamp))
|
servers: allServers.Cyberghost.Servers,
|
||||||
assert.Equal(t, "faQUVtOnLMVezN0giHSz3Q", digestServersTimestamp(t, allServers.Windscribe.Servers, allServers.Windscribe.Timestamp))
|
timestamp: allServers.Cyberghost.Timestamp,
|
||||||
|
digest: "160631de",
|
||||||
|
},
|
||||||
|
"Mullvad": {
|
||||||
|
servers: allServers.Mullvad.Servers,
|
||||||
|
timestamp: allServers.Mullvad.Timestamp,
|
||||||
|
digest: "e1fee56f",
|
||||||
|
},
|
||||||
|
"Nordvpn": {
|
||||||
|
servers: allServers.Nordvpn.Servers,
|
||||||
|
timestamp: allServers.Nordvpn.Timestamp,
|
||||||
|
digest: "9fc9a579",
|
||||||
|
},
|
||||||
|
"Private Internet Access": {
|
||||||
|
servers: allServers.Pia.Servers,
|
||||||
|
timestamp: allServers.Pia.Timestamp,
|
||||||
|
digest: "1571e777",
|
||||||
|
},
|
||||||
|
"Private Internet Access Old": {
|
||||||
|
servers: allServers.PiaOld.Servers,
|
||||||
|
timestamp: allServers.PiaOld.Timestamp,
|
||||||
|
digest: "3566a800",
|
||||||
|
},
|
||||||
|
"Purevpn": {
|
||||||
|
servers: allServers.Purevpn.Servers,
|
||||||
|
timestamp: allServers.Purevpn.Timestamp,
|
||||||
|
digest: "cdf9b708",
|
||||||
|
},
|
||||||
|
"Surfshark": {
|
||||||
|
servers: allServers.Surfshark.Servers,
|
||||||
|
timestamp: allServers.Surfshark.Timestamp,
|
||||||
|
digest: "79484811",
|
||||||
|
},
|
||||||
|
"Vyprvpn": {
|
||||||
|
servers: allServers.Vyprvpn.Servers,
|
||||||
|
timestamp: allServers.Vyprvpn.Timestamp,
|
||||||
|
digest: "1992457c",
|
||||||
|
},
|
||||||
|
"Windscribe": {
|
||||||
|
servers: allServers.Windscribe.Servers,
|
||||||
|
timestamp: allServers.Windscribe.Timestamp,
|
||||||
|
digest: "eacad593",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
name := name
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
digest := digestServersTimestamp(t, testCase.servers, testCase.timestamp)
|
||||||
|
failureMessage := fmt.Sprintf(format, name)
|
||||||
|
assert.Equal(t, testCase.digest, digest, failureMessage)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Announcement is a message announcement
|
// Announcement is a message announcement.
|
||||||
Announcement = "Port forwarding is working for PIA v4 servers"
|
Announcement = "Port forwarding is working for PIA v4 servers"
|
||||||
// AnnouncementExpiration is the expiration date of the announcement in format yyyy-mm-dd
|
// AnnouncementExpiration is the expiration date of the announcement in format yyyy-mm-dd.
|
||||||
AnnouncementExpiration = "2020-11-15"
|
AnnouncementExpiration = "2020-11-15"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// IssueLink is the link for users to use to create issues
|
// IssueLink is the link for users to use to create issues.
|
||||||
IssueLink = "https://github.com/qdm12/gluetun/issues/new"
|
IssueLink = "https://github.com/qdm12/gluetun/issues/new"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
SurfsharkCertificate = "MIIFTTCCAzWgAwIBAgIJAMs9S3fqwv+mMA0GCSqGSIb3DQEBCwUAMD0xCzAJBgNVBAYTAlZHMRIwEAYDVQQKDAlTdXJmc2hhcmsxGjAYBgNVBAMMEVN1cmZzaGFyayBSb290IENBMB4XDTE4MDMxNDA4NTkyM1oXDTI4MDMxMTA4NTkyM1owPTELMAkGA1UEBhMCVkcxEjAQBgNVBAoMCVN1cmZzaGFyazEaMBgGA1UEAwwRU3VyZnNoYXJrIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDEGMNj0aisM63oSkmVJyZPaYX7aPsZtzsxo6m6p5Wta3MGASoryRsBuRaH6VVa0fwbI1nw5ubyxkuaNa4v3zHVwuSq6F1p8S811+1YP1av+jqDcMyojH0ujZSHIcb/i5LtaHNXBQ3qN48Cc7sqBnTIIFpmb5HthQ/4pW+a82b1guM5dZHsh7q+LKQDIGmvtMtO1+NEnmj81BApFayiaD1ggvwDI4x7o/Y3ksfWSCHnqXGyqzSFLh8QuQrTmWUm84YHGFxoI1/8AKdIyVoB6BjcaMKtKs/pbctk6vkzmYf0XmGovDKPQF6MwUekchLjB5gSBNnptSQ9kNgnTLqi0OpSwI6ixX52Ksva6UM8P01ZIhWZ6ua/T/tArgODy5JZMW+pQ1A6L0b7egIeghpwKnPRG+5CzgO0J5UE6gv000mqbmC3CbiS8xi2xuNgruAyY2hUOoV9/BuBev8ttE5ZCsJH3YlG6NtbZ9hPc61GiBSx8NJnX5QHyCnfic/X87eST/amZsZCAOJ5v4EPSaKrItt+HrEFWZQIq4fJmHJNNbYvWzCE08AL+5/6Z+lxb/Bm3dapx2zdit3x2e+miGHekuiE8lQWD0rXD4+T+nDRi3X+kyt8Ex/8qRiUfrisrSHFzVMRungIMGdO9O/zCINFrb7wahm4PqU2f12Z9TRCOTXciQIDAQABo1AwTjAdBgNVHQ4EFgQUYRpbQwyDahLMN3F2ony3+UqOYOgwHwYDVR0jBBgwFoAUYRpbQwyDahLMN3F2ony3+UqOYOgwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAn9zV7F/XVnFNZhHFrt0ZS1Yqz+qM9CojLmiyblMFh0p7t+Hh+VKVgMwrz0LwDH4UsOosXA28eJPmech6/bjfymkoXISy/NUSTFpUChGO9RabGGxJsT4dugOw9MPaIVZffny4qYOc/rXDXDSfF2b+303lLPI43y9qoe0oyZ1vtk/UKG75FkWfFUogGNbpOkuz+et5Y0aIEiyg0yh6/l5Q5h8+yom0HZnREHhqieGbkaGKLkyu7zQ4D4tRK/mBhd8nv+09GtPEG+D5LPbabFVxKjBMP4Vp24WuSUOqcGSsURHevawPVBfgmsxf1UCjelaIwngdh6WfNCRXa5QQPQTKubQvkvXONCDdhmdXQccnRX1nJWhPYi0onffvjsWUfztRypsKzX4dvM9k7xnIcGSGEnCC4RCgt1UiZIj7frcCMssbA6vJ9naM0s7JF7N3VKeHJtqe1OCRHMYnWUZt9vrqX6IoIHlZCoLlv39wFW9QNxelcAOCVbD+19MZ0ZXt7LitjIqe7yF5WxDQN4xru087FzQ4Hfj7eH1SNLLyKZkA1eecjmRoi/OoqAt7afSnwtQLtMUc2bQDg6rHt5C0e4dCLqP/9PGZTSJiwmtRHJ/N5qYWIh9ju83APvLm/AGBTR2pXmj9G3KdVOkpIC7L35dI623cSEC3Q3UZutsEm/UplsM="
|
SurfsharkCertificate = "MIIFTTCCAzWgAwIBAgIJAMs9S3fqwv+mMA0GCSqGSIb3DQEBCwUAMD0xCzAJBgNVBAYTAlZHMRIwEAYDVQQKDAlTdXJmc2hhcmsxGjAYBgNVBAMMEVN1cmZzaGFyayBSb290IENBMB4XDTE4MDMxNDA4NTkyM1oXDTI4MDMxMTA4NTkyM1owPTELMAkGA1UEBhMCVkcxEjAQBgNVBAoMCVN1cmZzaGFyazEaMBgGA1UEAwwRU3VyZnNoYXJrIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDEGMNj0aisM63oSkmVJyZPaYX7aPsZtzsxo6m6p5Wta3MGASoryRsBuRaH6VVa0fwbI1nw5ubyxkuaNa4v3zHVwuSq6F1p8S811+1YP1av+jqDcMyojH0ujZSHIcb/i5LtaHNXBQ3qN48Cc7sqBnTIIFpmb5HthQ/4pW+a82b1guM5dZHsh7q+LKQDIGmvtMtO1+NEnmj81BApFayiaD1ggvwDI4x7o/Y3ksfWSCHnqXGyqzSFLh8QuQrTmWUm84YHGFxoI1/8AKdIyVoB6BjcaMKtKs/pbctk6vkzmYf0XmGovDKPQF6MwUekchLjB5gSBNnptSQ9kNgnTLqi0OpSwI6ixX52Ksva6UM8P01ZIhWZ6ua/T/tArgODy5JZMW+pQ1A6L0b7egIeghpwKnPRG+5CzgO0J5UE6gv000mqbmC3CbiS8xi2xuNgruAyY2hUOoV9/BuBev8ttE5ZCsJH3YlG6NtbZ9hPc61GiBSx8NJnX5QHyCnfic/X87eST/amZsZCAOJ5v4EPSaKrItt+HrEFWZQIq4fJmHJNNbYvWzCE08AL+5/6Z+lxb/Bm3dapx2zdit3x2e+miGHekuiE8lQWD0rXD4+T+nDRi3X+kyt8Ex/8qRiUfrisrSHFzVMRungIMGdO9O/zCINFrb7wahm4PqU2f12Z9TRCOTXciQIDAQABo1AwTjAdBgNVHQ4EFgQUYRpbQwyDahLMN3F2ony3+UqOYOgwHwYDVR0jBBgwFoAUYRpbQwyDahLMN3F2ony3+UqOYOgwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAn9zV7F/XVnFNZhHFrt0ZS1Yqz+qM9CojLmiyblMFh0p7t+Hh+VKVgMwrz0LwDH4UsOosXA28eJPmech6/bjfymkoXISy/NUSTFpUChGO9RabGGxJsT4dugOw9MPaIVZffny4qYOc/rXDXDSfF2b+303lLPI43y9qoe0oyZ1vtk/UKG75FkWfFUogGNbpOkuz+et5Y0aIEiyg0yh6/l5Q5h8+yom0HZnREHhqieGbkaGKLkyu7zQ4D4tRK/mBhd8nv+09GtPEG+D5LPbabFVxKjBMP4Vp24WuSUOqcGSsURHevawPVBfgmsxf1UCjelaIwngdh6WfNCRXa5QQPQTKubQvkvXONCDdhmdXQccnRX1nJWhPYi0onffvjsWUfztRypsKzX4dvM9k7xnIcGSGEnCC4RCgt1UiZIj7frcCMssbA6vJ9naM0s7JF7N3VKeHJtqe1OCRHMYnWUZt9vrqX6IoIHlZCoLlv39wFW9QNxelcAOCVbD+19MZ0ZXt7LitjIqe7yF5WxDQN4xru087FzQ4Hfj7eH1SNLLyKZkA1eecjmRoi/OoqAt7afSnwtQLtMUc2bQDg6rHt5C0e4dCLqP/9PGZTSJiwmtRHJ/N5qYWIh9ju83APvLm/AGBTR2pXmj9G3KdVOkpIC7L35dI623cSEC3Q3UZutsEm/UplsM="
|
||||||
SurfsharkOpenvpnStaticKeyV1 = "b02cb1d7c6fee5d4f89b8de72b51a8d0c7b282631d6fc19be1df6ebae9e2779e6d9f097058a31c97f57f0c35526a44ae09a01d1284b50b954d9246725a1ead1ff224a102ed9ab3da0152a15525643b2eee226c37041dc55539d475183b889a10e18bb94f079a4a49888da566b99783460ece01daaf93548beea6c827d9674897e7279ff1a19cb092659e8c1860fbad0db4ad0ad5732f1af4655dbd66214e552f04ed8fd0104e1d4bf99c249ac229ce169d9ba22068c6c0ab742424760911d4636aafb4b85f0c952a9ce4275bc821391aa65fcd0d2394f006e3fba0fd34c4bc4ab260f4b45dec3285875589c97d3087c9134d3a3aa2f904512e85aa2dc2202498"
|
SurfsharkOpenvpnStaticKeyV1 = "b02cb1d7c6fee5d4f89b8de72b51a8d0c7b282631d6fc19be1df6ebae9e2779e6d9f097058a31c97f57f0c35526a44ae09a01d1284b50b954d9246725a1ead1ff224a102ed9ab3da0152a15525643b2eee226c37041dc55539d475183b889a10e18bb94f079a4a49888da566b99783460ece01daaf93548beea6c827d9674897e7279ff1a19cb092659e8c1860fbad0db4ad0ad5732f1af4655dbd66214e552f04ed8fd0104e1d4bf99c249ac229ce169d9ba22068c6c0ab742424760911d4636aafb4b85f0c952a9ce4275bc821391aa65fcd0d2394f006e3fba0fd34c4bc4ab260f4b45dec3285875589c97d3087c9134d3a3aa2f904512e85aa2dc2202498"
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TinyProxyInfoLevel is the info log level for TinyProxy
|
// TinyProxyInfoLevel is the info log level for TinyProxy.
|
||||||
TinyProxyInfoLevel models.TinyProxyLogLevel = "Info"
|
TinyProxyInfoLevel models.TinyProxyLogLevel = "Info"
|
||||||
// TinyProxyConnectLevel is the info log level for TinyProxy
|
// TinyProxyConnectLevel is the info log level for TinyProxy.
|
||||||
TinyProxyConnectLevel models.TinyProxyLogLevel = "Connect"
|
TinyProxyConnectLevel models.TinyProxyLogLevel = "Connect"
|
||||||
// TinyProxyNoticeLevel is the info log level for TinyProxy
|
// TinyProxyNoticeLevel is the info log level for TinyProxy.
|
||||||
TinyProxyNoticeLevel models.TinyProxyLogLevel = "Notice"
|
TinyProxyNoticeLevel models.TinyProxyLogLevel = "Notice"
|
||||||
// TinyProxyWarnLevel is the warning log level for TinyProxy
|
// TinyProxyWarnLevel is the warning log level for TinyProxy.
|
||||||
TinyProxyWarnLevel models.TinyProxyLogLevel = "Warning"
|
TinyProxyWarnLevel models.TinyProxyLogLevel = "Warning"
|
||||||
// TinyProxyErrorLevel is the error log level for TinyProxy
|
// TinyProxyErrorLevel is the error log level for TinyProxy.
|
||||||
TinyProxyErrorLevel models.TinyProxyLogLevel = "Error"
|
TinyProxyErrorLevel models.TinyProxyLogLevel = "Error"
|
||||||
// TinyProxyCriticalLevel is the critical log level for TinyProxy
|
// TinyProxyCriticalLevel is the critical log level for TinyProxy.
|
||||||
TinyProxyCriticalLevel models.TinyProxyLogLevel = "Critical"
|
TinyProxyCriticalLevel models.TinyProxyLogLevel = "Critical"
|
||||||
)
|
)
|
||||||
|
|||||||
+11
-11
@@ -5,29 +5,29 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PrivateInternetAccess is a VPN provider
|
// PrivateInternetAccess is a VPN provider.
|
||||||
PrivateInternetAccess models.VPNProvider = "private internet access"
|
PrivateInternetAccess models.VPNProvider = "private internet access"
|
||||||
// PrivateInternetAccessOld is the pre summer 2020 PIA provider
|
// PrivateInternetAccessOld is the pre summer 2020 PIA provider.
|
||||||
PrivateInternetAccessOld models.VPNProvider = "private internet access old"
|
PrivateInternetAccessOld models.VPNProvider = "private internet access old"
|
||||||
// Mullvad is a VPN provider
|
// Mullvad is a VPN provider.
|
||||||
Mullvad models.VPNProvider = "mullvad"
|
Mullvad models.VPNProvider = "mullvad"
|
||||||
// Windscribe is a VPN provider
|
// Windscribe is a VPN provider.
|
||||||
Windscribe models.VPNProvider = "windscribe"
|
Windscribe models.VPNProvider = "windscribe"
|
||||||
// Surfshark is a VPN provider
|
// Surfshark is a VPN provider.
|
||||||
Surfshark models.VPNProvider = "surfshark"
|
Surfshark models.VPNProvider = "surfshark"
|
||||||
// Cyberghost is a VPN provider
|
// Cyberghost is a VPN provider.
|
||||||
Cyberghost models.VPNProvider = "cyberghost"
|
Cyberghost models.VPNProvider = "cyberghost"
|
||||||
// Vyprvpn is a VPN provider
|
// Vyprvpn is a VPN provider.
|
||||||
Vyprvpn models.VPNProvider = "vyprvpn"
|
Vyprvpn models.VPNProvider = "vyprvpn"
|
||||||
// NordVPN is a VPN provider
|
// NordVPN is a VPN provider.
|
||||||
Nordvpn models.VPNProvider = "nordvpn"
|
Nordvpn models.VPNProvider = "nordvpn"
|
||||||
// PureVPN is a VPN provider
|
// PureVPN is a VPN provider.
|
||||||
Purevpn models.VPNProvider = "purevpn"
|
Purevpn models.VPNProvider = "purevpn"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TCP is a network protocol (reliable and slower than UDP)
|
// TCP is a network protocol (reliable and slower than UDP).
|
||||||
TCP models.NetworkProtocol = "tcp"
|
TCP models.NetworkProtocol = "tcp"
|
||||||
// UDP is a network protocol (unreliable and faster than TCP)
|
// UDP is a network protocol (unreliable and faster than TCP).
|
||||||
UDP models.NetworkProtocol = "udp"
|
UDP models.NetworkProtocol = "udp"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
VyprvpnCertificate = "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"
|
VyprvpnCertificate = "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"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
WindscribeCertificate = "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"
|
WindscribeCertificate = "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"
|
||||||
WindscribeOpenvpnStaticKeyV1 = "5801926a57ac2ce27e3dfd1dd6ef82042d82bd4f3f0021296f57734f6f1ea714a6623845541c4b0c3dea0a050fe6746cb66dfab14cda27e5ae09d7c155aa554f399fa4a863f0e8c1af787e5c602a801d3a2ec41e395a978d56729457fe6102d7d9e9119aa83643210b33c678f9d4109e3154ac9c759e490cb309b319cf708cae83ddadc3060a7a26564d1a24411cd552fe6620ea16b755697a4fc5e6e9d0cfc0c5c4a1874685429046a424c026db672e4c2c492898052ba59128d46200b40f880027a8b6610a4d559bdc9346d33a0a6b08e75c7fd43192b162bfd0aef0c716b31584827693f676f9a5047123466f0654eade34972586b31c6ce7e395f4b478cb"
|
WindscribeOpenvpnStaticKeyV1 = "5801926a57ac2ce27e3dfd1dd6ef82042d82bd4f3f0021296f57734f6f1ea714a6623845541c4b0c3dea0a050fe6746cb66dfab14cda27e5ae09d7c155aa554f399fa4a863f0e8c1af787e5c602a801d3a2ec41e395a978d56729457fe6102d7d9e9119aa83643210b33c678f9d4109e3154ac9c759e490cb309b319cf708cae83ddadc3060a7a26564d1a24411cd552fe6620ea16b755697a4fc5e6e9d0cfc0c5c4a1874685429046a424c026db672e4c2c492898052ba59128d46200b40f880027a8b6610a4d559bdc9346d33a0a6b08e75c7fd43192b162bfd0aef0c716b31584827693f676f9a5047123466f0654eade34972586b31c6ce7e395f4b478cb"
|
||||||
@@ -20,7 +21,7 @@ func WindscribeRegionChoices() (choices []string) {
|
|||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:dupl
|
//nolint:lll
|
||||||
func WindscribeServers() []models.WindscribeServer {
|
func WindscribeServers() []models.WindscribeServer {
|
||||||
return []models.WindscribeServer{
|
return []models.WindscribeServer{
|
||||||
{Region: "Albania", IPs: []net.IP{{31, 171, 152, 179}}},
|
{Region: "Albania", IPs: []net.IP{{31, 171, 152, 179}}},
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *configurator) Start(ctx context.Context, verbosityDetailsLevel uint8) (stdout io.ReadCloser, waitFn func() error, err error) {
|
func (c *configurator) Start(ctx context.Context, verbosityDetailsLevel uint8) (
|
||||||
|
stdout io.ReadCloser, waitFn func() error, err error) {
|
||||||
c.logger.Info("starting unbound")
|
c.logger.Info("starting unbound")
|
||||||
args := []string{"-d", "-c", string(constants.UnboundConf)}
|
args := []string{"-d", "-c", string(constants.UnboundConf)}
|
||||||
if verbosityDetailsLevel > 0 {
|
if verbosityDetailsLevel > 0 {
|
||||||
@@ -28,7 +29,8 @@ func (c *configurator) Version(ctx context.Context) (version string, err error)
|
|||||||
for _, line := range strings.Split(output, "\n") {
|
for _, line := range strings.Split(output, "\n") {
|
||||||
if strings.Contains(line, "Version ") {
|
if strings.Contains(line, "Version ") {
|
||||||
words := strings.Fields(line)
|
words := strings.Fields(line)
|
||||||
if len(words) < 2 {
|
const minWords = 2
|
||||||
|
if len(words) < minWords {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
version = words[1]
|
version = words[1]
|
||||||
|
|||||||
@@ -6,12 +6,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/golibs/command/mock_command"
|
"github.com/qdm12/golibs/command/mock_command"
|
||||||
"github.com/qdm12/golibs/logging/mock_logging"
|
"github.com/qdm12/golibs/logging/mock_logging"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Start(t *testing.T) {
|
func Test_Start(t *testing.T) {
|
||||||
|
|||||||
@@ -24,11 +24,13 @@ func (c *configurator) MakeUnboundConf(ctx context.Context, settings settings.DN
|
|||||||
string(constants.UnboundConf),
|
string(constants.UnboundConf),
|
||||||
lines,
|
lines,
|
||||||
files.Ownership(uid, gid),
|
files.Ownership(uid, gid),
|
||||||
files.Permissions(0400))
|
files.Permissions(constants.UserReadPermission))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeUnboundConf generates an Unbound configuration from the user provided settings
|
// MakeUnboundConf generates an Unbound configuration from the user provided settings.
|
||||||
func generateUnboundConf(ctx context.Context, settings settings.DNS, client network.Client, logger logging.Logger) (lines []string, warnings []error) {
|
func generateUnboundConf(ctx context.Context, settings settings.DNS,
|
||||||
|
client network.Client, logger logging.Logger) (
|
||||||
|
lines []string, warnings []error) {
|
||||||
doIPv6 := "no"
|
doIPv6 := "no"
|
||||||
if settings.IPv6 {
|
if settings.IPv6 {
|
||||||
doIPv6 = "yes"
|
doIPv6 = "yes"
|
||||||
|
|||||||
@@ -92,9 +92,15 @@ func (l *looper) setEnabled(enabled bool) {
|
|||||||
func (l *looper) logAndWait(ctx context.Context, err error) {
|
func (l *looper) logAndWait(ctx context.Context, err error) {
|
||||||
l.logger.Warn(err)
|
l.logger.Warn(err)
|
||||||
l.logger.Info("attempting restart in 10 seconds")
|
l.logger.Info("attempting restart in 10 seconds")
|
||||||
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
const waitDuration = 10 * time.Second
|
||||||
defer cancel()
|
timer := time.NewTimer(waitDuration)
|
||||||
<-ctx.Done()
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
case <-ctx.Done():
|
||||||
|
if !timer.Stop() {
|
||||||
|
<-timer.C
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) waitForFirstStart(ctx context.Context, signalDNSReady func()) {
|
func (l *looper) waitForFirstStart(ctx context.Context, signalDNSReady func()) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UseDNSInternally is to change the Go program DNS only
|
// UseDNSInternally is to change the Go program DNS only.
|
||||||
func (c *configurator) UseDNSInternally(ip net.IP) {
|
func (c *configurator) UseDNSInternally(ip net.IP) {
|
||||||
c.logger.Info("using DNS address %s internally", ip.String())
|
c.logger.Info("using DNS address %s internally", ip.String())
|
||||||
net.DefaultResolver = &net.Resolver{
|
net.DefaultResolver = &net.Resolver{
|
||||||
@@ -20,7 +20,7 @@ func (c *configurator) UseDNSInternally(ip net.IP) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseDNSSystemWide changes the nameserver to use for DNS system wide
|
// UseDNSSystemWide changes the nameserver to use for DNS system wide.
|
||||||
func (c *configurator) UseDNSSystemWide(ip net.IP, keepNameserver bool) error {
|
func (c *configurator) UseDNSSystemWide(ip net.IP, keepNameserver bool) error {
|
||||||
c.logger.Info("using DNS address %s system wide", ip.String())
|
c.logger.Info("using DNS address %s system wide", ip.String())
|
||||||
data, err := c.fileManager.ReadFile(string(constants.ResolvConf))
|
data, err := c.fileManager.ReadFile(string(constants.ResolvConf))
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (c *configurator) DownloadRootHints(ctx context.Context, uid, gid int) erro
|
|||||||
string(constants.RootHints),
|
string(constants.RootHints),
|
||||||
content,
|
content,
|
||||||
files.Ownership(uid, gid),
|
files.Ownership(uid, gid),
|
||||||
files.Permissions(0400))
|
files.Permissions(constants.UserReadPermission))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurator) DownloadRootKey(ctx context.Context, uid, gid int) error {
|
func (c *configurator) DownloadRootKey(ctx context.Context, uid, gid int) error {
|
||||||
@@ -36,5 +36,5 @@ func (c *configurator) DownloadRootKey(ctx context.Context, uid, gid int) error
|
|||||||
string(constants.RootKey),
|
string(constants.RootKey),
|
||||||
content,
|
content,
|
||||||
files.Ownership(uid, gid),
|
files.Ownership(uid, gid),
|
||||||
files.Permissions(0400))
|
files.Permissions(constants.UserReadPermission))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/golibs/files"
|
"github.com/qdm12/golibs/files"
|
||||||
"github.com/qdm12/golibs/files/mock_files"
|
"github.com/qdm12/golibs/files/mock_files"
|
||||||
"github.com/qdm12/golibs/logging/mock_logging"
|
"github.com/qdm12/golibs/logging/mock_logging"
|
||||||
"github.com/qdm12/golibs/network/mock_network"
|
"github.com/qdm12/golibs/network/mock_network"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_DownloadRootHints(t *testing.T) { //nolint:dupl
|
func Test_DownloadRootHints(t *testing.T) { //nolint:dupl
|
||||||
@@ -31,7 +30,7 @@ func Test_DownloadRootHints(t *testing.T) { //nolint:dupl
|
|||||||
},
|
},
|
||||||
"bad status": {
|
"bad status": {
|
||||||
status: http.StatusBadRequest,
|
status: http.StatusBadRequest,
|
||||||
err: fmt.Errorf("HTTP status code is 400 for https://raw.githubusercontent.com/qdm12/files/master/named.root.updated"),
|
err: fmt.Errorf("HTTP status code is 400 for https://raw.githubusercontent.com/qdm12/files/master/named.root.updated"), //nolint:lll
|
||||||
},
|
},
|
||||||
"client error": {
|
"client error": {
|
||||||
clientErr: fmt.Errorf("error"),
|
clientErr: fmt.Errorf("error"),
|
||||||
@@ -94,7 +93,7 @@ func Test_DownloadRootKey(t *testing.T) { //nolint:dupl
|
|||||||
},
|
},
|
||||||
"bad status": {
|
"bad status": {
|
||||||
status: http.StatusBadRequest,
|
status: http.StatusBadRequest,
|
||||||
err: fmt.Errorf("HTTP status code is 400 for https://raw.githubusercontent.com/qdm12/files/master/root.key.updated"),
|
err: fmt.Errorf("HTTP status code is 400 for https://raw.githubusercontent.com/qdm12/files/master/root.key.updated"), //nolint:lll
|
||||||
},
|
},
|
||||||
"client error": {
|
"client error": {
|
||||||
clientErr: fmt.Errorf("error"),
|
clientErr: fmt.Errorf("error"),
|
||||||
|
|||||||
+12
-5
@@ -6,16 +6,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *configurator) WaitForUnbound() (err error) {
|
func (c *configurator) WaitForUnbound() (err error) {
|
||||||
const maxTries = 10
|
|
||||||
const hostToResolve = "github.com"
|
const hostToResolve = "github.com"
|
||||||
time.Sleep(300 * time.Millisecond)
|
waitDurations := [...]time.Duration{
|
||||||
for try := 1; try <= maxTries; try++ {
|
300 * time.Millisecond,
|
||||||
|
100 * time.Millisecond,
|
||||||
|
300 * time.Millisecond,
|
||||||
|
500 * time.Millisecond,
|
||||||
|
time.Second,
|
||||||
|
2 * time.Second,
|
||||||
|
}
|
||||||
|
maxTries := len(waitDurations)
|
||||||
|
for i, waitDuration := range waitDurations {
|
||||||
|
time.Sleep(waitDuration)
|
||||||
_, err := c.lookupIP(hostToResolve)
|
_, err := c.lookupIP(hostToResolve)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.logger.Warn("could not resolve %s (try %d of %d): %s", hostToResolve, try, maxTries, err)
|
c.logger.Warn("could not resolve %s (try %d of %d): %s", hostToResolve, i+1, maxTries, err)
|
||||||
time.Sleep(maxTries * 50 * time.Millisecond)
|
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Unbound does not seem to be working after %d tries", maxTries)
|
return fmt.Errorf("Unbound does not seem to be working after %d tries", maxTries)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func (c *configurator) disable(ctx context.Context) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// To use in defered call when enabling the firewall
|
// To use in defered call when enabling the firewall.
|
||||||
func (c *configurator) fallbackToDisabled(ctx context.Context) {
|
func (c *configurator) fallbackToDisabled(ctx context.Context) {
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
@@ -61,7 +61,7 @@ func (c *configurator) fallbackToDisabled(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurator) enable(ctx context.Context) (err error) { //nolint:gocognit
|
func (c *configurator) enable(ctx context.Context) (err error) {
|
||||||
if err = c.setAllPolicies(ctx, "DROP"); err != nil {
|
if err = c.setAllPolicies(ctx, "DROP"); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configurator allows to change firewall rules and modify network routes
|
// Configurator allows to change firewall rules and modify network routes.
|
||||||
type Configurator interface {
|
type Configurator interface {
|
||||||
Version(ctx context.Context) (string, error)
|
Version(ctx context.Context) (string, error)
|
||||||
SetEnabled(ctx context.Context, enabled bool) (err error)
|
SetEnabled(ctx context.Context, enabled bool) (err error)
|
||||||
@@ -45,7 +45,7 @@ type configurator struct { //nolint:maligned
|
|||||||
stateMutex sync.Mutex
|
stateMutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfigurator creates a new Configurator instance
|
// NewConfigurator creates a new Configurator instance.
|
||||||
func NewConfigurator(logger logging.Logger, routing routing.Routing, fileManager files.FileManager) Configurator {
|
func NewConfigurator(logger logging.Logger, routing routing.Routing, fileManager files.FileManager) Configurator {
|
||||||
return &configurator{
|
return &configurator{
|
||||||
commander: command.NewCommander(),
|
commander: command.NewCommander(),
|
||||||
|
|||||||
@@ -32,14 +32,15 @@ func flipRule(rule string) string {
|
|||||||
return rule
|
return rule
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version obtains the version of the installed iptables
|
// Version obtains the version of the installed iptables.
|
||||||
func (c *configurator) Version(ctx context.Context) (string, error) {
|
func (c *configurator) Version(ctx context.Context) (string, error) {
|
||||||
output, err := c.commander.Run(ctx, "iptables", "--version")
|
output, err := c.commander.Run(ctx, "iptables", "--version")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
words := strings.Fields(output)
|
words := strings.Fields(output)
|
||||||
if len(words) < 2 {
|
const minWords = 2
|
||||||
|
if len(words) < minWords {
|
||||||
return "", fmt.Errorf("iptables --version: output is too short: %q", output)
|
return "", fmt.Errorf("iptables --version: output is too short: %q", output)
|
||||||
}
|
}
|
||||||
return words[1], nil
|
return words[1], nil
|
||||||
@@ -106,34 +107,39 @@ func (c *configurator) acceptEstablishedRelatedTraffic(ctx context.Context, remo
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurator) acceptOutputTrafficToVPN(ctx context.Context, defaultInterface string, connection models.OpenVPNConnection, remove bool) error {
|
func (c *configurator) acceptOutputTrafficToVPN(ctx context.Context,
|
||||||
|
defaultInterface string, connection models.OpenVPNConnection, remove bool) error {
|
||||||
return c.runIptablesInstruction(ctx,
|
return c.runIptablesInstruction(ctx,
|
||||||
fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT",
|
fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT",
|
||||||
appendOrDelete(remove), connection.IP, defaultInterface, connection.Protocol, connection.Protocol, connection.Port))
|
appendOrDelete(remove), connection.IP, defaultInterface, connection.Protocol, connection.Protocol, connection.Port))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurator) acceptInputFromSubnetToSubnet(ctx context.Context, intf string, sourceSubnet, destinationSubnet net.IPNet, remove bool) error {
|
func (c *configurator) acceptInputFromSubnetToSubnet(ctx context.Context,
|
||||||
|
intf string, sourceSubnet, destinationSubnet net.IPNet, remove bool) error {
|
||||||
interfaceFlag := "-i " + intf
|
interfaceFlag := "-i " + intf
|
||||||
if intf == "*" { // all interfaces
|
if intf == "*" { // all interfaces
|
||||||
interfaceFlag = ""
|
interfaceFlag = ""
|
||||||
}
|
}
|
||||||
return c.runIptablesInstruction(ctx, fmt.Sprintf(
|
return c.runIptablesInstruction(ctx, fmt.Sprintf(
|
||||||
"%s INPUT %s -s %s -d %s -j ACCEPT", appendOrDelete(remove), interfaceFlag, sourceSubnet.String(), destinationSubnet.String(),
|
"%s INPUT %s -s %s -d %s -j ACCEPT",
|
||||||
|
appendOrDelete(remove), interfaceFlag, sourceSubnet.String(), destinationSubnet.String(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thanks to @npawelek
|
// Thanks to @npawelek.
|
||||||
func (c *configurator) acceptOutputFromSubnetToSubnet(ctx context.Context, intf string, sourceSubnet, destinationSubnet net.IPNet, remove bool) error {
|
func (c *configurator) acceptOutputFromSubnetToSubnet(ctx context.Context,
|
||||||
|
intf string, sourceSubnet, destinationSubnet net.IPNet, remove bool) error {
|
||||||
interfaceFlag := "-o " + intf
|
interfaceFlag := "-o " + intf
|
||||||
if intf == "*" { // all interfaces
|
if intf == "*" { // all interfaces
|
||||||
interfaceFlag = ""
|
interfaceFlag = ""
|
||||||
}
|
}
|
||||||
return c.runIptablesInstruction(ctx, fmt.Sprintf(
|
return c.runIptablesInstruction(ctx, fmt.Sprintf(
|
||||||
"%s OUTPUT %s -s %s -d %s -j ACCEPT", appendOrDelete(remove), interfaceFlag, sourceSubnet.String(), destinationSubnet.String(),
|
"%s OUTPUT %s -s %s -d %s -j ACCEPT",
|
||||||
|
appendOrDelete(remove), interfaceFlag, sourceSubnet.String(), destinationSubnet.String(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for port forwarding, with intf set to tun
|
// Used for port forwarding, with intf set to tun.
|
||||||
func (c *configurator) acceptInputToPort(ctx context.Context, intf string, port uint16, remove bool) error {
|
func (c *configurator) acceptInputToPort(ctx context.Context, intf string, port uint16, remove bool) error {
|
||||||
interfaceFlag := "-i " + intf
|
interfaceFlag := "-i " + intf
|
||||||
if intf == "*" { // all interfaces
|
if intf == "*" { // all interfaces
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ func (c *configurator) addSubnets(ctx context.Context, subnets []net.IPNet, defa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateSubnetRoutes does not return an error in order to try to run as many route commands as possible
|
// updateSubnetRoutes does not return an error in order to try to run as many route commands as possible.
|
||||||
func (c *configurator) updateSubnetRoutes(ctx context.Context, oldSubnets, newSubnets []net.IPNet) {
|
func (c *configurator) updateSubnetRoutes(ctx context.Context, oldSubnets, newSubnets []net.IPNet) {
|
||||||
subnetsToAdd := findSubnetsToAdd(oldSubnets, newSubnets)
|
subnetsToAdd := findSubnetsToAdd(oldSubnets, newSubnets)
|
||||||
subnetsToRemove := findSubnetsToRemove(oldSubnets, newSubnets)
|
subnetsToRemove := findSubnetsToRemove(oldSubnets, newSubnets)
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ func FormatDuration(duration time.Duration) string {
|
|||||||
switch {
|
switch {
|
||||||
case duration < time.Minute:
|
case duration < time.Minute:
|
||||||
seconds := int(duration.Round(time.Second).Seconds())
|
seconds := int(duration.Round(time.Second).Seconds())
|
||||||
if seconds < 2 {
|
const two = 2
|
||||||
|
if seconds < two {
|
||||||
return fmt.Sprintf("%d second", seconds)
|
return fmt.Sprintf("%d second", seconds)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%d seconds", seconds)
|
return fmt.Sprintf("%d seconds", seconds)
|
||||||
@@ -23,7 +24,8 @@ func FormatDuration(duration time.Duration) string {
|
|||||||
hours := int(duration.Truncate(time.Hour).Hours())
|
hours := int(duration.Truncate(time.Hour).Hours())
|
||||||
return fmt.Sprintf("%d hours", hours)
|
return fmt.Sprintf("%d hours", hours)
|
||||||
default:
|
default:
|
||||||
days := int(duration.Truncate(time.Hour).Hours() / 24)
|
const hoursInDay = 24
|
||||||
|
days := int(duration.Truncate(time.Hour).Hours() / hoursInDay)
|
||||||
return fmt.Sprintf("%d days", days)
|
return fmt.Sprintf("%d days", days)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
var regularExpressions = struct { //nolint:gochecknoglobals
|
var regularExpressions = struct { //nolint:gochecknoglobals
|
||||||
unboundPrefix *regexp.Regexp
|
unboundPrefix *regexp.Regexp
|
||||||
shadowsocksPrefix *regexp.Regexp
|
shadowsocksPrefix *regexp.Regexp
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Splash returns the welcome spash message
|
// Splash returns the welcome spash message.
|
||||||
func Splash(version, commit, buildDate string) string {
|
func Splash(version, commit, buildDate string) string {
|
||||||
lines := title()
|
lines := title()
|
||||||
lines = append(lines, "")
|
lines = append(lines, "")
|
||||||
|
|||||||
@@ -6,21 +6,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// VPNDevice is the device name used to tunnel using Openvpn
|
// VPNDevice is the device name used to tunnel using Openvpn.
|
||||||
VPNDevice string
|
VPNDevice string
|
||||||
// DNSProvider is a DNS over TLS server provider name
|
// DNSProvider is a DNS over TLS server provider name.
|
||||||
DNSProvider string
|
DNSProvider string
|
||||||
// DNSHost is the DNS host to use for TLS validation
|
// DNSHost is the DNS host to use for TLS validation.
|
||||||
DNSHost string
|
DNSHost string
|
||||||
// URL is an HTTP(s) URL address
|
// URL is an HTTP(s) URL address.
|
||||||
URL string
|
URL string
|
||||||
// Filepath is a local filesytem file path
|
// Filepath is a local filesytem file path.
|
||||||
Filepath string
|
Filepath string
|
||||||
// TinyProxyLogLevel is the log level for TinyProxy
|
// TinyProxyLogLevel is the log level for TinyProxy.
|
||||||
TinyProxyLogLevel string
|
TinyProxyLogLevel string
|
||||||
// VPNProvider is the name of the VPN provider to be used
|
// VPNProvider is the name of the VPN provider to be used.
|
||||||
VPNProvider string
|
VPNProvider string
|
||||||
// NetworkProtocol contains the network protocol to be used to communicate with the VPN servers
|
// NetworkProtocol contains the network protocol to be used to communicate with the VPN servers.
|
||||||
NetworkProtocol string
|
NetworkProtocol string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package models
|
|||||||
|
|
||||||
import "net"
|
import "net"
|
||||||
|
|
||||||
// DNSProviderData contains information for a DNS provider
|
// DNSProviderData contains information for a DNS provider.
|
||||||
type DNSProviderData struct {
|
type DNSProviderData struct {
|
||||||
IPs []net.IP
|
IPs []net.IP
|
||||||
SupportsTLS bool
|
SupportsTLS bool
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProviderSettings contains settings specific to a VPN provider
|
// ProviderSettings contains settings specific to a VPN provider.
|
||||||
type ProviderSettings struct {
|
type ProviderSettings struct {
|
||||||
Name VPNProvider `json:"name"`
|
Name VPNProvider `json:"name"`
|
||||||
ServerSelection ServerSelection `json:"serverSelection"`
|
ServerSelection ServerSelection `json:"serverSelection"`
|
||||||
@@ -14,7 +14,7 @@ type ProviderSettings struct {
|
|||||||
PortForwarding PortForwarding `json:"portForwarding"`
|
PortForwarding PortForwarding `json:"portForwarding"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerSelection struct { //nolint:maligned
|
type ServerSelection struct {
|
||||||
// Common
|
// Common
|
||||||
Protocol NetworkProtocol `json:"networkProtocol"`
|
Protocol NetworkProtocol `json:"networkProtocol"`
|
||||||
TargetIP net.IP `json:"targetIP,omitempty"`
|
TargetIP net.IP `json:"targetIP,omitempty"`
|
||||||
@@ -49,7 +49,7 @@ type ExtraConfigOptions struct {
|
|||||||
OpenVPNIPv6 bool `json:"openvpnIPv6"` // Mullvad
|
OpenVPNIPv6 bool `json:"openvpnIPv6"` // Mullvad
|
||||||
}
|
}
|
||||||
|
|
||||||
// PortForwarding contains settings for port forwarding
|
// PortForwarding contains settings for port forwarding.
|
||||||
type PortForwarding struct {
|
type PortForwarding struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Filepath Filepath `json:"filepath"`
|
Filepath Filepath `json:"filepath"`
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ func Test_MullvadServer_String(t *testing.T) {
|
|||||||
ISP: "not spying on you",
|
ISP: "not spying on you",
|
||||||
Owned: true,
|
Owned: true,
|
||||||
},
|
},
|
||||||
|
//nolint:lll
|
||||||
s: `{Country: "That Country", City: "That City", ISP: "not spying on you", Owned: true, IPs: []net.IP{{1, 1, 1, 1}}, IPsV6: []net.IP{{0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1}}}`,
|
s: `{Country: "That Country", City: "That City", ISP: "not spying on you", Owned: true, IPs: []net.IP{{1, 1, 1, 1}}, IPsV6: []net.IP{{0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1}}}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -127,6 +128,7 @@ func Test_stringifyIPs(t *testing.T) {
|
|||||||
{0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1},
|
{0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1},
|
||||||
{0, 0, 0, 0},
|
{0, 0, 0, 0},
|
||||||
},
|
},
|
||||||
|
//nolint:lll
|
||||||
s: "[]net.IP{{10, 16, 54, 25}, {0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1}, {}}",
|
s: "[]net.IP{{10, 16, 54, 25}, {0x20, 0x1, 0xd, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1}, {}}",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/qdm12/golibs/files"
|
"github.com/qdm12/golibs/files"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteAuthFile writes the OpenVPN auth file to disk with the right permissions
|
// WriteAuthFile writes the OpenVPN auth file to disk with the right permissions.
|
||||||
func (c *configurator) WriteAuthFile(user, password string, uid, gid int) error {
|
func (c *configurator) WriteAuthFile(user, password string, uid, gid int) error {
|
||||||
exists, err := c.fileManager.FileExists(string(constants.OpenVPNAuthConf))
|
exists, err := c.fileManager.FileExists(string(constants.OpenVPNAuthConf))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -27,5 +27,5 @@ func (c *configurator) WriteAuthFile(user, password string, uid, gid int) error
|
|||||||
string(constants.OpenVPNAuthConf),
|
string(constants.OpenVPNAuthConf),
|
||||||
[]string{user, password},
|
[]string{user, password},
|
||||||
files.Ownership(uid, gid),
|
files.Ownership(uid, gid),
|
||||||
files.Permissions(0400))
|
files.Permissions(constants.UserReadPermission))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ func (c *configurator) Version(ctx context.Context) (string, error) {
|
|||||||
}
|
}
|
||||||
firstLine := strings.Split(output, "\n")[0]
|
firstLine := strings.Split(output, "\n")[0]
|
||||||
words := strings.Fields(firstLine)
|
words := strings.Fields(firstLine)
|
||||||
if len(words) < 2 {
|
const minWords = 2
|
||||||
|
if len(words) < minWords {
|
||||||
return "", fmt.Errorf("openvpn --version: first line is too short: %q", firstLine)
|
return "", fmt.Errorf("openvpn --version: first line is too short: %q", firstLine)
|
||||||
}
|
}
|
||||||
return words[1], nil
|
return words[1], nil
|
||||||
|
|||||||
@@ -131,7 +131,8 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
settings.Auth,
|
settings.Auth,
|
||||||
settings.Provider.ExtraConfigOptions,
|
settings.Provider.ExtraConfigOptions,
|
||||||
)
|
)
|
||||||
if err := l.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(l.uid, l.gid), files.Permissions(0400)); err != nil {
|
if err := l.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines,
|
||||||
|
files.Ownership(l.uid, l.gid), files.Permissions(constants.UserReadPermission)); err != nil {
|
||||||
l.logger.Error(err)
|
l.logger.Error(err)
|
||||||
l.cancel()
|
l.cancel()
|
||||||
return
|
return
|
||||||
@@ -200,14 +201,20 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
|
|
||||||
func (l *looper) logAndWait(ctx context.Context, err error) {
|
func (l *looper) logAndWait(ctx context.Context, err error) {
|
||||||
l.logger.Error(err)
|
l.logger.Error(err)
|
||||||
l.logger.Info("retrying in 30 seconds")
|
const waitTime = 30 * time.Second
|
||||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
l.logger.Info("retrying in %s", waitTime)
|
||||||
defer cancel() // just for the linter
|
timer := time.NewTimer(waitTime)
|
||||||
<-ctx.Done()
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
case <-ctx.Done():
|
||||||
|
if !timer.Stop() {
|
||||||
|
<-timer.C
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// portForward is a blocking operation which may or may not be infinite.
|
// portForward is a blocking operation which may or may not be infinite.
|
||||||
// You should therefore always call it in a goroutine
|
// You should therefore always call it in a goroutine.
|
||||||
func (l *looper) portForward(ctx context.Context, wg *sync.WaitGroup,
|
func (l *looper) portForward(ctx context.Context, wg *sync.WaitGroup,
|
||||||
providerConf provider.Provider, client *http.Client, gateway net.IP) {
|
providerConf provider.Provider, client *http.Client, gateway net.IP) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckTUN checks the tunnel device is present and accessible
|
// CheckTUN checks the tunnel device is present and accessible.
|
||||||
func (c *configurator) CheckTUN() error {
|
func (c *configurator) CheckTUN() error {
|
||||||
c.logger.Info("checking for device %s", constants.TunnelDevice)
|
c.logger.Info("checking for device %s", constants.TunnelDevice)
|
||||||
f, err := c.openFile(string(constants.TunnelDevice), os.O_RDWR, 0)
|
f, err := c.openFile(string(constants.TunnelDevice), os.O_RDWR, 0)
|
||||||
@@ -26,7 +26,11 @@ func (c *configurator) CreateTUN() error {
|
|||||||
if err := c.fileManager.CreateDir("/dev/net"); err != nil {
|
if err := c.fileManager.CreateDir("/dev/net"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dev := c.mkDev(10, 200)
|
const (
|
||||||
|
major = 10
|
||||||
|
minor = 200
|
||||||
|
)
|
||||||
|
dev := c.mkDev(major, minor)
|
||||||
if err := c.mkNod(string(constants.TunnelDevice), unix.S_IFCHR, int(dev)); err != nil {
|
if err := c.mkNod(string(constants.TunnelDevice), unix.S_IFCHR, int(dev)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,21 +8,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetCyberghostGroup obtains the server group for the Cyberghost server from the
|
// GetCyberghostGroup obtains the server group for the Cyberghost server from the
|
||||||
// environment variable CYBERGHOST_GROUP
|
// environment variable CYBERGHOST_GROUP.
|
||||||
func (p *reader) GetCyberghostGroup() (group string, err error) {
|
func (p *reader) GetCyberghostGroup() (group string, err error) {
|
||||||
s, err := p.envParams.GetValueIfInside("CYBERGHOST_GROUP", constants.CyberghostGroupChoices(), libparams.Default("Premium UDP Europe"))
|
s, err := p.envParams.GetValueIfInside("CYBERGHOST_GROUP",
|
||||||
|
constants.CyberghostGroupChoices(), libparams.Default("Premium UDP Europe"))
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCyberghostRegions obtains the country names for the Cyberghost servers from the
|
// GetCyberghostRegions obtains the country names for the Cyberghost servers from the
|
||||||
// environment variable REGION
|
// environment variable REGION.
|
||||||
func (p *reader) GetCyberghostRegions() (regions []string, err error) {
|
func (p *reader) GetCyberghostRegions() (regions []string, err error) {
|
||||||
choices := append(constants.CyberghostRegionChoices(), "")
|
choices := append(constants.CyberghostRegionChoices(), "")
|
||||||
return p.envParams.GetCSVInPossibilities("REGION", choices)
|
return p.envParams.GetCSVInPossibilities("REGION", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCyberghostClientKey obtains the one line client key to use for openvpn from the
|
// GetCyberghostClientKey obtains the one line client key to use for openvpn from the
|
||||||
// environment variable CLIENT_KEY
|
// environment variable CLIENT_KEY.
|
||||||
func (p *reader) GetCyberghostClientKey() (clientKey string, err error) {
|
func (p *reader) GetCyberghostClientKey() (clientKey string, err error) {
|
||||||
clientKey, err = p.envParams.GetEnv("CLIENT_KEY", libparams.CaseSensitiveValue())
|
clientKey, err = p.envParams.GetEnv("CLIENT_KEY", libparams.CaseSensitiveValue())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+19
-17
@@ -12,13 +12,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetDNSOverTLS obtains if the DNS over TLS should be enabled
|
// GetDNSOverTLS obtains if the DNS over TLS should be enabled
|
||||||
// from the environment variable DOT
|
// from the environment variable DOT.
|
||||||
func (r *reader) GetDNSOverTLS() (DNSOverTLS bool, err error) { //nolint:gocritic
|
func (r *reader) GetDNSOverTLS() (DNSOverTLS bool, err error) { //nolint:gocritic
|
||||||
return r.envParams.GetOnOff("DOT", libparams.Default("on"))
|
return r.envParams.GetOnOff("DOT", libparams.Default("on"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSOverTLSProviders obtains the DNS over TLS providers to use
|
// GetDNSOverTLSProviders obtains the DNS over TLS providers to use
|
||||||
// from the environment variable DOT_PROVIDERS
|
// from the environment variable DOT_PROVIDERS.
|
||||||
func (r *reader) GetDNSOverTLSProviders() (providers []models.DNSProvider, err error) {
|
func (r *reader) GetDNSOverTLSProviders() (providers []models.DNSProvider, err error) {
|
||||||
s, err := r.envParams.GetEnv("DOT_PROVIDERS", libparams.Default("cloudflare"))
|
s, err := r.envParams.GetEnv("DOT_PROVIDERS", libparams.Default("cloudflare"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -27,7 +27,9 @@ func (r *reader) GetDNSOverTLSProviders() (providers []models.DNSProvider, err e
|
|||||||
for _, word := range strings.Split(s, ",") {
|
for _, word := range strings.Split(s, ",") {
|
||||||
provider := models.DNSProvider(word)
|
provider := models.DNSProvider(word)
|
||||||
switch provider {
|
switch provider {
|
||||||
case constants.Cloudflare, constants.Google, constants.Quad9, constants.Quadrant, constants.CleanBrowsing, constants.SecureDNS, constants.LibreDNS:
|
case constants.Cloudflare, constants.Google, constants.Quad9,
|
||||||
|
constants.Quadrant, constants.CleanBrowsing, constants.SecureDNS,
|
||||||
|
constants.LibreDNS:
|
||||||
providers = append(providers, provider)
|
providers = append(providers, provider)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("DNS over TLS provider %q is not valid", provider)
|
return nil, fmt.Errorf("DNS over TLS provider %q is not valid", provider)
|
||||||
@@ -37,55 +39,55 @@ func (r *reader) GetDNSOverTLSProviders() (providers []models.DNSProvider, err e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSOverTLSVerbosity obtains the verbosity level to use for Unbound
|
// GetDNSOverTLSVerbosity obtains the verbosity level to use for Unbound
|
||||||
// from the environment variable DOT_VERBOSITY
|
// from the environment variable DOT_VERBOSITY.
|
||||||
func (r *reader) GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error) {
|
func (r *reader) GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error) {
|
||||||
n, err := r.envParams.GetEnvIntRange("DOT_VERBOSITY", 0, 5, libparams.Default("1"))
|
n, err := r.envParams.GetEnvIntRange("DOT_VERBOSITY", 0, 5, libparams.Default("1"))
|
||||||
return uint8(n), err
|
return uint8(n), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSOverTLSVerbosityDetails obtains the log level to use for Unbound
|
// GetDNSOverTLSVerbosityDetails obtains the log level to use for Unbound
|
||||||
// from the environment variable DOT_VERBOSITY_DETAILS
|
// from the environment variable DOT_VERBOSITY_DETAILS.
|
||||||
func (r *reader) GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error) {
|
func (r *reader) GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error) {
|
||||||
n, err := r.envParams.GetEnvIntRange("DOT_VERBOSITY_DETAILS", 0, 4, libparams.Default("0"))
|
n, err := r.envParams.GetEnvIntRange("DOT_VERBOSITY_DETAILS", 0, 4, libparams.Default("0"))
|
||||||
return uint8(n), err
|
return uint8(n), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSOverTLSValidationLogLevel obtains the log level to use for Unbound DOT validation
|
// GetDNSOverTLSValidationLogLevel obtains the log level to use for Unbound DOT validation
|
||||||
// from the environment variable DOT_VALIDATION_LOGLEVEL
|
// from the environment variable DOT_VALIDATION_LOGLEVEL.
|
||||||
func (r *reader) GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error) {
|
func (r *reader) GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error) {
|
||||||
n, err := r.envParams.GetEnvIntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, libparams.Default("0"))
|
n, err := r.envParams.GetEnvIntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, libparams.Default("0"))
|
||||||
return uint8(n), err
|
return uint8(n), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSMaliciousBlocking obtains if malicious hostnames/IPs should be blocked
|
// GetDNSMaliciousBlocking obtains if malicious hostnames/IPs should be blocked
|
||||||
// from being resolved by Unbound, using the environment variable BLOCK_MALICIOUS
|
// from being resolved by Unbound, using the environment variable BLOCK_MALICIOUS.
|
||||||
func (r *reader) GetDNSMaliciousBlocking() (blocking bool, err error) {
|
func (r *reader) GetDNSMaliciousBlocking() (blocking bool, err error) {
|
||||||
return r.envParams.GetOnOff("BLOCK_MALICIOUS", libparams.Default("on"))
|
return r.envParams.GetOnOff("BLOCK_MALICIOUS", libparams.Default("on"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSSurveillanceBlocking obtains if surveillance hostnames/IPs should be blocked
|
// GetDNSSurveillanceBlocking obtains if surveillance hostnames/IPs should be blocked
|
||||||
// from being resolved by Unbound, using the environment variable BLOCK_SURVEILLANCE
|
// from being resolved by Unbound, using the environment variable BLOCK_SURVEILLANCE
|
||||||
// and BLOCK_NSA for retrocompatibility
|
// and BLOCK_NSA for retrocompatibility.
|
||||||
func (r *reader) GetDNSSurveillanceBlocking() (blocking bool, err error) {
|
func (r *reader) GetDNSSurveillanceBlocking() (blocking bool, err error) {
|
||||||
// Retro-compatibility
|
// Retro-compatibility
|
||||||
s, err := r.envParams.GetEnv("BLOCK_NSA")
|
s, err := r.envParams.GetEnv("BLOCK_NSA")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
} else if len(s) != 0 {
|
} else if len(s) != 0 {
|
||||||
r.logger.Warn("You are using the old environment variable BLOCK_NSA, please consider changing it to BLOCK_SURVEILLANCE")
|
r.logger.Warn("You are using the old environment variable BLOCK_NSA, please consider changing it to BLOCK_SURVEILLANCE") //nolint:lll
|
||||||
return r.envParams.GetOnOff("BLOCK_NSA", libparams.Compulsory())
|
return r.envParams.GetOnOff("BLOCK_NSA", libparams.Compulsory())
|
||||||
}
|
}
|
||||||
return r.envParams.GetOnOff("BLOCK_SURVEILLANCE", libparams.Default("off"))
|
return r.envParams.GetOnOff("BLOCK_SURVEILLANCE", libparams.Default("off"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSAdsBlocking obtains if ads hostnames/IPs should be blocked
|
// GetDNSAdsBlocking obtains if ads hostnames/IPs should be blocked
|
||||||
// from being resolved by Unbound, using the environment variable BLOCK_ADS
|
// from being resolved by Unbound, using the environment variable BLOCK_ADS.
|
||||||
func (r *reader) GetDNSAdsBlocking() (blocking bool, err error) {
|
func (r *reader) GetDNSAdsBlocking() (blocking bool, err error) {
|
||||||
return r.envParams.GetOnOff("BLOCK_ADS", libparams.Default("off"))
|
return r.envParams.GetOnOff("BLOCK_ADS", libparams.Default("off"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSUnblockedHostnames obtains a list of hostnames to unblock from block lists
|
// GetDNSUnblockedHostnames obtains a list of hostnames to unblock from block lists
|
||||||
// from the comma separated list for the environment variable UNBLOCK
|
// from the comma separated list for the environment variable UNBLOCK.
|
||||||
func (r *reader) GetDNSUnblockedHostnames() (hostnames []string, err error) {
|
func (r *reader) GetDNSUnblockedHostnames() (hostnames []string, err error) {
|
||||||
s, err := r.envParams.GetEnv("UNBLOCK")
|
s, err := r.envParams.GetEnv("UNBLOCK")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -103,13 +105,13 @@ func (r *reader) GetDNSUnblockedHostnames() (hostnames []string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSOverTLSCaching obtains if Unbound caching should be enable or not
|
// GetDNSOverTLSCaching obtains if Unbound caching should be enable or not
|
||||||
// from the environment variable DOT_CACHING
|
// from the environment variable DOT_CACHING.
|
||||||
func (r *reader) GetDNSOverTLSCaching() (caching bool, err error) {
|
func (r *reader) GetDNSOverTLSCaching() (caching bool, err error) {
|
||||||
return r.envParams.GetOnOff("DOT_CACHING")
|
return r.envParams.GetOnOff("DOT_CACHING")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSOverTLSPrivateAddresses obtains if Unbound caching should be enable or not
|
// GetDNSOverTLSPrivateAddresses obtains if Unbound caching should be enable or not
|
||||||
// from the environment variable DOT_PRIVATE_ADDRESS
|
// from the environment variable DOT_PRIVATE_ADDRESS.
|
||||||
func (r *reader) GetDNSOverTLSPrivateAddresses() (privateAddresses []string, err error) {
|
func (r *reader) GetDNSOverTLSPrivateAddresses() (privateAddresses []string, err error) {
|
||||||
s, err := r.envParams.GetEnv("DOT_PRIVATE_ADDRESS")
|
s, err := r.envParams.GetEnv("DOT_PRIVATE_ADDRESS")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -129,13 +131,13 @@ func (r *reader) GetDNSOverTLSPrivateAddresses() (privateAddresses []string, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSOverTLSIPv6 obtains if Unbound should resolve ipv6 addresses using ipv6 DNS over TLS
|
// GetDNSOverTLSIPv6 obtains if Unbound should resolve ipv6 addresses using ipv6 DNS over TLS
|
||||||
// servers from the environment variable DOT_IPV6
|
// servers from the environment variable DOT_IPV6.
|
||||||
func (r *reader) GetDNSOverTLSIPv6() (ipv6 bool, err error) {
|
func (r *reader) GetDNSOverTLSIPv6() (ipv6 bool, err error) {
|
||||||
return r.envParams.GetOnOff("DOT_IPV6", libparams.Default("off"))
|
return r.envParams.GetOnOff("DOT_IPV6", libparams.Default("off"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSUpdatePeriod obtains the period to use to update the block lists and cryptographic files
|
// GetDNSUpdatePeriod obtains the period to use to update the block lists and cryptographic files
|
||||||
// and restart Unbound from the environment variable DNS_UPDATE_PERIOD
|
// and restart Unbound from the environment variable DNS_UPDATE_PERIOD.
|
||||||
func (r *reader) GetDNSUpdatePeriod() (period time.Duration, err error) {
|
func (r *reader) GetDNSUpdatePeriod() (period time.Duration, err error) {
|
||||||
s, err := r.envParams.GetEnv("DNS_UPDATE_PERIOD", libparams.Default("24h"))
|
s, err := r.envParams.GetEnv("DNS_UPDATE_PERIOD", libparams.Default("24h"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -145,7 +147,7 @@ func (r *reader) GetDNSUpdatePeriod() (period time.Duration, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSPlaintext obtains the plaintext DNS address to use if DNS over TLS is disabled
|
// GetDNSPlaintext obtains the plaintext DNS address to use if DNS over TLS is disabled
|
||||||
// from the environment variable DNS_PLAINTEXT_ADDRESS
|
// from the environment variable DNS_PLAINTEXT_ADDRESS.
|
||||||
func (r *reader) GetDNSPlaintext() (ip net.IP, err error) {
|
func (r *reader) GetDNSPlaintext() (ip net.IP, err error) {
|
||||||
s, err := r.envParams.GetEnv("DNS_PLAINTEXT_ADDRESS", libparams.Default("1.1.1.1"))
|
s, err := r.envParams.GetEnv("DNS_PLAINTEXT_ADDRESS", libparams.Default("1.1.1.1"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -159,7 +161,7 @@ func (r *reader) GetDNSPlaintext() (ip net.IP, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetDNSKeepNameserver obtains if the nameserver present in /etc/resolv.conf
|
// GetDNSKeepNameserver obtains if the nameserver present in /etc/resolv.conf
|
||||||
// should be kept instead of overridden, from the environment variable DNS_KEEP_NAMESERVER
|
// should be kept instead of overridden, from the environment variable DNS_KEEP_NAMESERVER.
|
||||||
func (r *reader) GetDNSKeepNameserver() (on bool, err error) {
|
func (r *reader) GetDNSKeepNameserver() (on bool, err error) {
|
||||||
return r.envParams.GetOnOff("DNS_KEEP_NAMESERVER", libparams.Default("off"))
|
return r.envParams.GetOnOff("DNS_KEEP_NAMESERVER", libparams.Default("off"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import (
|
|||||||
libparams "github.com/qdm12/golibs/params"
|
libparams "github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetFirewall obtains if the firewall should be enabled from the environment variable FIREWALL
|
// GetFirewall obtains if the firewall should be enabled from the environment variable FIREWALL.
|
||||||
func (r *reader) GetFirewall() (enabled bool, err error) {
|
func (r *reader) GetFirewall() (enabled bool, err error) {
|
||||||
return r.envParams.GetOnOff("FIREWALL", libparams.Default("on"))
|
return r.envParams.GetOnOff("FIREWALL", libparams.Default("on"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtraSubnets obtains the CIDR subnets from the comma separated list of the
|
// GetExtraSubnets obtains the CIDR subnets from the comma separated list of the
|
||||||
// environment variable EXTRA_SUBNETS
|
// environment variable EXTRA_SUBNETS.
|
||||||
func (r *reader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) {
|
func (r *reader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) {
|
||||||
s, err := r.envParams.GetEnv("EXTRA_SUBNETS")
|
s, err := r.envParams.GetEnv("EXTRA_SUBNETS")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -37,7 +37,7 @@ func (r *reader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetAllowedVPNInputPorts obtains a list of input ports to allow from the
|
// GetAllowedVPNInputPorts obtains a list of input ports to allow from the
|
||||||
// VPN server side in the firewall, from the environment variable FIREWALL_VPN_INPUT_PORTS
|
// VPN server side in the firewall, from the environment variable FIREWALL_VPN_INPUT_PORTS.
|
||||||
func (r *reader) GetVPNInputPorts() (ports []uint16, err error) {
|
func (r *reader) GetVPNInputPorts() (ports []uint16, err error) {
|
||||||
s, err := r.envParams.GetEnv("FIREWALL_VPN_INPUT_PORTS", libparams.Default(""))
|
s, err := r.envParams.GetEnv("FIREWALL_VPN_INPUT_PORTS", libparams.Default(""))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -61,7 +61,7 @@ func (r *reader) GetVPNInputPorts() (ports []uint16, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetInputPorts obtains a list of input ports to allow through the
|
// GetInputPorts obtains a list of input ports to allow through the
|
||||||
// default interface in the firewall, from the environment variable FIREWALL_INPUT_PORTS
|
// default interface in the firewall, from the environment variable FIREWALL_INPUT_PORTS.
|
||||||
func (r *reader) GetInputPorts() (ports []uint16, err error) {
|
func (r *reader) GetInputPorts() (ports []uint16, err error) {
|
||||||
s, err := r.envParams.GetEnv("FIREWALL_INPUT_PORTS", libparams.Default(""))
|
s, err := r.envParams.GetEnv("FIREWALL_INPUT_PORTS", libparams.Default(""))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -84,7 +84,8 @@ func (r *reader) GetInputPorts() (ports []uint16, err error) {
|
|||||||
return ports, nil
|
return ports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFirewallDebug obtains if the firewall should run in debug verbose mode from the environment variable FIREWALL_DEBUG
|
// GetFirewallDebug obtains if the firewall should run in debug verbose mode
|
||||||
|
// from the environment variable FIREWALL_DEBUG.
|
||||||
func (r *reader) GetFirewallDebug() (debug bool, err error) {
|
func (r *reader) GetFirewallDebug() (debug bool, err error) {
|
||||||
return r.envParams.GetOnOff("FIREWALL_DEBUG", libparams.Default("off"))
|
return r.envParams.GetOnOff("FIREWALL_DEBUG", libparams.Default("off"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,35 +6,35 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetMullvadCountries obtains the countries for the Mullvad servers from the
|
// GetMullvadCountries obtains the countries for the Mullvad servers from the
|
||||||
// environment variable COUNTRY
|
// environment variable COUNTRY.
|
||||||
func (r *reader) GetMullvadCountries() (countries []string, err error) {
|
func (r *reader) GetMullvadCountries() (countries []string, err error) {
|
||||||
choices := append(constants.MullvadCountryChoices(), "")
|
choices := append(constants.MullvadCountryChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("COUNTRY", choices)
|
return r.envParams.GetCSVInPossibilities("COUNTRY", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMullvadCity obtains the cities for the Mullvad servers from the
|
// GetMullvadCity obtains the cities for the Mullvad servers from the
|
||||||
// environment variable CITY
|
// environment variable CITY.
|
||||||
func (r *reader) GetMullvadCities() (cities []string, err error) {
|
func (r *reader) GetMullvadCities() (cities []string, err error) {
|
||||||
choices := append(constants.MullvadCityChoices(), "")
|
choices := append(constants.MullvadCityChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("CITY", choices)
|
return r.envParams.GetCSVInPossibilities("CITY", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMullvadISPs obtains the ISPs for the Mullvad servers from the
|
// GetMullvadISPs obtains the ISPs for the Mullvad servers from the
|
||||||
// environment variable ISP
|
// environment variable ISP.
|
||||||
func (r *reader) GetMullvadISPs() (isps []string, err error) {
|
func (r *reader) GetMullvadISPs() (isps []string, err error) {
|
||||||
choices := append(constants.MullvadISPChoices(), "")
|
choices := append(constants.MullvadISPChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("ISP", choices)
|
return r.envParams.GetCSVInPossibilities("ISP", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
||||||
// environment variable PORT
|
// environment variable PORT.
|
||||||
func (r *reader) GetMullvadPort() (port uint16, err error) {
|
func (r *reader) GetMullvadPort() (port uint16, err error) {
|
||||||
n, err := r.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
|
n, err := r.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
|
||||||
return uint16(n), err
|
return uint16(n), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMullvadOwned obtains if the server should be owned by Mullvad or not from the
|
// GetMullvadOwned obtains if the server should be owned by Mullvad or not from the
|
||||||
// environment variable OWNED
|
// environment variable OWNED.
|
||||||
func (r *reader) GetMullvadOwned() (owned bool, err error) {
|
func (r *reader) GetMullvadOwned() (owned bool, err error) {
|
||||||
return r.envParams.GetYesNo("OWNED", libparams.Default("no"))
|
return r.envParams.GetYesNo("OWNED", libparams.Default("no"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetNordvpnRegions obtains the regions (countries) for the NordVPN server from the
|
// GetNordvpnRegions obtains the regions (countries) for the NordVPN server from the
|
||||||
// environment variable REGION
|
// environment variable REGION.
|
||||||
func (r *reader) GetNordvpnRegions() (regions []string, err error) {
|
func (r *reader) GetNordvpnRegions() (regions []string, err error) {
|
||||||
choices := append(constants.NordvpnRegionChoices(), "")
|
choices := append(constants.NordvpnRegionChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNordvpnRegion obtains the server numbers (optional) for the NordVPN servers from the
|
// GetNordvpnRegion obtains the server numbers (optional) for the NordVPN servers from the
|
||||||
// environment variable SERVER_NUMBER
|
// environment variable SERVER_NUMBER.
|
||||||
func (r *reader) GetNordvpnNumbers() (numbers []uint16, err error) {
|
func (r *reader) GetNordvpnNumbers() (numbers []uint16, err error) {
|
||||||
possibilities := make([]string, 65536)
|
possibilities := make([]string, 65536)
|
||||||
for i := range possibilities {
|
for i := range possibilities {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
libparams "github.com/qdm12/golibs/params"
|
libparams "github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetUser obtains the user to use to connect to the VPN servers
|
// GetUser obtains the user to use to connect to the VPN servers.
|
||||||
func (r *reader) GetUser() (s string, err error) {
|
func (r *reader) GetUser() (s string, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
unsetenvErr := r.unsetEnv("USER")
|
unsetenvErr := r.unsetEnv("USER")
|
||||||
@@ -19,7 +19,7 @@ func (r *reader) GetUser() (s string, err error) {
|
|||||||
return r.envParams.GetEnv("USER", libparams.CaseSensitiveValue(), libparams.Compulsory())
|
return r.envParams.GetEnv("USER", libparams.CaseSensitiveValue(), libparams.Compulsory())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPassword obtains the password to use to connect to the VPN servers
|
// GetPassword obtains the password to use to connect to the VPN servers.
|
||||||
func (r *reader) GetPassword(required bool) (s string, err error) {
|
func (r *reader) GetPassword(required bool) (s string, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
unsetenvErr := r.unsetEnv("PASSWORD")
|
unsetenvErr := r.unsetEnv("PASSWORD")
|
||||||
@@ -35,26 +35,26 @@ func (r *reader) GetPassword(required bool) (s string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetNetworkProtocol obtains the network protocol to use to connect to the
|
// GetNetworkProtocol obtains the network protocol to use to connect to the
|
||||||
// VPN servers from the environment variable PROTOCOL
|
// VPN servers from the environment variable PROTOCOL.
|
||||||
func (r *reader) GetNetworkProtocol() (protocol models.NetworkProtocol, err error) {
|
func (r *reader) GetNetworkProtocol() (protocol models.NetworkProtocol, err error) {
|
||||||
s, err := r.envParams.GetValueIfInside("PROTOCOL", []string{"tcp", "udp"}, libparams.Default("udp"))
|
s, err := r.envParams.GetValueIfInside("PROTOCOL", []string{"tcp", "udp"}, libparams.Default("udp"))
|
||||||
return models.NetworkProtocol(s), err
|
return models.NetworkProtocol(s), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOpenVPNVerbosity obtains the verbosity level for verbosity between 0 and 6
|
// GetOpenVPNVerbosity obtains the verbosity level for verbosity between 0 and 6
|
||||||
// from the environment variable OPENVPN_VERBOSITY
|
// from the environment variable OPENVPN_VERBOSITY.
|
||||||
func (r *reader) GetOpenVPNVerbosity() (verbosity int, err error) {
|
func (r *reader) GetOpenVPNVerbosity() (verbosity int, err error) {
|
||||||
return r.envParams.GetEnvIntRange("OPENVPN_VERBOSITY", 0, 6, libparams.Default("1"))
|
return r.envParams.GetEnvIntRange("OPENVPN_VERBOSITY", 0, 6, libparams.Default("1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOpenVPNRoot obtains if openvpn should be run as root
|
// GetOpenVPNRoot obtains if openvpn should be run as root
|
||||||
// from the environment variable OPENVPN_ROOT
|
// from the environment variable OPENVPN_ROOT.
|
||||||
func (r *reader) GetOpenVPNRoot() (root bool, err error) {
|
func (r *reader) GetOpenVPNRoot() (root bool, err error) {
|
||||||
return r.envParams.GetYesNo("OPENVPN_ROOT", libparams.Default("no"))
|
return r.envParams.GetYesNo("OPENVPN_ROOT", libparams.Default("no"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTargetIP obtains the IP address to override over the list of IP addresses filtered
|
// GetTargetIP obtains the IP address to override over the list of IP addresses filtered
|
||||||
// from the environment variable OPENVPN_TARGET_IP
|
// from the environment variable OPENVPN_TARGET_IP.
|
||||||
func (r *reader) GetTargetIP() (ip net.IP, err error) {
|
func (r *reader) GetTargetIP() (ip net.IP, err error) {
|
||||||
s, err := r.envParams.GetEnv("OPENVPN_TARGET_IP")
|
s, err := r.envParams.GetEnv("OPENVPN_TARGET_IP")
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
@@ -70,19 +70,19 @@ func (r *reader) GetTargetIP() (ip net.IP, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetOpenVPNCipher obtains a custom cipher to use with OpenVPN
|
// GetOpenVPNCipher obtains a custom cipher to use with OpenVPN
|
||||||
// from the environment variable OPENVPN_CIPHER
|
// from the environment variable OPENVPN_CIPHER.
|
||||||
func (r *reader) GetOpenVPNCipher() (cipher string, err error) {
|
func (r *reader) GetOpenVPNCipher() (cipher string, err error) {
|
||||||
return r.envParams.GetEnv("OPENVPN_CIPHER")
|
return r.envParams.GetEnv("OPENVPN_CIPHER")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOpenVPNAuth obtains a custom auth algorithm to use with OpenVPN
|
// GetOpenVPNAuth obtains a custom auth algorithm to use with OpenVPN
|
||||||
// from the environment variable OPENVPN_AUTH
|
// from the environment variable OPENVPN_AUTH.
|
||||||
func (r *reader) GetOpenVPNAuth() (auth string, err error) {
|
func (r *reader) GetOpenVPNAuth() (auth string, err error) {
|
||||||
return r.envParams.GetEnv("OPENVPN_AUTH")
|
return r.envParams.GetEnv("OPENVPN_AUTH")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOpenVPNIPv6 obtains if ipv6 should be tunneled through the
|
// GetOpenVPNIPv6 obtains if ipv6 should be tunneled through the
|
||||||
// openvpn tunnel from the environment variable OPENVPN_IPV6
|
// openvpn tunnel from the environment variable OPENVPN_IPV6.
|
||||||
func (r *reader) GetOpenVPNIPv6() (ipv6 bool, err error) {
|
func (r *reader) GetOpenVPNIPv6() (ipv6 bool, err error) {
|
||||||
return r.envParams.GetOnOff("OPENVPN_IPV6", libparams.Default("off"))
|
return r.envParams.GetOnOff("OPENVPN_IPV6", libparams.Default("off"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/qdm12/golibs/verification"
|
"github.com/qdm12/golibs/verification"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reader contains methods to obtain parameters
|
// Reader contains methods to obtain parameters.
|
||||||
type Reader interface {
|
type Reader interface {
|
||||||
GetVPNSP() (vpnServiceProvider models.VPNProvider, err error)
|
GetVPNSP() (vpnServiceProvider models.VPNProvider, err error)
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ type reader struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Newreader returns a paramsReadeer object to read parameters from
|
// Newreader returns a paramsReadeer object to read parameters from
|
||||||
// environment variables
|
// environment variables.
|
||||||
func NewReader(logger logging.Logger, fileManager files.FileManager) Reader {
|
func NewReader(logger logging.Logger, fileManager files.FileManager) Reader {
|
||||||
return &reader{
|
return &reader{
|
||||||
envParams: libparams.NewEnvParams(),
|
envParams: libparams.NewEnvParams(),
|
||||||
@@ -141,9 +141,15 @@ func NewReader(logger logging.Logger, fileManager files.FileManager) Reader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVPNSP obtains the VPN service provider to use from the environment variable VPNSP
|
// GetVPNSP obtains the VPN service provider to use from the environment variable VPNSP.
|
||||||
func (r *reader) GetVPNSP() (vpnServiceProvider models.VPNProvider, err error) {
|
func (r *reader) GetVPNSP() (vpnServiceProvider models.VPNProvider, err error) {
|
||||||
s, err := r.envParams.GetValueIfInside("VPNSP", []string{"pia", "private internet access", "private internet access old", "mullvad", "windscribe", "surfshark", "cyberghost", "vyprvpn", "nordvpn", "purevpn"})
|
s, err := r.envParams.GetValueIfInside(
|
||||||
|
"VPNSP",
|
||||||
|
[]string{
|
||||||
|
"pia", "private internet access", "private internet access old",
|
||||||
|
"mullvad", "windscribe", "surfshark", "cyberghost",
|
||||||
|
"vyprvpn", "nordvpn", "purevpn",
|
||||||
|
})
|
||||||
if s == "pia" {
|
if s == "pia" {
|
||||||
s = "private internet access"
|
s = "private internet access"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
// GetPortForwarding obtains if port forwarding on the VPN provider server
|
// GetPortForwarding obtains if port forwarding on the VPN provider server
|
||||||
// side is enabled or not from the environment variable PORT_FORWARDING
|
// side is enabled or not from the environment variable PORT_FORWARDING
|
||||||
// Only valid for older PIA servers for now
|
// Only valid for older PIA servers for now.
|
||||||
func (r *reader) GetPortForwarding() (activated bool, err error) {
|
func (r *reader) GetPortForwarding() (activated bool, err error) {
|
||||||
s, err := r.envParams.GetEnv("PORT_FORWARDING", libparams.Default("off"))
|
s, err := r.envParams.GetEnv("PORT_FORWARDING", libparams.Default("off"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -26,15 +26,18 @@ func (r *reader) GetPortForwarding() (activated bool, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetPortForwardingStatusFilepath obtains the port forwarding status file path
|
// GetPortForwardingStatusFilepath obtains the port forwarding status file path
|
||||||
// from the environment variable PORT_FORWARDING_STATUS_FILE
|
// from the environment variable PORT_FORWARDING_STATUS_FILE.
|
||||||
func (r *reader) GetPortForwardingStatusFilepath() (filepath models.Filepath, err error) {
|
func (r *reader) GetPortForwardingStatusFilepath() (filepath models.Filepath, err error) {
|
||||||
filepathStr, err := r.envParams.GetPath("PORT_FORWARDING_STATUS_FILE", libparams.Default("/tmp/gluetun/forwarded_port"), libparams.CaseSensitiveValue())
|
filepathStr, err := r.envParams.GetPath(
|
||||||
|
"PORT_FORWARDING_STATUS_FILE",
|
||||||
|
libparams.Default("/tmp/gluetun/forwarded_port"),
|
||||||
|
libparams.CaseSensitiveValue())
|
||||||
return models.Filepath(filepathStr), err
|
return models.Filepath(filepathStr), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPIAEncryptionPreset obtains the encryption level for the PIA connection
|
// GetPIAEncryptionPreset obtains the encryption level for the PIA connection
|
||||||
// from the environment variable PIA_ENCRYPTION, and using ENCRYPTION for
|
// from the environment variable PIA_ENCRYPTION, and using ENCRYPTION for
|
||||||
// retro compatibility
|
// retro compatibility.
|
||||||
func (r *reader) GetPIAEncryptionPreset() (preset string, err error) {
|
func (r *reader) GetPIAEncryptionPreset() (preset string, err error) {
|
||||||
// Retro-compatibility
|
// Retro-compatibility
|
||||||
s, err := r.envParams.GetValueIfInside("ENCRYPTION", []string{
|
s, err := r.envParams.GetValueIfInside("ENCRYPTION", []string{
|
||||||
@@ -57,14 +60,14 @@ func (r *reader) GetPIAEncryptionPreset() (preset string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetPIARegions obtains the regions for the PIA servers from the
|
// GetPIARegions obtains the regions for the PIA servers from the
|
||||||
// environment variable REGION
|
// environment variable REGION.
|
||||||
func (r *reader) GetPIARegions() (regions []string, err error) {
|
func (r *reader) GetPIARegions() (regions []string, err error) {
|
||||||
choices := append(constants.PIAGeoChoices(), "")
|
choices := append(constants.PIAGeoChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPIAOldRegions obtains the regions for the PIA servers from the
|
// GetPIAOldRegions obtains the regions for the PIA servers from the
|
||||||
// environment variable REGION
|
// environment variable REGION.
|
||||||
func (r *reader) GetPIAOldRegions() (regions []string, err error) {
|
func (r *reader) GetPIAOldRegions() (regions []string, err error) {
|
||||||
choices := append(constants.PIAOldGeoChoices(), "")
|
choices := append(constants.PIAOldGeoChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetPublicIPPeriod obtains the period to fetch the IP address periodically.
|
// GetPublicIPPeriod obtains the period to fetch the IP address periodically.
|
||||||
// Set to 0 to disable
|
// Set to 0 to disable.
|
||||||
func (r *reader) GetPublicIPPeriod() (period time.Duration, err error) {
|
func (r *reader) GetPublicIPPeriod() (period time.Duration, err error) {
|
||||||
s, err := r.envParams.GetEnv("PUBLICIP_PERIOD", libparams.Default("12h"))
|
s, err := r.envParams.GetEnv("PUBLICIP_PERIOD", libparams.Default("12h"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,21 +5,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetPurevpnRegions obtains the regions (continents) for the PureVPN servers from the
|
// GetPurevpnRegions obtains the regions (continents) for the PureVPN servers from the
|
||||||
// environment variable REGION
|
// environment variable REGION.
|
||||||
func (r *reader) GetPurevpnRegions() (regions []string, err error) {
|
func (r *reader) GetPurevpnRegions() (regions []string, err error) {
|
||||||
choices := append(constants.PurevpnRegionChoices(), "")
|
choices := append(constants.PurevpnRegionChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPurevpnCountries obtains the countries for the PureVPN servers from the
|
// GetPurevpnCountries obtains the countries for the PureVPN servers from the
|
||||||
// environment variable COUNTRY
|
// environment variable COUNTRY.
|
||||||
func (r *reader) GetPurevpnCountries() (countries []string, err error) {
|
func (r *reader) GetPurevpnCountries() (countries []string, err error) {
|
||||||
choices := append(constants.PurevpnCountryChoices(), "")
|
choices := append(constants.PurevpnCountryChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("COUNTRY", choices)
|
return r.envParams.GetCSVInPossibilities("COUNTRY", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPurevpnCities obtains the cities for the PureVPN servers from the
|
// GetPurevpnCities obtains the cities for the PureVPN servers from the
|
||||||
// environment variable CITY
|
// environment variable CITY.
|
||||||
func (r *reader) GetPurevpnCities() (cities []string, err error) {
|
func (r *reader) GetPurevpnCities() (cities []string, err error) {
|
||||||
choices := append(constants.PurevpnCityChoices(), "")
|
choices := append(constants.PurevpnCityChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("CITY", choices)
|
return r.envParams.GetCSVInPossibilities("CITY", choices)
|
||||||
|
|||||||
@@ -7,19 +7,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetShadowSocks obtains if ShadowSocks is on from the environment variable
|
// GetShadowSocks obtains if ShadowSocks is on from the environment variable
|
||||||
// SHADOWSOCKS
|
// SHADOWSOCKS.
|
||||||
func (r *reader) GetShadowSocks() (activated bool, err error) {
|
func (r *reader) GetShadowSocks() (activated bool, err error) {
|
||||||
return r.envParams.GetOnOff("SHADOWSOCKS", libparams.Default("off"))
|
return r.envParams.GetOnOff("SHADOWSOCKS", libparams.Default("off"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetShadowSocksLog obtains the ShadowSocks log level from the environment variable
|
// GetShadowSocksLog obtains the ShadowSocks log level from the environment variable
|
||||||
// SHADOWSOCKS_LOG
|
// SHADOWSOCKS_LOG.
|
||||||
func (r *reader) GetShadowSocksLog() (activated bool, err error) {
|
func (r *reader) GetShadowSocksLog() (activated bool, err error) {
|
||||||
return r.envParams.GetOnOff("SHADOWSOCKS_LOG", libparams.Default("off"))
|
return r.envParams.GetOnOff("SHADOWSOCKS_LOG", libparams.Default("off"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetShadowSocksPort obtains the ShadowSocks listening port from the environment variable
|
// GetShadowSocksPort obtains the ShadowSocks listening port from the environment variable
|
||||||
// SHADOWSOCKS_PORT
|
// SHADOWSOCKS_PORT.
|
||||||
func (r *reader) GetShadowSocksPort() (port uint16, err error) {
|
func (r *reader) GetShadowSocksPort() (port uint16, err error) {
|
||||||
portStr, err := r.envParams.GetEnv("SHADOWSOCKS_PORT", libparams.Default("8388"))
|
portStr, err := r.envParams.GetEnv("SHADOWSOCKS_PORT", libparams.Default("8388"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -33,7 +33,7 @@ func (r *reader) GetShadowSocksPort() (port uint16, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetShadowSocksPassword obtains the ShadowSocks server password from the environment variable
|
// GetShadowSocksPassword obtains the ShadowSocks server password from the environment variable
|
||||||
// SHADOWSOCKS_PASSWORD
|
// SHADOWSOCKS_PASSWORD.
|
||||||
func (r *reader) GetShadowSocksPassword() (password string, err error) {
|
func (r *reader) GetShadowSocksPassword() (password string, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
unsetErr := r.unsetEnv("SHADOWSOCKS_PASSWORD")
|
unsetErr := r.unsetEnv("SHADOWSOCKS_PASSWORD")
|
||||||
@@ -45,7 +45,7 @@ func (r *reader) GetShadowSocksPassword() (password string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetShadowSocksMethod obtains the ShadowSocks method to use from the environment variable
|
// GetShadowSocksMethod obtains the ShadowSocks method to use from the environment variable
|
||||||
// SHADOWSOCKS_METHOD
|
// SHADOWSOCKS_METHOD.
|
||||||
func (r *reader) GetShadowSocksMethod() (method string, err error) {
|
func (r *reader) GetShadowSocksMethod() (method string, err error) {
|
||||||
return r.envParams.GetEnv("SHADOWSOCKS_METHOD", libparams.Default("chacha20-ietf-poly1305"))
|
return r.envParams.GetEnv("SHADOWSOCKS_METHOD", libparams.Default("chacha20-ietf-poly1305"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetSurfsharkRegions obtains the regions for the Surfshark servers from the
|
// GetSurfsharkRegions obtains the regions for the Surfshark servers from the
|
||||||
// environment variable REGION
|
// environment variable REGION.
|
||||||
func (r *reader) GetSurfsharkRegions() (regions []string, err error) {
|
func (r *reader) GetSurfsharkRegions() (regions []string, err error) {
|
||||||
choices := append(constants.SurfsharkRegionChoices(), "")
|
choices := append(constants.SurfsharkRegionChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
||||||
|
|||||||
@@ -5,24 +5,25 @@ import (
|
|||||||
libparams "github.com/qdm12/golibs/params"
|
libparams "github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetUID obtains the user ID to use from the environment variable UID
|
// GetUID obtains the user ID to use from the environment variable UID.
|
||||||
func (r *reader) GetUID() (uid int, err error) {
|
func (r *reader) GetUID() (uid int, err error) {
|
||||||
return r.envParams.GetEnvIntRange("UID", 0, 65535, libparams.Default("1000"))
|
return r.envParams.GetEnvIntRange("UID", 0, 65535, libparams.Default("1000"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGID obtains the group ID to use from the environment variable GID
|
// GetGID obtains the group ID to use from the environment variable GID.
|
||||||
func (r *reader) GetGID() (gid int, err error) {
|
func (r *reader) GetGID() (gid int, err error) {
|
||||||
return r.envParams.GetEnvIntRange("GID", 0, 65535, libparams.Default("1000"))
|
return r.envParams.GetEnvIntRange("GID", 0, 65535, libparams.Default("1000"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTZ obtains the timezone from the environment variable TZ
|
// GetTZ obtains the timezone from the environment variable TZ.
|
||||||
func (r *reader) GetTimezone() (timezone string, err error) {
|
func (r *reader) GetTimezone() (timezone string, err error) {
|
||||||
return r.envParams.GetEnv("TZ")
|
return r.envParams.GetEnv("TZ")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIPStatusFilepath obtains the IP status file path
|
// GetIPStatusFilepath obtains the IP status file path
|
||||||
// from the environment variable IP_STATUS_FILE
|
// from the environment variable IP_STATUS_FILE.
|
||||||
func (r *reader) GetIPStatusFilepath() (filepath models.Filepath, err error) {
|
func (r *reader) GetIPStatusFilepath() (filepath models.Filepath, err error) {
|
||||||
filepathStr, err := r.envParams.GetPath("IP_STATUS_FILE", libparams.Default("/tmp/gluetun/ip"), libparams.CaseSensitiveValue())
|
filepathStr, err := r.envParams.GetPath("IP_STATUS_FILE",
|
||||||
|
libparams.Default("/tmp/gluetun/ip"), libparams.CaseSensitiveValue())
|
||||||
return models.Filepath(filepathStr), err
|
return models.Filepath(filepathStr), err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetTinyProxy obtains if TinyProxy is on from the environment variable
|
// GetTinyProxy obtains if TinyProxy is on from the environment variable
|
||||||
// TINYPROXY, and using PROXY as a retro-compatibility name
|
// TINYPROXY, and using PROXY as a retro-compatibility name.
|
||||||
func (r *reader) GetTinyProxy() (activated bool, err error) {
|
func (r *reader) GetTinyProxy() (activated bool, err error) {
|
||||||
// Retro-compatibility
|
// Retro-compatibility
|
||||||
s, err := r.envParams.GetEnv("PROXY")
|
s, err := r.envParams.GetEnv("PROXY")
|
||||||
@@ -22,23 +22,27 @@ func (r *reader) GetTinyProxy() (activated bool, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTinyProxyLog obtains the TinyProxy log level from the environment variable
|
// GetTinyProxyLog obtains the TinyProxy log level from the environment variable
|
||||||
// TINYPROXY_LOG, and using PROXY_LOG_LEVEL as a retro-compatibility name
|
// TINYPROXY_LOG, and using PROXY_LOG_LEVEL as a retro-compatibility name.
|
||||||
func (r *reader) GetTinyProxyLog() (models.TinyProxyLogLevel, error) {
|
func (r *reader) GetTinyProxyLog() (models.TinyProxyLogLevel, error) {
|
||||||
// Retro-compatibility
|
// Retro-compatibility
|
||||||
s, err := r.envParams.GetEnv("PROXY_LOG_LEVEL")
|
s, err := r.envParams.GetEnv("PROXY_LOG_LEVEL")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return models.TinyProxyLogLevel(s), err
|
return models.TinyProxyLogLevel(s), err
|
||||||
} else if len(s) != 0 {
|
} else if len(s) != 0 {
|
||||||
r.logger.Warn("You are using the old environment variable PROXY_LOG_LEVEL, please consider changing it to TINYPROXY_LOG")
|
r.logger.Warn("You are using the old environment variable PROXY_LOG_LEVEL, please consider changing it to TINYPROXY_LOG") //nolint:lll
|
||||||
s, err = r.envParams.GetValueIfInside("PROXY_LOG_LEVEL", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Compulsory())
|
s, err = r.envParams.GetValueIfInside("PROXY_LOG_LEVEL",
|
||||||
|
[]string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"},
|
||||||
|
libparams.Compulsory())
|
||||||
return models.TinyProxyLogLevel(s), err
|
return models.TinyProxyLogLevel(s), err
|
||||||
}
|
}
|
||||||
s, err = r.envParams.GetValueIfInside("TINYPROXY_LOG", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Default("Connect"))
|
s, err = r.envParams.GetValueIfInside("TINYPROXY_LOG",
|
||||||
|
[]string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"},
|
||||||
|
libparams.Default("Connect"))
|
||||||
return models.TinyProxyLogLevel(s), err
|
return models.TinyProxyLogLevel(s), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTinyProxyPort obtains the TinyProxy listening port from the environment variable
|
// GetTinyProxyPort obtains the TinyProxy listening port from the environment variable
|
||||||
// TINYPROXY_PORT, and using PROXY_PORT as a retro-compatibility name
|
// TINYPROXY_PORT, and using PROXY_PORT as a retro-compatibility name.
|
||||||
func (r *reader) GetTinyProxyPort() (port uint16, err error) {
|
func (r *reader) GetTinyProxyPort() (port uint16, err error) {
|
||||||
// Retro-compatibility
|
// Retro-compatibility
|
||||||
portStr, err := r.envParams.GetEnv("PROXY_PORT")
|
portStr, err := r.envParams.GetEnv("PROXY_PORT")
|
||||||
@@ -61,7 +65,7 @@ func (r *reader) GetTinyProxyPort() (port uint16, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTinyProxyUser obtains the TinyProxy server user from the environment variable
|
// GetTinyProxyUser obtains the TinyProxy server user from the environment variable
|
||||||
// TINYPROXY_USER, and using PROXY_USER as a retro-compatibility name
|
// TINYPROXY_USER, and using PROXY_USER as a retro-compatibility name.
|
||||||
func (r *reader) GetTinyProxyUser() (user string, err error) {
|
func (r *reader) GetTinyProxyUser() (user string, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
unsetErr := r.unsetEnv("PROXY_USER")
|
unsetErr := r.unsetEnv("PROXY_USER")
|
||||||
@@ -88,7 +92,7 @@ func (r *reader) GetTinyProxyUser() (user string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTinyProxyPassword obtains the TinyProxy server password from the environment variable
|
// GetTinyProxyPassword obtains the TinyProxy server password from the environment variable
|
||||||
// TINYPROXY_PASSWORD, and using PROXY_PASSWORD as a retro-compatibility name
|
// TINYPROXY_PASSWORD, and using PROXY_PASSWORD as a retro-compatibility name.
|
||||||
func (r *reader) GetTinyProxyPassword() (password string, err error) {
|
func (r *reader) GetTinyProxyPassword() (password string, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
unsetErr := r.unsetEnv("PROXY_PASSWORD")
|
unsetErr := r.unsetEnv("PROXY_PASSWORD")
|
||||||
@@ -109,7 +113,7 @@ func (r *reader) GetTinyProxyPassword() (password string, err error) {
|
|||||||
return password, err
|
return password, err
|
||||||
}
|
}
|
||||||
if len(password) != 0 {
|
if len(password) != 0 {
|
||||||
r.logger.Warn("You are using the old environment variable PROXY_PASSWORD, please consider changing it to TINYPROXY_PASSWORD")
|
r.logger.Warn("You are using the old environment variable PROXY_PASSWORD, please consider changing it to TINYPROXY_PASSWORD") //nolint:lll
|
||||||
return password, nil
|
return password, nil
|
||||||
}
|
}
|
||||||
return r.envParams.GetEnv("TINYPROXY_PASSWORD", libparams.CaseSensitiveValue())
|
return r.envParams.GetEnv("TINYPROXY_PASSWORD", libparams.CaseSensitiveValue())
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetUpdaterPeriod obtains the period to fetch the servers information when the tunnel is up.
|
// GetUpdaterPeriod obtains the period to fetch the servers information when the tunnel is up.
|
||||||
// Set to 0 to disable
|
// Set to 0 to disable.
|
||||||
func (r *reader) GetUpdaterPeriod() (period time.Duration, err error) {
|
func (r *reader) GetUpdaterPeriod() (period time.Duration, err error) {
|
||||||
s, err := r.envParams.GetEnv("UPDATER_PERIOD", libparams.Default("0"))
|
s, err := r.envParams.GetEnv("UPDATER_PERIOD", libparams.Default("0"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetVyprvpnRegions obtains the regions for the Vyprvpn servers from the
|
// GetVyprvpnRegions obtains the regions for the Vyprvpn servers from the
|
||||||
// environment variable REGION
|
// environment variable REGION.
|
||||||
func (r *reader) GetVyprvpnRegions() (regions []string, err error) {
|
func (r *reader) GetVyprvpnRegions() (regions []string, err error) {
|
||||||
choices := append(constants.VyprvpnRegionChoices(), "")
|
choices := append(constants.VyprvpnRegionChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
||||||
|
|||||||
@@ -9,14 +9,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetWindscribeRegions obtains the regions for the Windscribe servers from the
|
// GetWindscribeRegions obtains the regions for the Windscribe servers from the
|
||||||
// environment variable REGION
|
// environment variable REGION.
|
||||||
func (r *reader) GetWindscribeRegions() (regions []string, err error) {
|
func (r *reader) GetWindscribeRegions() (regions []string, err error) {
|
||||||
choices := append(constants.WindscribeRegionChoices(), "")
|
choices := append(constants.WindscribeRegionChoices(), "")
|
||||||
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
return r.envParams.GetCSVInPossibilities("REGION", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
||||||
// environment variable PORT
|
// environment variable PORT.
|
||||||
|
//nolint:gomnd
|
||||||
func (r *reader) GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error) {
|
func (r *reader) GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error) {
|
||||||
n, err := r.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
|
n, err := r.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -39,27 +39,31 @@ func (c *cyberghost) filterServers(regions []string, group string) (servers []mo
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cyberghost) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) {
|
func (c *cyberghost) GetOpenVPNConnection(selection models.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
|
const httpsPort = 443
|
||||||
if selection.TargetIP != nil {
|
if selection.TargetIP != nil {
|
||||||
return models.OpenVPNConnection{IP: selection.TargetIP, Port: 443, Protocol: selection.Protocol}, nil
|
return models.OpenVPNConnection{IP: selection.TargetIP, Port: httpsPort, Protocol: selection.Protocol}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
servers := c.filterServers(selection.Regions, selection.Group)
|
servers := c.filterServers(selection.Regions, selection.Group)
|
||||||
if len(servers) == 0 {
|
if len(servers) == 0 {
|
||||||
return connection, fmt.Errorf("no server found for regions %s and group %q", commaJoin(selection.Regions), selection.Group)
|
return connection,
|
||||||
|
fmt.Errorf("no server found for regions %s and group %q", commaJoin(selection.Regions), selection.Group)
|
||||||
}
|
}
|
||||||
|
|
||||||
var connections []models.OpenVPNConnection
|
var connections []models.OpenVPNConnection
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
for _, IP := range server.IPs {
|
for _, IP := range server.IPs {
|
||||||
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: 443, Protocol: selection.Protocol})
|
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: httpsPort, Protocol: selection.Protocol})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pickRandomConnection(connections, c.randSource), nil
|
return pickRandomConnection(connections, c.randSource), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cyberghost) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
func (c *cyberghost) BuildConf(connection models.OpenVPNConnection, verbosity,
|
||||||
|
uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
if len(cipher) == 0 {
|
if len(cipher) == 0 {
|
||||||
cipher = aes256cbc
|
cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ func (m *mullvad) filterServers(countries, cities, isps []string, owned bool) (s
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mullvad) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) {
|
func (m *mullvad) GetOpenVPNConnection(selection models.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
var defaultPort uint16 = 1194
|
var defaultPort uint16 = 1194
|
||||||
if selection.Protocol == constants.TCP {
|
if selection.Protocol == constants.TCP {
|
||||||
defaultPort = 443
|
defaultPort = 443
|
||||||
@@ -71,7 +72,8 @@ func (m *mullvad) GetOpenVPNConnection(selection models.ServerSelection) (connec
|
|||||||
return pickRandomConnection(connections, m.randSource), nil
|
return pickRandomConnection(connections, m.randSource), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mullvad) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
func (m *mullvad) BuildConf(connection models.OpenVPNConnection,
|
||||||
|
verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
if len(cipher) == 0 {
|
if len(cipher) == 0 {
|
||||||
cipher = aes256cbc
|
cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ func newNordvpn(servers []models.NordvpnServer, timeNow timeNowFunc) *nordvpn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *nordvpn) filterServers(regions []string, protocol models.NetworkProtocol, numbers []uint16) (servers []models.NordvpnServer) {
|
func (n *nordvpn) filterServers(regions []string, protocol models.NetworkProtocol, numbers []uint16) (
|
||||||
|
servers []models.NordvpnServer) {
|
||||||
numbersStr := make([]string, len(numbers))
|
numbersStr := make([]string, len(numbers))
|
||||||
for i := range numbers {
|
for i := range numbers {
|
||||||
numbersStr[i] = fmt.Sprintf("%d", numbers[i])
|
numbersStr[i] = fmt.Sprintf("%d", numbers[i])
|
||||||
@@ -46,7 +47,8 @@ func (n *nordvpn) filterServers(regions []string, protocol models.NetworkProtoco
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *nordvpn) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) { //nolint:dupl
|
func (n *nordvpn) GetOpenVPNConnection(selection models.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
case selection.Protocol == constants.UDP:
|
case selection.Protocol == constants.UDP:
|
||||||
@@ -63,18 +65,21 @@ func (n *nordvpn) GetOpenVPNConnection(selection models.ServerSelection) (connec
|
|||||||
|
|
||||||
servers := n.filterServers(selection.Regions, selection.Protocol, selection.Numbers)
|
servers := n.filterServers(selection.Regions, selection.Protocol, selection.Numbers)
|
||||||
if len(servers) == 0 {
|
if len(servers) == 0 {
|
||||||
return connection, fmt.Errorf("no server found for region %s, protocol %s and numbers %v", commaJoin(selection.Regions), selection.Protocol, selection.Numbers)
|
return connection, fmt.Errorf("no server found for region %s, protocol %s and numbers %v",
|
||||||
|
commaJoin(selection.Regions), selection.Protocol, selection.Numbers)
|
||||||
}
|
}
|
||||||
|
|
||||||
connections := make([]models.OpenVPNConnection, len(servers))
|
connections := make([]models.OpenVPNConnection, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
connections = append(connections, models.OpenVPNConnection{IP: servers[i].IP, Port: port, Protocol: selection.Protocol})
|
connection := models.OpenVPNConnection{IP: servers[i].IP, Port: port, Protocol: selection.Protocol}
|
||||||
|
connections = append(connections, connection)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pickRandomConnection(connections, n.randSource), nil
|
return pickRandomConnection(connections, n.randSource), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *nordvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { //nolint:dupl
|
func (n *nordvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
|
||||||
|
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
if len(cipher) == 0 {
|
if len(cipher) == 0 {
|
||||||
cipher = aes256cbc
|
cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-13
@@ -8,27 +8,27 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildPIAConf(connection models.OpenVPNConnection, verbosity int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
func buildPIAConf(connection models.OpenVPNConnection, verbosity int, root bool, cipher, auth string,
|
||||||
|
extras models.ExtraConfigOptions) (lines []string) {
|
||||||
var X509CRL, certificate string
|
var X509CRL, certificate string
|
||||||
|
var defaultCipher, defaultAuth string
|
||||||
if extras.EncryptionPreset == constants.PIAEncryptionPresetNormal {
|
if extras.EncryptionPreset == constants.PIAEncryptionPresetNormal {
|
||||||
if len(cipher) == 0 {
|
defaultCipher = "aes-128-cbc"
|
||||||
cipher = "aes-128-cbc"
|
defaultAuth = "sha1"
|
||||||
}
|
|
||||||
if len(auth) == 0 {
|
|
||||||
auth = "sha1"
|
|
||||||
}
|
|
||||||
X509CRL = constants.PiaX509CRLNormal
|
X509CRL = constants.PiaX509CRLNormal
|
||||||
certificate = constants.PIACertificateNormal
|
certificate = constants.PIACertificateNormal
|
||||||
} else { // strong encryption
|
} else { // strong encryption
|
||||||
if len(cipher) == 0 {
|
defaultCipher = aes256cbc
|
||||||
cipher = aes256cbc
|
defaultAuth = "sha256"
|
||||||
}
|
|
||||||
if len(auth) == 0 {
|
|
||||||
auth = "sha256"
|
|
||||||
}
|
|
||||||
X509CRL = constants.PiaX509CRLStrong
|
X509CRL = constants.PiaX509CRLStrong
|
||||||
certificate = constants.PIACertificateStrong
|
certificate = constants.PIACertificateStrong
|
||||||
}
|
}
|
||||||
|
if len(cipher) == 0 {
|
||||||
|
cipher = defaultCipher
|
||||||
|
}
|
||||||
|
if len(auth) == 0 {
|
||||||
|
auth = defaultAuth
|
||||||
|
}
|
||||||
lines = []string{
|
lines = []string{
|
||||||
"client",
|
"client",
|
||||||
"dev tun",
|
"dev tun",
|
||||||
|
|||||||
+15
-10
@@ -30,7 +30,8 @@ func newPrivateInternetAccessV3(servers []models.PIAOldServer, timeNow timeNowFu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *piaV3) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) {
|
func (p *piaV3) GetOpenVPNConnection(selection models.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch selection.Protocol {
|
switch selection.Protocol {
|
||||||
case constants.TCP:
|
case constants.TCP:
|
||||||
@@ -49,7 +50,9 @@ func (p *piaV3) GetOpenVPNConnection(selection models.ServerSelection) (connecti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
return connection, fmt.Errorf("combination of protocol %q and encryption %q does not yield any port number", selection.Protocol, selection.EncryptionPreset)
|
return connection, fmt.Errorf(
|
||||||
|
"combination of protocol %q and encryption %q does not yield any port number",
|
||||||
|
selection.Protocol, selection.EncryptionPreset)
|
||||||
}
|
}
|
||||||
|
|
||||||
if selection.TargetIP != nil {
|
if selection.TargetIP != nil {
|
||||||
@@ -71,20 +74,22 @@ func (p *piaV3) GetOpenVPNConnection(selection models.ServerSelection) (connecti
|
|||||||
return pickRandomConnection(connections, p.randSource), nil
|
return pickRandomConnection(connections, p.randSource), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *piaV3) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
func (p *piaV3) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int,
|
||||||
|
root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
return buildPIAConf(connection, verbosity, root, cipher, auth, extras)
|
return buildPIAConf(connection, verbosity, root, cipher, auth, extras)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *piaV3) PortForward(ctx context.Context, client *http.Client,
|
func (p *piaV3) PortForward(ctx context.Context, client *http.Client,
|
||||||
fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,
|
fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,
|
||||||
syncState func(port uint16) (pfFilepath models.Filepath)) {
|
syncState func(port uint16) (pfFilepath models.Filepath)) {
|
||||||
b := make([]byte, 32)
|
const uuidLength = 32
|
||||||
|
b := make([]byte, uuidLength)
|
||||||
n, err := rand.New(p.randSource).Read(b) //nolint:gosec
|
n, err := rand.New(p.randSource).Read(b) //nolint:gosec
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pfLogger.Error(err)
|
pfLogger.Error(err)
|
||||||
return
|
return
|
||||||
} else if n != 32 {
|
} else if n != uuidLength {
|
||||||
pfLogger.Error("only read %d bytes instead of 32", n)
|
pfLogger.Error("only read %d bytes instead of %d", n, uuidLength)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clientID := hex.EncodeToString(b)
|
clientID := hex.EncodeToString(b)
|
||||||
@@ -96,7 +101,7 @@ func (p *piaV3) PortForward(ctx context.Context, client *http.Client,
|
|||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
if response.StatusCode != http.StatusOK {
|
if response.StatusCode != http.StatusOK {
|
||||||
pfLogger.Error(fmt.Errorf("%s for %s; does your PIA server support port forwarding?", response.Status, url))
|
pfLogger.Error("%s for %s; does your PIA server support port forwarding?", response.Status, url)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b, err = ioutil.ReadAll(response.Body)
|
b, err = ioutil.ReadAll(response.Body)
|
||||||
@@ -104,14 +109,14 @@ func (p *piaV3) PortForward(ctx context.Context, client *http.Client,
|
|||||||
pfLogger.Error(err)
|
pfLogger.Error(err)
|
||||||
return
|
return
|
||||||
} else if len(b) == 0 {
|
} else if len(b) == 0 {
|
||||||
pfLogger.Error(fmt.Errorf("port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding"))
|
pfLogger.Error("port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding") //nolint:lll
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
body := struct {
|
body := struct {
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
}{}
|
}{}
|
||||||
if err := json.Unmarshal(b, &body); err != nil {
|
if err := json.Unmarshal(b, &body); err != nil {
|
||||||
pfLogger.Error(fmt.Errorf("port forwarding response: %w", err))
|
pfLogger.Error("port forwarding response: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
port := body.Port
|
port := body.Port
|
||||||
@@ -120,7 +125,7 @@ func (p *piaV3) PortForward(ctx context.Context, client *http.Client,
|
|||||||
pfLogger.Info("Writing port to %s", filepath)
|
pfLogger.Info("Writing port to %s", filepath)
|
||||||
if err := fileManager.WriteToFile(
|
if err := fileManager.WriteToFile(
|
||||||
string(filepath), []byte(fmt.Sprintf("%d", port)),
|
string(filepath), []byte(fmt.Sprintf("%d", port)),
|
||||||
files.Permissions(0666),
|
files.Permissions(constants.AllReadWritePermissions),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
pfLogger.Error(err)
|
pfLogger.Error(err)
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-11
@@ -40,7 +40,8 @@ func newPrivateInternetAccessV4(servers []models.PIAServer, timeNow timeNowFunc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *piaV4) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) {
|
func (p *piaV4) GetOpenVPNConnection(selection models.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch selection.Protocol {
|
switch selection.Protocol {
|
||||||
case constants.TCP:
|
case constants.TCP:
|
||||||
@@ -59,7 +60,9 @@ func (p *piaV4) GetOpenVPNConnection(selection models.ServerSelection) (connecti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
return connection, fmt.Errorf("combination of protocol %q and encryption %q does not yield any port number", selection.Protocol, selection.EncryptionPreset)
|
return connection, fmt.Errorf(
|
||||||
|
"combination of protocol %q and encryption %q does not yield any port number",
|
||||||
|
selection.Protocol, selection.EncryptionPreset)
|
||||||
}
|
}
|
||||||
|
|
||||||
if selection.TargetIP != nil {
|
if selection.TargetIP != nil {
|
||||||
@@ -107,7 +110,8 @@ func (p *piaV4) GetOpenVPNConnection(selection models.ServerSelection) (connecti
|
|||||||
return connection, nil
|
return connection, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *piaV4) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
func (p *piaV4) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
|
||||||
|
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
return buildPIAConf(connection, verbosity, root, cipher, auth, extras)
|
return buildPIAConf(connection, verbosity, root, cipher, auth, extras)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +178,7 @@ func (p *piaV4) PortForward(ctx context.Context, client *http.Client,
|
|||||||
pfLogger.Info("Writing port to %s", filepath)
|
pfLogger.Info("Writing port to %s", filepath)
|
||||||
if err := fileManager.WriteToFile(
|
if err := fileManager.WriteToFile(
|
||||||
string(filepath), []byte(fmt.Sprintf("%d", data.Port)),
|
string(filepath), []byte(fmt.Sprintf("%d", data.Port)),
|
||||||
files.Permissions(0666),
|
files.Permissions(constants.AllReadWritePermissions),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
pfLogger.Error(err)
|
pfLogger.Error(err)
|
||||||
}
|
}
|
||||||
@@ -230,7 +234,7 @@ func (p *piaV4) PortForward(ctx context.Context, client *http.Client,
|
|||||||
pfLogger.Info("Writing port to %s", filepath)
|
pfLogger.Info("Writing port to %s", filepath)
|
||||||
if err := fileManager.WriteToFile(
|
if err := fileManager.WriteToFile(
|
||||||
string(filepath), []byte(fmt.Sprintf("%d", data.Port)),
|
string(filepath), []byte(fmt.Sprintf("%d", data.Port)),
|
||||||
files.Permissions(0666),
|
files.Permissions(constants.AllReadWritePermissions),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
pfLogger.Error(err)
|
pfLogger.Error(err)
|
||||||
}
|
}
|
||||||
@@ -274,6 +278,7 @@ func newPIAv4HTTPClient(serverName string) (client *http.Client, err error) {
|
|||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
}
|
}
|
||||||
|
//nolint:gomnd
|
||||||
transport := http.Transport{
|
transport := http.Transport{
|
||||||
TLSClientConfig: TLSClientConfig,
|
TLSClientConfig: TLSClientConfig,
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
@@ -293,8 +298,9 @@ func newPIAv4HTTPClient(serverName string) (client *http.Client, err error) {
|
|||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshPIAPortForwardData(ctx context.Context, client *http.Client, gateway net.IP, fileManager files.FileManager) (data piaPortForwardData, err error) {
|
func refreshPIAPortForwardData(ctx context.Context, client *http.Client,
|
||||||
data.Token, err = fetchPIAToken(fileManager, client)
|
gateway net.IP, fileManager files.FileManager) (data piaPortForwardData, err error) {
|
||||||
|
data.Token, err = fetchPIAToken(ctx, fileManager, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data, fmt.Errorf("cannot obtain token: %w", err)
|
return data, fmt.Errorf("cannot obtain token: %w", err)
|
||||||
}
|
}
|
||||||
@@ -377,7 +383,7 @@ func packPIAPayload(port uint16, token string, expiration time.Time) (payload st
|
|||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchPIAToken(fileManager files.FileManager, client *http.Client) (token string, err error) {
|
func fetchPIAToken(ctx context.Context, fileManager files.FileManager, client *http.Client) (token string, err error) {
|
||||||
username, password, err := getOpenvpnCredentials(fileManager)
|
username, password, err := getOpenvpnCredentials(fileManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("cannot get Openvpn credentials: %w", err)
|
return "", fmt.Errorf("cannot get Openvpn credentials: %w", err)
|
||||||
@@ -388,7 +394,7 @@ func fetchPIAToken(fileManager files.FileManager, client *http.Client) (token st
|
|||||||
Host: "185.216.33.146",
|
Host: "185.216.33.146",
|
||||||
Path: "/authv3/generateToken",
|
Path: "/authv3/generateToken",
|
||||||
}
|
}
|
||||||
request, err := http.NewRequest(http.MethodGet, url.String(), nil)
|
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -423,14 +429,16 @@ func getOpenvpnCredentials(fileManager files.FileManager) (username, password st
|
|||||||
return "", "", fmt.Errorf("cannot read openvpn auth file: %w", err)
|
return "", "", fmt.Errorf("cannot read openvpn auth file: %w", err)
|
||||||
}
|
}
|
||||||
lines := strings.Split(string(authData), "\n")
|
lines := strings.Split(string(authData), "\n")
|
||||||
if len(lines) < 2 {
|
const minLines = 2
|
||||||
|
if len(lines) < minLines {
|
||||||
return "", "", fmt.Errorf("not enough lines (%d) in openvpn auth file", len(lines))
|
return "", "", fmt.Errorf("not enough lines (%d) in openvpn auth file", len(lines))
|
||||||
}
|
}
|
||||||
username, password = lines[0], lines[1]
|
username, password = lines[0], lines[1]
|
||||||
return username, password, nil
|
return username, password, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchPIAPortForwardData(ctx context.Context, client *http.Client, gateway net.IP, token string) (port uint16, signature string, expiration time.Time, err error) {
|
func fetchPIAPortForwardData(ctx context.Context, client *http.Client, gateway net.IP, token string) (
|
||||||
|
port uint16, signature string, expiration time.Time, err error) {
|
||||||
queryParams := url.Values{}
|
queryParams := url.Values{}
|
||||||
queryParams.Add("token", token)
|
queryParams.Add("token", token)
|
||||||
url := url.URL{
|
url := url.URL{
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ import (
|
|||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provider contains methods to read and modify the openvpn configuration to connect as a client
|
// Provider contains methods to read and modify the openvpn configuration to connect as a client.
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error)
|
GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error)
|
||||||
BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string)
|
BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int,
|
||||||
|
root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string)
|
||||||
PortForward(ctx context.Context, client *http.Client,
|
PortForward(ctx context.Context, client *http.Client,
|
||||||
fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,
|
fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,
|
||||||
syncState func(port uint16) (pfFilepath models.Filepath))
|
syncState func(port uint16) (pfFilepath models.Filepath))
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ func (p *purevpn) filterServers(regions, countries, cities []string) (servers []
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *purevpn) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) { //nolint:dupl
|
func (p *purevpn) GetOpenVPNConnection(selection models.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
case selection.Protocol == constants.UDP:
|
case selection.Protocol == constants.UDP:
|
||||||
@@ -71,7 +72,8 @@ func (p *purevpn) GetOpenVPNConnection(selection models.ServerSelection) (connec
|
|||||||
return pickRandomConnection(connections, p.randSource), nil
|
return pickRandomConnection(connections, p.randSource), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *purevpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { //nolint:dupl
|
func (p *purevpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
|
||||||
|
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
if len(cipher) == 0 {
|
if len(cipher) == 0 {
|
||||||
cipher = aes256cbc
|
cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ func (s *surfshark) filterServers(regions []string) (servers []models.SurfsharkS
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *surfshark) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) { //nolint:dupl
|
func (s *surfshark) GetOpenVPNConnection(selection models.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
case selection.Protocol == constants.TCP:
|
case selection.Protocol == constants.TCP:
|
||||||
@@ -72,7 +73,8 @@ func (s *surfshark) GetOpenVPNConnection(selection models.ServerSelection) (conn
|
|||||||
return pickRandomConnection(connections, s.randSource), nil
|
return pickRandomConnection(connections, s.randSource), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *surfshark) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { //nolint:dupl
|
func (s *surfshark) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
|
||||||
|
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
if len(cipher) == 0 {
|
if len(cipher) == 0 {
|
||||||
cipher = aes256cbc
|
cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ func (v *vyprvpn) filterServers(regions []string) (servers []models.VyprvpnServe
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vyprvpn) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) {
|
func (v *vyprvpn) GetOpenVPNConnection(selection models.ServerSelection) (
|
||||||
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
case selection.Protocol == constants.TCP:
|
case selection.Protocol == constants.TCP:
|
||||||
@@ -68,7 +69,8 @@ func (v *vyprvpn) GetOpenVPNConnection(selection models.ServerSelection) (connec
|
|||||||
return pickRandomConnection(connections, v.randSource), nil
|
return pickRandomConnection(connections, v.randSource), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vyprvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
func (v *vyprvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int,
|
||||||
|
root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
if len(cipher) == 0 {
|
if len(cipher) == 0 {
|
||||||
cipher = aes256cbc
|
cipher = aes256cbc
|
||||||
}
|
}
|
||||||
@@ -86,7 +88,7 @@ func (v *vyprvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid,
|
|||||||
"comp-lzo",
|
"comp-lzo",
|
||||||
"keepalive 10 60",
|
"keepalive 10 60",
|
||||||
// "verify-x509-name lu1.vyprvpn.com name",
|
// "verify-x509-name lu1.vyprvpn.com name",
|
||||||
"tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
|
"tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA", //nolint:lll
|
||||||
|
|
||||||
// Added constant values
|
// Added constant values
|
||||||
"auth-nocache",
|
"auth-nocache",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ func (w *windscribe) filterServers(regions []string) (servers []models.Windscrib
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func (w *windscribe) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) {
|
func (w *windscribe) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
@@ -71,7 +72,8 @@ func (w *windscribe) GetOpenVPNConnection(selection models.ServerSelection) (con
|
|||||||
return pickRandomConnection(connections, w.randSource), nil
|
return pickRandomConnection(connections, w.randSource), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *windscribe) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
func (w *windscribe) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int,
|
||||||
|
root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
if len(cipher) == 0 {
|
if len(cipher) == 0 {
|
||||||
cipher = aes256cbc
|
cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,10 +72,16 @@ func (l *looper) SetPeriod(period time.Duration) {
|
|||||||
|
|
||||||
func (l *looper) logAndWait(ctx context.Context, err error) {
|
func (l *looper) logAndWait(ctx context.Context, err error) {
|
||||||
l.logger.Error(err)
|
l.logger.Error(err)
|
||||||
l.logger.Info("retrying in 5 seconds")
|
const waitTime = 5 * time.Second
|
||||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
l.logger.Info("retrying in %s", waitTime)
|
||||||
defer cancel() // just for the linter
|
timer := time.NewTimer(waitTime)
|
||||||
<-ctx.Done()
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
case <-ctx.Done():
|
||||||
|
if !timer.Stop() {
|
||||||
|
<-timer.C
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
||||||
@@ -110,11 +116,12 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
l.logger.Info("Public IP address is %s", ip)
|
l.logger.Info("Public IP address is %s", ip)
|
||||||
|
const userReadWritePermissions = 0600
|
||||||
err = l.fileManager.WriteLinesToFile(
|
err = l.fileManager.WriteLinesToFile(
|
||||||
string(l.ipStatusFilepath),
|
string(l.ipStatusFilepath),
|
||||||
[]string{ip.String()},
|
[]string{ip.String()},
|
||||||
files.Ownership(l.uid, l.gid),
|
files.Ownership(l.uid, l.gid),
|
||||||
files.Permissions(0600))
|
files.Permissions(userReadWritePermissions))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.logAndWait(ctx, err)
|
l.logAndWait(ctx, err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,7 +27,8 @@ func parseRoutingEntry(s string) (r routingEntry, err error) {
|
|||||||
return fmt.Errorf("line %q: %w", s, err)
|
return fmt.Errorf("line %q: %w", s, err)
|
||||||
}
|
}
|
||||||
fields := strings.Fields(s)
|
fields := strings.Fields(s)
|
||||||
if len(fields) < 11 {
|
const minFields = 11
|
||||||
|
if len(fields) < minFields {
|
||||||
return r, wrapError(fmt.Errorf("not enough fields"))
|
return r, wrapError(fmt.Errorf("not enough fields"))
|
||||||
}
|
}
|
||||||
r.iface = fields[0]
|
r.iface = fields[0]
|
||||||
@@ -74,20 +74,22 @@ func parseRoutingEntry(s string) (r routingEntry, err error) {
|
|||||||
|
|
||||||
func reversedHexToIPv4(reversedHex string) (ip net.IP, err error) {
|
func reversedHexToIPv4(reversedHex string) (ip net.IP, err error) {
|
||||||
bytes, err := hex.DecodeString(reversedHex)
|
bytes, err := hex.DecodeString(reversedHex)
|
||||||
|
const nBytesRequired = 4
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot parse reversed IP hex %q: %s", reversedHex, err)
|
return nil, fmt.Errorf("cannot parse reversed IP hex %q: %s", reversedHex, err)
|
||||||
} else if len(bytes) != 4 {
|
} else if L := len(bytes); L != nBytesRequired {
|
||||||
return nil, fmt.Errorf("hex string contains %d bytes instead of 4", len(bytes))
|
return nil, fmt.Errorf("hex string contains %d bytes instead of %d", L, nBytesRequired)
|
||||||
}
|
}
|
||||||
return []byte{bytes[3], bytes[2], bytes[1], bytes[0]}, nil
|
return []byte{bytes[3], bytes[2], bytes[1], bytes[0]}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hexToIPv4Mask(hexString string) (mask net.IPMask, err error) {
|
func hexToIPv4Mask(hexString string) (mask net.IPMask, err error) {
|
||||||
bytes, err := hex.DecodeString(hexString)
|
bytes, err := hex.DecodeString(hexString)
|
||||||
|
const nBytesRequired = 4
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot parse hex mask %q: %s", hexString, err)
|
return nil, fmt.Errorf("cannot parse hex mask %q: %s", hexString, err)
|
||||||
} else if len(bytes) != 4 {
|
} else if L := len(bytes); L != nBytesRequired {
|
||||||
return nil, fmt.Errorf("hex string contains %d bytes instead of 4", len(bytes))
|
return nil, fmt.Errorf("hex string contains %d bytes instead of %d", L, nBytesRequired)
|
||||||
}
|
}
|
||||||
return []byte{bytes[3], bytes[2], bytes[1], bytes[0]}, nil
|
return []byte{bytes[3], bytes[2], bytes[1], bytes[0]}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func Test_parseRoutingEntry(t *testing.T) {
|
func Test_parseRoutingEntry(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package routing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *routing) AddRouteVia(ctx context.Context, subnet net.IPNet, defaultGateway net.IP, defaultInterface string) error {
|
func (r *routing) AddRouteVia(ctx context.Context,
|
||||||
|
subnet net.IPNet, defaultGateway net.IP, defaultInterface string) error {
|
||||||
subnetStr := subnet.String()
|
subnetStr := subnet.String()
|
||||||
r.logger.Info("adding %s as route via %s %s", subnetStr, defaultGateway, defaultInterface)
|
r.logger.Info("adding %s as route via %s %s", subnetStr, defaultGateway, defaultInterface)
|
||||||
exists, err := r.routeExists(subnet)
|
exists, err := r.routeExists(subnet)
|
||||||
@@ -19,9 +19,11 @@ func (r *routing) AddRouteVia(ctx context.Context, subnet net.IPNet, defaultGate
|
|||||||
if r.debug {
|
if r.debug {
|
||||||
fmt.Printf("ip route add %s via %s dev %s\n", subnetStr, defaultGateway, defaultInterface)
|
fmt.Printf("ip route add %s via %s dev %s\n", subnetStr, defaultGateway, defaultInterface)
|
||||||
}
|
}
|
||||||
output, err := r.commander.Run(ctx, "ip", "route", "add", subnetStr, "via", defaultGateway.String(), "dev", defaultInterface)
|
output, err := r.commander.Run(ctx,
|
||||||
|
"ip", "route", "add", subnetStr, "via", defaultGateway.String(), "dev", defaultInterface)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot add route for %s via %s %s %s: %s: %w", subnetStr, defaultGateway, "dev", defaultInterface, output, err)
|
return fmt.Errorf("cannot add route for %s via %s %s %s: %s: %w",
|
||||||
|
subnetStr, defaultGateway, "dev", defaultInterface, output, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ func Test_DeleteRouteVia(t *testing.T) {
|
|||||||
commander.EXPECT().Run(ctx, "ip", "route", "del", subnetStr).
|
commander.EXPECT().Run(ctx, "ip", "route", "del", subnetStr).
|
||||||
Return(tc.runOutput, tc.runErr).Times(1)
|
Return(tc.runOutput, tc.runErr).Times(1)
|
||||||
fileManager := mock_files.NewMockFileManager(mockCtrl)
|
fileManager := mock_files.NewMockFileManager(mockCtrl)
|
||||||
|
//nolint:lll
|
||||||
routesData := []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
routesData := []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||||
eth0 0002A8C0 0100000A 0003 0 0 0 00FFFFFF 0 0 0
|
eth0 0002A8C0 0100000A 0003 0 0 0 00FFFFFF 0 0 0
|
||||||
`)
|
`)
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ package routing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"net"
|
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
@@ -37,7 +36,8 @@ func (r *routing) DefaultRoute() (defaultInterface string, defaultGateway net.IP
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
if len(entries) < 2 {
|
const minEntries = 2
|
||||||
|
if len(entries) < minEntries {
|
||||||
return "", nil, fmt.Errorf("not enough entries (%d) found in %s", len(entries), constants.NetRoute)
|
return "", nil, fmt.Errorf("not enough entries (%d) found in %s", len(entries), constants.NetRoute)
|
||||||
}
|
}
|
||||||
var defaultRouteEntry routingEntry
|
var defaultRouteEntry routingEntry
|
||||||
@@ -61,7 +61,8 @@ func (r *routing) LocalSubnet() (defaultSubnet net.IPNet, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return defaultSubnet, err
|
return defaultSubnet, err
|
||||||
}
|
}
|
||||||
if len(entries) < 2 {
|
const minEntries = 2
|
||||||
|
if len(entries) < minEntries {
|
||||||
return defaultSubnet, fmt.Errorf("not enough entries (%d) found in %s", len(entries), constants.NetRoute)
|
return defaultSubnet, fmt.Errorf("not enough entries (%d) found in %s", len(entries), constants.NetRoute)
|
||||||
}
|
}
|
||||||
var localSubnetEntry routingEntry
|
var localSubnetEntry routingEntry
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/golibs/files/mock_files"
|
"github.com/qdm12/golibs/files/mock_files"
|
||||||
"github.com/qdm12/golibs/logging/mock_logging"
|
"github.com/qdm12/golibs/logging/mock_logging"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
const exampleRouteData = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
const exampleRouteData = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||||
tun0 00000000 050A030A 0003 0 0 0 00000080 0 0 0
|
tun0 00000000 050A030A 0003 0 0 0 00000080 0 0 0
|
||||||
eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0
|
eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0
|
||||||
@@ -24,6 +24,7 @@ tun0 00000080 050A030A 0003 0 0 0 00000080
|
|||||||
eth0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0
|
eth0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0
|
||||||
`
|
`
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func Test_parseRoutingTable(t *testing.T) {
|
func Test_parseRoutingTable(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
@@ -96,6 +97,7 @@ eth0 x 0100000A 0003 0 0 0 00FFFFFF 0 0 0
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func Test_DefaultRoute(t *testing.T) {
|
func Test_DefaultRoute(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
@@ -164,6 +166,7 @@ eth0 000011AC 00000000 0001 0 0 0 0000FFFF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func Test_LocalSubnet(t *testing.T) {
|
func Test_LocalSubnet(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
@@ -229,6 +232,7 @@ eth0 000011AC 10000000 0001 0 0 0 0000FFFF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func Test_routeExists(t *testing.T) {
|
func Test_routeExists(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
@@ -291,6 +295,7 @@ eth0 0002A8C0 0100000A 0003 0 0 0 00FFFFFF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
func Test_VPNDestinationIP(t *testing.T) {
|
func Test_VPNDestinationIP(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type routing struct {
|
|||||||
debug bool
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfigurator creates a new Configurator instance
|
// NewConfigurator creates a new Configurator instance.
|
||||||
func NewRouting(logger logging.Logger, fileManager files.FileManager) Routing {
|
func NewRouting(logger logging.Logger, fileManager files.FileManager) Routing {
|
||||||
return &routing{
|
return &routing{
|
||||||
commander: command.NewCommander(),
|
commander: command.NewCommander(),
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ type server struct {
|
|||||||
lookupIP func(host string) ([]net.IP, error)
|
lookupIP func(host string) ([]net.IP, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(address string, logging bool, logger logging.Logger, openvpnLooper openvpn.Looper, unboundLooper dns.Looper, updaterLooper updater.Looper) Server {
|
func New(address string, logging bool, logger logging.Logger,
|
||||||
|
openvpnLooper openvpn.Looper, unboundLooper dns.Looper, updaterLooper updater.Looper) Server {
|
||||||
return &server{
|
return &server{
|
||||||
address: address,
|
address: address,
|
||||||
logging: logging,
|
logging: logging,
|
||||||
@@ -47,7 +48,8 @@ func (s *server) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
s.logger.Warn("context canceled: exiting loop")
|
s.logger.Warn("context canceled: exiting loop")
|
||||||
defer s.logger.Warn("loop exited")
|
defer s.logger.Warn("loop exited")
|
||||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
const shutdownGraceDuration = 2 * time.Second
|
||||||
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownGraceDuration)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if err := server.Shutdown(shutdownCtx); err != nil {
|
if err := server.Shutdown(shutdownCtx); err != nil {
|
||||||
s.logger.Error("failed shutting down: %s", err)
|
s.logger.Error("failed shutting down: %s", err)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/params"
|
"github.com/qdm12/gluetun/internal/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNS contains settings to configure Unbound for DNS over TLS operation
|
// DNS contains settings to configure Unbound for DNS over TLS operation.
|
||||||
type DNS struct {
|
type DNS struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
KeepNameserver bool
|
KeepNameserver bool
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/params"
|
"github.com/qdm12/gluetun/internal/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Firewall contains settings to customize the firewall operation
|
// Firewall contains settings to customize the firewall operation.
|
||||||
type Firewall struct {
|
type Firewall struct {
|
||||||
AllowedSubnets []net.IPNet
|
AllowedSubnets []net.IPNet
|
||||||
VPNInputPorts []uint16
|
VPNInputPorts []uint16
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/params"
|
"github.com/qdm12/gluetun/internal/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OpenVPN contains settings to configure the OpenVPN client
|
// OpenVPN contains settings to configure the OpenVPN client.
|
||||||
type OpenVPN struct {
|
type OpenVPN struct {
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
Password string `json:"-"`
|
Password string `json:"-"`
|
||||||
@@ -20,7 +20,7 @@ type OpenVPN struct {
|
|||||||
Provider models.ProviderSettings `json:"provider"`
|
Provider models.ProviderSettings `json:"provider"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOpenVPNSettings obtains the OpenVPN settings using the params functions
|
// GetOpenVPNSettings obtains the OpenVPN settings using the params functions.
|
||||||
func GetOpenVPNSettings(paramsReader params.Reader, vpnProvider models.VPNProvider) (settings OpenVPN, err error) {
|
func GetOpenVPNSettings(paramsReader params.Reader, vpnProvider models.VPNProvider) (settings OpenVPN, err error) {
|
||||||
settings.User, err = paramsReader.GetUser()
|
settings.User, err = paramsReader.GetUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ func Test_OpenVPN_JSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
data, err := json.Marshal(in)
|
data, err := json.Marshal(in)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
//nolint:lll
|
||||||
assert.Equal(t, `{"user":"","verbosity":0,"runAsRoot":true,"cipher":"","auth":"","provider":{"name":"name","serverSelection":{"networkProtocol":"","regions":null,"group":"","countries":null,"cities":null,"isps":null,"owned":false,"customPort":0,"numbers":null,"encryptionPreset":""},"extraConfig":{"encryptionPreset":"","openvpnIPv6":false},"portForwarding":{"enabled":false,"filepath":""}}}`, string(data))
|
assert.Equal(t, `{"user":"","verbosity":0,"runAsRoot":true,"cipher":"","auth":"","provider":{"name":"name","serverSelection":{"networkProtocol":"","regions":null,"group":"","countries":null,"cities":null,"isps":null,"owned":false,"customPort":0,"numbers":null,"encryptionPreset":""},"extraConfig":{"encryptionPreset":"","openvpnIPv6":false},"portForwarding":{"enabled":false,"filepath":""}}}`, string(data))
|
||||||
var out OpenVPN
|
var out OpenVPN
|
||||||
err = json.Unmarshal(data, &out)
|
err = json.Unmarshal(data, &out)
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ func GetPIASettings(paramsReader params.Reader) (settings models.ProviderSetting
|
|||||||
return getPIASettings(paramsReader, constants.PrivateInternetAccess)
|
return getPIASettings(paramsReader, constants.PrivateInternetAccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPIAOldSettings obtains PIA settings for the older PIA servers (pre summer 2020) from environment variables using the params package.
|
// GetPIAOldSettings obtains PIA settings for the older PIA servers (pre summer 2020)
|
||||||
|
// from environment variables using the params package.
|
||||||
func GetPIAOldSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
func GetPIAOldSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
||||||
return getPIASettings(paramsReader, constants.PrivateInternetAccessOld)
|
return getPIASettings(paramsReader, constants.PrivateInternetAccessOld)
|
||||||
}
|
}
|
||||||
@@ -80,13 +81,13 @@ func GetMullvadSettings(paramsReader params.Reader) (settings models.ProviderSet
|
|||||||
}
|
}
|
||||||
if settings.ServerSelection.Protocol == constants.TCP {
|
if settings.ServerSelection.Protocol == constants.TCP {
|
||||||
switch settings.ServerSelection.CustomPort {
|
switch settings.ServerSelection.CustomPort {
|
||||||
case 0, 80, 443, 1401:
|
case 0, 80, 443, 1401: //nolint:gomnd
|
||||||
default:
|
default:
|
||||||
return settings, fmt.Errorf("port %d is not valid for TCP protocol", settings.ServerSelection.CustomPort)
|
return settings, fmt.Errorf("port %d is not valid for TCP protocol", settings.ServerSelection.CustomPort)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch settings.ServerSelection.CustomPort {
|
switch settings.ServerSelection.CustomPort {
|
||||||
case 0, 53, 1194, 1195, 1196, 1197, 1300, 1301, 1302, 1303, 1400:
|
case 0, 53, 1194, 1195, 1196, 1197, 1300, 1301, 1302, 1303, 1400: //nolint:gomnd
|
||||||
default:
|
default:
|
||||||
return settings, fmt.Errorf("port %d is not valid for UDP protocol", settings.ServerSelection.CustomPort)
|
return settings, fmt.Errorf("port %d is not valid for UDP protocol", settings.ServerSelection.CustomPort)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/params"
|
"github.com/qdm12/gluetun/internal/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ControlServer contains settings to customize the control server operation
|
// ControlServer contains settings to customize the control server operation.
|
||||||
type ControlServer struct {
|
type ControlServer struct {
|
||||||
Port uint16
|
Port uint16
|
||||||
Log bool
|
Log bool
|
||||||
@@ -22,7 +22,8 @@ func (c *ControlServer) String() string {
|
|||||||
return strings.Join(settingsList, "\n |--")
|
return strings.Join(settingsList, "\n |--")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetControlServerSettings obtains the HTTP control server settings from environment variables using the params package.
|
// GetControlServerSettings obtains the HTTP control server settings from
|
||||||
|
// environment variables using the params package.
|
||||||
func GetControlServerSettings(paramsReader params.Reader) (settings ControlServer, err error) {
|
func GetControlServerSettings(paramsReader params.Reader) (settings ControlServer, err error) {
|
||||||
settings.Port, err = paramsReader.GetControlServerPort()
|
settings.Port, err = paramsReader.GetControlServerPort()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const (
|
|||||||
disabled = "disabled"
|
disabled = "disabled"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Settings contains all settings for the program to run
|
// Settings contains all settings for the program to run.
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
VPNSP models.VPNProvider
|
VPNSP models.VPNProvider
|
||||||
OpenVPN OpenVPN
|
OpenVPN OpenVPN
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/params"
|
"github.com/qdm12/gluetun/internal/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShadowSocks contains settings to configure the Shadowsocks server
|
// ShadowSocks contains settings to configure the Shadowsocks server.
|
||||||
type ShadowSocks struct {
|
type ShadowSocks struct {
|
||||||
Method string
|
Method string
|
||||||
Password string
|
Password string
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/params"
|
"github.com/qdm12/gluetun/internal/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// System contains settings to configure system related elements
|
// System contains settings to configure system related elements.
|
||||||
type System struct {
|
type System struct {
|
||||||
UID int
|
UID int
|
||||||
GID int
|
GID int
|
||||||
@@ -16,7 +16,7 @@ type System struct {
|
|||||||
IPStatusFilepath models.Filepath
|
IPStatusFilepath models.Filepath
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSystemSettings obtains the System settings using the params functions
|
// GetSystemSettings obtains the System settings using the params functions.
|
||||||
func GetSystemSettings(paramsReader params.Reader) (settings System, err error) {
|
func GetSystemSettings(paramsReader params.Reader) (settings System, err error) {
|
||||||
settings.UID, err = paramsReader.GetUID()
|
settings.UID, err = paramsReader.GetUID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/params"
|
"github.com/qdm12/gluetun/internal/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TinyProxy contains settings to configure TinyProxy
|
// TinyProxy contains settings to configure TinyProxy.
|
||||||
type TinyProxy struct {
|
type TinyProxy struct {
|
||||||
User string
|
User string
|
||||||
Password string
|
Password string
|
||||||
|
|||||||
@@ -34,10 +34,16 @@ type looper struct {
|
|||||||
|
|
||||||
func (l *looper) logAndWait(ctx context.Context, err error) {
|
func (l *looper) logAndWait(ctx context.Context, err error) {
|
||||||
l.logger.Error(err)
|
l.logger.Error(err)
|
||||||
l.logger.Info("retrying in 1 minute")
|
const waitTime = time.Minute
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
l.logger.Info("retrying in %s", waitTime)
|
||||||
defer cancel() // just for the linter
|
timer := time.NewTimer(waitTime)
|
||||||
<-ctx.Done()
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
case <-ctx.Done():
|
||||||
|
if !timer.Stop() {
|
||||||
|
<-timer.C
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLooper(firewallConf firewall.Configurator, settings settings.ShadowSocks,
|
func NewLooper(firewallConf firewall.Configurator, settings settings.ShadowSocks,
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ func countServers(allServers models.AllServers) int {
|
|||||||
len(allServers.Windscribe.Servers)
|
len(allServers.Windscribe.Servers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) SyncServers(hardcodedServers models.AllServers, write bool) (allServers models.AllServers, err error) {
|
func (s *storage) SyncServers(hardcodedServers models.AllServers, write bool) (
|
||||||
|
allServers models.AllServers, err error) {
|
||||||
// Eventually read file
|
// Eventually read file
|
||||||
var serversOnFile models.AllServers
|
var serversOnFile models.AllServers
|
||||||
_, err = s.osStat(jsonFilepath)
|
_, err = s.osStat(jsonFilepath)
|
||||||
|
|||||||
@@ -13,14 +13,15 @@ func (c *configurator) Start(ctx context.Context) (stdout io.ReadCloser, waitFn
|
|||||||
return stdout, waitFn, err
|
return stdout, waitFn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version obtains the version of the installed Tinyproxy server
|
// Version obtains the version of the installed Tinyproxy server.
|
||||||
func (c *configurator) Version(ctx context.Context) (string, error) {
|
func (c *configurator) Version(ctx context.Context) (string, error) {
|
||||||
output, err := c.commander.Run(ctx, "tinyproxy", "-v")
|
output, err := c.commander.Run(ctx, "tinyproxy", "-v")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
words := strings.Fields(output)
|
words := strings.Fields(output)
|
||||||
if len(words) < 2 {
|
const minWords = 2
|
||||||
|
if len(words) < minWords {
|
||||||
return "", fmt.Errorf("tinyproxy -v: output is too short: %q", output)
|
return "", fmt.Errorf("tinyproxy -v: output is too short: %q", output)
|
||||||
}
|
}
|
||||||
return words[1], nil
|
return words[1], nil
|
||||||
|
|||||||
@@ -9,16 +9,18 @@ import (
|
|||||||
"github.com/qdm12/golibs/files"
|
"github.com/qdm12/golibs/files"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *configurator) MakeConf(logLevel models.TinyProxyLogLevel, port uint16, user, password string, uid, gid int) error {
|
func (c *configurator) MakeConf(logLevel models.TinyProxyLogLevel,
|
||||||
|
port uint16, user, password string, uid, gid int) error {
|
||||||
c.logger.Info("generating tinyproxy configuration file")
|
c.logger.Info("generating tinyproxy configuration file")
|
||||||
lines := generateConf(logLevel, port, user, password, uid, gid)
|
lines := generateConf(logLevel, port, user, password, uid, gid)
|
||||||
return c.fileManager.WriteLinesToFile(string(constants.TinyProxyConf),
|
return c.fileManager.WriteLinesToFile(string(constants.TinyProxyConf),
|
||||||
lines,
|
lines,
|
||||||
files.Ownership(uid, gid),
|
files.Ownership(uid, gid),
|
||||||
files.Permissions(0400))
|
files.Permissions(constants.UserReadPermission))
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateConf(logLevel models.TinyProxyLogLevel, port uint16, user, password string, uid, gid int) (lines []string) {
|
func generateConf(logLevel models.TinyProxyLogLevel, port uint16, user, password string, uid, gid int) (
|
||||||
|
lines []string) {
|
||||||
confMapping := map[string]string{
|
confMapping := map[string]string{
|
||||||
"User": fmt.Sprintf("%d", uid),
|
"User": fmt.Sprintf("%d", uid),
|
||||||
"Group": fmt.Sprintf("%d", gid),
|
"Group": fmt.Sprintf("%d", gid),
|
||||||
|
|||||||
@@ -37,10 +37,16 @@ type looper struct {
|
|||||||
|
|
||||||
func (l *looper) logAndWait(ctx context.Context, err error) {
|
func (l *looper) logAndWait(ctx context.Context, err error) {
|
||||||
l.logger.Error(err)
|
l.logger.Error(err)
|
||||||
l.logger.Info("retrying in 1 minute")
|
const waitTime = time.Minute
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
l.logger.Info("retrying in %s", waitTime)
|
||||||
defer cancel() // just for the linter
|
timer := time.NewTimer(waitTime)
|
||||||
<-ctx.Done()
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
case <-ctx.Done():
|
||||||
|
if !timer.Stop() {
|
||||||
|
<-timer.C
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLooper(conf Configurator, firewallConf firewall.Configurator, settings settings.TinyProxy,
|
func NewLooper(conf Configurator, firewallConf firewall.Configurator, settings settings.TinyProxy,
|
||||||
|
|||||||
@@ -3,10 +3,8 @@ package updater
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
httpGetFunc func(url string) (r *http.Response, err error)
|
|
||||||
lookupIPFunc func(ctx context.Context, host string) (ips []net.IP, err error)
|
lookupIPFunc func(ctx context.Context, host string) (ips []net.IP, err error)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -70,10 +70,16 @@ func (l *looper) SetPeriod(period time.Duration) {
|
|||||||
|
|
||||||
func (l *looper) logAndWait(ctx context.Context, err error) {
|
func (l *looper) logAndWait(ctx context.Context, err error) {
|
||||||
l.logger.Error(err)
|
l.logger.Error(err)
|
||||||
l.logger.Info("retrying in 5 minutes")
|
const waitTime = 5 * time.Minute
|
||||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
|
l.logger.Info("retrying in %s", waitTime)
|
||||||
defer cancel() // just for the linter
|
timer := time.NewTimer(waitTime)
|
||||||
<-ctx.Done()
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
case <-ctx.Done():
|
||||||
|
if !timer.Stop() {
|
||||||
|
<-timer.C
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
package updater
|
package updater
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (u *updater) updateMullvad() (err error) {
|
func (u *updater) updateMullvad(ctx context.Context) (err error) {
|
||||||
servers, err := findMullvadServers(u.httpGet)
|
servers, err := findMullvadServers(ctx, u.client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot update Mullvad servers: %w", err)
|
return fmt.Errorf("cannot update Mullvad servers: %w", err)
|
||||||
}
|
}
|
||||||
@@ -24,19 +25,14 @@ func (u *updater) updateMullvad() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func findMullvadServers(httpGet httpGetFunc) (servers []models.MullvadServer, err error) {
|
func findMullvadServers(ctx context.Context, client network.Client) (servers []models.MullvadServer, err error) {
|
||||||
const url = "https://api.mullvad.net/www/relays/openvpn/"
|
const url = "https://api.mullvad.net/www/relays/openvpn/"
|
||||||
response, err := httpGet(url)
|
bytes, status, err := client.Get(ctx, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
if status != http.StatusOK {
|
||||||
if response.StatusCode != http.StatusOK {
|
return nil, fmt.Errorf("HTTP status code %d", status)
|
||||||
return nil, fmt.Errorf(response.Status)
|
|
||||||
}
|
|
||||||
bytes, err := ioutil.ReadAll(response.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
var data []struct {
|
var data []struct {
|
||||||
Country string `json:"country_name"`
|
Country string `json:"country_name"`
|
||||||
@@ -89,7 +85,6 @@ func findMullvadServers(httpGet httpGetFunc) (servers []models.MullvadServer, er
|
|||||||
return servers, nil
|
return servers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:goconst
|
|
||||||
func stringifyMullvadServers(servers []models.MullvadServer) (s string) {
|
func stringifyMullvadServers(servers []models.MullvadServer) (s string) {
|
||||||
s = "func MullvadServers() []models.MullvadServer {\n"
|
s = "func MullvadServers() []models.MullvadServer {\n"
|
||||||
s += " return []models.MullvadServer{\n"
|
s += " return []models.MullvadServer{\n"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ func Test_stringifyMullvadServers(t *testing.T) {
|
|||||||
IPs: []net.IP{{1, 1, 1, 1}},
|
IPs: []net.IP{{1, 1, 1, 1}},
|
||||||
IPsV6: []net.IP{{1, 1, 1, 1}},
|
IPsV6: []net.IP{{1, 1, 1, 1}},
|
||||||
}}
|
}}
|
||||||
|
//nolint:lll
|
||||||
expected := `
|
expected := `
|
||||||
func MullvadServers() []models.MullvadServer {
|
func MullvadServers() []models.MullvadServer {
|
||||||
return []models.MullvadServer{
|
return []models.MullvadServer{
|
||||||
|
|||||||
+12
-14
@@ -1,9 +1,9 @@
|
|||||||
package updater
|
package updater
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -11,10 +11,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (u *updater) updateNordvpn() (err error) {
|
func (u *updater) updateNordvpn(ctx context.Context) (err error) {
|
||||||
servers, warnings, err := findNordvpnServers(u.httpGet)
|
servers, warnings, err := findNordvpnServers(ctx, u.client)
|
||||||
if u.options.CLI {
|
if u.options.CLI {
|
||||||
for _, warning := range warnings {
|
for _, warning := range warnings {
|
||||||
u.logger.Warn("Nordvpn: %s", warning)
|
u.logger.Warn("Nordvpn: %s", warning)
|
||||||
@@ -31,19 +32,15 @@ func (u *updater) updateNordvpn() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func findNordvpnServers(httpGet httpGetFunc) (servers []models.NordvpnServer, warnings []string, err error) {
|
func findNordvpnServers(ctx context.Context, client network.Client) (
|
||||||
|
servers []models.NordvpnServer, warnings []string, err error) {
|
||||||
const url = "https://nordvpn.com/api/server"
|
const url = "https://nordvpn.com/api/server"
|
||||||
response, err := httpGet(url)
|
bytes, status, err := client.Get(ctx, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
if status != http.StatusOK {
|
||||||
if response.StatusCode != http.StatusOK {
|
return nil, nil, fmt.Errorf("HTTP status code %d", status)
|
||||||
return nil, nil, fmt.Errorf(response.Status)
|
|
||||||
}
|
|
||||||
bytes, err := ioutil.ReadAll(response.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
}
|
||||||
var data []struct {
|
var data []struct {
|
||||||
IPAddress string `json:"ip_address"`
|
IPAddress string `json:"ip_address"`
|
||||||
@@ -71,7 +68,9 @@ func findNordvpnServers(httpGet httpGetFunc) (servers []models.NordvpnServer, wa
|
|||||||
}
|
}
|
||||||
ip := net.ParseIP(jsonServer.IPAddress)
|
ip := net.ParseIP(jsonServer.IPAddress)
|
||||||
if ip == nil || ip.To4() == nil {
|
if ip == nil || ip.To4() == nil {
|
||||||
return nil, nil, fmt.Errorf("IP address %q is not a valid IPv4 address for server %q", jsonServer.IPAddress, jsonServer.Name)
|
return nil, nil,
|
||||||
|
fmt.Errorf("IP address %q is not a valid IPv4 address for server %q",
|
||||||
|
jsonServer.IPAddress, jsonServer.Name)
|
||||||
}
|
}
|
||||||
i := strings.IndexRune(jsonServer.Name, '#')
|
i := strings.IndexRune(jsonServer.Name, '#')
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
@@ -94,7 +93,6 @@ func findNordvpnServers(httpGet httpGetFunc) (servers []models.NordvpnServer, wa
|
|||||||
return servers, warnings, nil
|
return servers, warnings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:goconst
|
|
||||||
func stringifyNordvpnServers(servers []models.NordvpnServer) (s string) {
|
func stringifyNordvpnServers(servers []models.NordvpnServer) (s string) {
|
||||||
s = "func NordvpnServers() []models.NordvpnServer {\n"
|
s = "func NordvpnServers() []models.NordvpnServer {\n"
|
||||||
s += " return []models.NordvpnServer{\n"
|
s += " return []models.NordvpnServer{\n"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user