diff --git a/.golangci.yml b/.golangci.yml index 5a5ec970..dd129421 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -7,30 +7,43 @@ linters-settings: linters: disable-all: true enable: + - asciicheck - bodyclose - deadcode - dogsled - dupl - errcheck + - exhaustive + - exportloopref + - gci - gochecknoglobals - gochecknoinits - gocognit - goconst - gocritic - gocyclo + - godot + - goheader - goimports - golint + - gomnd + - goprintffuncname - gosec - gosimple - govet - ineffassign - interfacer + - lll - maligned - misspell - nakedret + - nestif + - noctx + - nolintlint - prealloc - rowserrcheck - scopelint + - sqlclosecheck - staticcheck - structcheck - typecheck diff --git a/cmd/gluetun/main.go b/cmd/gluetun/main.go index 55fd2b45..526b6f85 100644 --- a/cmd/gluetun/main.go +++ b/cmd/gluetun/main.go @@ -73,8 +73,9 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go defer cancel() logger := createLogger() - httpClient := &http.Client{Timeout: 15 * time.Second} - client := network.NewClient(15 * time.Second) + const clientTimeout = 15 * time.Second + httpClient := &http.Client{Timeout: clientTimeout} + client := network.NewClient(clientTimeout) // Create configurators fileManager := files.NewFileManager() alpineConf := alpine.NewConfigurator(fileManager) @@ -205,7 +206,8 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go go openvpnLooper.Run(ctx, wg) 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) // wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker 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 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) go publicIPLooper.Run(ctx, wg) wg.Add(1) go publicIPLooper.RunRestartTicker(ctx, wg) 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 wg.Add(1) 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) 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) go httpServer.Run(ctx, wg) @@ -309,8 +314,10 @@ func createLogger() logging.Logger { return logger } -func printVersions(ctx context.Context, logger logging.Logger, versionFunctions map[string]func(ctx context.Context) (string, error)) { - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) +func printVersions(ctx context.Context, logger logging.Logger, + versionFunctions map[string]func(ctx context.Context) (string, error)) { + const timeout = 5 * time.Second + ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() for name, f := range versionFunctions { 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 logger.Info("Launching standard output merger") streamMerger.CollectLines(ctx, func(line string) { @@ -331,6 +340,8 @@ func collectStreamLines(ctx context.Context, streamMerger command.StreamMerger, return } switch level { + case logging.DebugLevel: + logger.Debug(line) case logging.InfoLevel: logger.Info(line) case logging.WarnLevel: @@ -374,7 +385,7 @@ func routeReadyEvents(ctx context.Context, wg *sync.WaitGroup, tunnelReadyCh, dn restartTickerCancel() // stop previous restart tickers tickerWg.Wait() restartTickerContext, restartTickerCancel = context.WithCancel(ctx) - tickerWg.Add(2) + tickerWg.Add(2) //nolint:gomnd go unboundLooper.RunRestartTicker(restartTickerContext, tickerWg) go updaterLooper.RunRestartTicker(restartTickerContext, tickerWg) defaultInterface, _, err := routing.DefaultRoute() diff --git a/internal/alpine/users.go b/internal/alpine/users.go index 0c30d81e..d3e90c3e 100644 --- a/internal/alpine/users.go +++ b/internal/alpine/users.go @@ -5,7 +5,7 @@ import ( "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 { UIDStr := fmt.Sprintf("%d", uid) u, err := c.lookupUID(UIDStr) @@ -23,7 +23,8 @@ func (c *configurator) CreateUser(username string, uid int) error { if err != nil && !unknownUsername { return fmt.Errorf("cannot create user: %w", err) } 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") if err != nil { diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 2d99763f..d94eb44e 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -117,7 +117,8 @@ func Update(args []string) error { return fmt.Errorf("at least one of -file or -stdout must be specified") } ctx := context.Background() - httpClient := &http.Client{Timeout: 10 * time.Second} + const clientTimeout = 10 * time.Second + httpClient := &http.Client{Timeout: clientTimeout} storage := storage.New(logger) const writeSync = false currentServers, err := storage.SyncServers(constants.GetAllServers(), writeSync) diff --git a/internal/constants/cyberghost.go b/internal/constants/cyberghost.go index 7c3f2658..4b73ed11 100644 --- a/internal/constants/cyberghost.go +++ b/internal/constants/cyberghost.go @@ -7,6 +7,7 @@ import ( "github.com/qdm12/gluetun/internal/models" ) +//nolint:lll const ( CyberghostCertificate = "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" CyberghostClientCertificate = "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" @@ -40,6 +41,7 @@ func CyberghostGroupChoices() (choices []string) { return choices } +//nolint:lll func CyberghostServers() []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}}}, diff --git a/internal/constants/dns.go b/internal/constants/dns.go index 902302de..485097ec 100644 --- a/internal/constants/dns.go +++ b/internal/constants/dns.go @@ -7,19 +7,19 @@ import ( ) const ( - // Cloudflare is a DNS over TLS provider + // Cloudflare is a DNS over TLS provider. Cloudflare models.DNSProvider = "cloudflare" - // Google is a DNS over TLS provider + // Google is a DNS over TLS provider. Google models.DNSProvider = "google" - // Quad9 is a DNS over TLS provider + // Quad9 is a DNS over TLS provider. Quad9 models.DNSProvider = "quad9" - // Quadrant is a DNS over TLS provider + // Quadrant is a DNS over TLS provider. Quadrant models.DNSProvider = "quadrant" - // CleanBrowsing is a DNS over TLS provider + // CleanBrowsing is a DNS over TLS provider. CleanBrowsing models.DNSProvider = "cleanbrowsing" - // SecureDNS is a DNS over TLS provider + // SecureDNS is a DNS over TLS provider. SecureDNS models.DNSProvider = "securedns" - // LibreDNS is a DNS over TLS provider + // LibreDNS is a DNS over TLS provider. LibreDNS models.DNSProvider = "libredns" ) @@ -28,37 +28,63 @@ const ( func DNSProviderMapping() map[models.DNSProvider]models.DNSProviderData { return map[models.DNSProvider]models.DNSProviderData{ 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, SupportsIPv6: true, Host: models.DNSHost("cloudflare-dns.com"), }, 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, SupportsIPv6: true, Host: models.DNSHost("dns.google"), }, 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, SupportsIPv6: true, Host: models.DNSHost("dns.quad9.net"), }, 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, SupportsIPv6: true, Host: models.DNSHost("dns-tls.qis.io"), }, 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, SupportsIPv6: true, Host: models.DNSHost("security-filter-dns.cleanbrowsing.org"), }, 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, SupportsIPv6: true, Host: models.DNSHost("dot.securedns.eu"), @@ -72,6 +98,7 @@ func DNSProviderMapping() map[models.DNSProvider]models.DNSProviderData { } // Block lists URLs +//nolint:lll const ( 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" @@ -81,8 +108,8 @@ const ( SurveillanceBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/surveillance-ips.updated" ) -// DNS certificates to fetch -// TODO obtain from source directly, see qdm12/updated) +// DNS certificates to fetch. +// TODO obtain from source directly, see qdm12/updated). const ( 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" diff --git a/internal/constants/mullvad.go b/internal/constants/mullvad.go index 9c7af389..879167e7 100644 --- a/internal/constants/mullvad.go +++ b/internal/constants/mullvad.go @@ -7,6 +7,7 @@ import ( "github.com/qdm12/gluetun/internal/models" ) +//nolint:lll const ( MullvadCertificate = "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" ) @@ -53,7 +54,7 @@ func MullvadISPChoices() (choices []string) { return choices } -//nolint:dupl +//nolint:dupl,lll func MullvadServers() []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}}}, diff --git a/internal/constants/nordvpn.go b/internal/constants/nordvpn.go index 90531307..76631d2a 100644 --- a/internal/constants/nordvpn.go +++ b/internal/constants/nordvpn.go @@ -6,6 +6,7 @@ import ( "github.com/qdm12/gluetun/internal/models" ) +//nolint:lll 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==" NordvpnOpenvpnStaticKeyV1 = "e685bdaf659a25a200e2b9e39e51ff030fc72cf1ce07232bd8b2be5e6c670143f51e937e670eee09d4f2ea5a6e4e69965db852c275351b86fc4ca892d78ae002d6f70d029bd79c4d1c26cf14e9588033cf639f8a74809f29f72b9d58f9b8f5fefc7938eade40e9fed6cb92184abb2cc10eb1a296df243b251df0643d53724cdb5a92a1d6cb817804c4a9319b57d53be580815bcfcb2df55018cc83fc43bc7ff82d51f9b88364776ee9d12fc85cc7ea5b9741c4f598c485316db066d52db4540e212e1518a9bd4828219e24b20d88f598a196c9de96012090e333519ae18d35099427e7b372d348d352dc4c85e18cd4b93f8a56ddb2e64eb67adfc9b337157ff4" @@ -20,6 +21,7 @@ func NordvpnRegionChoices() (choices []string) { return choices } +//nolint:gomnd func NordvpnServers() []models.NordvpnServer { return []models.NordvpnServer{ {Region: "Albania", Number: 18, TCP: true, UDP: true, IP: net.IP{31, 171, 152, 19}}, diff --git a/internal/constants/paths.go b/internal/constants/paths.go index c0d2a9b8..02682ee2 100644 --- a/internal/constants/paths.go +++ b/internal/constants/paths.go @@ -5,28 +5,28 @@ import ( ) 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" - // 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" - // 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" - // 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" - // 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" - // 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" - // TunnelDevice is the file path to tun device + // TunnelDevice is the file path to tun device. 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" - // 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" - // ShadowsocksConf is the filepath to the shadowsocks configuration file + // ShadowsocksConf is the filepath to the shadowsocks configuration file. 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" - // 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" ) diff --git a/internal/constants/permissions.go b/internal/constants/permissions.go new file mode 100644 index 00000000..1cb738fd --- /dev/null +++ b/internal/constants/permissions.go @@ -0,0 +1,8 @@ +package constants + +import "os" + +const ( + UserReadPermission os.FileMode = 0400 + AllReadWritePermissions os.FileMode = 0666 +) diff --git a/internal/constants/pia.go b/internal/constants/pia.go index fcfc9f03..f0d2ffa0 100644 --- a/internal/constants/pia.go +++ b/internal/constants/pia.go @@ -6,6 +6,7 @@ import ( "github.com/qdm12/gluetun/internal/models" ) +//nolint:lll const ( PIAEncryptionPresetNormal = "normal" PIAEncryptionPresetStrong = "strong" @@ -24,6 +25,7 @@ func PIAGeoChoices() (choices []string) { return choices } +//nolint:lll func PIAServers() []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}}}}, @@ -133,6 +135,7 @@ func PIAOldGeoChoices() (choices []string) { return choices } +//nolint:lll func PIAOldServers() []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}}}, diff --git a/internal/constants/purevpn.go b/internal/constants/purevpn.go index a5801a38..918e70d3 100644 --- a/internal/constants/purevpn.go +++ b/internal/constants/purevpn.go @@ -6,6 +6,7 @@ import ( "github.com/qdm12/gluetun/internal/models" ) +//nolint:lll 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" 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 } +//nolint:lll func PurevpnServers() []models.PurevpnServer { return []models.PurevpnServer{ {Region: "Africa", Country: "Algeria", City: "Algiers", IPs: []net.IP{{172, 94, 64, 2}}}, diff --git a/internal/constants/servers.go b/internal/constants/servers.go index 90fa2577..9b68e1d4 100644 --- a/internal/constants/servers.go +++ b/internal/constants/servers.go @@ -3,6 +3,7 @@ package constants import "github.com/qdm12/gluetun/internal/models" func GetAllServers() (allServers models.AllServers) { + //nolint:gomnd return models.AllServers{ Version: 1, // used for migration of the top level scheme Cyberghost: models.CyberghostServers{ diff --git a/internal/constants/servers_test.go b/internal/constants/servers_test.go index 3368ea57..bee237b0 100644 --- a/internal/constants/servers_test.go +++ b/internal/constants/servers_test.go @@ -1,8 +1,8 @@ package constants import ( - "crypto/md5" //nolint:gosec - "encoding/base64" + "crypto/sha256" + "encoding/hex" "encoding/json" "fmt" "testing" @@ -11,49 +11,164 @@ import ( "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) if err != nil { t.Fatal(err) } bytes = append(bytes, []byte(fmt.Sprintf("%d", version))...) - arr := md5.Sum(bytes) //nolint:gosec - return base64.RawStdEncoding.EncodeToString(arr[:]) + arr := sha256.Sum256(bytes) + hexString := hex.EncodeToString(arr[:]) + if len(hexString) > 8 { + hexString = hexString[:8] + } + return hexString } func Test_versions(t *testing.T) { t.Parallel() allServers := GetAllServers() - assert.Equal(t, "e8eLGRpb1sNX8mDNPOjA6g", digestServerModelVersion(t, models.CyberghostServer{}, allServers.Cyberghost.Version)) - assert.Equal(t, "4yL2lFcxXd/l1ByxBQ7d3g", digestServerModelVersion(t, models.MullvadServer{}, allServers.Mullvad.Version)) - assert.Equal(t, "fjzfUqJH0KvetGRdZYEtOg", digestServerModelVersion(t, models.NordvpnServer{}, allServers.Nordvpn.Version)) - assert.Equal(t, "1Ux7clCAJI6fwj0O61Dtpg", digestServerModelVersion(t, models.PIAServer{}, allServers.Pia.Version)) - assert.Equal(t, "EZ/SBXQOCS/iJU7A9yc7vg", digestServerModelVersion(t, models.PurevpnServer{}, allServers.Purevpn.Version)) - assert.Equal(t, "7yfMpHwzRpEngA/6nYsNag", digestServerModelVersion(t, models.SurfsharkServer{}, allServers.Surfshark.Version)) - assert.Equal(t, "7yfMpHwzRpEngA/6nYsNag", digestServerModelVersion(t, models.VyprvpnServer{}, allServers.Vyprvpn.Version)) - assert.Equal(t, "7yfMpHwzRpEngA/6nYsNag", digestServerModelVersion(t, models.WindscribeServer{}, allServers.Windscribe.Version)) + const format = "you forgot to update the version for %s" + testCases := map[string]struct { + model interface{} + version uint16 + digest string + }{ + "Cyberghost": { + 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) if err != nil { t.Fatal(err) } bytes = append(bytes, []byte(fmt.Sprintf("%d", timestamp))...) - arr := md5.Sum(bytes) //nolint:gosec - return base64.RawStdEncoding.EncodeToString(arr[:]) + arr := sha256.Sum256(bytes) + hexString := hex.EncodeToString(arr[:]) + if len(hexString) > 8 { + hexString = hexString[:8] + } + return hexString } func Test_timestamps(t *testing.T) { t.Parallel() allServers := GetAllServers() - assert.Equal(t, "EFMpdq2b9COLevjXmje5zg", digestServersTimestamp(t, allServers.Cyberghost.Servers, allServers.Cyberghost.Timestamp)) - assert.Equal(t, "EU4fTzD7jWC9N5kmN5bOEg", digestServersTimestamp(t, allServers.Mullvad.Servers, allServers.Mullvad.Timestamp)) - assert.Equal(t, "OLI62FoTf2wis25Nw4FLpg", digestServersTimestamp(t, allServers.Nordvpn.Servers, allServers.Nordvpn.Timestamp)) - assert.Equal(t, "beZCOXNWxzrPsUWCyQM99A", digestServersTimestamp(t, allServers.Pia.Servers, allServers.Pia.Timestamp)) - assert.Equal(t, "e8mWsWynkSUGiJLvjALRvQ", digestServersTimestamp(t, allServers.PiaOld.Servers, allServers.PiaOld.Timestamp)) - 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)) - assert.Equal(t, "KdIQWi2tYUM4aMXvWfVBEg", digestServersTimestamp(t, allServers.Vyprvpn.Servers, allServers.Vyprvpn.Timestamp)) - assert.Equal(t, "faQUVtOnLMVezN0giHSz3Q", digestServersTimestamp(t, allServers.Windscribe.Servers, allServers.Windscribe.Timestamp)) + const format = "you forgot to update the timestamp for %s" + testCases := map[string]struct { + servers interface{} + timestamp int64 + digest string + }{ + "Cyberghost": { + servers: allServers.Cyberghost.Servers, + 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) + }) + } } diff --git a/internal/constants/splash.go b/internal/constants/splash.go index 8b2754f6..9276d2e8 100644 --- a/internal/constants/splash.go +++ b/internal/constants/splash.go @@ -1,13 +1,13 @@ package constants const ( - // Announcement is a message announcement + // Announcement is a message announcement. 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" ) 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" ) diff --git a/internal/constants/surfshark.go b/internal/constants/surfshark.go index 6c82255d..7206300d 100644 --- a/internal/constants/surfshark.go +++ b/internal/constants/surfshark.go @@ -6,6 +6,7 @@ import ( "github.com/qdm12/gluetun/internal/models" ) +//nolint:lll 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=" SurfsharkOpenvpnStaticKeyV1 = "b02cb1d7c6fee5d4f89b8de72b51a8d0c7b282631d6fc19be1df6ebae9e2779e6d9f097058a31c97f57f0c35526a44ae09a01d1284b50b954d9246725a1ead1ff224a102ed9ab3da0152a15525643b2eee226c37041dc55539d475183b889a10e18bb94f079a4a49888da566b99783460ece01daaf93548beea6c827d9674897e7279ff1a19cb092659e8c1860fbad0db4ad0ad5732f1af4655dbd66214e552f04ed8fd0104e1d4bf99c249ac229ce169d9ba22068c6c0ab742424760911d4636aafb4b85f0c952a9ce4275bc821391aa65fcd0d2394f006e3fba0fd34c4bc4ab260f4b45dec3285875589c97d3087c9134d3a3aa2f904512e85aa2dc2202498" diff --git a/internal/constants/tinyproxy.go b/internal/constants/tinyproxy.go index 9ea15ece..53cf643f 100644 --- a/internal/constants/tinyproxy.go +++ b/internal/constants/tinyproxy.go @@ -5,16 +5,16 @@ import ( ) const ( - // TinyProxyInfoLevel is the info log level for TinyProxy + // TinyProxyInfoLevel is the info log level for TinyProxy. TinyProxyInfoLevel models.TinyProxyLogLevel = "Info" - // TinyProxyConnectLevel is the info log level for TinyProxy + // TinyProxyConnectLevel is the info log level for TinyProxy. TinyProxyConnectLevel models.TinyProxyLogLevel = "Connect" - // TinyProxyNoticeLevel is the info log level for TinyProxy + // TinyProxyNoticeLevel is the info log level for TinyProxy. TinyProxyNoticeLevel models.TinyProxyLogLevel = "Notice" - // TinyProxyWarnLevel is the warning log level for TinyProxy + // TinyProxyWarnLevel is the warning log level for TinyProxy. TinyProxyWarnLevel models.TinyProxyLogLevel = "Warning" - // TinyProxyErrorLevel is the error log level for TinyProxy + // TinyProxyErrorLevel is the error log level for TinyProxy. TinyProxyErrorLevel models.TinyProxyLogLevel = "Error" - // TinyProxyCriticalLevel is the critical log level for TinyProxy + // TinyProxyCriticalLevel is the critical log level for TinyProxy. TinyProxyCriticalLevel models.TinyProxyLogLevel = "Critical" ) diff --git a/internal/constants/vpn.go b/internal/constants/vpn.go index 241c4c0c..7142e045 100644 --- a/internal/constants/vpn.go +++ b/internal/constants/vpn.go @@ -5,29 +5,29 @@ import ( ) const ( - // PrivateInternetAccess is a VPN provider + // PrivateInternetAccess is a VPN provider. 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" - // Mullvad is a VPN provider + // Mullvad is a VPN provider. Mullvad models.VPNProvider = "mullvad" - // Windscribe is a VPN provider + // Windscribe is a VPN provider. Windscribe models.VPNProvider = "windscribe" - // Surfshark is a VPN provider + // Surfshark is a VPN provider. Surfshark models.VPNProvider = "surfshark" - // Cyberghost is a VPN provider + // Cyberghost is a VPN provider. Cyberghost models.VPNProvider = "cyberghost" - // Vyprvpn is a VPN provider + // Vyprvpn is a VPN provider. Vyprvpn models.VPNProvider = "vyprvpn" - // NordVPN is a VPN provider + // NordVPN is a VPN provider. Nordvpn models.VPNProvider = "nordvpn" - // PureVPN is a VPN provider + // PureVPN is a VPN provider. Purevpn models.VPNProvider = "purevpn" ) 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" - // UDP is a network protocol (unreliable and faster than TCP) + // UDP is a network protocol (unreliable and faster than TCP). UDP models.NetworkProtocol = "udp" ) diff --git a/internal/constants/vyprvpn.go b/internal/constants/vyprvpn.go index 33d991e7..3082760d 100644 --- a/internal/constants/vyprvpn.go +++ b/internal/constants/vyprvpn.go @@ -6,6 +6,7 @@ import ( "github.com/qdm12/gluetun/internal/models" ) +//nolint:lll const ( VyprvpnCertificate = "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" ) diff --git a/internal/constants/windscribe.go b/internal/constants/windscribe.go index 3b3df967..d4ed96b3 100644 --- a/internal/constants/windscribe.go +++ b/internal/constants/windscribe.go @@ -6,6 +6,7 @@ import ( "github.com/qdm12/gluetun/internal/models" ) +//nolint:lll const ( WindscribeCertificate = "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" WindscribeOpenvpnStaticKeyV1 = "5801926a57ac2ce27e3dfd1dd6ef82042d82bd4f3f0021296f57734f6f1ea714a6623845541c4b0c3dea0a050fe6746cb66dfab14cda27e5ae09d7c155aa554f399fa4a863f0e8c1af787e5c602a801d3a2ec41e395a978d56729457fe6102d7d9e9119aa83643210b33c678f9d4109e3154ac9c759e490cb309b319cf708cae83ddadc3060a7a26564d1a24411cd552fe6620ea16b755697a4fc5e6e9d0cfc0c5c4a1874685429046a424c026db672e4c2c492898052ba59128d46200b40f880027a8b6610a4d559bdc9346d33a0a6b08e75c7fd43192b162bfd0aef0c716b31584827693f676f9a5047123466f0654eade34972586b31c6ce7e395f4b478cb" @@ -20,7 +21,7 @@ func WindscribeRegionChoices() (choices []string) { return choices } -//nolint:dupl +//nolint:lll func WindscribeServers() []models.WindscribeServer { return []models.WindscribeServer{ {Region: "Albania", IPs: []net.IP{{31, 171, 152, 179}}}, diff --git a/internal/dns/command.go b/internal/dns/command.go index 2db494b9..5f6e447d 100644 --- a/internal/dns/command.go +++ b/internal/dns/command.go @@ -9,7 +9,8 @@ import ( "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") args := []string{"-d", "-c", string(constants.UnboundConf)} 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") { if strings.Contains(line, "Version ") { words := strings.Fields(line) - if len(words) < 2 { + const minWords = 2 + if len(words) < minWords { continue } version = words[1] diff --git a/internal/dns/command_test.go b/internal/dns/command_test.go index 8aace668..214d1de3 100644 --- a/internal/dns/command_test.go +++ b/internal/dns/command_test.go @@ -6,12 +6,11 @@ import ( "testing" "github.com/golang/mock/gomock" + "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/golibs/command/mock_command" "github.com/qdm12/golibs/logging/mock_logging" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/qdm12/gluetun/internal/constants" ) func Test_Start(t *testing.T) { diff --git a/internal/dns/conf.go b/internal/dns/conf.go index 3c614376..2156bc85 100644 --- a/internal/dns/conf.go +++ b/internal/dns/conf.go @@ -24,11 +24,13 @@ func (c *configurator) MakeUnboundConf(ctx context.Context, settings settings.DN string(constants.UnboundConf), lines, files.Ownership(uid, gid), - files.Permissions(0400)) + files.Permissions(constants.UserReadPermission)) } -// 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) { +// 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) { doIPv6 := "no" if settings.IPv6 { doIPv6 = "yes" diff --git a/internal/dns/loop.go b/internal/dns/loop.go index b8aaf565..3d7c3955 100644 --- a/internal/dns/loop.go +++ b/internal/dns/loop.go @@ -92,9 +92,15 @@ func (l *looper) setEnabled(enabled bool) { func (l *looper) logAndWait(ctx context.Context, err error) { l.logger.Warn(err) l.logger.Info("attempting restart in 10 seconds") - ctx, cancel := context.WithTimeout(ctx, 10*time.Second) - defer cancel() - <-ctx.Done() + const waitDuration = 10 * time.Second + timer := time.NewTimer(waitDuration) + select { + case <-timer.C: + case <-ctx.Done(): + if !timer.Stop() { + <-timer.C + } + } } func (l *looper) waitForFirstStart(ctx context.Context, signalDNSReady func()) { diff --git a/internal/dns/nameserver.go b/internal/dns/nameserver.go index 07030280..ab0d4f10 100644 --- a/internal/dns/nameserver.go +++ b/internal/dns/nameserver.go @@ -8,7 +8,7 @@ import ( "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) { c.logger.Info("using DNS address %s internally", ip.String()) 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 { c.logger.Info("using DNS address %s system wide", ip.String()) data, err := c.fileManager.ReadFile(string(constants.ResolvConf)) diff --git a/internal/dns/roots.go b/internal/dns/roots.go index 1e59f279..3fc190f1 100644 --- a/internal/dns/roots.go +++ b/internal/dns/roots.go @@ -21,7 +21,7 @@ func (c *configurator) DownloadRootHints(ctx context.Context, uid, gid int) erro string(constants.RootHints), content, files.Ownership(uid, gid), - files.Permissions(0400)) + files.Permissions(constants.UserReadPermission)) } 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), content, files.Ownership(uid, gid), - files.Permissions(0400)) + files.Permissions(constants.UserReadPermission)) } diff --git a/internal/dns/roots_test.go b/internal/dns/roots_test.go index 28ad5dac..a774244c 100644 --- a/internal/dns/roots_test.go +++ b/internal/dns/roots_test.go @@ -7,14 +7,13 @@ import ( "testing" "github.com/golang/mock/gomock" + "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/golibs/files" "github.com/qdm12/golibs/files/mock_files" "github.com/qdm12/golibs/logging/mock_logging" "github.com/qdm12/golibs/network/mock_network" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/qdm12/gluetun/internal/constants" ) func Test_DownloadRootHints(t *testing.T) { //nolint:dupl @@ -31,7 +30,7 @@ func Test_DownloadRootHints(t *testing.T) { //nolint:dupl }, "bad status": { 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": { clientErr: fmt.Errorf("error"), @@ -94,7 +93,7 @@ func Test_DownloadRootKey(t *testing.T) { //nolint:dupl }, "bad status": { 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": { clientErr: fmt.Errorf("error"), diff --git a/internal/dns/wait.go b/internal/dns/wait.go index 2d1431be..139cda38 100644 --- a/internal/dns/wait.go +++ b/internal/dns/wait.go @@ -6,16 +6,23 @@ import ( ) func (c *configurator) WaitForUnbound() (err error) { - const maxTries = 10 const hostToResolve = "github.com" - time.Sleep(300 * time.Millisecond) - for try := 1; try <= maxTries; try++ { + waitDurations := [...]time.Duration{ + 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) if err == nil { return nil } - c.logger.Warn("could not resolve %s (try %d of %d): %s", hostToResolve, try, maxTries, err) - time.Sleep(maxTries * 50 * time.Millisecond) + c.logger.Warn("could not resolve %s (try %d of %d): %s", hostToResolve, i+1, maxTries, err) } return fmt.Errorf("Unbound does not seem to be working after %d tries", maxTries) } diff --git a/internal/firewall/enable.go b/internal/firewall/enable.go index 0650c513..620caeb6 100644 --- a/internal/firewall/enable.go +++ b/internal/firewall/enable.go @@ -51,7 +51,7 @@ func (c *configurator) disable(ctx context.Context) (err error) { 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) { if ctx.Err() != nil { 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 { return fmt.Errorf("cannot enable firewall: %w", err) } diff --git a/internal/firewall/firewall.go b/internal/firewall/firewall.go index 6c33ca69..9a173508 100644 --- a/internal/firewall/firewall.go +++ b/internal/firewall/firewall.go @@ -12,7 +12,7 @@ import ( "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 { Version(ctx context.Context) (string, error) SetEnabled(ctx context.Context, enabled bool) (err error) @@ -45,7 +45,7 @@ type configurator struct { //nolint:maligned 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 { return &configurator{ commander: command.NewCommander(), diff --git a/internal/firewall/iptables.go b/internal/firewall/iptables.go index 1a2f293d..2efe389f 100644 --- a/internal/firewall/iptables.go +++ b/internal/firewall/iptables.go @@ -32,14 +32,15 @@ func flipRule(rule string) string { 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) { output, err := c.commander.Run(ctx, "iptables", "--version") if err != nil { return "", err } 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 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, 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)) } -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 if intf == "*" { // all interfaces interfaceFlag = "" } 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 -func (c *configurator) acceptOutputFromSubnetToSubnet(ctx context.Context, intf string, sourceSubnet, destinationSubnet net.IPNet, remove bool) error { +// Thanks to @npawelek. +func (c *configurator) acceptOutputFromSubnetToSubnet(ctx context.Context, + intf string, sourceSubnet, destinationSubnet net.IPNet, remove bool) error { interfaceFlag := "-o " + intf if intf == "*" { // all interfaces interfaceFlag = "" } 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 { interfaceFlag := "-i " + intf if intf == "*" { // all interfaces diff --git a/internal/firewall/subnets.go b/internal/firewall/subnets.go index d8715776..d5a77738 100644 --- a/internal/firewall/subnets.go +++ b/internal/firewall/subnets.go @@ -124,7 +124,7 @@ func (c *configurator) addSubnets(ctx context.Context, subnets []net.IPNet, defa 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) { subnetsToAdd := findSubnetsToAdd(oldSubnets, newSubnets) subnetsToRemove := findSubnetsToRemove(oldSubnets, newSubnets) diff --git a/internal/logging/duration.go b/internal/logging/duration.go index aa1869bb..8a7efc28 100644 --- a/internal/logging/duration.go +++ b/internal/logging/duration.go @@ -9,7 +9,8 @@ func FormatDuration(duration time.Duration) string { switch { case duration < time.Minute: 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 seconds", seconds) @@ -23,7 +24,8 @@ func FormatDuration(duration time.Duration) string { hours := int(duration.Truncate(time.Hour).Hours()) return fmt.Sprintf("%d hours", hours) 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) } } diff --git a/internal/logging/line.go b/internal/logging/line.go index 6a9155ab..3e8d98e1 100644 --- a/internal/logging/line.go +++ b/internal/logging/line.go @@ -10,6 +10,7 @@ import ( "github.com/qdm12/golibs/logging" ) +//nolint:lll var regularExpressions = struct { //nolint:gochecknoglobals unboundPrefix *regexp.Regexp shadowsocksPrefix *regexp.Regexp diff --git a/internal/logging/splash.go b/internal/logging/splash.go index 4fc5ae05..4ebbf0d4 100644 --- a/internal/logging/splash.go +++ b/internal/logging/splash.go @@ -9,7 +9,7 @@ import ( "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 { lines := title() lines = append(lines, "") diff --git a/internal/models/alias.go b/internal/models/alias.go index e0aa2087..6dc7b6ae 100644 --- a/internal/models/alias.go +++ b/internal/models/alias.go @@ -6,21 +6,21 @@ import ( ) type ( - // VPNDevice is the device name used to tunnel using Openvpn + // VPNDevice is the device name used to tunnel using Openvpn. VPNDevice string - // DNSProvider is a DNS over TLS server provider name + // DNSProvider is a DNS over TLS server provider name. DNSProvider string - // DNSHost is the DNS host to use for TLS validation + // DNSHost is the DNS host to use for TLS validation. DNSHost string - // URL is an HTTP(s) URL address + // URL is an HTTP(s) URL address. URL string - // Filepath is a local filesytem file path + // Filepath is a local filesytem file path. Filepath string - // TinyProxyLogLevel is the log level for TinyProxy + // TinyProxyLogLevel is the log level for TinyProxy. 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 - // 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 ) diff --git a/internal/models/dns.go b/internal/models/dns.go index ccdd984b..b04d7ca3 100644 --- a/internal/models/dns.go +++ b/internal/models/dns.go @@ -2,7 +2,7 @@ package models import "net" -// DNSProviderData contains information for a DNS provider +// DNSProviderData contains information for a DNS provider. type DNSProviderData struct { IPs []net.IP SupportsTLS bool diff --git a/internal/models/selection.go b/internal/models/selection.go index e0a8a07f..d9d6c2b2 100644 --- a/internal/models/selection.go +++ b/internal/models/selection.go @@ -6,7 +6,7 @@ import ( "strings" ) -// ProviderSettings contains settings specific to a VPN provider +// ProviderSettings contains settings specific to a VPN provider. type ProviderSettings struct { Name VPNProvider `json:"name"` ServerSelection ServerSelection `json:"serverSelection"` @@ -14,7 +14,7 @@ type ProviderSettings struct { PortForwarding PortForwarding `json:"portForwarding"` } -type ServerSelection struct { //nolint:maligned +type ServerSelection struct { // Common Protocol NetworkProtocol `json:"networkProtocol"` TargetIP net.IP `json:"targetIP,omitempty"` @@ -49,7 +49,7 @@ type ExtraConfigOptions struct { OpenVPNIPv6 bool `json:"openvpnIPv6"` // Mullvad } -// PortForwarding contains settings for port forwarding +// PortForwarding contains settings for port forwarding. type PortForwarding struct { Enabled bool `json:"enabled"` Filepath Filepath `json:"filepath"` diff --git a/internal/models/server_test.go b/internal/models/server_test.go index d122fdc5..3cabbb74 100644 --- a/internal/models/server_test.go +++ b/internal/models/server_test.go @@ -47,6 +47,7 @@ func Test_MullvadServer_String(t *testing.T) { ISP: "not spying on you", 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}}}`, }, } @@ -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}, {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}, {}}", }, } diff --git a/internal/openvpn/auth.go b/internal/openvpn/auth.go index b3043fc7..231b8967 100644 --- a/internal/openvpn/auth.go +++ b/internal/openvpn/auth.go @@ -7,7 +7,7 @@ import ( "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 { exists, err := c.fileManager.FileExists(string(constants.OpenVPNAuthConf)) if err != nil { @@ -27,5 +27,5 @@ func (c *configurator) WriteAuthFile(user, password string, uid, gid int) error string(constants.OpenVPNAuthConf), []string{user, password}, files.Ownership(uid, gid), - files.Permissions(0400)) + files.Permissions(constants.UserReadPermission)) } diff --git a/internal/openvpn/command.go b/internal/openvpn/command.go index 6a1f0f2a..13b805ce 100644 --- a/internal/openvpn/command.go +++ b/internal/openvpn/command.go @@ -22,7 +22,8 @@ func (c *configurator) Version(ctx context.Context) (string, error) { } firstLine := strings.Split(output, "\n")[0] 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 words[1], nil diff --git a/internal/openvpn/loop.go b/internal/openvpn/loop.go index f3be3564..f47649b5 100644 --- a/internal/openvpn/loop.go +++ b/internal/openvpn/loop.go @@ -131,7 +131,8 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { settings.Auth, 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.cancel() return @@ -200,14 +201,20 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { func (l *looper) logAndWait(ctx context.Context, err error) { l.logger.Error(err) - l.logger.Info("retrying in 30 seconds") - ctx, cancel := context.WithTimeout(ctx, 30*time.Second) - defer cancel() // just for the linter - <-ctx.Done() + const waitTime = 30 * time.Second + l.logger.Info("retrying in %s", waitTime) + timer := time.NewTimer(waitTime) + select { + case <-timer.C: + case <-ctx.Done(): + if !timer.Stop() { + <-timer.C + } + } } // 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, providerConf provider.Provider, client *http.Client, gateway net.IP) { defer wg.Done() diff --git a/internal/openvpn/tun.go b/internal/openvpn/tun.go index 947217a1..bc760bbf 100644 --- a/internal/openvpn/tun.go +++ b/internal/openvpn/tun.go @@ -8,7 +8,7 @@ import ( "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 { c.logger.Info("checking for device %s", constants.TunnelDevice) 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 { 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 { return err } diff --git a/internal/params/cyberghost.go b/internal/params/cyberghost.go index f5490de4..0f1cf1b7 100644 --- a/internal/params/cyberghost.go +++ b/internal/params/cyberghost.go @@ -8,21 +8,22 @@ import ( ) // 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) { - 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 } // 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) { choices := append(constants.CyberghostRegionChoices(), "") return p.envParams.GetCSVInPossibilities("REGION", choices) } // 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) { clientKey, err = p.envParams.GetEnv("CLIENT_KEY", libparams.CaseSensitiveValue()) if err != nil { diff --git a/internal/params/dns.go b/internal/params/dns.go index 0a8536d9..aa337bf0 100644 --- a/internal/params/dns.go +++ b/internal/params/dns.go @@ -12,13 +12,13 @@ import ( ) // 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 return r.envParams.GetOnOff("DOT", libparams.Default("on")) } // 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) { s, err := r.envParams.GetEnv("DOT_PROVIDERS", libparams.Default("cloudflare")) if err != nil { @@ -27,7 +27,9 @@ func (r *reader) GetDNSOverTLSProviders() (providers []models.DNSProvider, err e for _, word := range strings.Split(s, ",") { provider := models.DNSProvider(word) 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) default: 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 -// from the environment variable DOT_VERBOSITY +// from the environment variable DOT_VERBOSITY. func (r *reader) GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error) { n, err := r.envParams.GetEnvIntRange("DOT_VERBOSITY", 0, 5, libparams.Default("1")) return uint8(n), err } // 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) { n, err := r.envParams.GetEnvIntRange("DOT_VERBOSITY_DETAILS", 0, 4, libparams.Default("0")) return uint8(n), err } // 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) { n, err := r.envParams.GetEnvIntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, libparams.Default("0")) return uint8(n), err } // 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) { return r.envParams.GetOnOff("BLOCK_MALICIOUS", libparams.Default("on")) } // GetDNSSurveillanceBlocking obtains if surveillance hostnames/IPs should be blocked // 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) { // Retro-compatibility s, err := r.envParams.GetEnv("BLOCK_NSA") if err != nil { return false, err } 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_SURVEILLANCE", libparams.Default("off")) } // 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) { return r.envParams.GetOnOff("BLOCK_ADS", libparams.Default("off")) } // 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) { s, err := r.envParams.GetEnv("UNBLOCK") 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 -// from the environment variable DOT_CACHING +// from the environment variable DOT_CACHING. func (r *reader) GetDNSOverTLSCaching() (caching bool, err error) { return r.envParams.GetOnOff("DOT_CACHING") } // 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) { s, err := r.envParams.GetEnv("DOT_PRIVATE_ADDRESS") 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 -// servers from the environment variable DOT_IPV6 +// servers from the environment variable DOT_IPV6. func (r *reader) GetDNSOverTLSIPv6() (ipv6 bool, err error) { return r.envParams.GetOnOff("DOT_IPV6", libparams.Default("off")) } // 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) { s, err := r.envParams.GetEnv("DNS_UPDATE_PERIOD", libparams.Default("24h")) 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 -// from the environment variable DNS_PLAINTEXT_ADDRESS +// from the environment variable DNS_PLAINTEXT_ADDRESS. func (r *reader) GetDNSPlaintext() (ip net.IP, err error) { s, err := r.envParams.GetEnv("DNS_PLAINTEXT_ADDRESS", libparams.Default("1.1.1.1")) 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 -// 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) { return r.envParams.GetOnOff("DNS_KEEP_NAMESERVER", libparams.Default("off")) } diff --git a/internal/params/firewall.go b/internal/params/firewall.go index a25a5882..e41b1247 100644 --- a/internal/params/firewall.go +++ b/internal/params/firewall.go @@ -9,13 +9,13 @@ import ( 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) { return r.envParams.GetOnOff("FIREWALL", libparams.Default("on")) } // 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) { s, err := r.envParams.GetEnv("EXTRA_SUBNETS") 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 -// 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) { s, err := r.envParams.GetEnv("FIREWALL_VPN_INPUT_PORTS", libparams.Default("")) 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 -// 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) { s, err := r.envParams.GetEnv("FIREWALL_INPUT_PORTS", libparams.Default("")) if err != nil { @@ -84,7 +84,8 @@ func (r *reader) GetInputPorts() (ports []uint16, err error) { 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) { return r.envParams.GetOnOff("FIREWALL_DEBUG", libparams.Default("off")) } diff --git a/internal/params/mullvad.go b/internal/params/mullvad.go index bfe51370..d0838e47 100644 --- a/internal/params/mullvad.go +++ b/internal/params/mullvad.go @@ -6,35 +6,35 @@ import ( ) // GetMullvadCountries obtains the countries for the Mullvad servers from the -// environment variable COUNTRY +// environment variable COUNTRY. func (r *reader) GetMullvadCountries() (countries []string, err error) { choices := append(constants.MullvadCountryChoices(), "") return r.envParams.GetCSVInPossibilities("COUNTRY", choices) } // GetMullvadCity obtains the cities for the Mullvad servers from the -// environment variable CITY +// environment variable CITY. func (r *reader) GetMullvadCities() (cities []string, err error) { choices := append(constants.MullvadCityChoices(), "") return r.envParams.GetCSVInPossibilities("CITY", choices) } // GetMullvadISPs obtains the ISPs for the Mullvad servers from the -// environment variable ISP +// environment variable ISP. func (r *reader) GetMullvadISPs() (isps []string, err error) { choices := append(constants.MullvadISPChoices(), "") return r.envParams.GetCSVInPossibilities("ISP", choices) } // 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) { n, err := r.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0")) return uint16(n), err } // 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) { return r.envParams.GetYesNo("OWNED", libparams.Default("no")) } diff --git a/internal/params/nordvpn.go b/internal/params/nordvpn.go index 27d162da..0e6513b7 100644 --- a/internal/params/nordvpn.go +++ b/internal/params/nordvpn.go @@ -8,14 +8,14 @@ import ( ) // 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) { choices := append(constants.NordvpnRegionChoices(), "") return r.envParams.GetCSVInPossibilities("REGION", choices) } // 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) { possibilities := make([]string, 65536) for i := range possibilities { diff --git a/internal/params/openvpn.go b/internal/params/openvpn.go index 8271ec83..5ba3cda6 100644 --- a/internal/params/openvpn.go +++ b/internal/params/openvpn.go @@ -8,7 +8,7 @@ import ( 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) { defer func() { 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()) } -// 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) { defer func() { 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 -// VPN servers from the environment variable PROTOCOL +// VPN servers from the environment variable PROTOCOL. func (r *reader) GetNetworkProtocol() (protocol models.NetworkProtocol, err error) { s, err := r.envParams.GetValueIfInside("PROTOCOL", []string{"tcp", "udp"}, libparams.Default("udp")) return models.NetworkProtocol(s), err } // 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) { return r.envParams.GetEnvIntRange("OPENVPN_VERBOSITY", 0, 6, libparams.Default("1")) } // 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) { return r.envParams.GetYesNo("OPENVPN_ROOT", libparams.Default("no")) } // 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) { s, err := r.envParams.GetEnv("OPENVPN_TARGET_IP") 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 -// from the environment variable OPENVPN_CIPHER +// from the environment variable OPENVPN_CIPHER. func (r *reader) GetOpenVPNCipher() (cipher string, err error) { return r.envParams.GetEnv("OPENVPN_CIPHER") } // 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) { return r.envParams.GetEnv("OPENVPN_AUTH") } // 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) { return r.envParams.GetOnOff("OPENVPN_IPV6", libparams.Default("off")) } diff --git a/internal/params/params.go b/internal/params/params.go index 96ab4b72..587dffc2 100644 --- a/internal/params/params.go +++ b/internal/params/params.go @@ -12,7 +12,7 @@ import ( "github.com/qdm12/golibs/verification" ) -// Reader contains methods to obtain parameters +// Reader contains methods to obtain parameters. type Reader interface { GetVPNSP() (vpnServiceProvider models.VPNProvider, err error) @@ -130,7 +130,7 @@ type reader struct { } // Newreader returns a paramsReadeer object to read parameters from -// environment variables +// environment variables. func NewReader(logger logging.Logger, fileManager files.FileManager) Reader { return &reader{ 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) { - 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" { s = "private internet access" } diff --git a/internal/params/pia.go b/internal/params/pia.go index 05c29f5e..c2603fbf 100644 --- a/internal/params/pia.go +++ b/internal/params/pia.go @@ -10,7 +10,7 @@ import ( // GetPortForwarding obtains if port forwarding on the VPN provider server // 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) { s, err := r.envParams.GetEnv("PORT_FORWARDING", libparams.Default("off")) if err != nil { @@ -26,15 +26,18 @@ func (r *reader) GetPortForwarding() (activated bool, err error) { } // 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) { - 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 } // GetPIAEncryptionPreset obtains the encryption level for the PIA connection // from the environment variable PIA_ENCRYPTION, and using ENCRYPTION for -// retro compatibility +// retro compatibility. func (r *reader) GetPIAEncryptionPreset() (preset string, err error) { // Retro-compatibility 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 -// environment variable REGION +// environment variable REGION. func (r *reader) GetPIARegions() (regions []string, err error) { choices := append(constants.PIAGeoChoices(), "") return r.envParams.GetCSVInPossibilities("REGION", choices) } // GetPIAOldRegions obtains the regions for the PIA servers from the -// environment variable REGION +// environment variable REGION. func (r *reader) GetPIAOldRegions() (regions []string, err error) { choices := append(constants.PIAOldGeoChoices(), "") return r.envParams.GetCSVInPossibilities("REGION", choices) diff --git a/internal/params/publicip.go b/internal/params/publicip.go index ab47a7f3..04845fa4 100644 --- a/internal/params/publicip.go +++ b/internal/params/publicip.go @@ -7,7 +7,7 @@ import ( ) // 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) { s, err := r.envParams.GetEnv("PUBLICIP_PERIOD", libparams.Default("12h")) if err != nil { diff --git a/internal/params/purevpn.go b/internal/params/purevpn.go index 440dc995..d404d4b0 100644 --- a/internal/params/purevpn.go +++ b/internal/params/purevpn.go @@ -5,21 +5,21 @@ import ( ) // 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) { choices := append(constants.PurevpnRegionChoices(), "") return r.envParams.GetCSVInPossibilities("REGION", choices) } // GetPurevpnCountries obtains the countries for the PureVPN servers from the -// environment variable COUNTRY +// environment variable COUNTRY. func (r *reader) GetPurevpnCountries() (countries []string, err error) { choices := append(constants.PurevpnCountryChoices(), "") return r.envParams.GetCSVInPossibilities("COUNTRY", choices) } // GetPurevpnCities obtains the cities for the PureVPN servers from the -// environment variable CITY +// environment variable CITY. func (r *reader) GetPurevpnCities() (cities []string, err error) { choices := append(constants.PurevpnCityChoices(), "") return r.envParams.GetCSVInPossibilities("CITY", choices) diff --git a/internal/params/shadowsocks.go b/internal/params/shadowsocks.go index f0c4e9f1..94a27fb0 100644 --- a/internal/params/shadowsocks.go +++ b/internal/params/shadowsocks.go @@ -7,19 +7,19 @@ import ( ) // GetShadowSocks obtains if ShadowSocks is on from the environment variable -// SHADOWSOCKS +// SHADOWSOCKS. func (r *reader) GetShadowSocks() (activated bool, err error) { return r.envParams.GetOnOff("SHADOWSOCKS", libparams.Default("off")) } // GetShadowSocksLog obtains the ShadowSocks log level from the environment variable -// SHADOWSOCKS_LOG +// SHADOWSOCKS_LOG. func (r *reader) GetShadowSocksLog() (activated bool, err error) { return r.envParams.GetOnOff("SHADOWSOCKS_LOG", libparams.Default("off")) } // GetShadowSocksPort obtains the ShadowSocks listening port from the environment variable -// SHADOWSOCKS_PORT +// SHADOWSOCKS_PORT. func (r *reader) GetShadowSocksPort() (port uint16, err error) { portStr, err := r.envParams.GetEnv("SHADOWSOCKS_PORT", libparams.Default("8388")) 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 -// SHADOWSOCKS_PASSWORD +// SHADOWSOCKS_PASSWORD. func (r *reader) GetShadowSocksPassword() (password string, err error) { defer func() { 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 -// SHADOWSOCKS_METHOD +// SHADOWSOCKS_METHOD. func (r *reader) GetShadowSocksMethod() (method string, err error) { return r.envParams.GetEnv("SHADOWSOCKS_METHOD", libparams.Default("chacha20-ietf-poly1305")) } diff --git a/internal/params/surfshark.go b/internal/params/surfshark.go index 82084d5b..97503b38 100644 --- a/internal/params/surfshark.go +++ b/internal/params/surfshark.go @@ -5,7 +5,7 @@ import ( ) // GetSurfsharkRegions obtains the regions for the Surfshark servers from the -// environment variable REGION +// environment variable REGION. func (r *reader) GetSurfsharkRegions() (regions []string, err error) { choices := append(constants.SurfsharkRegionChoices(), "") return r.envParams.GetCSVInPossibilities("REGION", choices) diff --git a/internal/params/system.go b/internal/params/system.go index d111536a..ac82b928 100644 --- a/internal/params/system.go +++ b/internal/params/system.go @@ -5,24 +5,25 @@ import ( 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) { 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) { 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) { return r.envParams.GetEnv("TZ") } // 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) { - 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 } diff --git a/internal/params/tinyproxy.go b/internal/params/tinyproxy.go index ade88f3f..f61ac183 100644 --- a/internal/params/tinyproxy.go +++ b/internal/params/tinyproxy.go @@ -8,7 +8,7 @@ import ( ) // 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) { // Retro-compatibility 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 -// 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) { // Retro-compatibility s, err := r.envParams.GetEnv("PROXY_LOG_LEVEL") if err != nil { return models.TinyProxyLogLevel(s), err } 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") - s, err = r.envParams.GetValueIfInside("PROXY_LOG_LEVEL", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Compulsory()) + 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()) 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 } // 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) { // Retro-compatibility 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 -// 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) { defer func() { 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 -// 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) { defer func() { unsetErr := r.unsetEnv("PROXY_PASSWORD") @@ -109,7 +113,7 @@ func (r *reader) GetTinyProxyPassword() (password string, err error) { return password, err } 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 r.envParams.GetEnv("TINYPROXY_PASSWORD", libparams.CaseSensitiveValue()) diff --git a/internal/params/updater.go b/internal/params/updater.go index 96a7bada..8d83a002 100644 --- a/internal/params/updater.go +++ b/internal/params/updater.go @@ -7,7 +7,7 @@ import ( ) // 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) { s, err := r.envParams.GetEnv("UPDATER_PERIOD", libparams.Default("0")) if err != nil { diff --git a/internal/params/vypervpn.go b/internal/params/vypervpn.go index 948f6d04..fd1827aa 100644 --- a/internal/params/vypervpn.go +++ b/internal/params/vypervpn.go @@ -5,7 +5,7 @@ import ( ) // GetVyprvpnRegions obtains the regions for the Vyprvpn servers from the -// environment variable REGION +// environment variable REGION. func (r *reader) GetVyprvpnRegions() (regions []string, err error) { choices := append(constants.VyprvpnRegionChoices(), "") return r.envParams.GetCSVInPossibilities("REGION", choices) diff --git a/internal/params/windscribe.go b/internal/params/windscribe.go index 87c4e1be..331e7139 100644 --- a/internal/params/windscribe.go +++ b/internal/params/windscribe.go @@ -9,14 +9,15 @@ import ( ) // GetWindscribeRegions obtains the regions for the Windscribe servers from the -// environment variable REGION +// environment variable REGION. func (r *reader) GetWindscribeRegions() (regions []string, err error) { choices := append(constants.WindscribeRegionChoices(), "") return r.envParams.GetCSVInPossibilities("REGION", choices) } // 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) { n, err := r.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0")) if err != nil { diff --git a/internal/provider/cyberghost.go b/internal/provider/cyberghost.go index aecc95ea..d8919137 100644 --- a/internal/provider/cyberghost.go +++ b/internal/provider/cyberghost.go @@ -39,27 +39,31 @@ func (c *cyberghost) filterServers(regions []string, group string) (servers []mo 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 { - 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) 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 for _, server := range servers { 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 } -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 { cipher = aes256cbc } diff --git a/internal/provider/mullvad.go b/internal/provider/mullvad.go index 06d0dc43..3d3d0b9c 100644 --- a/internal/provider/mullvad.go +++ b/internal/provider/mullvad.go @@ -41,7 +41,8 @@ func (m *mullvad) filterServers(countries, cities, isps []string, owned bool) (s 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 if selection.Protocol == constants.TCP { defaultPort = 443 @@ -71,7 +72,8 @@ func (m *mullvad) GetOpenVPNConnection(selection models.ServerSelection) (connec 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 { cipher = aes256cbc } diff --git a/internal/provider/nordvpn.go b/internal/provider/nordvpn.go index f0322d8d..1c29ebd1 100644 --- a/internal/provider/nordvpn.go +++ b/internal/provider/nordvpn.go @@ -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)) for i := range numbers { numbersStr[i] = fmt.Sprintf("%d", numbers[i]) @@ -46,7 +47,8 @@ func (n *nordvpn) filterServers(regions []string, protocol models.NetworkProtoco 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 switch { 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) 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)) 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 } -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 { cipher = aes256cbc } diff --git a/internal/provider/pia.go b/internal/provider/pia.go index 0fca64e0..4d0470b8 100644 --- a/internal/provider/pia.go +++ b/internal/provider/pia.go @@ -8,27 +8,27 @@ import ( "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 defaultCipher, defaultAuth string if extras.EncryptionPreset == constants.PIAEncryptionPresetNormal { - if len(cipher) == 0 { - cipher = "aes-128-cbc" - } - if len(auth) == 0 { - auth = "sha1" - } + defaultCipher = "aes-128-cbc" + defaultAuth = "sha1" X509CRL = constants.PiaX509CRLNormal certificate = constants.PIACertificateNormal } else { // strong encryption - if len(cipher) == 0 { - cipher = aes256cbc - } - if len(auth) == 0 { - auth = "sha256" - } + defaultCipher = aes256cbc + defaultAuth = "sha256" X509CRL = constants.PiaX509CRLStrong certificate = constants.PIACertificateStrong } + if len(cipher) == 0 { + cipher = defaultCipher + } + if len(auth) == 0 { + auth = defaultAuth + } lines = []string{ "client", "dev tun", diff --git a/internal/provider/piav3.go b/internal/provider/piav3.go index 2ca937a4..409491aa 100644 --- a/internal/provider/piav3.go +++ b/internal/provider/piav3.go @@ -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 switch selection.Protocol { case constants.TCP: @@ -49,7 +50,9 @@ func (p *piaV3) GetOpenVPNConnection(selection models.ServerSelection) (connecti } } 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 { @@ -71,20 +74,22 @@ func (p *piaV3) GetOpenVPNConnection(selection models.ServerSelection) (connecti 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) } func (p *piaV3) PortForward(ctx context.Context, client *http.Client, fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator, 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 if err != nil { pfLogger.Error(err) return - } else if n != 32 { - pfLogger.Error("only read %d bytes instead of 32", n) + } else if n != uuidLength { + pfLogger.Error("only read %d bytes instead of %d", n, uuidLength) return } clientID := hex.EncodeToString(b) @@ -96,7 +101,7 @@ func (p *piaV3) PortForward(ctx context.Context, client *http.Client, } defer response.Body.Close() 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 } b, err = ioutil.ReadAll(response.Body) @@ -104,14 +109,14 @@ func (p *piaV3) PortForward(ctx context.Context, client *http.Client, pfLogger.Error(err) return } 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 } body := struct { Port uint16 `json:"port"` }{} 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 } port := body.Port @@ -120,7 +125,7 @@ func (p *piaV3) PortForward(ctx context.Context, client *http.Client, pfLogger.Info("Writing port to %s", filepath) if err := fileManager.WriteToFile( string(filepath), []byte(fmt.Sprintf("%d", port)), - files.Permissions(0666), + files.Permissions(constants.AllReadWritePermissions), ); err != nil { pfLogger.Error(err) } diff --git a/internal/provider/piav4.go b/internal/provider/piav4.go index 46cba19a..d05d7447 100644 --- a/internal/provider/piav4.go +++ b/internal/provider/piav4.go @@ -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 switch selection.Protocol { case constants.TCP: @@ -59,7 +60,9 @@ func (p *piaV4) GetOpenVPNConnection(selection models.ServerSelection) (connecti } } 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 { @@ -107,7 +110,8 @@ func (p *piaV4) GetOpenVPNConnection(selection models.ServerSelection) (connecti 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) } @@ -174,7 +178,7 @@ func (p *piaV4) PortForward(ctx context.Context, client *http.Client, pfLogger.Info("Writing port to %s", filepath) if err := fileManager.WriteToFile( string(filepath), []byte(fmt.Sprintf("%d", data.Port)), - files.Permissions(0666), + files.Permissions(constants.AllReadWritePermissions), ); err != nil { pfLogger.Error(err) } @@ -230,7 +234,7 @@ func (p *piaV4) PortForward(ctx context.Context, client *http.Client, pfLogger.Info("Writing port to %s", filepath) if err := fileManager.WriteToFile( string(filepath), []byte(fmt.Sprintf("%d", data.Port)), - files.Permissions(0666), + files.Permissions(constants.AllReadWritePermissions), ); err != nil { pfLogger.Error(err) } @@ -274,6 +278,7 @@ func newPIAv4HTTPClient(serverName string) (client *http.Client, err error) { MinVersion: tls.VersionTLS12, ServerName: serverName, } + //nolint:gomnd transport := http.Transport{ TLSClientConfig: TLSClientConfig, Proxy: http.ProxyFromEnvironment, @@ -293,8 +298,9 @@ func newPIAv4HTTPClient(serverName string) (client *http.Client, err error) { return client, nil } -func refreshPIAPortForwardData(ctx context.Context, client *http.Client, gateway net.IP, fileManager files.FileManager) (data piaPortForwardData, err error) { - data.Token, err = fetchPIAToken(fileManager, client) +func refreshPIAPortForwardData(ctx context.Context, client *http.Client, + gateway net.IP, fileManager files.FileManager) (data piaPortForwardData, err error) { + data.Token, err = fetchPIAToken(ctx, fileManager, client) if err != nil { 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 } -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) if err != nil { 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", 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 { return "", err } @@ -423,14 +429,16 @@ func getOpenvpnCredentials(fileManager files.FileManager) (username, password st return "", "", fmt.Errorf("cannot read openvpn auth file: %w", err) } 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)) } username, password = lines[0], lines[1] 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.Add("token", token) url := url.URL{ diff --git a/internal/provider/provider.go b/internal/provider/provider.go index c3f6278d..3565a603 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -12,10 +12,11 @@ import ( "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 { 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, fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator, syncState func(port uint16) (pfFilepath models.Filepath)) diff --git a/internal/provider/purevpn.go b/internal/provider/purevpn.go index 9b594c9c..ce88d3ba 100644 --- a/internal/provider/purevpn.go +++ b/internal/provider/purevpn.go @@ -40,7 +40,8 @@ func (p *purevpn) filterServers(regions, countries, cities []string) (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 switch { case selection.Protocol == constants.UDP: @@ -71,7 +72,8 @@ func (p *purevpn) GetOpenVPNConnection(selection models.ServerSelection) (connec 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 { cipher = aes256cbc } diff --git a/internal/provider/surfshark.go b/internal/provider/surfshark.go index df0f8a02..36d75fa1 100644 --- a/internal/provider/surfshark.go +++ b/internal/provider/surfshark.go @@ -38,7 +38,8 @@ func (s *surfshark) filterServers(regions []string) (servers []models.SurfsharkS 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 switch { case selection.Protocol == constants.TCP: @@ -72,7 +73,8 @@ func (s *surfshark) GetOpenVPNConnection(selection models.ServerSelection) (conn 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 { cipher = aes256cbc } diff --git a/internal/provider/vyprvpn.go b/internal/provider/vyprvpn.go index c389024d..5a1ed4d0 100644 --- a/internal/provider/vyprvpn.go +++ b/internal/provider/vyprvpn.go @@ -38,7 +38,8 @@ func (v *vyprvpn) filterServers(regions []string) (servers []models.VyprvpnServe 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 switch { case selection.Protocol == constants.TCP: @@ -68,7 +69,8 @@ func (v *vyprvpn) GetOpenVPNConnection(selection models.ServerSelection) (connec 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 { cipher = aes256cbc } @@ -86,7 +88,7 @@ func (v *vyprvpn) BuildConf(connection models.OpenVPNConnection, verbosity, uid, "comp-lzo", "keepalive 10 60", // "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 "auth-nocache", diff --git a/internal/provider/windscribe.go b/internal/provider/windscribe.go index cbb3fce7..433a2df4 100644 --- a/internal/provider/windscribe.go +++ b/internal/provider/windscribe.go @@ -39,6 +39,7 @@ func (w *windscribe) filterServers(regions []string) (servers []models.Windscrib return servers } +//nolint:lll func (w *windscribe) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) { var port uint16 switch { @@ -71,7 +72,8 @@ func (w *windscribe) GetOpenVPNConnection(selection models.ServerSelection) (con 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 { cipher = aes256cbc } diff --git a/internal/publicip/loop.go b/internal/publicip/loop.go index 153ee080..76adaf13 100644 --- a/internal/publicip/loop.go +++ b/internal/publicip/loop.go @@ -72,10 +72,16 @@ func (l *looper) SetPeriod(period time.Duration) { func (l *looper) logAndWait(ctx context.Context, err error) { l.logger.Error(err) - l.logger.Info("retrying in 5 seconds") - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() // just for the linter - <-ctx.Done() + const waitTime = 5 * time.Second + l.logger.Info("retrying in %s", waitTime) + timer := time.NewTimer(waitTime) + select { + case <-timer.C: + case <-ctx.Done(): + if !timer.Stop() { + <-timer.C + } + } } 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 } l.logger.Info("Public IP address is %s", ip) + const userReadWritePermissions = 0600 err = l.fileManager.WriteLinesToFile( string(l.ipStatusFilepath), []string{ip.String()}, files.Ownership(l.uid, l.gid), - files.Permissions(0600)) + files.Permissions(userReadWritePermissions)) if err != nil { l.logAndWait(ctx, err) continue diff --git a/internal/routing/entry.go b/internal/routing/entry.go index e7cfe021..760be48d 100644 --- a/internal/routing/entry.go +++ b/internal/routing/entry.go @@ -5,7 +5,6 @@ import ( "fmt" "net" "strconv" - "strings" ) @@ -28,7 +27,8 @@ func parseRoutingEntry(s string) (r routingEntry, err error) { return fmt.Errorf("line %q: %w", s, err) } fields := strings.Fields(s) - if len(fields) < 11 { + const minFields = 11 + if len(fields) < minFields { return r, wrapError(fmt.Errorf("not enough fields")) } 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) { bytes, err := hex.DecodeString(reversedHex) + const nBytesRequired = 4 if err != nil { return nil, fmt.Errorf("cannot parse reversed IP hex %q: %s", reversedHex, err) - } else if len(bytes) != 4 { - return nil, fmt.Errorf("hex string contains %d bytes instead of 4", len(bytes)) + } else if L := len(bytes); L != nBytesRequired { + 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 } func hexToIPv4Mask(hexString string) (mask net.IPMask, err error) { bytes, err := hex.DecodeString(hexString) + const nBytesRequired = 4 if err != nil { return nil, fmt.Errorf("cannot parse hex mask %q: %s", hexString, err) - } else if len(bytes) != 4 { - return nil, fmt.Errorf("hex string contains %d bytes instead of 4", len(bytes)) + } else if L := len(bytes); L != nBytesRequired { + 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 } diff --git a/internal/routing/entry_test.go b/internal/routing/entry_test.go index b4bb82c2..195eb003 100644 --- a/internal/routing/entry_test.go +++ b/internal/routing/entry_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" ) +//nolint:lll func Test_parseRoutingEntry(t *testing.T) { t.Parallel() tests := map[string]struct { diff --git a/internal/routing/mutate.go b/internal/routing/mutate.go index e48a8811..0cc3fc56 100644 --- a/internal/routing/mutate.go +++ b/internal/routing/mutate.go @@ -2,12 +2,12 @@ package routing import ( "context" - "net" - "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() r.logger.Info("adding %s as route via %s %s", subnetStr, defaultGateway, defaultInterface) exists, err := r.routeExists(subnet) @@ -19,9 +19,11 @@ func (r *routing) AddRouteVia(ctx context.Context, subnet net.IPNet, defaultGate if r.debug { 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 { - 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 } diff --git a/internal/routing/mutate_test.go b/internal/routing/mutate_test.go index 7af904c8..53d9f08e 100644 --- a/internal/routing/mutate_test.go +++ b/internal/routing/mutate_test.go @@ -63,6 +63,7 @@ func Test_DeleteRouteVia(t *testing.T) { commander.EXPECT().Run(ctx, "ip", "route", "del", subnetStr). Return(tc.runOutput, tc.runErr).Times(1) fileManager := mock_files.NewMockFileManager(mockCtrl) + //nolint:lll routesData := []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT eth0 0002A8C0 0100000A 0003 0 0 0 00FFFFFF 0 0 0 `) diff --git a/internal/routing/reader.go b/internal/routing/reader.go index 2caf239c..4a6d175b 100644 --- a/internal/routing/reader.go +++ b/internal/routing/reader.go @@ -2,9 +2,8 @@ package routing import ( "bytes" - "net" - "fmt" + "net" "strings" "github.com/qdm12/gluetun/internal/constants" @@ -37,7 +36,8 @@ func (r *routing) DefaultRoute() (defaultInterface string, defaultGateway net.IP if err != nil { 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) } var defaultRouteEntry routingEntry @@ -61,7 +61,8 @@ func (r *routing) LocalSubnet() (defaultSubnet net.IPNet, err error) { if err != nil { 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) } var localSubnetEntry routingEntry diff --git a/internal/routing/reader_test.go b/internal/routing/reader_test.go index c90d11ea..169e0e50 100644 --- a/internal/routing/reader_test.go +++ b/internal/routing/reader_test.go @@ -6,14 +6,14 @@ import ( "testing" "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/golibs/files/mock_files" "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 tun0 00000000 050A030A 0003 0 0 0 00000080 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 ` +//nolint:lll func Test_parseRoutingTable(t *testing.T) { t.Parallel() 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) { t.Parallel() tests := map[string]struct { @@ -164,6 +166,7 @@ eth0 000011AC 00000000 0001 0 0 0 0000FFFF } } +//nolint:lll func Test_LocalSubnet(t *testing.T) { t.Parallel() tests := map[string]struct { @@ -229,6 +232,7 @@ eth0 000011AC 10000000 0001 0 0 0 0000FFFF } } +//nolint:lll func Test_routeExists(t *testing.T) { t.Parallel() tests := map[string]struct { @@ -291,6 +295,7 @@ eth0 0002A8C0 0100000A 0003 0 0 0 00FFFFFF } } +//nolint:lll func Test_VPNDestinationIP(t *testing.T) { t.Parallel() tests := map[string]struct { diff --git a/internal/routing/routing.go b/internal/routing/routing.go index 4cc57c2b..845420e0 100644 --- a/internal/routing/routing.go +++ b/internal/routing/routing.go @@ -26,7 +26,7 @@ type routing struct { debug bool } -// NewConfigurator creates a new Configurator instance +// NewConfigurator creates a new Configurator instance. func NewRouting(logger logging.Logger, fileManager files.FileManager) Routing { return &routing{ commander: command.NewCommander(), diff --git a/internal/server/server.go b/internal/server/server.go index f3a52c03..12e3a228 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -28,7 +28,8 @@ type server struct { 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{ address: address, logging: logging, @@ -47,7 +48,8 @@ func (s *server) Run(ctx context.Context, wg *sync.WaitGroup) { <-ctx.Done() s.logger.Warn("context canceled: exiting loop") 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() if err := server.Shutdown(shutdownCtx); err != nil { s.logger.Error("failed shutting down: %s", err) diff --git a/internal/settings/dns.go b/internal/settings/dns.go index b2150c69..b4b28291 100644 --- a/internal/settings/dns.go +++ b/internal/settings/dns.go @@ -11,7 +11,7 @@ import ( "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 { Enabled bool KeepNameserver bool diff --git a/internal/settings/firewall.go b/internal/settings/firewall.go index 661e0077..34bd21b2 100644 --- a/internal/settings/firewall.go +++ b/internal/settings/firewall.go @@ -8,7 +8,7 @@ import ( "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 { AllowedSubnets []net.IPNet VPNInputPorts []uint16 diff --git a/internal/settings/openvpn.go b/internal/settings/openvpn.go index a148afe0..51b34756 100644 --- a/internal/settings/openvpn.go +++ b/internal/settings/openvpn.go @@ -9,7 +9,7 @@ import ( "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 { User string `json:"user"` Password string `json:"-"` @@ -20,7 +20,7 @@ type OpenVPN struct { 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) { settings.User, err = paramsReader.GetUser() if err != nil { diff --git a/internal/settings/openvpn_test.go b/internal/settings/openvpn_test.go index dc3a8f89..d5170458 100644 --- a/internal/settings/openvpn_test.go +++ b/internal/settings/openvpn_test.go @@ -19,6 +19,7 @@ func Test_OpenVPN_JSON(t *testing.T) { } data, err := json.Marshal(in) 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)) var out OpenVPN err = json.Unmarshal(data, &out) diff --git a/internal/settings/providers.go b/internal/settings/providers.go index ec0cf91e..a79aaaea 100644 --- a/internal/settings/providers.go +++ b/internal/settings/providers.go @@ -13,7 +13,8 @@ func GetPIASettings(paramsReader params.Reader) (settings models.ProviderSetting 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) { return getPIASettings(paramsReader, constants.PrivateInternetAccessOld) } @@ -80,13 +81,13 @@ func GetMullvadSettings(paramsReader params.Reader) (settings models.ProviderSet } if settings.ServerSelection.Protocol == constants.TCP { switch settings.ServerSelection.CustomPort { - case 0, 80, 443, 1401: + case 0, 80, 443, 1401: //nolint:gomnd default: return settings, fmt.Errorf("port %d is not valid for TCP protocol", settings.ServerSelection.CustomPort) } } else { 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: return settings, fmt.Errorf("port %d is not valid for UDP protocol", settings.ServerSelection.CustomPort) } diff --git a/internal/settings/server.go b/internal/settings/server.go index 5c6520b8..75f8cb76 100644 --- a/internal/settings/server.go +++ b/internal/settings/server.go @@ -7,7 +7,7 @@ import ( "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 { Port uint16 Log bool @@ -22,7 +22,8 @@ func (c *ControlServer) String() string { 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) { settings.Port, err = paramsReader.GetControlServerPort() if err != nil { diff --git a/internal/settings/settings.go b/internal/settings/settings.go index 5e943605..065459a6 100644 --- a/internal/settings/settings.go +++ b/internal/settings/settings.go @@ -14,7 +14,7 @@ const ( disabled = "disabled" ) -// Settings contains all settings for the program to run +// Settings contains all settings for the program to run. type Settings struct { VPNSP models.VPNProvider OpenVPN OpenVPN diff --git a/internal/settings/shadowsocks.go b/internal/settings/shadowsocks.go index c49e5161..4a1a76dc 100644 --- a/internal/settings/shadowsocks.go +++ b/internal/settings/shadowsocks.go @@ -7,7 +7,7 @@ import ( "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 { Method string Password string diff --git a/internal/settings/system.go b/internal/settings/system.go index 769e66b0..7bae2014 100644 --- a/internal/settings/system.go +++ b/internal/settings/system.go @@ -8,7 +8,7 @@ import ( "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 { UID int GID int @@ -16,7 +16,7 @@ type System struct { 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) { settings.UID, err = paramsReader.GetUID() if err != nil { diff --git a/internal/settings/tinyproxy.go b/internal/settings/tinyproxy.go index f578e77e..d6481df7 100644 --- a/internal/settings/tinyproxy.go +++ b/internal/settings/tinyproxy.go @@ -8,7 +8,7 @@ import ( "github.com/qdm12/gluetun/internal/params" ) -// TinyProxy contains settings to configure TinyProxy +// TinyProxy contains settings to configure TinyProxy. type TinyProxy struct { User string Password string diff --git a/internal/shadowsocks/loop.go b/internal/shadowsocks/loop.go index 83b2a5dc..b78e3e7c 100644 --- a/internal/shadowsocks/loop.go +++ b/internal/shadowsocks/loop.go @@ -34,10 +34,16 @@ type looper struct { func (l *looper) logAndWait(ctx context.Context, err error) { l.logger.Error(err) - l.logger.Info("retrying in 1 minute") - ctx, cancel := context.WithTimeout(ctx, time.Minute) - defer cancel() // just for the linter - <-ctx.Done() + const waitTime = time.Minute + l.logger.Info("retrying in %s", waitTime) + timer := time.NewTimer(waitTime) + select { + case <-timer.C: + case <-ctx.Done(): + if !timer.Stop() { + <-timer.C + } + } } func NewLooper(firewallConf firewall.Configurator, settings settings.ShadowSocks, diff --git a/internal/storage/sync.go b/internal/storage/sync.go index 64965173..3823f86e 100644 --- a/internal/storage/sync.go +++ b/internal/storage/sync.go @@ -25,7 +25,8 @@ func countServers(allServers models.AllServers) int { 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 var serversOnFile models.AllServers _, err = s.osStat(jsonFilepath) diff --git a/internal/tinyproxy/command.go b/internal/tinyproxy/command.go index 65fd9285..c850250b 100644 --- a/internal/tinyproxy/command.go +++ b/internal/tinyproxy/command.go @@ -13,14 +13,15 @@ func (c *configurator) Start(ctx context.Context) (stdout io.ReadCloser, waitFn 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) { output, err := c.commander.Run(ctx, "tinyproxy", "-v") if err != nil { return "", err } 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 words[1], nil diff --git a/internal/tinyproxy/conf.go b/internal/tinyproxy/conf.go index c79e4998..bf4efe57 100644 --- a/internal/tinyproxy/conf.go +++ b/internal/tinyproxy/conf.go @@ -9,16 +9,18 @@ import ( "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") lines := generateConf(logLevel, port, user, password, uid, gid) return c.fileManager.WriteLinesToFile(string(constants.TinyProxyConf), lines, 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{ "User": fmt.Sprintf("%d", uid), "Group": fmt.Sprintf("%d", gid), diff --git a/internal/tinyproxy/loop.go b/internal/tinyproxy/loop.go index 30a8eb48..7267072d 100644 --- a/internal/tinyproxy/loop.go +++ b/internal/tinyproxy/loop.go @@ -37,10 +37,16 @@ type looper struct { func (l *looper) logAndWait(ctx context.Context, err error) { l.logger.Error(err) - l.logger.Info("retrying in 1 minute") - ctx, cancel := context.WithTimeout(ctx, time.Minute) - defer cancel() // just for the linter - <-ctx.Done() + const waitTime = time.Minute + l.logger.Info("retrying in %s", waitTime) + timer := time.NewTimer(waitTime) + select { + case <-timer.C: + case <-ctx.Done(): + if !timer.Stop() { + <-timer.C + } + } } func NewLooper(conf Configurator, firewallConf firewall.Configurator, settings settings.TinyProxy, diff --git a/internal/updater/alias.go b/internal/updater/alias.go index 5e5c623c..8ba87c5b 100644 --- a/internal/updater/alias.go +++ b/internal/updater/alias.go @@ -3,10 +3,8 @@ package updater import ( "context" "net" - "net/http" ) type ( - httpGetFunc func(url string) (r *http.Response, err error) lookupIPFunc func(ctx context.Context, host string) (ips []net.IP, err error) ) diff --git a/internal/updater/loop.go b/internal/updater/loop.go index 608f0cd8..91ec74e0 100644 --- a/internal/updater/loop.go +++ b/internal/updater/loop.go @@ -70,10 +70,16 @@ func (l *looper) SetPeriod(period time.Duration) { func (l *looper) logAndWait(ctx context.Context, err error) { l.logger.Error(err) - l.logger.Info("retrying in 5 minutes") - ctx, cancel := context.WithTimeout(ctx, 5*time.Minute) - defer cancel() // just for the linter - <-ctx.Done() + const waitTime = 5 * time.Minute + l.logger.Info("retrying in %s", waitTime) + timer := time.NewTimer(waitTime) + select { + case <-timer.C: + case <-ctx.Done(): + if !timer.Stop() { + <-timer.C + } + } } func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { diff --git a/internal/updater/mullvad.go b/internal/updater/mullvad.go index 85b8e30e..d6616fe0 100644 --- a/internal/updater/mullvad.go +++ b/internal/updater/mullvad.go @@ -1,18 +1,19 @@ package updater import ( + "context" "encoding/json" "fmt" - "io/ioutil" "net" "net/http" "sort" "github.com/qdm12/gluetun/internal/models" + "github.com/qdm12/golibs/network" ) -func (u *updater) updateMullvad() (err error) { - servers, err := findMullvadServers(u.httpGet) +func (u *updater) updateMullvad(ctx context.Context) (err error) { + servers, err := findMullvadServers(ctx, u.client) if err != nil { return fmt.Errorf("cannot update Mullvad servers: %w", err) } @@ -24,19 +25,14 @@ func (u *updater) updateMullvad() (err error) { 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/" - response, err := httpGet(url) + bytes, status, err := client.Get(ctx, url) if err != nil { return nil, err } - defer response.Body.Close() - if response.StatusCode != http.StatusOK { - return nil, fmt.Errorf(response.Status) - } - bytes, err := ioutil.ReadAll(response.Body) - if err != nil { - return nil, err + if status != http.StatusOK { + return nil, fmt.Errorf("HTTP status code %d", status) } var data []struct { Country string `json:"country_name"` @@ -89,7 +85,6 @@ func findMullvadServers(httpGet httpGetFunc) (servers []models.MullvadServer, er return servers, nil } -//nolint:goconst func stringifyMullvadServers(servers []models.MullvadServer) (s string) { s = "func MullvadServers() []models.MullvadServer {\n" s += " return []models.MullvadServer{\n" diff --git a/internal/updater/mullvad_test.go b/internal/updater/mullvad_test.go index e271baa1..b2a305f7 100644 --- a/internal/updater/mullvad_test.go +++ b/internal/updater/mullvad_test.go @@ -18,6 +18,7 @@ func Test_stringifyMullvadServers(t *testing.T) { IPs: []net.IP{{1, 1, 1, 1}}, IPsV6: []net.IP{{1, 1, 1, 1}}, }} + //nolint:lll expected := ` func MullvadServers() []models.MullvadServer { return []models.MullvadServer{ diff --git a/internal/updater/nordvpn.go b/internal/updater/nordvpn.go index cc6630c0..d1dc470f 100644 --- a/internal/updater/nordvpn.go +++ b/internal/updater/nordvpn.go @@ -1,9 +1,9 @@ package updater import ( + "context" "encoding/json" "fmt" - "io/ioutil" "net" "net/http" "sort" @@ -11,10 +11,11 @@ import ( "strings" "github.com/qdm12/gluetun/internal/models" + "github.com/qdm12/golibs/network" ) -func (u *updater) updateNordvpn() (err error) { - servers, warnings, err := findNordvpnServers(u.httpGet) +func (u *updater) updateNordvpn(ctx context.Context) (err error) { + servers, warnings, err := findNordvpnServers(ctx, u.client) if u.options.CLI { for _, warning := range warnings { u.logger.Warn("Nordvpn: %s", warning) @@ -31,19 +32,15 @@ func (u *updater) updateNordvpn() (err error) { 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" - response, err := httpGet(url) + bytes, status, err := client.Get(ctx, url) if err != nil { return nil, nil, err } - defer response.Body.Close() - if response.StatusCode != http.StatusOK { - return nil, nil, fmt.Errorf(response.Status) - } - bytes, err := ioutil.ReadAll(response.Body) - if err != nil { - return nil, nil, err + if status != http.StatusOK { + return nil, nil, fmt.Errorf("HTTP status code %d", status) } var data []struct { IPAddress string `json:"ip_address"` @@ -71,7 +68,9 @@ func findNordvpnServers(httpGet httpGetFunc) (servers []models.NordvpnServer, wa } ip := net.ParseIP(jsonServer.IPAddress) 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, '#') if i < 0 { @@ -94,7 +93,6 @@ func findNordvpnServers(httpGet httpGetFunc) (servers []models.NordvpnServer, wa return servers, warnings, nil } -//nolint:goconst func stringifyNordvpnServers(servers []models.NordvpnServer) (s string) { s = "func NordvpnServers() []models.NordvpnServer {\n" s += " return []models.NordvpnServer{\n" diff --git a/internal/updater/piav3.go b/internal/updater/piav3.go index b511c92b..362afba6 100644 --- a/internal/updater/piav3.go +++ b/internal/updater/piav3.go @@ -13,7 +13,7 @@ import ( func (u *updater) updatePIAOld(ctx context.Context) (err error) { const zipURL = "https://www.privateinternetaccess.com/openvpn/openvpn.zip" - contents, err := fetchAndExtractFiles(ctx, zipURL) + contents, err := fetchAndExtractFiles(ctx, u.client, zipURL) if err != nil { return err } diff --git a/internal/updater/piav4.go b/internal/updater/piav4.go index bde20f96..b38e54b4 100644 --- a/internal/updater/piav4.go +++ b/internal/updater/piav4.go @@ -2,9 +2,9 @@ package updater import ( "bytes" + "context" "encoding/json" "fmt" - "io/ioutil" "net" "net/http" "sort" @@ -13,18 +13,14 @@ import ( "github.com/qdm12/gluetun/internal/models" ) -func (u *updater) updatePIA() (err error) { +func (u *updater) updatePIA(ctx context.Context) (err error) { const url = "https://serverlist.piaservers.net/vpninfo/servers/v4" - response, err := u.httpGet(url) + b, status, err := u.client.Get(ctx, url) if err != nil { return err } - defer response.Body.Close() - b, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } else if response.StatusCode != http.StatusOK { - return fmt.Errorf("%s: %s", response.Status, strings.ReplaceAll(string(b), "\n", "")) + if status != http.StatusOK { + return fmt.Errorf("HTTP status code %d: %s", status, strings.ReplaceAll(string(b), "\n", "")) } // remove key/signature at the bottom @@ -58,7 +54,8 @@ func (u *updater) updatePIA() (err error) { } for _, udpServer := range region.Servers.UDP { if len(server.OpenvpnUDP.CN) > 0 && server.OpenvpnUDP.CN != udpServer.CN { - return fmt.Errorf("CN is different for UDP for region %q: %q and %q", region.Name, server.OpenvpnUDP.CN, udpServer.CN) + return fmt.Errorf("CN is different for UDP for region %q: %q and %q", + region.Name, server.OpenvpnUDP.CN, udpServer.CN) } if udpServer.IP != nil { server.OpenvpnUDP.IPs = append(server.OpenvpnUDP.IPs, udpServer.IP) @@ -67,7 +64,8 @@ func (u *updater) updatePIA() (err error) { } for _, tcpServer := range region.Servers.TCP { if len(server.OpenvpnTCP.CN) > 0 && server.OpenvpnTCP.CN != tcpServer.CN { - return fmt.Errorf("CN is different for TCP for region %q: %q and %q", region.Name, server.OpenvpnTCP.CN, tcpServer.CN) + return fmt.Errorf("CN is different for TCP for region %q: %q and %q", + region.Name, server.OpenvpnTCP.CN, tcpServer.CN) } if tcpServer.IP != nil { server.OpenvpnTCP.IPs = append(server.OpenvpnTCP.IPs, tcpServer.IP) diff --git a/internal/updater/purevpn.go b/internal/updater/purevpn.go index 5f9ba17e..c64b4347 100644 --- a/internal/updater/purevpn.go +++ b/internal/updater/purevpn.go @@ -4,16 +4,16 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" "net/http" "sort" "strings" "github.com/qdm12/gluetun/internal/models" + "github.com/qdm12/golibs/network" ) func (u *updater) updatePurevpn(ctx context.Context) (err error) { - servers, warnings, err := findPurevpnServers(ctx, u.httpGet, u.lookupIP) + servers, warnings, err := findPurevpnServers(ctx, u.client, u.lookupIP) if u.options.CLI { for _, warning := range warnings { u.logger.Warn("PureVPN: %s", warning) @@ -30,20 +30,15 @@ func (u *updater) updatePurevpn(ctx context.Context) (err error) { return nil } -func findPurevpnServers(ctx context.Context, httpGet httpGetFunc, lookupIP lookupIPFunc) ( +func findPurevpnServers(ctx context.Context, client network.Client, lookupIP lookupIPFunc) ( servers []models.PurevpnServer, warnings []string, err error) { const url = "https://support.purevpn.com/vpn-servers" - response, err := httpGet(url) + bytes, status, err := client.Get(ctx, url) if err != nil { return nil, nil, err } - defer response.Body.Close() - if response.StatusCode != http.StatusOK { - return nil, nil, fmt.Errorf(response.Status) - } - bytes, err := ioutil.ReadAll(response.Body) - if err != nil { - return nil, nil, err + if status != http.StatusOK { + return nil, nil, fmt.Errorf("HTTP status code %d", status) } const jsonPrefix = "" @@ -82,11 +77,13 @@ func findPurevpnServers(ctx context.Context, httpGet httpGetFunc, lookupIP looku return nil, warnings, err } if jsonServer.UDP == "" && jsonServer.TCP == "" { - warnings = append(warnings, fmt.Sprintf("server %s %s %s does not support TCP and UDP for openvpn", jsonServer.Region, jsonServer.Country, jsonServer.City)) + warnings = append(warnings, fmt.Sprintf("server %s %s %s does not support TCP and UDP for openvpn", + jsonServer.Region, jsonServer.Country, jsonServer.City)) continue } if jsonServer.UDP == "" || jsonServer.TCP == "" { - warnings = append(warnings, fmt.Sprintf("server %s %s %s does not support TCP or UDP for openvpn", jsonServer.Region, jsonServer.Country, jsonServer.City)) + warnings = append(warnings, fmt.Sprintf("server %s %s %s does not support TCP or UDP for openvpn", + jsonServer.Region, jsonServer.Country, jsonServer.City)) continue } host := jsonServer.UDP diff --git a/internal/updater/surfshark.go b/internal/updater/surfshark.go index f0922180..eac90c00 100644 --- a/internal/updater/surfshark.go +++ b/internal/updater/surfshark.go @@ -4,16 +4,17 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" "net" + "net/http" "sort" "strings" "github.com/qdm12/gluetun/internal/models" + "github.com/qdm12/golibs/network" ) func (u *updater) updateSurfshark(ctx context.Context) (err error) { - servers, warnings, err := findSurfsharkServersFromZip(ctx, u.lookupIP) + servers, warnings, err := findSurfsharkServersFromZip(ctx, u.client, u.lookupIP) if u.options.CLI { for _, warning := range warnings { u.logger.Warn("Surfshark: %s", warning) @@ -31,16 +32,14 @@ func (u *updater) updateSurfshark(ctx context.Context) (err error) { } //nolint:deadcode,unused -func findSurfsharkServersFromAPI(ctx context.Context, lookupIP lookupIPFunc, httpGet httpGetFunc) (servers []models.SurfsharkServer, warnings []string, err error) { +func findSurfsharkServersFromAPI(ctx context.Context, client network.Client, lookupIP lookupIPFunc) ( + servers []models.SurfsharkServer, warnings []string, err error) { const url = "https://my.surfshark.com/vpn/api/v1/server/clusters" - response, err := httpGet(url) - if err != nil { - return nil, nil, err - } - defer response.Body.Close() - b, err := ioutil.ReadAll(response.Body) + b, status, err := client.Get(ctx, url) if err != nil { return nil, nil, err + } else if status != http.StatusOK { + return nil, nil, fmt.Errorf("HTTP status code %d", status) } var jsonServers []struct { Host string `json:"connectionName"` @@ -70,9 +69,10 @@ func findSurfsharkServersFromAPI(ctx context.Context, lookupIP lookupIPFunc, htt return servers, warnings, nil } -func findSurfsharkServersFromZip(ctx context.Context, lookupIP lookupIPFunc) (servers []models.SurfsharkServer, warnings []string, err error) { +func findSurfsharkServersFromZip(ctx context.Context, client network.Client, lookupIP lookupIPFunc) ( + servers []models.SurfsharkServer, warnings []string, err error) { const zipURL = "https://my.surfshark.com/vpn/api/v1/server/configurations" - contents, err := fetchAndExtractFiles(ctx, zipURL) + contents, err := fetchAndExtractFiles(ctx, client, zipURL) if err != nil { return nil, nil, err } @@ -154,7 +154,8 @@ func getRemainingServers(ctx context.Context, mapping map[string]string, lookupI warnings = append(warnings, warning) continue } else if len(IPs) == 0 { - warning := fmt.Sprintf("subdomain %q for region %q from mapping did not resolve to any IP address", subdomain, region) + warning := fmt.Sprintf("subdomain %q for region %q from mapping did not resolve to any IP address", + subdomain, region) warnings = append(warnings, warning) continue } diff --git a/internal/updater/updater.go b/internal/updater/updater.go index 14be6fa7..d67cce94 100644 --- a/internal/updater/updater.go +++ b/internal/updater/updater.go @@ -8,6 +8,7 @@ import ( "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/golibs/logging" + "github.com/qdm12/golibs/network" ) type Updater interface { @@ -25,8 +26,8 @@ type updater struct { logger logging.Logger timeNow func() time.Time println func(s string) - httpGet httpGetFunc lookupIP lookupIPFunc + client network.Client } func New(options Options, httpClient *http.Client, currentServers models.AllServers, logger logging.Logger) Updater { @@ -34,18 +35,19 @@ func New(options Options, httpClient *http.Client, currentServers models.AllServ options.DNSAddress = "1.1.1.1" } resolver := newResolver(options.DNSAddress) + const clientTimeout = 10 * time.Second return &updater{ logger: logger, timeNow: time.Now, println: func(s string) { fmt.Println(s) }, - httpGet: httpClient.Get, lookupIP: newLookupIP(resolver), + client: network.NewClient(clientTimeout), options: options, servers: currentServers, } } -// TODO parallelize DNS resolution +// TODO parallelize DNS resolution. func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServers, err error) { //nolint:gocognit if u.options.Cyberghost { u.logger.Info("updating Cyberghost servers...") @@ -59,7 +61,7 @@ func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServe if u.options.Mullvad { u.logger.Info("updating Mullvad servers...") - if err := u.updateMullvad(); err != nil { + if err := u.updateMullvad(ctx); err != nil { u.logger.Error(err) } if err := ctx.Err(); err != nil { @@ -70,7 +72,7 @@ func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServe if u.options.Nordvpn { // TODO support servers offering only TCP or only UDP u.logger.Info("updating NordVPN servers...") - if err := u.updateNordvpn(); err != nil { + if err := u.updateNordvpn(ctx); err != nil { u.logger.Error(err) } if err := ctx.Err(); err != nil { @@ -80,7 +82,7 @@ func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServe if u.options.PIA { u.logger.Info("updating Private Internet Access (v4) servers...") - if err := u.updatePIA(); err != nil { + if err := u.updatePIA(ctx); err != nil { u.logger.Error(err) } if ctx.Err() != nil { diff --git a/internal/updater/vyprvpn.go b/internal/updater/vyprvpn.go index 9c13b36a..d56c1646 100644 --- a/internal/updater/vyprvpn.go +++ b/internal/updater/vyprvpn.go @@ -8,10 +8,11 @@ import ( "strings" "github.com/qdm12/gluetun/internal/models" + "github.com/qdm12/golibs/network" ) func (u *updater) updateVyprvpn(ctx context.Context) (err error) { - servers, err := findVyprvpnServers(ctx, u.lookupIP) + servers, err := findVyprvpnServers(ctx, u.client, u.lookupIP) if err != nil { return fmt.Errorf("cannot update Vyprvpn servers: %w", err) } @@ -23,9 +24,10 @@ func (u *updater) updateVyprvpn(ctx context.Context) (err error) { return nil } -func findVyprvpnServers(ctx context.Context, lookupIP lookupIPFunc) (servers []models.VyprvpnServer, err error) { +func findVyprvpnServers(ctx context.Context, client network.Client, lookupIP lookupIPFunc) ( + servers []models.VyprvpnServer, err error) { const zipURL = "https://support.vyprvpn.com/hc/article_attachments/360052617332/Vypr_OpenVPN_20200320.zip" - contents, err := fetchAndExtractFiles(ctx, zipURL) + contents, err := fetchAndExtractFiles(ctx, client, zipURL) if err != nil { return nil, err } diff --git a/internal/updater/zip.go b/internal/updater/zip.go index 9d81f43c..a5778007 100644 --- a/internal/updater/zip.go +++ b/internal/updater/zip.go @@ -9,13 +9,12 @@ import ( "net/http" "path/filepath" "strings" - "time" "github.com/qdm12/golibs/network" ) -func fetchAndExtractFiles(ctx context.Context, urls ...string) (contents map[string][]byte, err error) { - client := network.NewClient(10 * time.Second) +func fetchAndExtractFiles(ctx context.Context, client network.Client, urls ...string) ( + contents map[string][]byte, err error) { contents = make(map[string][]byte) for _, url := range urls { zipBytes, status, err := client.Get(ctx, url)