Configuration package (#369)
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/qdm12/dns/pkg/unbound"
|
"github.com/qdm12/dns/pkg/unbound"
|
||||||
"github.com/qdm12/gluetun/internal/alpine"
|
"github.com/qdm12/gluetun/internal/alpine"
|
||||||
"github.com/qdm12/gluetun/internal/cli"
|
"github.com/qdm12/gluetun/internal/cli"
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/dns"
|
"github.com/qdm12/gluetun/internal/dns"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
@@ -22,11 +23,9 @@ import (
|
|||||||
gluetunLogging "github.com/qdm12/gluetun/internal/logging"
|
gluetunLogging "github.com/qdm12/gluetun/internal/logging"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/openvpn"
|
"github.com/qdm12/gluetun/internal/openvpn"
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
"github.com/qdm12/gluetun/internal/publicip"
|
"github.com/qdm12/gluetun/internal/publicip"
|
||||||
"github.com/qdm12/gluetun/internal/routing"
|
"github.com/qdm12/gluetun/internal/routing"
|
||||||
"github.com/qdm12/gluetun/internal/server"
|
"github.com/qdm12/gluetun/internal/server"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/gluetun/internal/shadowsocks"
|
"github.com/qdm12/gluetun/internal/shadowsocks"
|
||||||
"github.com/qdm12/gluetun/internal/storage"
|
"github.com/qdm12/gluetun/internal/storage"
|
||||||
"github.com/qdm12/gluetun/internal/unix"
|
"github.com/qdm12/gluetun/internal/unix"
|
||||||
@@ -35,6 +34,7 @@ import (
|
|||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
"github.com/qdm12/golibs/os/user"
|
"github.com/qdm12/golibs/os/user"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
"github.com/qdm12/updated/pkg/dnscrypto"
|
"github.com/qdm12/updated/pkg/dnscrypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -140,7 +140,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
routingConf := routing.NewRouting(logger)
|
routingConf := routing.NewRouting(logger)
|
||||||
firewallConf := firewall.NewConfigurator(logger, routingConf, os.OpenFile)
|
firewallConf := firewall.NewConfigurator(logger, routingConf, os.OpenFile)
|
||||||
|
|
||||||
paramsReader := params.NewReader(logger, os)
|
|
||||||
fmt.Println(gluetunLogging.Splash(buildInfo))
|
fmt.Println(gluetunLogging.Splash(buildInfo))
|
||||||
|
|
||||||
printVersions(ctx, logger, map[string]func(ctx context.Context) (string, error){
|
printVersions(ctx, logger, map[string]func(ctx context.Context) (string, error){
|
||||||
@@ -149,10 +148,8 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
"IPtables": firewallConf.Version,
|
"IPtables": firewallConf.Version,
|
||||||
})
|
})
|
||||||
|
|
||||||
allSettings, warnings, err := settings.GetAllSettings(paramsReader)
|
var allSettings configuration.Settings
|
||||||
for _, warning := range warnings {
|
err := allSettings.Read(params.NewEnv(), os, logger.WithPrefix("configuration: "))
|
||||||
logger.Warn(warning)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -7,7 +7,7 @@ require (
|
|||||||
github.com/golang/mock v1.4.4
|
github.com/golang/mock v1.4.4
|
||||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||||
github.com/qdm12/dns v1.4.0
|
github.com/qdm12/dns v1.4.0
|
||||||
github.com/qdm12/golibs v0.0.0-20210124192933-79a950eaf217
|
github.com/qdm12/golibs v0.0.0-20210206072445-35759e951561
|
||||||
github.com/qdm12/ss-server v0.1.0
|
github.com/qdm12/ss-server v0.1.0
|
||||||
github.com/qdm12/updated v0.0.0-20210102005021-dd457d77f94a
|
github.com/qdm12/updated v0.0.0-20210102005021-dd457d77f94a
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -97,6 +97,8 @@ github.com/qdm12/dns v1.4.0/go.mod h1:WUY4/U8Z2O8888DPrahrIBv8GdYeoIcEy4aUDecZ+U
|
|||||||
github.com/qdm12/golibs v0.0.0-20201227203847-2fd99ffdfdba/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
github.com/qdm12/golibs v0.0.0-20201227203847-2fd99ffdfdba/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
||||||
github.com/qdm12/golibs v0.0.0-20210124192933-79a950eaf217 h1:/eMBq0vbc/KmVPXbwLfssp547pp6APRS1x/JNmPvm0s=
|
github.com/qdm12/golibs v0.0.0-20210124192933-79a950eaf217 h1:/eMBq0vbc/KmVPXbwLfssp547pp6APRS1x/JNmPvm0s=
|
||||||
github.com/qdm12/golibs v0.0.0-20210124192933-79a950eaf217/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
github.com/qdm12/golibs v0.0.0-20210124192933-79a950eaf217/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
||||||
|
github.com/qdm12/golibs v0.0.0-20210206072445-35759e951561 h1:YgdQYYj4cEq8jK9TWCItlOOLfmDMVMajcp0YGVCW7cA=
|
||||||
|
github.com/qdm12/golibs v0.0.0-20210206072445-35759e951561/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
||||||
github.com/qdm12/ss-server v0.1.0 h1:WV9MkHCDEWRwe4WpnYFeR/zcZAxYoTbfntLDnw9AQ50=
|
github.com/qdm12/ss-server v0.1.0 h1:WV9MkHCDEWRwe4WpnYFeR/zcZAxYoTbfntLDnw9AQ50=
|
||||||
github.com/qdm12/ss-server v0.1.0/go.mod h1:ABVUkxubboL3vqBkOwDV9glX1/x7SnYrckBe5d+M/zw=
|
github.com/qdm12/ss-server v0.1.0/go.mod h1:ABVUkxubboL3vqBkOwDV9glX1/x7SnYrckBe5d+M/zw=
|
||||||
github.com/qdm12/updated v0.0.0-20210102005021-dd457d77f94a h1:gkyP+gMEeBgMgyRYGrVNcoy6cL1065IvXsyfB6xboIc=
|
github.com/qdm12/updated v0.0.0-20210102005021-dd457d77f94a h1:gkyP+gMEeBgMgyRYGrVNcoy6cL1065IvXsyfB6xboIc=
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
"github.com/qdm12/gluetun/internal/provider"
|
"github.com/qdm12/gluetun/internal/provider"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/gluetun/internal/storage"
|
"github.com/qdm12/gluetun/internal/storage"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *cli) OpenvpnConfig(os os.OS) error {
|
func (c *cli) OpenvpnConfig(os os.OS) error {
|
||||||
@@ -19,8 +19,9 @@ func (c *cli) OpenvpnConfig(os os.OS) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
paramsReader := params.NewReader(logger, os)
|
|
||||||
allSettings, _, err := settings.GetAllSettings(paramsReader)
|
var allSettings configuration.Settings
|
||||||
|
err = allSettings.Read(params.NewEnv(), os, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/gluetun/internal/storage"
|
"github.com/qdm12/gluetun/internal/storage"
|
||||||
"github.com/qdm12/gluetun/internal/updater"
|
"github.com/qdm12/gluetun/internal/updater"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *cli) Update(ctx context.Context, args []string, os os.OS) error {
|
func (c *cli) Update(ctx context.Context, args []string, os os.OS) error {
|
||||||
options := settings.Updater{CLI: true}
|
options := configuration.Updater{CLI: true}
|
||||||
var flushToFile bool
|
var flushToFile bool
|
||||||
flagSet := flag.NewFlagSet("update", flag.ExitOnError)
|
flagSet := flag.NewFlagSet("update", flag.ExitOnError)
|
||||||
flagSet.BoolVar(&flushToFile, "file", false, "Write results to /gluetun/servers.json (for end users)")
|
flagSet.BoolVar(&flushToFile, "file", false, "Write results to /gluetun/servers.json (for end users)")
|
||||||
|
|||||||
3
internal/configuration/configuration.go
Normal file
3
internal/configuration/configuration.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// Package configuration reads initial settings from environment variables
|
||||||
|
// and secret files.
|
||||||
|
package configuration
|
||||||
6
internal/configuration/constants.go
Normal file
6
internal/configuration/constants.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
const (
|
||||||
|
lastIndent = "|--"
|
||||||
|
indent = " "
|
||||||
|
)
|
||||||
107
internal/configuration/cyberghost.go
Normal file
107
internal/configuration/cyberghost.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) cyberghostLines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"Server group: "+settings.ServerSelection.Group)
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.Regions) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.ExtraConfigOptions.ClientKey != "" {
|
||||||
|
lines = append(lines, lastIndent+"Client key is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.ExtraConfigOptions.ClientCertificate != "" {
|
||||||
|
lines = append(lines, lastIndent+"Client certificate is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readCyberghost(r reader) (err error) {
|
||||||
|
settings.Name = constants.Cyberghost
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ExtraConfigOptions.ClientKey, err = readCyberghostClientKey(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ExtraConfigOptions.ClientCertificate, err = readCyberghostClientCertificate(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Group, err = r.env.Inside("CYBERGHOST_GROUP",
|
||||||
|
constants.CyberghostGroupChoices(), params.Default("Premium UDP Europe"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.CyberghostRegionChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCyberghostClientKey(r reader) (clientKey string, err error) {
|
||||||
|
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTKEY", string(constants.ClientKey))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return extractClientKey(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractClientKey(b []byte) (key string, err error) {
|
||||||
|
pemBlock, _ := pem.Decode(b)
|
||||||
|
if pemBlock == nil {
|
||||||
|
return "", fmt.Errorf("cannot decode PEM block from client key")
|
||||||
|
}
|
||||||
|
parsedBytes := pem.EncodeToMemory(pemBlock)
|
||||||
|
s := string(parsedBytes)
|
||||||
|
s = strings.ReplaceAll(s, "\n", "")
|
||||||
|
s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----")
|
||||||
|
s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----")
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCyberghostClientCertificate(r reader) (clientCertificate string, err error) {
|
||||||
|
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTCRT", string(constants.ClientCertificate))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return extractClientCertificate(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractClientCertificate(b []byte) (certificate string, err error) {
|
||||||
|
pemBlock, _ := pem.Decode(b)
|
||||||
|
if pemBlock == nil {
|
||||||
|
return "", fmt.Errorf("cannot decode PEM block from client certificate")
|
||||||
|
}
|
||||||
|
parsedBytes := pem.EncodeToMemory(pemBlock)
|
||||||
|
s := string(parsedBytes)
|
||||||
|
s = strings.ReplaceAll(s, "\n", "")
|
||||||
|
s = strings.TrimPrefix(s, "-----BEGIN CERTIFICATE-----")
|
||||||
|
s = strings.TrimSuffix(s, "-----END CERTIFICATE-----")
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package params
|
package configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
154
internal/configuration/dns.go
Normal file
154
internal/configuration/dns.go
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
unboundmodels "github.com/qdm12/dns/pkg/models"
|
||||||
|
unbound "github.com/qdm12/dns/pkg/unbound"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DNS contains settings to configure Unbound for DNS over TLS operation.
|
||||||
|
type DNS struct { //nolint:maligned
|
||||||
|
Enabled bool
|
||||||
|
PlaintextAddress net.IP
|
||||||
|
KeepNameserver bool
|
||||||
|
BlockMalicious bool
|
||||||
|
BlockAds bool
|
||||||
|
BlockSurveillance bool
|
||||||
|
UpdatePeriod time.Duration
|
||||||
|
Unbound unboundmodels.Settings
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *DNS) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *DNS) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"DNS:")
|
||||||
|
|
||||||
|
if settings.PlaintextAddress != nil {
|
||||||
|
lines = append(lines, indent+lastIndent+"Plaintext address: "+settings.PlaintextAddress.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.KeepNameserver {
|
||||||
|
lines = append(lines, indent+lastIndent+"Keep nameserver (disabled blocking): yes")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !settings.Enabled {
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"DNS over TLS:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+indent+lastIndent+"Unbound:")
|
||||||
|
for _, line := range settings.Unbound.Lines() {
|
||||||
|
lines = append(lines, indent+indent+indent+line)
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.BlockMalicious {
|
||||||
|
lines = append(lines, indent+indent+lastIndent+"Block malicious: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.BlockAds {
|
||||||
|
lines = append(lines, indent+indent+lastIndent+"Block ads: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.BlockSurveillance {
|
||||||
|
lines = append(lines, indent+indent+lastIndent+"Block surveillance: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.UpdatePeriod > 0 {
|
||||||
|
lines = append(lines, indent+indent+lastIndent+"Update: every "+settings.UpdatePeriod.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrUnboundSettings = errors.New("failed getting Unbound settings")
|
||||||
|
ErrDNSProviderNoData = errors.New("DNS provider has no associated data")
|
||||||
|
ErrDNSProviderNoTLS = errors.New("DNS provider does not support DNS over TLS")
|
||||||
|
ErrDNSNoIPv6Support = errors.New("no DNS provider supports IPv6")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *DNS) read(r reader) (err error) {
|
||||||
|
settings.Enabled, err = r.env.OnOff("DOT", params.Default("on"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plain DNS settings
|
||||||
|
if err := settings.readDNSPlaintext(r.env); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.KeepNameserver, err = r.env.OnOff("DNS_KEEP_NAMESERVER", params.Default("off"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNS over TLS external settings
|
||||||
|
settings.BlockMalicious, err = r.env.OnOff("BLOCK_MALICIOUS", params.Default("on"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.BlockSurveillance, err = r.env.OnOff("BLOCK_SURVEILLANCE", params.Default("on"),
|
||||||
|
params.RetroKeys([]string{"BLOCK_NSA"}, r.onRetroActive))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.BlockAds, err = r.env.OnOff("BLOCK_ADS", params.Default("off"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.UpdatePeriod, err = r.env.Duration("DNS_UPDATE_PERIOD", params.Default("24h"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.readUnbound(r); err != nil {
|
||||||
|
return fmt.Errorf("%w: %s", ErrUnboundSettings, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consistency check
|
||||||
|
IPv6Support := false
|
||||||
|
for _, provider := range settings.Unbound.Providers {
|
||||||
|
providerData, ok := unbound.GetProviderData(provider)
|
||||||
|
switch {
|
||||||
|
case !ok:
|
||||||
|
return fmt.Errorf("%w: %s", ErrDNSProviderNoData, provider)
|
||||||
|
case !providerData.SupportsTLS:
|
||||||
|
return fmt.Errorf("%w: %s", ErrDNSProviderNoTLS, provider)
|
||||||
|
case providerData.SupportsIPv6:
|
||||||
|
IPv6Support = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.Unbound.IPv6 && !IPv6Support {
|
||||||
|
return ErrDNSNoIPv6Support
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrDNSAddressNotAnIP = errors.New("DNS plaintext address is not an IP address")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *DNS) readDNSPlaintext(env params.Env) error {
|
||||||
|
s, err := env.Get("DNS_PLAINTEXT_ADDRESS", params.Default("1.1.1.1"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.PlaintextAddress = net.ParseIP(s)
|
||||||
|
if settings.PlaintextAddress == nil {
|
||||||
|
return fmt.Errorf("%w: %s", ErrDNSAddressNotAnIP, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
73
internal/configuration/dns_test.go
Normal file
73
internal/configuration/dns_test.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/dns/pkg/models"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_DNS_Lines(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testCases := map[string]struct {
|
||||||
|
settings DNS
|
||||||
|
lines []string
|
||||||
|
}{
|
||||||
|
"disabled DOT": {
|
||||||
|
settings: DNS{
|
||||||
|
PlaintextAddress: net.IP{1, 1, 1, 1},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--DNS:",
|
||||||
|
" |--Plaintext address: 1.1.1.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"enabled DOT": {
|
||||||
|
settings: DNS{
|
||||||
|
Enabled: true,
|
||||||
|
KeepNameserver: true,
|
||||||
|
Unbound: models.Settings{
|
||||||
|
Providers: []string{"cloudflare"},
|
||||||
|
},
|
||||||
|
BlockMalicious: true,
|
||||||
|
BlockAds: true,
|
||||||
|
BlockSurveillance: true,
|
||||||
|
UpdatePeriod: time.Hour,
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--DNS:",
|
||||||
|
" |--Keep nameserver (disabled blocking): yes",
|
||||||
|
" |--DNS over TLS:",
|
||||||
|
" |--Unbound:",
|
||||||
|
" |--DNS over TLS providers:",
|
||||||
|
" |--cloudflare",
|
||||||
|
" |--Listening port: 0",
|
||||||
|
" |--Access control:",
|
||||||
|
" |--Allowed:",
|
||||||
|
" |--Caching: disabled",
|
||||||
|
" |--IPv4 resolution: disabled",
|
||||||
|
" |--IPv6 resolution: disabled",
|
||||||
|
" |--Verbosity level: 0/5",
|
||||||
|
" |--Verbosity details level: 0/4",
|
||||||
|
" |--Validation log level: 0/2",
|
||||||
|
" |--Blocked hostnames:",
|
||||||
|
" |--Blocked IP addresses:",
|
||||||
|
" |--Allowed hostnames:",
|
||||||
|
" |--Block malicious: enabled",
|
||||||
|
" |--Block ads: enabled",
|
||||||
|
" |--Block surveillance: enabled",
|
||||||
|
" |--Update: every 1h0m0s",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
lines := testCase.settings.lines()
|
||||||
|
assert.Equal(t, testCase.lines, lines)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
93
internal/configuration/firewall.go
Normal file
93
internal/configuration/firewall.go
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Firewall contains settings to customize the firewall operation.
|
||||||
|
type Firewall struct {
|
||||||
|
VPNInputPorts []uint16
|
||||||
|
InputPorts []uint16
|
||||||
|
OutboundSubnets []net.IPNet
|
||||||
|
Enabled bool
|
||||||
|
Debug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Firewall) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Firewall) lines() (lines []string) {
|
||||||
|
if !settings.Enabled {
|
||||||
|
lines = append(lines, lastIndent+"Firewall: disabled ⚠️")
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, lastIndent+"Firewall:")
|
||||||
|
|
||||||
|
if settings.Debug {
|
||||||
|
lines = append(lines, indent+lastIndent+"Debug: on")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.VPNInputPorts) > 0 {
|
||||||
|
lines = append(lines, indent+lastIndent+"VPN input ports: "+
|
||||||
|
strings.Join(uint16sToStrings(settings.VPNInputPorts), ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.InputPorts) > 0 {
|
||||||
|
lines = append(lines, indent+lastIndent+"Input ports: "+
|
||||||
|
strings.Join(uint16sToStrings(settings.InputPorts), ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.OutboundSubnets) > 0 {
|
||||||
|
lines = append(lines, indent+lastIndent+"Outbound subnets: "+
|
||||||
|
strings.Join(ipNetsToStrings(settings.OutboundSubnets), ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Firewall) read(r reader) (err error) {
|
||||||
|
settings.Enabled, err = r.env.OnOff("FIREWALL", params.Default("on"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Debug, err = r.env.OnOff("FIREWALL_DEBUG", params.Default("off"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.readVPNInputPorts(r.env); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.readInputPorts(r.env); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.readOutboundSubnets(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Firewall) readVPNInputPorts(env params.Env) (err error) {
|
||||||
|
settings.VPNInputPorts, err = readCSVPorts(env, "FIREWALL_VPN_INPUT_PORTS")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Firewall) readInputPorts(env params.Env) (err error) {
|
||||||
|
settings.VPNInputPorts, err = readCSVPorts(env, "FIREWALL_INPUT_PORTS")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Firewall) readOutboundSubnets(r reader) (err error) {
|
||||||
|
retroOption := params.RetroKeys([]string{"EXTRA_SUBNETS"}, r.onRetroActive)
|
||||||
|
settings.OutboundSubnets, err = readCSVIPNets(r.env, "FIREWALL_OUTBOUND_SUBNETS", retroOption)
|
||||||
|
return err
|
||||||
|
}
|
||||||
105
internal/configuration/httpproxy.go
Normal file
105
internal/configuration/httpproxy.go
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HTTPProxy contains settings to configure the HTTP proxy.
|
||||||
|
type HTTPProxy struct {
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
Port uint16
|
||||||
|
Enabled bool
|
||||||
|
Stealth bool
|
||||||
|
Log bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *HTTPProxy) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *HTTPProxy) lines() (lines []string) {
|
||||||
|
if !settings.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, lastIndent+"HTTP proxy:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Port: "+strconv.Itoa(int(settings.Port)))
|
||||||
|
|
||||||
|
if settings.User != "" {
|
||||||
|
lines = append(lines, indent+lastIndent+"Authentication: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.Log {
|
||||||
|
lines = append(lines, indent+lastIndent+"Log: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.Stealth {
|
||||||
|
lines = append(lines, indent+lastIndent+"Stealth: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *HTTPProxy) read(r reader) (err error) {
|
||||||
|
settings.Enabled, err = r.env.OnOff("HTTPPROXY", params.Default("off"),
|
||||||
|
params.RetroKeys([]string{"TINYPROXY", "PROXY"}, r.onRetroActive))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.User, err = r.getFromEnvOrSecretFile("HTTPPROXY_USER", false, // compulsory
|
||||||
|
[]string{"TINYPROXY_USER", "PROXY_USER"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Password, err = r.getFromEnvOrSecretFile("HTTPPROXY_USER", false,
|
||||||
|
[]string{"TINYPROXY_PASSWORD", "PROXY_PASSWORD"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Stealth, err = r.env.OnOff("HTTPPROXY_STEALTH", params.Default("off"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.readLog(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var warning string
|
||||||
|
settings.Port, warning, err = r.env.ListeningPort("HTTPPROXY_PORT", params.Default("8888"),
|
||||||
|
params.RetroKeys([]string{"TINYPROXY_PORT", "PROXY_PORT"}, r.onRetroActive))
|
||||||
|
if len(warning) > 0 {
|
||||||
|
r.logger.Warn(warning)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *HTTPProxy) readLog(r reader) error {
|
||||||
|
s, err := r.env.Get("HTTPPROXY_LOG",
|
||||||
|
params.RetroKeys([]string{"PROXY_LOG_LEVEL", "TINYPROXY_LOG"}, r.onRetroActive))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch strings.ToLower(s) {
|
||||||
|
case "on":
|
||||||
|
settings.Enabled = true
|
||||||
|
// Retro compatibility
|
||||||
|
case "info", "connect", "notice":
|
||||||
|
settings.Enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
22
internal/configuration/lines.go
Normal file
22
internal/configuration/lines.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func uint16sToStrings(uint16s []uint16) (strings []string) {
|
||||||
|
strings = make([]string, len(uint16s))
|
||||||
|
for i := range uint16s {
|
||||||
|
strings[i] = strconv.Itoa(int(uint16s[i]))
|
||||||
|
}
|
||||||
|
return strings
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipNetsToStrings(ipNets []net.IPNet) (strings []string) {
|
||||||
|
strings = make([]string, len(ipNets))
|
||||||
|
for i := range ipNets {
|
||||||
|
strings[i] = ipNets[i].String()
|
||||||
|
}
|
||||||
|
return strings
|
||||||
|
}
|
||||||
79
internal/configuration/mullvad.go
Normal file
79
internal/configuration/mullvad.go
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) mullvadLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Countries) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.Cities) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.ISPs) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"ISPs: "+commaJoin(settings.ServerSelection.ISPs))
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.ServerSelection.CustomPort > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Custom port: "+strconv.Itoa(int(settings.ServerSelection.CustomPort)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.ExtraConfigOptions.OpenVPNIPv6 {
|
||||||
|
lines = append(lines, lastIndent+"IPv6: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readMullvad(r reader) (err error) {
|
||||||
|
settings.Name = constants.Mullvad
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.MullvadCountryChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.MullvadCityChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.MullvadISPChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.CustomPort, err = readCustomPort(r.env, settings.ServerSelection.Protocol,
|
||||||
|
[]uint16{80, 443, 1401}, []uint16{53, 1194, 1195, 1196, 1197, 1300, 1301, 1302, 1303, 1400})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Owned, err = r.env.YesNo("OWNED", params.Default("no"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ExtraConfigOptions.OpenVPNIPv6, err = r.env.OnOff("OPENVPN_IPV6", params.Default("off"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
72
internal/configuration/nordvpn.go
Normal file
72
internal/configuration/nordvpn.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) nordvpnLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Regions) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
||||||
|
}
|
||||||
|
|
||||||
|
if numbersUint16 := settings.ServerSelection.Numbers; len(numbersUint16) > 0 {
|
||||||
|
numbersString := make([]string, len(numbersUint16))
|
||||||
|
for i, numberUint16 := range numbersUint16 {
|
||||||
|
numbersString[i] = strconv.Itoa(int(numberUint16))
|
||||||
|
}
|
||||||
|
lines = append(lines, lastIndent+"Numbers: "+commaJoin(numbersString))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readNordvpn(r reader) (err error) {
|
||||||
|
settings.Name = constants.Nordvpn
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.NordvpnRegionChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Numbers, err = readNordVPNServerNumbers(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readNordVPNServerNumbers(env params.Env) (numbers []uint16, err error) {
|
||||||
|
possibilities := make([]string, 65537)
|
||||||
|
for i := range possibilities {
|
||||||
|
possibilities[i] = fmt.Sprintf("%d", i)
|
||||||
|
}
|
||||||
|
possibilities[65536] = ""
|
||||||
|
values, err := env.CSVInside("SERVER_NUMBER", possibilities)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
numbers = make([]uint16, len(values))
|
||||||
|
for i := range values {
|
||||||
|
n, err := strconv.Atoi(values[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
numbers[i] = uint16(n)
|
||||||
|
}
|
||||||
|
return numbers, nil
|
||||||
|
}
|
||||||
139
internal/configuration/openvpn.go
Normal file
139
internal/configuration/openvpn.go
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OpenVPN contains settings to configure the OpenVPN client.
|
||||||
|
type OpenVPN struct {
|
||||||
|
User string `json:"user"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Verbosity int `json:"verbosity"`
|
||||||
|
MSSFix uint16 `json:"mssfix"`
|
||||||
|
Root bool `json:"run_as_root"`
|
||||||
|
Cipher string `json:"cipher"`
|
||||||
|
Auth string `json:"auth"`
|
||||||
|
Provider Provider `json:"provider"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPN) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPN) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"OpenVPN:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Verbosity level: "+strconv.Itoa(settings.Verbosity))
|
||||||
|
|
||||||
|
if settings.Root {
|
||||||
|
lines = append(lines, indent+lastIndent+"Run as root: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.Cipher) > 0 {
|
||||||
|
lines = append(lines, indent+lastIndent+"Custom cipher: "+settings.Cipher)
|
||||||
|
}
|
||||||
|
if len(settings.Auth) > 0 {
|
||||||
|
lines = append(lines, indent+lastIndent+"Custom auth algorithm: "+settings.Auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Provider:")
|
||||||
|
for _, line := range settings.Provider.lines() {
|
||||||
|
lines = append(lines, indent+indent+line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidVPNProvider = errors.New("invalid VPN provider")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *OpenVPN) read(r reader) (err error) {
|
||||||
|
vpnsp, err := r.env.Inside("VPNSP", []string{
|
||||||
|
"pia", "private internet access", "mullvad", "windscribe", "surfshark",
|
||||||
|
"cyberghost", "vyprvpn", "nordvpn", "purevpn", "privado"},
|
||||||
|
params.Default("private internet access"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if vpnsp == "pia" { // retro compatibility
|
||||||
|
vpnsp = "private internet access"
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Provider.Name = models.VPNProvider(vpnsp)
|
||||||
|
|
||||||
|
settings.User, err = r.getFromEnvOrSecretFile("OPENVPN_USER", true, []string{"USER"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Remove spaces in user ID to simplify user's life, thanks @JeordyR
|
||||||
|
settings.User = strings.ReplaceAll(settings.User, " ", "")
|
||||||
|
|
||||||
|
if settings.Provider.Name == constants.Mullvad {
|
||||||
|
settings.Password = "m"
|
||||||
|
} else {
|
||||||
|
settings.Password, err = r.getFromEnvOrSecretFile("OPENVPN_PASSWORD", true, []string{"PASSWORD"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Verbosity, err = r.env.IntRange("OPENVPN_VERBOSITY", 0, 6, params.Default("1"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Root, err = r.env.YesNo("OPENVPN_ROOT", params.Default("no"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Cipher, err = r.env.Get("OPENVPN_CIPHER")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Auth, err = r.env.Get("OPENVPN_AUTH")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mssFix, err := r.env.IntRange("OPENVPN_MSSFIX", 0, 10000, params.Default("0"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.MSSFix = uint16(mssFix)
|
||||||
|
|
||||||
|
var readProvider func(r reader) error
|
||||||
|
switch settings.Provider.Name {
|
||||||
|
case constants.PrivateInternetAccess:
|
||||||
|
readProvider = settings.Provider.readPrivateInternetAccess
|
||||||
|
case constants.Mullvad:
|
||||||
|
readProvider = settings.Provider.readMullvad
|
||||||
|
case constants.Windscribe:
|
||||||
|
readProvider = settings.Provider.readWindscribe
|
||||||
|
case constants.Surfshark:
|
||||||
|
readProvider = settings.Provider.readSurfshark
|
||||||
|
case constants.Cyberghost:
|
||||||
|
readProvider = settings.Provider.readCyberghost
|
||||||
|
case constants.Vyprvpn:
|
||||||
|
readProvider = settings.Provider.readVyprvpn
|
||||||
|
case constants.Nordvpn:
|
||||||
|
readProvider = settings.Provider.readNordvpn
|
||||||
|
case constants.Purevpn:
|
||||||
|
readProvider = settings.Provider.readPurevpn
|
||||||
|
case constants.Privado:
|
||||||
|
readProvider = settings.Provider.readPrivado
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("%w: %s", ErrInvalidVPNProvider, settings.Provider.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return readProvider(r)
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package settings
|
package configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -13,7 +12,7 @@ func Test_OpenVPN_JSON(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
in := OpenVPN{
|
in := OpenVPN{
|
||||||
Root: true,
|
Root: true,
|
||||||
Provider: models.ProviderSettings{
|
Provider: Provider{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
36
internal/configuration/privado.go
Normal file
36
internal/configuration/privado.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) privadoLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Hostnames) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readPrivado(r reader) (err error) {
|
||||||
|
settings.Name = constants.Privado
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.PrivadoHostnameChoices(), params.RetroKeys([]string{"HOSTNAME"}, r.onRetroActive))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
79
internal/configuration/privateinternetaccess.go
Normal file
79
internal/configuration/privateinternetaccess.go
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) privateinternetaccessLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Regions) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, lastIndent+"Encryption preset: "+settings.ServerSelection.EncryptionPreset)
|
||||||
|
|
||||||
|
lines = append(lines, lastIndent+"Custom port: "+strconv.Itoa(int(settings.ServerSelection.CustomPort)))
|
||||||
|
|
||||||
|
if settings.PortForwarding.Enabled {
|
||||||
|
lines = append(lines, lastIndent+"Port forwarding:")
|
||||||
|
for _, line := range settings.PortForwarding.lines() {
|
||||||
|
lines = append(lines, indent+line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readPrivateInternetAccess(r reader) (err error) {
|
||||||
|
settings.Name = constants.PrivateInternetAccess
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptionPreset, err := r.env.Inside("PIA_ENCRYPTION",
|
||||||
|
[]string{constants.PIAEncryptionPresetNormal, constants.PIAEncryptionPresetStrong},
|
||||||
|
params.RetroKeys([]string{"ENCRYPTION"}, r.onRetroActive),
|
||||||
|
params.Default(constants.PIACertificateStrong),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.ServerSelection.EncryptionPreset = encryptionPreset
|
||||||
|
settings.ExtraConfigOptions.EncryptionPreset = encryptionPreset
|
||||||
|
|
||||||
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PIAGeoChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.CustomPort, err = readPortOrZero(r.env, "PORT")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.PortForwarding.Enabled, err = r.env.OnOff("PORT_FORWARDING", params.Default("off"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.PortForwarding.Enabled {
|
||||||
|
filepathStr, err := r.env.Path("PORT_FORWARDING_STATUS_FILE",
|
||||||
|
params.Default("/tmp/gluetun/forwarded_port"), params.CaseSensitiveValue())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.PortForwarding.Filepath = models.Filepath(filepathStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
112
internal/configuration/provider.go
Normal file
112
internal/configuration/provider.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider contains settings specific to a VPN provider.
|
||||||
|
type Provider struct {
|
||||||
|
Name models.VPNProvider `json:"name"`
|
||||||
|
ServerSelection ServerSelection `json:"server_selection"`
|
||||||
|
ExtraConfigOptions ExtraConfigOptions `json:"extra_config"`
|
||||||
|
PortForwarding PortForwarding `json:"port_forwarding"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+strings.Title(string(settings.Name))+" settings:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Network protocol: "+string(settings.ServerSelection.Protocol))
|
||||||
|
|
||||||
|
if settings.ServerSelection.TargetIP != nil {
|
||||||
|
lines = append(lines, indent+lastIndent+"Target IP address: "+settings.ServerSelection.TargetIP.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var providerLines []string
|
||||||
|
switch strings.ToLower(string(settings.Name)) {
|
||||||
|
case "cyberghost":
|
||||||
|
providerLines = settings.cyberghostLines()
|
||||||
|
case "mullvad":
|
||||||
|
providerLines = settings.mullvadLines()
|
||||||
|
case "nordvpn":
|
||||||
|
providerLines = settings.nordvpnLines()
|
||||||
|
case "privado":
|
||||||
|
providerLines = settings.privadoLines()
|
||||||
|
case "private internet access":
|
||||||
|
providerLines = settings.privateinternetaccessLines()
|
||||||
|
case "purevpn":
|
||||||
|
providerLines = settings.purevpnLines()
|
||||||
|
case "surfshark":
|
||||||
|
providerLines = settings.surfsharkLines()
|
||||||
|
case "vyprvpn":
|
||||||
|
providerLines = settings.vyprvpnLines()
|
||||||
|
case "windscribe":
|
||||||
|
providerLines = settings.windscribeLines()
|
||||||
|
default:
|
||||||
|
panic(`Missing lines method for provider "` +
|
||||||
|
settings.Name + `"! Please create a Github issue.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range providerLines {
|
||||||
|
lines = append(lines, indent+line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func commaJoin(slice []string) string {
|
||||||
|
return strings.Join(slice, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func readProtocol(env params.Env) (protocol models.NetworkProtocol, err error) {
|
||||||
|
s, err := env.Inside("PROTOCOL",
|
||||||
|
[]string{string(constants.TCP), string(constants.UDP)},
|
||||||
|
params.Default(string(constants.UDP)))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return models.NetworkProtocol(s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readTargetIP(env params.Env) (targetIP net.IP, err error) {
|
||||||
|
return readIP(env, "OPENVPN_TARGET_IP")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidProtocol = errors.New("invalid network protocol")
|
||||||
|
)
|
||||||
|
|
||||||
|
func readCustomPort(env params.Env, protocol models.NetworkProtocol,
|
||||||
|
allowedTCP, allowedUDP []uint16) (port uint16, err error) {
|
||||||
|
port, err = readPortOrZero(env, "PORT")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if port == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch protocol {
|
||||||
|
case constants.TCP:
|
||||||
|
for i := range allowedTCP {
|
||||||
|
if allowedTCP[i] == port {
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("%w: port %d for TCP protocol", ErrInvalidPort, port)
|
||||||
|
case constants.UDP:
|
||||||
|
for i := range allowedUDP {
|
||||||
|
if allowedTCP[i] == port {
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("%w: port %d for UDP protocol", ErrInvalidPort, port)
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("%w: %s", ErrInvalidProtocol, protocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
246
internal/configuration/provider_test.go
Normal file
246
internal/configuration/provider_test.go
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/params/mock_params"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errDummy = errors.New("dummy")
|
||||||
|
|
||||||
|
func Test_Provider_lines(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
settings Provider
|
||||||
|
lines []string
|
||||||
|
}{
|
||||||
|
"cyberghost": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Cyberghost,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Group: "group",
|
||||||
|
Regions: []string{"a", "El country"},
|
||||||
|
},
|
||||||
|
ExtraConfigOptions: ExtraConfigOptions{
|
||||||
|
ClientKey: "a",
|
||||||
|
ClientCertificate: "a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Cyberghost settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Server group: group",
|
||||||
|
" |--Regions: a, El country",
|
||||||
|
" |--Client key is set",
|
||||||
|
" |--Client certificate is set",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"mullvad": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Mullvad,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Countries: []string{"a", "b"},
|
||||||
|
Cities: []string{"c", "d"},
|
||||||
|
ISPs: []string{"e", "f"},
|
||||||
|
CustomPort: 1,
|
||||||
|
},
|
||||||
|
ExtraConfigOptions: ExtraConfigOptions{
|
||||||
|
OpenVPNIPv6: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Mullvad settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Countries: a, b",
|
||||||
|
" |--Cities: c, d",
|
||||||
|
" |--ISPs: e, f",
|
||||||
|
" |--Custom port: 1",
|
||||||
|
" |--IPv6: enabled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"nordvpn": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Nordvpn,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Regions: []string{"a", "b"},
|
||||||
|
Numbers: []uint16{1, 2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Nordvpn settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Regions: a, b",
|
||||||
|
" |--Numbers: 1, 2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"privado": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Privado,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Hostnames: []string{"a", "b"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Privado settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Hostnames: a, b",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"private internet access": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.PrivateInternetAccess,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Regions: []string{"a", "b"},
|
||||||
|
EncryptionPreset: constants.PIAEncryptionPresetStrong,
|
||||||
|
CustomPort: 1,
|
||||||
|
},
|
||||||
|
PortForwarding: PortForwarding{
|
||||||
|
Enabled: true,
|
||||||
|
Filepath: models.Filepath("/here"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Private Internet Access settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Regions: a, b",
|
||||||
|
" |--Encryption preset: strong",
|
||||||
|
" |--Custom port: 1",
|
||||||
|
" |--Port forwarding:",
|
||||||
|
" |--File path: /here",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"purevpn": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Purevpn,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Regions: []string{"a", "b"},
|
||||||
|
Countries: []string{"c", "d"},
|
||||||
|
Cities: []string{"e", "f"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Purevpn settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Regions: a, b",
|
||||||
|
" |--Countries: c, d",
|
||||||
|
" |--Cities: e, f",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"surfshark": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Regions: []string{"a", "b"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Surfshark settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Regions: a, b",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"vyprvpn": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Vyprvpn,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Regions: []string{"a", "b"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Vyprvpn settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Regions: a, b",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"windscribe": {
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Windscribe,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Protocol: constants.UDP,
|
||||||
|
Regions: []string{"a", "b"},
|
||||||
|
Cities: []string{"c", "d"},
|
||||||
|
Hostnames: []string{"e", "f"},
|
||||||
|
CustomPort: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"|--Windscribe settings:",
|
||||||
|
" |--Network protocol: udp",
|
||||||
|
" |--Regions: a, b",
|
||||||
|
" |--Cities: c, d",
|
||||||
|
" |--Hostnames: e, f",
|
||||||
|
" |--Custom port: 1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
lines := testCase.settings.lines()
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.lines, lines)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_readProtocol(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
mockStr string
|
||||||
|
mockErr error
|
||||||
|
protocol models.NetworkProtocol
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
"error": {
|
||||||
|
mockErr: errDummy,
|
||||||
|
err: errDummy,
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
mockStr: "tcp",
|
||||||
|
protocol: constants.TCP,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
|
||||||
|
env := mock_params.NewMockEnv(ctrl)
|
||||||
|
env.EXPECT().
|
||||||
|
Inside("PROTOCOL", []string{"tcp", "udp"}, gomock.Any()).
|
||||||
|
Return(testCase.mockStr, testCase.mockErr)
|
||||||
|
|
||||||
|
protocol, err := readProtocol(env)
|
||||||
|
|
||||||
|
if testCase.err != nil {
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.protocol, protocol)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
48
internal/configuration/publicip.go
Normal file
48
internal/configuration/publicip.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PublicIP struct {
|
||||||
|
Period time.Duration `json:"period"`
|
||||||
|
IPFilepath models.Filepath `json:"ip_filepath"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *PublicIP) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *PublicIP) lines() (lines []string) {
|
||||||
|
if settings.Period == 0 {
|
||||||
|
lines = append(lines, lastIndent+"Public IP getter: disabled")
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, lastIndent+"Public IP getter:")
|
||||||
|
lines = append(lines, indent+lastIndent+"Fetch period: "+settings.Period.String())
|
||||||
|
lines = append(lines, indent+lastIndent+"IP file: "+string(settings.IPFilepath))
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *PublicIP) read(r reader) (err error) {
|
||||||
|
settings.Period, err = r.env.Duration("PUBLICIP_PERIOD", params.Default("12h"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filepathStr, err := r.env.Path("PUBLICIP_FILE", params.CaseSensitiveValue(),
|
||||||
|
params.Default("/tmp/gluetun/ip"),
|
||||||
|
params.RetroKeys([]string{"IP_STATUS_FILE"}, r.onRetroActive))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.IPFilepath = models.Filepath(filepathStr)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
52
internal/configuration/purevpn.go
Normal file
52
internal/configuration/purevpn.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) purevpnLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Regions) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.Countries) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.Cities) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readPurevpn(r reader) (err error) {
|
||||||
|
settings.Name = constants.Purevpn
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PurevpnRegionChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PurevpnCountryChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PurevpnCityChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
129
internal/configuration/reader.go
Normal file
129
internal/configuration/reader.go
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
"github.com/qdm12/golibs/os"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
"github.com/qdm12/golibs/verification"
|
||||||
|
)
|
||||||
|
|
||||||
|
type reader struct {
|
||||||
|
env params.Env
|
||||||
|
logger logging.Logger
|
||||||
|
regex verification.Regex
|
||||||
|
os os.OS
|
||||||
|
}
|
||||||
|
|
||||||
|
func newReader(env params.Env, os os.OS, logger logging.Logger) reader {
|
||||||
|
return reader{
|
||||||
|
env: env,
|
||||||
|
logger: logger,
|
||||||
|
regex: verification.NewRegex(),
|
||||||
|
os: os,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) onRetroActive(oldKey, newKey string) {
|
||||||
|
r.logger.Warn(
|
||||||
|
"You are using the old environment variable %s, please consider changing it to %s",
|
||||||
|
oldKey, newKey,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidPort = errors.New("invalid port")
|
||||||
|
)
|
||||||
|
|
||||||
|
func readCSVPorts(env params.Env, key string) (ports []uint16, err error) {
|
||||||
|
s, err := env.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if len(s) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
portsStr := strings.Split(s, ",")
|
||||||
|
ports = make([]uint16, len(portsStr))
|
||||||
|
for i, portStr := range portsStr {
|
||||||
|
portInt, err := strconv.Atoi(portStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%w: %q from environment variable %s: %s",
|
||||||
|
ErrInvalidPort, portStr, key, err)
|
||||||
|
} else if portInt <= 0 || portInt > 65535 {
|
||||||
|
return nil, fmt.Errorf("%w: %d from environment variable %s: must be between 1 and 65535",
|
||||||
|
ErrInvalidPort, portInt, key)
|
||||||
|
}
|
||||||
|
ports[i] = uint16(portInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ports, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidIPNet = errors.New("invalid IP network")
|
||||||
|
)
|
||||||
|
|
||||||
|
func readCSVIPNets(env params.Env, key string, options ...params.OptionSetter) (
|
||||||
|
ipNets []net.IPNet, err error) {
|
||||||
|
s, err := env.Get(key, options...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if s == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ipNetsStr := strings.Split(s, ",")
|
||||||
|
ipNets = make([]net.IPNet, len(ipNetsStr))
|
||||||
|
for i, ipNetStr := range ipNetsStr {
|
||||||
|
_, ipNet, err := net.ParseCIDR(ipNetStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%w: %q from environment variable %s: %s",
|
||||||
|
ErrInvalidIPNet, ipNetStr, key, err)
|
||||||
|
} else if ipNet == nil {
|
||||||
|
return nil, fmt.Errorf("%w: %q from environment variable %s: subnet is nil",
|
||||||
|
ErrInvalidIPNet, ipNetStr, key)
|
||||||
|
}
|
||||||
|
ipNets[i] = *ipNet
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipNets, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidIP = errors.New("invalid IP address")
|
||||||
|
)
|
||||||
|
|
||||||
|
func readIP(env params.Env, key string) (ip net.IP, err error) {
|
||||||
|
s, err := env.Get(key)
|
||||||
|
if len(s) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = net.ParseIP(s)
|
||||||
|
if ip == nil {
|
||||||
|
return nil, fmt.Errorf("%w: %s", ErrInvalidIP, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readPortOrZero(env params.Env, key string) (port uint16, err error) {
|
||||||
|
s, err := env.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s) == 0 || s == "0" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return env.Port(key)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package params
|
package configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
libparams "github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -19,11 +19,11 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (r *reader) getFromEnvOrSecretFile(envKey string, compulsory bool, retroKeys []string) (value string, err error) {
|
func (r *reader) getFromEnvOrSecretFile(envKey string, compulsory bool, retroKeys []string) (value string, err error) {
|
||||||
envOptions := []libparams.OptionSetter{
|
envOptions := []params.OptionSetter{
|
||||||
libparams.Compulsory(), // to fallback on file reading
|
params.Compulsory(), // to fallback on file reading
|
||||||
libparams.CaseSensitiveValue(),
|
params.CaseSensitiveValue(),
|
||||||
libparams.Unset(),
|
params.Unset(),
|
||||||
libparams.RetroKeys(retroKeys, r.onRetroActive),
|
params.RetroKeys(retroKeys, r.onRetroActive),
|
||||||
}
|
}
|
||||||
value, envErr := r.env.Get(envKey, envOptions...)
|
value, envErr := r.env.Get(envKey, envOptions...)
|
||||||
if envErr == nil {
|
if envErr == nil {
|
||||||
@@ -32,8 +32,8 @@ func (r *reader) getFromEnvOrSecretFile(envKey string, compulsory bool, retroKey
|
|||||||
|
|
||||||
defaultSecretFile := "/run/secrets/" + strings.ToLower(envKey)
|
defaultSecretFile := "/run/secrets/" + strings.ToLower(envKey)
|
||||||
filepath, err := r.env.Get(envKey+"_SECRETFILE",
|
filepath, err := r.env.Get(envKey+"_SECRETFILE",
|
||||||
libparams.CaseSensitiveValue(),
|
params.CaseSensitiveValue(),
|
||||||
libparams.Default(defaultSecretFile),
|
params.Default(defaultSecretFile),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("%w: %s", ErrGetSecretFilepath, err)
|
return "", fmt.Errorf("%w: %s", ErrGetSecretFilepath, err)
|
||||||
@@ -68,8 +68,8 @@ func (r *reader) getFromFileOrSecretFile(secretName, filepath string) (
|
|||||||
b []byte, err error) {
|
b []byte, err error) {
|
||||||
defaultSecretFile := "/run/secrets/" + strings.ToLower(secretName)
|
defaultSecretFile := "/run/secrets/" + strings.ToLower(secretName)
|
||||||
secretFilepath, err := r.env.Get(strings.ToUpper(secretName)+"_SECRETFILE",
|
secretFilepath, err := r.env.Get(strings.ToUpper(secretName)+"_SECRETFILE",
|
||||||
libparams.CaseSensitiveValue(),
|
params.CaseSensitiveValue(),
|
||||||
libparams.Default(defaultSecretFile),
|
params.Default(defaultSecretFile),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return b, fmt.Errorf("%w: %s", ErrGetSecretFilepath, err)
|
return b, fmt.Errorf("%w: %s", ErrGetSecretFilepath, err)
|
||||||
55
internal/configuration/selection.go
Normal file
55
internal/configuration/selection.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerSelection struct {
|
||||||
|
// Common
|
||||||
|
Protocol models.NetworkProtocol `json:"network_protocol"`
|
||||||
|
TargetIP net.IP `json:"target_ip,omitempty"`
|
||||||
|
|
||||||
|
// Cyberghost, PIA, Surfshark, Windscribe, Vyprvpn, NordVPN
|
||||||
|
Regions []string `json:"regions"`
|
||||||
|
|
||||||
|
// Cyberghost
|
||||||
|
Group string `json:"group"`
|
||||||
|
|
||||||
|
Countries []string `json:"countries"` // Mullvad, PureVPN
|
||||||
|
Cities []string `json:"cities"` // Mullvad, PureVPN, Windscribe
|
||||||
|
Hostnames []string `json:"hostnames"` // Windscribe, Privado
|
||||||
|
|
||||||
|
// Mullvad
|
||||||
|
ISPs []string `json:"isps"`
|
||||||
|
Owned bool `json:"owned"`
|
||||||
|
|
||||||
|
// Mullvad, Windscribe, PIA
|
||||||
|
CustomPort uint16 `json:"custom_port"`
|
||||||
|
|
||||||
|
// NordVPN
|
||||||
|
Numbers []uint16 `json:"numbers"`
|
||||||
|
|
||||||
|
// PIA
|
||||||
|
EncryptionPreset string `json:"encryption_preset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtraConfigOptions struct {
|
||||||
|
ClientCertificate string `json:"-"` // Cyberghost
|
||||||
|
ClientKey string `json:"-"` // Cyberghost
|
||||||
|
EncryptionPreset string `json:"encryption_preset"` // PIA
|
||||||
|
OpenVPNIPv6 bool `json:"openvpn_ipv6"` // Mullvad
|
||||||
|
}
|
||||||
|
|
||||||
|
// PortForwarding contains settings for port forwarding.
|
||||||
|
type PortForwarding struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Filepath models.Filepath `json:"filepath"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PortForwarding) lines() (lines []string) {
|
||||||
|
return []string{
|
||||||
|
lastIndent + "File path: " + string(p.Filepath),
|
||||||
|
}
|
||||||
|
}
|
||||||
49
internal/configuration/server.go
Normal file
49
internal/configuration/server.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ControlServer contains settings to customize the control server operation.
|
||||||
|
type ControlServer struct {
|
||||||
|
Port uint16
|
||||||
|
Log bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *ControlServer) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *ControlServer) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"HTTP control server:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Listening port: "+strconv.Itoa(int(settings.Port)))
|
||||||
|
|
||||||
|
if settings.Log {
|
||||||
|
lines = append(lines, indent+lastIndent+"Logging: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *ControlServer) read(r reader) (err error) {
|
||||||
|
settings.Log, err = r.env.OnOff("HTTP_CONTROL_SERVER_LOG", params.Default("on"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var warning string
|
||||||
|
settings.Port, warning, err = r.env.ListeningPort(
|
||||||
|
"HTTP_CONTROL_SERVER_PORT", params.Default("8000"))
|
||||||
|
if len(warning) > 0 {
|
||||||
|
r.logger.Warn(warning)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
93
internal/configuration/settings.go
Normal file
93
internal/configuration/settings.go
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
"github.com/qdm12/golibs/os"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Settings contains all settings for the program to run.
|
||||||
|
type Settings struct {
|
||||||
|
OpenVPN OpenVPN
|
||||||
|
System System
|
||||||
|
DNS DNS
|
||||||
|
Firewall Firewall
|
||||||
|
HTTPProxy HTTPProxy
|
||||||
|
ShadowSocks ShadowSocks
|
||||||
|
Updater Updater
|
||||||
|
PublicIP PublicIP
|
||||||
|
VersionInformation bool
|
||||||
|
ControlServer ControlServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Settings) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Settings) lines() (lines []string) {
|
||||||
|
lines = append(lines, "Settings summary below:")
|
||||||
|
lines = append(lines, settings.OpenVPN.lines()...)
|
||||||
|
lines = append(lines, settings.DNS.lines()...)
|
||||||
|
lines = append(lines, settings.Firewall.lines()...)
|
||||||
|
lines = append(lines, settings.System.lines()...)
|
||||||
|
lines = append(lines, settings.HTTPProxy.lines()...)
|
||||||
|
lines = append(lines, settings.ShadowSocks.lines()...)
|
||||||
|
lines = append(lines, settings.ControlServer.lines()...)
|
||||||
|
lines = append(lines, settings.Updater.lines()...)
|
||||||
|
lines = append(lines, settings.PublicIP.lines()...)
|
||||||
|
if settings.VersionInformation {
|
||||||
|
lines = append(lines, lastIndent+"Github version information: enabled")
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read obtains all configuration options for the program and returns an error as soon
|
||||||
|
// as an error is encountered reading them.
|
||||||
|
func (settings *Settings) Read(env params.Env, os os.OS, logger logging.Logger) (err error) {
|
||||||
|
r := newReader(env, os, logger)
|
||||||
|
|
||||||
|
settings.VersionInformation, err = r.env.OnOff("VERSION_INFORMATION", params.Default("on"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.OpenVPN.read(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.System.read(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.DNS.read(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.Firewall.read(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.HTTPProxy.read(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.ShadowSocks.read(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.ControlServer.read(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.Updater.read(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.PublicIP.read(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
55
internal/configuration/settings_test.go
Normal file
55
internal/configuration/settings_test.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Settings_lines(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
settings Settings
|
||||||
|
lines []string
|
||||||
|
}{
|
||||||
|
"default settings": {
|
||||||
|
settings: Settings{
|
||||||
|
OpenVPN: OpenVPN{
|
||||||
|
Provider: Provider{
|
||||||
|
Name: constants.Mullvad,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lines: []string{
|
||||||
|
"Settings summary below:",
|
||||||
|
"|--OpenVPN:",
|
||||||
|
" |--Verbosity level: 0",
|
||||||
|
" |--Provider:",
|
||||||
|
" |--Mullvad settings:",
|
||||||
|
" |--Network protocol: ",
|
||||||
|
"|--DNS:",
|
||||||
|
"|--Firewall: disabled ⚠️",
|
||||||
|
"|--System:",
|
||||||
|
" |--Process user ID: 0",
|
||||||
|
" |--Process group ID: 0",
|
||||||
|
" |--Timezone: NOT SET ⚠️ - it can cause time related issues",
|
||||||
|
"|--HTTP control server:",
|
||||||
|
" |--Listening port: 0",
|
||||||
|
"|--Public IP getter: disabled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
lines := testCase.settings.lines()
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.lines, lines)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
72
internal/configuration/shadowsocks.go
Normal file
72
internal/configuration/shadowsocks.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ShadowSocks contains settings to configure the Shadowsocks server.
|
||||||
|
type ShadowSocks struct {
|
||||||
|
Method string
|
||||||
|
Password string
|
||||||
|
Port uint16
|
||||||
|
Enabled bool
|
||||||
|
Log bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *ShadowSocks) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *ShadowSocks) lines() (lines []string) {
|
||||||
|
if !settings.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, lastIndent+"Shadowsocks server:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Listening port: "+strconv.Itoa(int(settings.Port)))
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Method: "+settings.Method)
|
||||||
|
|
||||||
|
if settings.Log {
|
||||||
|
lines = append(lines, indent+lastIndent+"Logging: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *ShadowSocks) read(r reader) (err error) {
|
||||||
|
settings.Enabled, err = r.env.OnOff("SHADOWSOCKS", params.Default("off"))
|
||||||
|
if err != nil || !settings.Enabled {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Password, err = r.getFromEnvOrSecretFile("SHADOWSOCKS_PASSWORD", false, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Log, err = r.env.OnOff("SHADOWSOCKS_LOG", params.Default("off"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Method, err = r.env.Get("SHADOWSOCKS_METHOD", params.Default("chacha20-ietf-poly1305"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var warning string
|
||||||
|
settings.Port, warning, err = r.env.ListeningPort("SHADOWSOCKS_PORT", params.Default("8388"))
|
||||||
|
if len(warning) > 0 {
|
||||||
|
r.logger.Warn(warning)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
34
internal/configuration/surfshark.go
Normal file
34
internal/configuration/surfshark.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) surfsharkLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Regions) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readSurfshark(r reader) (err error) {
|
||||||
|
settings.Name = constants.Surfshark
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.SurfsharkRegionChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
53
internal/configuration/system.go
Normal file
53
internal/configuration/system.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// System contains settings to configure system related elements.
|
||||||
|
type System struct {
|
||||||
|
PUID int
|
||||||
|
PGID int
|
||||||
|
Timezone string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *System) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *System) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"System:")
|
||||||
|
lines = append(lines, indent+lastIndent+"Process user ID: "+strconv.Itoa(settings.PUID))
|
||||||
|
lines = append(lines, indent+lastIndent+"Process group ID: "+strconv.Itoa(settings.PGID))
|
||||||
|
|
||||||
|
if len(settings.Timezone) > 0 {
|
||||||
|
lines = append(lines, indent+lastIndent+"Timezone: "+settings.Timezone)
|
||||||
|
} else {
|
||||||
|
lines = append(lines, indent+lastIndent+"Timezone: NOT SET ⚠️ - it can cause time related issues")
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *System) read(r reader) (err error) {
|
||||||
|
settings.PUID, err = r.env.IntRange("PUID", 0, 65535, params.Default("1000"),
|
||||||
|
params.RetroKeys([]string{"UID"}, r.onRetroActive))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.PGID, err = r.env.IntRange("PGID", 0, 65535, params.Default("1000"),
|
||||||
|
params.RetroKeys([]string{"GID"}, r.onRetroActive))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Timezone, err = r.env.Get("TZ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
133
internal/configuration/unbound.go
Normal file
133
internal/configuration/unbound.go
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
unbound "github.com/qdm12/dns/pkg/unbound"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *DNS) readUnbound(r reader) (err error) {
|
||||||
|
if err := settings.readUnboundProviders(r.env); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Unbound.ListeningPort = 53
|
||||||
|
|
||||||
|
settings.Unbound.Caching, err = r.env.OnOff("DOT_CACHING", params.Default("on"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Unbound.IPv4 = true
|
||||||
|
|
||||||
|
settings.Unbound.IPv6, err = r.env.OnOff("DOT_IPV6", params.Default("off"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
verbosityLevel, err := r.env.IntRange("DOT_VERBOSITY", 0, 5, params.Default("1"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.Unbound.VerbosityLevel = uint8(verbosityLevel)
|
||||||
|
|
||||||
|
verbosityDetailsLevel, err := r.env.IntRange("DOT_VERBOSITY_DETAILS", 0, 4, params.Default("0"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.Unbound.VerbosityDetailsLevel = uint8(verbosityDetailsLevel)
|
||||||
|
|
||||||
|
validationLogLevel, err := r.env.IntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, params.Default("0"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
settings.Unbound.ValidationLogLevel = uint8(validationLogLevel)
|
||||||
|
|
||||||
|
if err := settings.readUnboundPrivateAddresses(r.env); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := settings.readUnboundUnblockedHostnames(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Unbound.AccessControl.Allowed = []net.IPNet{
|
||||||
|
{
|
||||||
|
IP: net.IPv4zero,
|
||||||
|
Mask: net.IPv4Mask(0, 0, 0, 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
IP: net.IPv6zero,
|
||||||
|
Mask: net.IPMask{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidDNSOverTLSProvider = errors.New("invalid DNS over TLS provider")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *DNS) readUnboundProviders(env params.Env) (err error) {
|
||||||
|
s, err := env.Get("DOT_PROVIDERS", params.Default("cloudflare"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, provider := range strings.Split(s, ",") {
|
||||||
|
_, ok := unbound.GetProviderData(provider)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("%w: %s", ErrInvalidDNSOverTLSProvider, provider)
|
||||||
|
}
|
||||||
|
settings.Unbound.Providers = append(settings.Unbound.Providers, provider)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidPrivateAddress = errors.New("private address is not a valid IP or CIDR range")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *DNS) readUnboundPrivateAddresses(env params.Env) (err error) {
|
||||||
|
privateAddresses, err := env.CSV("DOT_PRIVATE_ADDRESS")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(privateAddresses) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, address := range privateAddresses {
|
||||||
|
ip := net.ParseIP(address)
|
||||||
|
_, _, err := net.ParseCIDR(address)
|
||||||
|
if ip == nil && err != nil {
|
||||||
|
return fmt.Errorf("%w: %s", ErrInvalidPrivateAddress, address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings.Unbound.BlockedIPs = append(
|
||||||
|
settings.Unbound.BlockedIPs, privateAddresses...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidHostname = errors.New("invalid hostname")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *DNS) readUnboundUnblockedHostnames(r reader) (err error) {
|
||||||
|
hostnames, err := r.env.CSV("UNBLOCK")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(hostnames) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, hostname := range hostnames {
|
||||||
|
if !r.regex.MatchHostname(hostname) {
|
||||||
|
return fmt.Errorf("%w: %s", ErrInvalidHostname, hostname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings.Unbound.AllowedHostnames = append(
|
||||||
|
settings.Unbound.AllowedHostnames, hostnames...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
62
internal/configuration/updater.go
Normal file
62
internal/configuration/updater.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Updater struct {
|
||||||
|
Period time.Duration `json:"period"`
|
||||||
|
DNSAddress string `json:"dns_address"`
|
||||||
|
Cyberghost bool `json:"cyberghost"`
|
||||||
|
Mullvad bool `json:"mullvad"`
|
||||||
|
Nordvpn bool `json:"nordvpn"`
|
||||||
|
PIA bool `json:"pia"`
|
||||||
|
Privado bool `json:"privado"`
|
||||||
|
Purevpn bool `json:"purevpn"`
|
||||||
|
Surfshark bool `json:"surfshark"`
|
||||||
|
Vyprvpn bool `json:"vyprvpn"`
|
||||||
|
Windscribe bool `json:"windscribe"`
|
||||||
|
// The two below should be used in CLI mode only
|
||||||
|
Stdout bool `json:"-"` // in order to update constants file (maintainer side)
|
||||||
|
CLI bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Updater) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Updater) lines() (lines []string) {
|
||||||
|
if settings.Period == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, lastIndent+"Updater:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Period: every "+settings.Period.String())
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Updater) read(r reader) (err error) {
|
||||||
|
settings.Cyberghost = true
|
||||||
|
settings.Mullvad = true
|
||||||
|
settings.Nordvpn = true
|
||||||
|
settings.PIA = true
|
||||||
|
settings.Purevpn = true
|
||||||
|
settings.Surfshark = true
|
||||||
|
settings.Vyprvpn = true
|
||||||
|
settings.Windscribe = true
|
||||||
|
settings.Stdout = false
|
||||||
|
settings.CLI = false
|
||||||
|
settings.DNSAddress = "127.0.0.1"
|
||||||
|
|
||||||
|
settings.Period, err = r.env.Duration("UPDATER_PERIOD", params.Default("0"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
34
internal/configuration/vyprvpn.go
Normal file
34
internal/configuration/vyprvpn.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) vyprvpnLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Regions) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readVyprvpn(r reader) (err error) {
|
||||||
|
settings.Name = constants.Vyprvpn
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.VyprvpnRegionChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
65
internal/configuration/windscribe.go
Normal file
65
internal/configuration/windscribe.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) windscribeLines() (lines []string) {
|
||||||
|
if len(settings.ServerSelection.Regions) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.Cities) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.ServerSelection.Hostnames) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, lastIndent+"Custom port: "+strconv.Itoa(int(settings.ServerSelection.CustomPort)))
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Provider) readWindscribe(r reader) (err error) {
|
||||||
|
settings.Name = constants.Windscribe
|
||||||
|
|
||||||
|
settings.ServerSelection.Protocol, err = readProtocol(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.WindscribeRegionChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.WindscribeCityChoices())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.WindscribeHostnameChoices(), params.RetroKeys([]string{"HOSTNAME"}, r.onRetroActive))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.CustomPort, err = readCustomPort(r.env, settings.ServerSelection.Protocol,
|
||||||
|
[]uint16{21, 22, 80, 123, 143, 443, 587, 1194, 3306, 8080, 54783},
|
||||||
|
[]uint16{53, 80, 123, 443, 1194, 54783})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/dns/pkg/unbound"
|
"github.com/qdm12/dns/pkg/unbound"
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ type Looper interface {
|
|||||||
RunRestartTicker(ctx context.Context, wg *sync.WaitGroup)
|
RunRestartTicker(ctx context.Context, wg *sync.WaitGroup)
|
||||||
GetStatus() (status models.LoopStatus)
|
GetStatus() (status models.LoopStatus)
|
||||||
SetStatus(status models.LoopStatus) (outcome string, err error)
|
SetStatus(status models.LoopStatus) (outcome string, err error)
|
||||||
GetSettings() (settings settings.DNS)
|
GetSettings() (settings configuration.DNS)
|
||||||
SetSettings(settings settings.DNS) (outcome string)
|
SetSettings(settings configuration.DNS) (outcome string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type looper struct {
|
type looper struct {
|
||||||
@@ -45,7 +45,7 @@ type looper struct {
|
|||||||
|
|
||||||
const defaultBackoffTime = 10 * time.Second
|
const defaultBackoffTime = 10 * time.Second
|
||||||
|
|
||||||
func NewLooper(conf unbound.Configurator, settings settings.DNS, client *http.Client,
|
func NewLooper(conf unbound.Configurator, settings configuration.DNS, client *http.Client,
|
||||||
logger logging.Logger, username string, puid, pgid int) Looper {
|
logger logging.Logger, username string, puid, pgid int) Looper {
|
||||||
return &looper{
|
return &looper{
|
||||||
state: state{
|
state: state{
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type state struct {
|
type state struct {
|
||||||
status models.LoopStatus
|
status models.LoopStatus
|
||||||
settings settings.DNS
|
settings configuration.DNS
|
||||||
statusMu sync.RWMutex
|
statusMu sync.RWMutex
|
||||||
settingsMu sync.RWMutex
|
settingsMu sync.RWMutex
|
||||||
}
|
}
|
||||||
@@ -69,13 +69,13 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) GetSettings() (settings settings.DNS) {
|
func (l *looper) GetSettings() (settings configuration.DNS) {
|
||||||
l.state.settingsMu.RLock()
|
l.state.settingsMu.RLock()
|
||||||
defer l.state.settingsMu.RUnlock()
|
defer l.state.settingsMu.RUnlock()
|
||||||
return l.state.settings
|
return l.state.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) SetSettings(settings settings.DNS) (outcome string) {
|
func (l *looper) SetSettings(settings configuration.DNS) (outcome string) {
|
||||||
l.state.settingsMu.Lock()
|
l.state.settingsMu.Lock()
|
||||||
settingsUnchanged := reflect.DeepEqual(l.state.settings, settings)
|
settingsUnchanged := reflect.DeepEqual(l.state.settings, settings)
|
||||||
if settingsUnchanged {
|
if settingsUnchanged {
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,8 +16,8 @@ type Looper interface {
|
|||||||
Run(ctx context.Context, wg *sync.WaitGroup)
|
Run(ctx context.Context, wg *sync.WaitGroup)
|
||||||
SetStatus(status models.LoopStatus) (outcome string, err error)
|
SetStatus(status models.LoopStatus) (outcome string, err error)
|
||||||
GetStatus() (status models.LoopStatus)
|
GetStatus() (status models.LoopStatus)
|
||||||
GetSettings() (settings settings.HTTPProxy)
|
GetSettings() (settings configuration.HTTPProxy)
|
||||||
SetSettings(settings settings.HTTPProxy) (outcome string)
|
SetSettings(settings configuration.HTTPProxy) (outcome string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type looper struct {
|
type looper struct {
|
||||||
@@ -34,7 +34,7 @@ type looper struct {
|
|||||||
|
|
||||||
const defaultBackoffTime = 10 * time.Second
|
const defaultBackoffTime = 10 * time.Second
|
||||||
|
|
||||||
func NewLooper(logger logging.Logger, settings settings.HTTPProxy) Looper {
|
func NewLooper(logger logging.Logger, settings configuration.HTTPProxy) Looper {
|
||||||
return &looper{
|
return &looper{
|
||||||
state: state{
|
state: state{
|
||||||
status: constants.Stopped,
|
status: constants.Stopped,
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type state struct {
|
type state struct {
|
||||||
status models.LoopStatus
|
status models.LoopStatus
|
||||||
settings settings.HTTPProxy
|
settings configuration.HTTPProxy
|
||||||
statusMu sync.RWMutex
|
statusMu sync.RWMutex
|
||||||
settingsMu sync.RWMutex
|
settingsMu sync.RWMutex
|
||||||
}
|
}
|
||||||
@@ -69,13 +69,13 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) GetSettings() (settings settings.HTTPProxy) {
|
func (l *looper) GetSettings() (settings configuration.HTTPProxy) {
|
||||||
l.state.settingsMu.RLock()
|
l.state.settingsMu.RLock()
|
||||||
defer l.state.settingsMu.RUnlock()
|
defer l.state.settingsMu.RUnlock()
|
||||||
return l.state.settings
|
return l.state.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) SetSettings(settings settings.HTTPProxy) (outcome string) {
|
func (l *looper) SetSettings(settings configuration.HTTPProxy) (outcome string) {
|
||||||
l.state.settingsMu.Lock()
|
l.state.settingsMu.Lock()
|
||||||
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
|
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
|
||||||
if settingsUnchanged {
|
if settingsUnchanged {
|
||||||
|
|||||||
@@ -1,155 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProviderSettings contains settings specific to a VPN provider.
|
|
||||||
type ProviderSettings struct {
|
|
||||||
Name VPNProvider `json:"name"`
|
|
||||||
ServerSelection ServerSelection `json:"server_selection"`
|
|
||||||
ExtraConfigOptions ExtraConfigOptions `json:"extra_config"`
|
|
||||||
PortForwarding PortForwarding `json:"port_forwarding"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServerSelection struct {
|
|
||||||
// Common
|
|
||||||
Protocol NetworkProtocol `json:"network_protocol"`
|
|
||||||
TargetIP net.IP `json:"target_ip,omitempty"`
|
|
||||||
|
|
||||||
// Cyberghost, PIA, Surfshark, Windscribe, Vyprvpn, NordVPN
|
|
||||||
Regions []string `json:"regions"`
|
|
||||||
|
|
||||||
// Cyberghost
|
|
||||||
Group string `json:"group"`
|
|
||||||
|
|
||||||
Countries []string `json:"countries"` // Mullvad, PureVPN
|
|
||||||
Cities []string `json:"cities"` // Mullvad, PureVPN, Windscribe
|
|
||||||
Hostnames []string `json:"hostnames"` // Windscribe, Privado
|
|
||||||
|
|
||||||
// Mullvad
|
|
||||||
ISPs []string `json:"isps"`
|
|
||||||
Owned bool `json:"owned"`
|
|
||||||
|
|
||||||
// Mullvad, Windscribe, PIA
|
|
||||||
CustomPort uint16 `json:"custom_port"`
|
|
||||||
|
|
||||||
// NordVPN
|
|
||||||
Numbers []uint16 `json:"numbers"`
|
|
||||||
|
|
||||||
// PIA
|
|
||||||
EncryptionPreset string `json:"encryption_preset"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExtraConfigOptions struct {
|
|
||||||
ClientCertificate string `json:"-"` // Cyberghost
|
|
||||||
ClientKey string `json:"-"` // Cyberghost
|
|
||||||
EncryptionPreset string `json:"encryption_preset"` // PIA
|
|
||||||
OpenVPNIPv6 bool `json:"openvpn_ipv6"` // Mullvad
|
|
||||||
}
|
|
||||||
|
|
||||||
// PortForwarding contains settings for port forwarding.
|
|
||||||
type PortForwarding struct {
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
Filepath Filepath `json:"filepath"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PortForwarding) String() string {
|
|
||||||
if p.Enabled {
|
|
||||||
return fmt.Sprintf("on, saved in %s", p.Filepath)
|
|
||||||
}
|
|
||||||
return "off"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProviderSettings) String() string {
|
|
||||||
settingsList := []string{
|
|
||||||
fmt.Sprintf("%s settings:", strings.Title(string(p.Name))),
|
|
||||||
"Network protocol: " + string(p.ServerSelection.Protocol),
|
|
||||||
}
|
|
||||||
customPort := ""
|
|
||||||
if p.ServerSelection.CustomPort > 0 {
|
|
||||||
customPort = fmt.Sprintf("%d", p.ServerSelection.CustomPort)
|
|
||||||
}
|
|
||||||
numbers := make([]string, len(p.ServerSelection.Numbers))
|
|
||||||
for i, number := range p.ServerSelection.Numbers {
|
|
||||||
numbers[i] = fmt.Sprintf("%d", number)
|
|
||||||
}
|
|
||||||
ipv6 := "off"
|
|
||||||
if p.ExtraConfigOptions.OpenVPNIPv6 {
|
|
||||||
ipv6 = "on"
|
|
||||||
}
|
|
||||||
switch strings.ToLower(string(p.Name)) {
|
|
||||||
case "private internet access old":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Regions: "+commaJoin(p.ServerSelection.Regions),
|
|
||||||
"Encryption preset: "+p.ExtraConfigOptions.EncryptionPreset,
|
|
||||||
"Port forwarding: "+p.PortForwarding.String(),
|
|
||||||
)
|
|
||||||
case "private internet access":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Regions: "+commaJoin(p.ServerSelection.Regions),
|
|
||||||
"Encryption preset: "+p.ExtraConfigOptions.EncryptionPreset,
|
|
||||||
"Port forwarding: "+p.PortForwarding.String(),
|
|
||||||
"Custom port: "+customPort,
|
|
||||||
)
|
|
||||||
case "mullvad":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Countries: "+commaJoin(p.ServerSelection.Countries),
|
|
||||||
"Cities: "+commaJoin(p.ServerSelection.Cities),
|
|
||||||
"ISPs: "+commaJoin(p.ServerSelection.ISPs),
|
|
||||||
"Custom port: "+customPort,
|
|
||||||
"IPv6: "+ipv6,
|
|
||||||
)
|
|
||||||
case "windscribe":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Regions: "+commaJoin(p.ServerSelection.Regions),
|
|
||||||
"Custom port: "+customPort,
|
|
||||||
)
|
|
||||||
case "surfshark":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Regions: "+commaJoin(p.ServerSelection.Regions),
|
|
||||||
)
|
|
||||||
case "cyberghost":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Client key: [redacted]",
|
|
||||||
"Client certificate: [redacted]",
|
|
||||||
"Group: "+p.ServerSelection.Group,
|
|
||||||
"Regions: "+commaJoin(p.ServerSelection.Regions),
|
|
||||||
)
|
|
||||||
case "vyprvpn":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Regions: "+commaJoin(p.ServerSelection.Regions),
|
|
||||||
)
|
|
||||||
case "nordvpn":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Regions: "+commaJoin(p.ServerSelection.Regions),
|
|
||||||
"Numbers: "+commaJoin(numbers),
|
|
||||||
)
|
|
||||||
case "purevpn":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Regions: "+commaJoin(p.ServerSelection.Regions),
|
|
||||||
"Countries: "+commaJoin(p.ServerSelection.Countries),
|
|
||||||
"Cities: "+commaJoin(p.ServerSelection.Cities),
|
|
||||||
)
|
|
||||||
case "privado":
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Hostnames: "+commaJoin(p.ServerSelection.Hostnames),
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"<Missing String method, please implement me!>",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if p.ServerSelection.TargetIP != nil {
|
|
||||||
settingsList = append(settingsList,
|
|
||||||
"Target IP address: "+string(p.ServerSelection.TargetIP),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return strings.Join(settingsList, "\n |--")
|
|
||||||
}
|
|
||||||
|
|
||||||
func commaJoin(slice []string) string {
|
|
||||||
return strings.Join(slice, ", ")
|
|
||||||
}
|
|
||||||
@@ -8,12 +8,12 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/provider"
|
"github.com/qdm12/gluetun/internal/provider"
|
||||||
"github.com/qdm12/gluetun/internal/routing"
|
"github.com/qdm12/gluetun/internal/routing"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -22,8 +22,8 @@ type Looper interface {
|
|||||||
Run(ctx context.Context, wg *sync.WaitGroup)
|
Run(ctx context.Context, wg *sync.WaitGroup)
|
||||||
GetStatus() (status models.LoopStatus)
|
GetStatus() (status models.LoopStatus)
|
||||||
SetStatus(status models.LoopStatus) (outcome string, err error)
|
SetStatus(status models.LoopStatus) (outcome string, err error)
|
||||||
GetSettings() (settings settings.OpenVPN)
|
GetSettings() (settings configuration.OpenVPN)
|
||||||
SetSettings(settings settings.OpenVPN) (outcome string)
|
SetSettings(settings configuration.OpenVPN) (outcome string)
|
||||||
GetServers() (servers models.AllServers)
|
GetServers() (servers models.AllServers)
|
||||||
SetServers(servers models.AllServers)
|
SetServers(servers models.AllServers)
|
||||||
GetPortForwarded() (port uint16)
|
GetPortForwarded() (port uint16)
|
||||||
@@ -58,7 +58,7 @@ type looper struct {
|
|||||||
|
|
||||||
const defaultBackoffTime = 15 * time.Second
|
const defaultBackoffTime = 15 * time.Second
|
||||||
|
|
||||||
func NewLooper(settings settings.OpenVPN,
|
func NewLooper(settings configuration.OpenVPN,
|
||||||
username string, puid, pgid int, allServers models.AllServers,
|
username string, puid, pgid int, allServers models.AllServers,
|
||||||
conf Configurator, fw firewall.Configurator, routing routing.Routing,
|
conf Configurator, fw firewall.Configurator, routing routing.Routing,
|
||||||
logger logging.Logger, client *http.Client, openFile os.OpenFileFunc,
|
logger logging.Logger, client *http.Client, openFile os.OpenFileFunc,
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type state struct {
|
type state struct {
|
||||||
status models.LoopStatus
|
status models.LoopStatus
|
||||||
settings settings.OpenVPN
|
settings configuration.OpenVPN
|
||||||
allServers models.AllServers
|
allServers models.AllServers
|
||||||
portForwarded uint16
|
portForwarded uint16
|
||||||
statusMu sync.RWMutex
|
statusMu sync.RWMutex
|
||||||
@@ -27,7 +27,7 @@ func (s *state) setStatusWithLock(status models.LoopStatus) {
|
|||||||
s.status = status
|
s.status = status
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) getSettingsAndServers() (settings settings.OpenVPN, allServers models.AllServers) {
|
func (s *state) getSettingsAndServers() (settings configuration.OpenVPN, allServers models.AllServers) {
|
||||||
s.settingsMu.RLock()
|
s.settingsMu.RLock()
|
||||||
s.allServersMu.RLock()
|
s.allServersMu.RLock()
|
||||||
settings = s.settings
|
settings = s.settings
|
||||||
@@ -83,13 +83,13 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) GetSettings() (settings settings.OpenVPN) {
|
func (l *looper) GetSettings() (settings configuration.OpenVPN) {
|
||||||
l.state.settingsMu.RLock()
|
l.state.settingsMu.RLock()
|
||||||
defer l.state.settingsMu.RUnlock()
|
defer l.state.settingsMu.RUnlock()
|
||||||
return l.state.settings
|
return l.state.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) SetSettings(settings settings.OpenVPN) (outcome string) {
|
func (l *looper) SetSettings(settings configuration.OpenVPN) (outcome string) {
|
||||||
l.state.settingsMu.Lock()
|
l.state.settingsMu.Lock()
|
||||||
settingsUnchanged := reflect.DeepEqual(l.state.settings, settings)
|
settingsUnchanged := reflect.DeepEqual(l.state.settings, settings)
|
||||||
if settingsUnchanged {
|
if settingsUnchanged {
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetCyberghostGroup obtains the server group for the Cyberghost server from the
|
|
||||||
// environment variable CYBERGHOST_GROUP.
|
|
||||||
func (r *reader) GetCyberghostGroup() (group string, err error) {
|
|
||||||
s, err := r.env.Inside("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.
|
|
||||||
func (r *reader) GetCyberghostRegions() (regions []string, err error) {
|
|
||||||
return r.env.CSVInside("REGION", constants.CyberghostRegionChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCyberghostClientKey obtains the client key to use for openvpn
|
|
||||||
// from the secret file /run/secrets/openvpn_clientkey or from the file
|
|
||||||
// /gluetun/client.key.
|
|
||||||
func (r *reader) GetCyberghostClientKey() (clientKey string, err error) {
|
|
||||||
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTKEY", string(constants.ClientKey))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return extractClientKey(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractClientKey(b []byte) (key string, err error) {
|
|
||||||
pemBlock, _ := pem.Decode(b)
|
|
||||||
if pemBlock == nil {
|
|
||||||
return "", fmt.Errorf("cannot decode PEM block from client key")
|
|
||||||
}
|
|
||||||
parsedBytes := pem.EncodeToMemory(pemBlock)
|
|
||||||
s := string(parsedBytes)
|
|
||||||
s = strings.ReplaceAll(s, "\n", "")
|
|
||||||
s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----")
|
|
||||||
s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----")
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCyberghostClientCertificate obtains the client certificate to use for openvpn
|
|
||||||
// from the secret file /run/secrets/openvpn_clientcrt or from the file
|
|
||||||
// /gluetun/client.crt.
|
|
||||||
func (r *reader) GetCyberghostClientCertificate() (clientCertificate string, err error) {
|
|
||||||
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTCRT", string(constants.ClientCertificate))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return extractClientCertificate(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractClientCertificate(b []byte) (certificate string, err error) {
|
|
||||||
pemBlock, _ := pem.Decode(b)
|
|
||||||
if pemBlock == nil {
|
|
||||||
return "", fmt.Errorf("cannot decode PEM block from client certificate")
|
|
||||||
}
|
|
||||||
parsedBytes := pem.EncodeToMemory(pemBlock)
|
|
||||||
s := string(parsedBytes)
|
|
||||||
s = strings.ReplaceAll(s, "\n", "")
|
|
||||||
s = strings.TrimPrefix(s, "-----BEGIN CERTIFICATE-----")
|
|
||||||
s = strings.TrimSuffix(s, "-----END CERTIFICATE-----")
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
dns "github.com/qdm12/dns/pkg/unbound"
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetDNSOverTLS obtains if the DNS over TLS should be enabled
|
|
||||||
// from the environment variable DOT.
|
|
||||||
func (r *reader) GetDNSOverTLS() (DNSOverTLS bool, err error) { //nolint:gocritic
|
|
||||||
return r.env.OnOff("DOT", libparams.Default("on"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDNSOverTLSProviders obtains the DNS over TLS providers to use
|
|
||||||
// from the environment variable DOT_PROVIDERS.
|
|
||||||
func (r *reader) GetDNSOverTLSProviders() (providers []string, err error) {
|
|
||||||
s, err := r.env.Get("DOT_PROVIDERS", libparams.Default("cloudflare"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, provider := range strings.Split(s, ",") {
|
|
||||||
_, ok := dns.GetProviderData(provider)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("DNS over TLS provider %q is not valid", provider)
|
|
||||||
}
|
|
||||||
providers = append(providers, provider)
|
|
||||||
}
|
|
||||||
return providers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDNSOverTLSVerbosity obtains the verbosity level to use for Unbound
|
|
||||||
// from the environment variable DOT_VERBOSITY.
|
|
||||||
func (r *reader) GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error) {
|
|
||||||
n, err := r.env.IntRange("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.
|
|
||||||
func (r *reader) GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error) {
|
|
||||||
n, err := r.env.IntRange("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.
|
|
||||||
func (r *reader) GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error) {
|
|
||||||
n, err := r.env.IntRange("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.
|
|
||||||
func (r *reader) GetDNSMaliciousBlocking() (blocking bool, err error) {
|
|
||||||
return r.env.OnOff("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.
|
|
||||||
func (r *reader) GetDNSSurveillanceBlocking() (blocking bool, err error) {
|
|
||||||
// Retro-compatibility
|
|
||||||
s, err := r.env.Get("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") //nolint:lll
|
|
||||||
return r.env.OnOff("BLOCK_NSA", libparams.Compulsory())
|
|
||||||
}
|
|
||||||
return r.env.OnOff("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.
|
|
||||||
func (r *reader) GetDNSAdsBlocking() (blocking bool, err error) {
|
|
||||||
return r.env.OnOff("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.
|
|
||||||
func (r *reader) GetDNSUnblockedHostnames() (hostnames []string, err error) {
|
|
||||||
s, err := r.env.Get("UNBLOCK")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if len(s) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
hostnames = strings.Split(s, ",")
|
|
||||||
for _, hostname := range hostnames {
|
|
||||||
if !r.regex.MatchHostname(hostname) {
|
|
||||||
return nil, fmt.Errorf("hostname %q does not seem valid", hostname)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hostnames, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDNSOverTLSCaching obtains if Unbound caching should be enable or not
|
|
||||||
// from the environment variable DOT_CACHING.
|
|
||||||
func (r *reader) GetDNSOverTLSCaching() (caching bool, err error) {
|
|
||||||
return r.env.OnOff("DOT_CACHING", libparams.Default("on"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDNSOverTLSPrivateAddresses obtains if Unbound caching should be enable or not
|
|
||||||
// from the environment variable DOT_PRIVATE_ADDRESS.
|
|
||||||
func (r *reader) GetDNSOverTLSPrivateAddresses() (privateAddresses []string, err error) {
|
|
||||||
s, err := r.env.Get("DOT_PRIVATE_ADDRESS")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if len(s) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
privateAddresses = strings.Split(s, ",")
|
|
||||||
for _, address := range privateAddresses {
|
|
||||||
ip := net.ParseIP(address)
|
|
||||||
_, _, err := net.ParseCIDR(address)
|
|
||||||
if ip == nil && err != nil {
|
|
||||||
return nil, fmt.Errorf("private address %q is not a valid IP or CIDR range", address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return privateAddresses, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDNSOverTLSIPv6 obtains if Unbound should resolve ipv6 addresses using
|
|
||||||
// ipv6 DNS over TLS from the environment variable DOT_IPV6.
|
|
||||||
func (r *reader) GetDNSOverTLSIPv6() (ipv6 bool, err error) {
|
|
||||||
return r.env.OnOff("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.
|
|
||||||
func (r *reader) GetDNSUpdatePeriod() (period time.Duration, err error) {
|
|
||||||
s, err := r.env.Get("DNS_UPDATE_PERIOD", libparams.Default("24h"))
|
|
||||||
if err != nil {
|
|
||||||
return period, err
|
|
||||||
}
|
|
||||||
return time.ParseDuration(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDNSPlaintext obtains the plaintext DNS address to use if DNS over TLS is disabled
|
|
||||||
// from the environment variable DNS_PLAINTEXT_ADDRESS.
|
|
||||||
func (r *reader) GetDNSPlaintext() (ip net.IP, err error) {
|
|
||||||
s, err := r.env.Get("DNS_PLAINTEXT_ADDRESS", libparams.Default("1.1.1.1"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ip = net.ParseIP(s)
|
|
||||||
if ip == nil {
|
|
||||||
return nil, fmt.Errorf("DNS plaintext address %q is not a valid IP address", s)
|
|
||||||
}
|
|
||||||
return ip, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDNSKeepNameserver obtains if the nameserver present in /etc/resolv.conf
|
|
||||||
// should be kept instead of overridden, from the environment variable DNS_KEEP_NAMESERVER.
|
|
||||||
func (r *reader) GetDNSKeepNameserver() (on bool, err error) {
|
|
||||||
return r.env.OnOff("DNS_KEEP_NAMESERVER", libparams.Default("off"))
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetFirewall obtains if the firewall should be enabled from the environment variable FIREWALL.
|
|
||||||
func (r *reader) GetFirewall() (enabled bool, err error) {
|
|
||||||
return r.env.OnOff("FIREWALL", libparams.Default("on"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
func (r *reader) GetVPNInputPorts() (ports []uint16, err error) {
|
|
||||||
s, err := r.env.Get("FIREWALL_VPN_INPUT_PORTS", libparams.Default(""))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(s) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
portsStr := strings.Split(s, ",")
|
|
||||||
ports = make([]uint16, len(portsStr))
|
|
||||||
for i := range portsStr {
|
|
||||||
portInt, err := strconv.Atoi(portsStr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("VPN input port %q is not valid (%s)", portInt, err)
|
|
||||||
} else if portInt <= 0 || portInt > 65535 {
|
|
||||||
return nil, fmt.Errorf("VPN input port %d must be between 1 and 65535", portInt)
|
|
||||||
}
|
|
||||||
ports[i] = uint16(portInt)
|
|
||||||
}
|
|
||||||
return ports, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInputPorts obtains a list of input ports to allow through the
|
|
||||||
// default interface in the firewall, from the environment variable FIREWALL_INPUT_PORTS.
|
|
||||||
func (r *reader) GetInputPorts() (ports []uint16, err error) {
|
|
||||||
s, err := r.env.Get("FIREWALL_INPUT_PORTS", libparams.Default(""))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(s) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
portsStr := strings.Split(s, ",")
|
|
||||||
ports = make([]uint16, len(portsStr))
|
|
||||||
for i := range portsStr {
|
|
||||||
portInt, err := strconv.Atoi(portsStr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Input port %q is not valid (%s)", portInt, err)
|
|
||||||
} else if portInt <= 0 || portInt > 65535 {
|
|
||||||
return nil, fmt.Errorf("Input port %d must be between 1 and 65535", portInt)
|
|
||||||
}
|
|
||||||
ports[i] = uint16(portInt)
|
|
||||||
}
|
|
||||||
return ports, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.env.OnOff("FIREWALL_DEBUG", libparams.Default("off"))
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetHTTPProxy obtains if the HTTP proxy is on from the environment variable
|
|
||||||
// HTTPPROXY, and using PROXY and TINYPROXY as retro-compatibility names.
|
|
||||||
func (r *reader) GetHTTPProxy() (enabled bool, err error) {
|
|
||||||
retroKeysOption := libparams.RetroKeys(
|
|
||||||
[]string{"TINYPROXY", "PROXY"},
|
|
||||||
r.onRetroActive,
|
|
||||||
)
|
|
||||||
return r.env.OnOff("HTTPPROXY", retroKeysOption, libparams.Default("off"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPProxyLog obtains the if http proxy requests should be logged from
|
|
||||||
// the environment variable HTTPPROXY_LOG, and using PROXY_LOG_LEVEL and
|
|
||||||
// TINYPROXY_LOG as retro-compatibility names.
|
|
||||||
func (r *reader) GetHTTPProxyLog() (log bool, err error) {
|
|
||||||
s, _ := r.env.Get("HTTPPROXY_LOG")
|
|
||||||
if len(s) == 0 {
|
|
||||||
s, _ = r.env.Get("PROXY_LOG_LEVEL")
|
|
||||||
if len(s) == 0 {
|
|
||||||
s, _ = r.env.Get("TINYPROXY_LOG")
|
|
||||||
if len(s) == 0 {
|
|
||||||
return false, nil // default log disabled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch strings.ToLower(s) {
|
|
||||||
case "info", "connect", "notice":
|
|
||||||
return true, nil
|
|
||||||
default:
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r.env.OnOff("HTTPPROXY_LOG", libparams.Default("off"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPProxyPort obtains the HTTP proxy listening port from the environment variable
|
|
||||||
// HTTPPROXY_PORT, and using PROXY_PORT and TINYPROXY_PORT as retro-compatibility names.
|
|
||||||
func (r *reader) GetHTTPProxyPort() (port uint16, warning string, err error) {
|
|
||||||
retroKeysOption := libparams.RetroKeys(
|
|
||||||
[]string{"TINYPROXY_PORT", "PROXY_PORT"},
|
|
||||||
r.onRetroActive,
|
|
||||||
)
|
|
||||||
return r.env.ListeningPort("HTTPPROXY_PORT", retroKeysOption, libparams.Default("8888"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPProxyUser obtains the HTTP proxy server user.
|
|
||||||
// It first tries to use the HTTPPROXY_USER environment variable (easier for the end user)
|
|
||||||
// and then tries to read from the secret file httpproxy_user if nothing was found.
|
|
||||||
func (r *reader) GetHTTPProxyUser() (user string, err error) {
|
|
||||||
const compulsory = false
|
|
||||||
return r.getFromEnvOrSecretFile(
|
|
||||||
"HTTPPROXY_USER",
|
|
||||||
compulsory,
|
|
||||||
[]string{"TINYPROXY_USER", "PROXY_USER"},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPProxyPassword obtains the HTTP proxy server password.
|
|
||||||
// It first tries to use the HTTPPROXY_PASSWORD environment variable (easier for the end user)
|
|
||||||
// and then tries to read from the secret file httpproxy_password if nothing was found.
|
|
||||||
func (r *reader) GetHTTPProxyPassword() (password string, err error) {
|
|
||||||
const compulsory = false
|
|
||||||
return r.getFromEnvOrSecretFile(
|
|
||||||
"HTTPPROXY_USER",
|
|
||||||
compulsory,
|
|
||||||
[]string{"TINYPROXY_PASSWORD", "PROXY_PASSWORD"},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPProxyStealth obtains the HTTP proxy server stealth mode
|
|
||||||
// from the environment variable HTTPPROXY_STEALTH.
|
|
||||||
func (r *reader) GetHTTPProxyStealth() (stealth bool, err error) {
|
|
||||||
return r.env.OnOff("HTTPPROXY_STEALTH", libparams.Default("off"))
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetMullvadCountries obtains the countries for the Mullvad servers from the
|
|
||||||
// environment variable COUNTRY.
|
|
||||||
func (r *reader) GetMullvadCountries() (countries []string, err error) {
|
|
||||||
return r.env.CSVInside("COUNTRY", constants.MullvadCountryChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMullvadCity obtains the cities for the Mullvad servers from the
|
|
||||||
// environment variable CITY.
|
|
||||||
func (r *reader) GetMullvadCities() (cities []string, err error) {
|
|
||||||
return r.env.CSVInside("CITY", constants.MullvadCityChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMullvadISPs obtains the ISPs for the Mullvad servers from the
|
|
||||||
// environment variable ISP.
|
|
||||||
func (r *reader) GetMullvadISPs() (isps []string, err error) {
|
|
||||||
return r.env.CSVInside("ISP", constants.MullvadISPChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
|
||||||
// environment variable PORT.
|
|
||||||
func (r *reader) GetMullvadPort() (port uint16, err error) {
|
|
||||||
n, err := r.env.IntRange("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.
|
|
||||||
func (r *reader) GetMullvadOwned() (owned bool, err error) {
|
|
||||||
return r.env.YesNo("OWNED", libparams.Default("no"))
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetNordvpnRegions obtains the regions (countries) for the NordVPN server from the
|
|
||||||
// environment variable REGION.
|
|
||||||
func (r *reader) GetNordvpnRegions() (regions []string, err error) {
|
|
||||||
return r.env.CSVInside("REGION", constants.NordvpnRegionChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetNordvpnRegion obtains the server numbers (optional) for the NordVPN servers from the
|
|
||||||
// environment variable SERVER_NUMBER.
|
|
||||||
func (r *reader) GetNordvpnNumbers() (numbers []uint16, err error) {
|
|
||||||
possibilities := make([]string, 65537)
|
|
||||||
for i := range possibilities {
|
|
||||||
possibilities[i] = fmt.Sprintf("%d", i)
|
|
||||||
}
|
|
||||||
possibilities[65536] = ""
|
|
||||||
values, err := r.env.CSVInside("SERVER_NUMBER", possibilities)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
numbers = make([]uint16, len(values))
|
|
||||||
for i := range values {
|
|
||||||
n, err := strconv.Atoi(values[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
numbers[i] = uint16(n)
|
|
||||||
}
|
|
||||||
return numbers, nil
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetUser obtains the user to use to connect to the VPN servers.
|
|
||||||
// It first tries to use the OPENVPN_USER environment variable (easier for the end user)
|
|
||||||
// and then tries to read from the secret file openvpn_user if nothing was found.
|
|
||||||
func (r *reader) GetUser() (user string, err error) {
|
|
||||||
const compulsory = true
|
|
||||||
return r.getFromEnvOrSecretFile("OPENVPN_USER", compulsory, []string{"USER"})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPassword obtains the password to use to connect to the VPN servers.
|
|
||||||
// It first tries to use the OPENVPN_PASSWORD environment variable (easier for the end user)
|
|
||||||
// and then tries to read from the secret file openvpn_password if nothing was found.
|
|
||||||
func (r *reader) GetPassword() (s string, err error) {
|
|
||||||
const compulsory = true
|
|
||||||
return r.getFromEnvOrSecretFile("OPENVPN_PASSWORD", compulsory, []string{"PASSWORD"})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetNetworkProtocol obtains the network protocol to use to connect to the
|
|
||||||
// VPN servers from the environment variable PROTOCOL.
|
|
||||||
func (r *reader) GetNetworkProtocol() (protocol models.NetworkProtocol, err error) {
|
|
||||||
s, err := r.env.Inside("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.
|
|
||||||
func (r *reader) GetOpenVPNVerbosity() (verbosity int, err error) {
|
|
||||||
return r.env.IntRange("OPENVPN_VERBOSITY", 0, 6, libparams.Default("1"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOpenVPNRoot obtains if openvpn should be run as root
|
|
||||||
// from the environment variable OPENVPN_ROOT.
|
|
||||||
func (r *reader) GetOpenVPNRoot() (root bool, err error) {
|
|
||||||
return r.env.YesNo("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.
|
|
||||||
func (r *reader) GetTargetIP() (ip net.IP, err error) {
|
|
||||||
s, err := r.env.Get("OPENVPN_TARGET_IP")
|
|
||||||
if len(s) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ip = net.ParseIP(s)
|
|
||||||
if ip == nil {
|
|
||||||
return nil, fmt.Errorf("target IP address %q is not valid", s)
|
|
||||||
}
|
|
||||||
return ip, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOpenVPNCipher obtains a custom cipher to use with OpenVPN
|
|
||||||
// from the environment variable OPENVPN_CIPHER.
|
|
||||||
func (r *reader) GetOpenVPNCipher() (cipher string, err error) {
|
|
||||||
return r.env.Get("OPENVPN_CIPHER")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOpenVPNAuth obtains a custom auth algorithm to use with OpenVPN
|
|
||||||
// from the environment variable OPENVPN_AUTH.
|
|
||||||
func (r *reader) GetOpenVPNAuth() (auth string, err error) {
|
|
||||||
return r.env.Get("OPENVPN_AUTH")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOpenVPNIPv6 obtains if ipv6 should be tunneled through the
|
|
||||||
// openvpn tunnel from the environment variable OPENVPN_IPV6.
|
|
||||||
func (r *reader) GetOpenVPNIPv6() (ipv6 bool, err error) {
|
|
||||||
return r.env.OnOff("OPENVPN_IPV6", libparams.Default("off"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reader) GetOpenVPNMSSFix() (mssFix uint16, err error) {
|
|
||||||
n, err := r.env.IntRange("OPENVPN_MSSFIX", 0, 10000, libparams.Default("0"))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return uint16(n), nil
|
|
||||||
}
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
|
||||||
"github.com/qdm12/golibs/os"
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
"github.com/qdm12/golibs/verification"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reader contains methods to obtain parameters.
|
|
||||||
type Reader interface {
|
|
||||||
GetVPNSP() (vpnServiceProvider models.VPNProvider, err error)
|
|
||||||
|
|
||||||
// DNS over TLS getters
|
|
||||||
GetDNSOverTLS() (DNSOverTLS bool, err error)
|
|
||||||
GetDNSOverTLSProviders() (providers []string, err error)
|
|
||||||
GetDNSOverTLSCaching() (caching bool, err error)
|
|
||||||
GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error)
|
|
||||||
GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error)
|
|
||||||
GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error)
|
|
||||||
GetDNSMaliciousBlocking() (blocking bool, err error)
|
|
||||||
GetDNSSurveillanceBlocking() (blocking bool, err error)
|
|
||||||
GetDNSAdsBlocking() (blocking bool, err error)
|
|
||||||
GetDNSUnblockedHostnames() (hostnames []string, err error)
|
|
||||||
GetDNSOverTLSPrivateAddresses() (privateAddresses []string, err error)
|
|
||||||
GetDNSOverTLSIPv6() (ipv6 bool, err error)
|
|
||||||
GetDNSUpdatePeriod() (period time.Duration, err error)
|
|
||||||
GetDNSPlaintext() (ip net.IP, err error)
|
|
||||||
GetDNSKeepNameserver() (on bool, err error)
|
|
||||||
|
|
||||||
// System
|
|
||||||
GetPUID() (puid int, err error)
|
|
||||||
GetPGID() (pgid int, err error)
|
|
||||||
GetTimezone() (timezone string, err error)
|
|
||||||
GetPublicIPFilepath() (filepath models.Filepath, err error)
|
|
||||||
|
|
||||||
// Firewall getters
|
|
||||||
GetFirewall() (enabled bool, err error)
|
|
||||||
GetVPNInputPorts() (ports []uint16, err error)
|
|
||||||
GetInputPorts() (ports []uint16, err error)
|
|
||||||
GetOutboundSubnets() (outboundSubnets []net.IPNet, err error)
|
|
||||||
GetFirewallDebug() (debug bool, err error)
|
|
||||||
|
|
||||||
// VPN getters
|
|
||||||
GetUser() (s string, err error)
|
|
||||||
GetPassword() (s string, err error)
|
|
||||||
GetNetworkProtocol() (protocol models.NetworkProtocol, err error)
|
|
||||||
GetOpenVPNVerbosity() (verbosity int, err error)
|
|
||||||
GetOpenVPNRoot() (root bool, err error)
|
|
||||||
GetTargetIP() (ip net.IP, err error)
|
|
||||||
GetOpenVPNCipher() (cipher string, err error)
|
|
||||||
GetOpenVPNAuth() (auth string, err error)
|
|
||||||
GetOpenVPNIPv6() (tunnel bool, err error)
|
|
||||||
GetOpenVPNMSSFix() (mssFix uint16, err error)
|
|
||||||
|
|
||||||
// PIA getters
|
|
||||||
GetPortForwarding() (activated bool, err error)
|
|
||||||
GetPortForwardingStatusFilepath() (filepath models.Filepath, err error)
|
|
||||||
GetPIAEncryptionPreset() (preset string, err error)
|
|
||||||
GetPIARegions() (regions []string, err error)
|
|
||||||
GetPIAPort() (port uint16, err error)
|
|
||||||
|
|
||||||
// Mullvad getters
|
|
||||||
GetMullvadCountries() (countries []string, err error)
|
|
||||||
GetMullvadCities() (cities []string, err error)
|
|
||||||
GetMullvadISPs() (ips []string, err error)
|
|
||||||
GetMullvadPort() (port uint16, err error)
|
|
||||||
GetMullvadOwned() (owned bool, err error)
|
|
||||||
|
|
||||||
// Windscribe getters
|
|
||||||
GetWindscribeRegions() (countries []string, err error)
|
|
||||||
GetWindscribeCities() (cities []string, err error)
|
|
||||||
GetWindscribeHostnames() (hostnames []string, err error)
|
|
||||||
GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error)
|
|
||||||
|
|
||||||
// Surfshark getters
|
|
||||||
GetSurfsharkRegions() (countries []string, err error)
|
|
||||||
|
|
||||||
// Cyberghost getters
|
|
||||||
GetCyberghostGroup() (group string, err error)
|
|
||||||
GetCyberghostRegions() (regions []string, err error)
|
|
||||||
GetCyberghostClientKey() (clientKey string, err error)
|
|
||||||
GetCyberghostClientCertificate() (clientCertificate string, err error)
|
|
||||||
|
|
||||||
// Vyprvpn getters
|
|
||||||
GetVyprvpnRegions() (regions []string, err error)
|
|
||||||
|
|
||||||
// NordVPN getters
|
|
||||||
GetNordvpnRegions() (regions []string, err error)
|
|
||||||
GetNordvpnNumbers() (numbers []uint16, err error)
|
|
||||||
|
|
||||||
// Privado getters
|
|
||||||
GetPrivadoHostnames() (hostnames []string, err error)
|
|
||||||
|
|
||||||
// PureVPN getters
|
|
||||||
GetPurevpnRegions() (regions []string, err error)
|
|
||||||
GetPurevpnCountries() (countries []string, err error)
|
|
||||||
GetPurevpnCities() (cities []string, err error)
|
|
||||||
|
|
||||||
// Shadowsocks getters
|
|
||||||
GetShadowSocks() (activated bool, err error)
|
|
||||||
GetShadowSocksLog() (activated bool, err error)
|
|
||||||
GetShadowSocksPort() (port uint16, warning string, err error)
|
|
||||||
GetShadowSocksPassword() (password string, err error)
|
|
||||||
GetShadowSocksMethod() (method string, err error)
|
|
||||||
|
|
||||||
// HTTP proxy getters
|
|
||||||
GetHTTPProxy() (activated bool, err error)
|
|
||||||
GetHTTPProxyLog() (log bool, err error)
|
|
||||||
GetHTTPProxyPort() (port uint16, warning string, err error)
|
|
||||||
GetHTTPProxyUser() (user string, err error)
|
|
||||||
GetHTTPProxyPassword() (password string, err error)
|
|
||||||
GetHTTPProxyStealth() (stealth bool, err error)
|
|
||||||
|
|
||||||
// Public IP getters
|
|
||||||
GetPublicIPPeriod() (period time.Duration, err error)
|
|
||||||
|
|
||||||
// Control server
|
|
||||||
GetControlServerPort() (port uint16, warning string, err error)
|
|
||||||
GetControlServerLog() (enabled bool, err error)
|
|
||||||
|
|
||||||
GetVersionInformation() (enabled bool, err error)
|
|
||||||
|
|
||||||
GetUpdaterPeriod() (period time.Duration, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type reader struct {
|
|
||||||
env libparams.Env
|
|
||||||
logger logging.Logger
|
|
||||||
regex verification.Regex
|
|
||||||
os os.OS
|
|
||||||
}
|
|
||||||
|
|
||||||
// Newreader returns a paramsReadeer object to read parameters from
|
|
||||||
// environment variables.
|
|
||||||
func NewReader(logger logging.Logger, os os.OS) Reader {
|
|
||||||
return &reader{
|
|
||||||
env: libparams.NewEnv(),
|
|
||||||
logger: logger,
|
|
||||||
regex: verification.NewRegex(),
|
|
||||||
os: os,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.env.Inside(
|
|
||||||
"VPNSP",
|
|
||||||
[]string{
|
|
||||||
"pia", "private internet access",
|
|
||||||
"mullvad", "windscribe", "surfshark", "cyberghost",
|
|
||||||
"vyprvpn", "nordvpn", "purevpn", "privado",
|
|
||||||
}, libparams.Default("private internet access"))
|
|
||||||
if s == "pia" {
|
|
||||||
s = "private internet access"
|
|
||||||
}
|
|
||||||
return models.VPNProvider(s), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reader) GetVersionInformation() (enabled bool, err error) {
|
|
||||||
return r.env.OnOff("VERSION_INFORMATION", libparams.Default("on"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reader) onRetroActive(oldKey, newKey string) {
|
|
||||||
r.logger.Warn(
|
|
||||||
"You are using the old environment variable %s, please consider changing it to %s",
|
|
||||||
oldKey, newKey,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
func (r *reader) GetPortForwarding() (activated bool, err error) {
|
|
||||||
s, err := r.env.Get("PORT_FORWARDING", libparams.Default("off"))
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
// Custom for retro-compatibility
|
|
||||||
if s == "false" || s == "off" {
|
|
||||||
return false, nil
|
|
||||||
} else if s == "true" || s == "on" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("PORT_FORWARDING can only be \"on\" or \"off\"")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPortForwardingStatusFilepath obtains the port forwarding status file path
|
|
||||||
// from the environment variable PORT_FORWARDING_STATUS_FILE.
|
|
||||||
func (r *reader) GetPortForwardingStatusFilepath() (filepath models.Filepath, err error) {
|
|
||||||
filepathStr, err := r.env.Path(
|
|
||||||
"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.
|
|
||||||
func (r *reader) GetPIAEncryptionPreset() (preset string, err error) {
|
|
||||||
// Retro-compatibility
|
|
||||||
s, err := r.env.Inside("ENCRYPTION", []string{
|
|
||||||
constants.PIAEncryptionPresetNormal,
|
|
||||||
constants.PIAEncryptionPresetStrong})
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
} else if len(s) != 0 {
|
|
||||||
r.logger.Warn("You are using the old environment variable ENCRYPTION, please consider changing it to PIA_ENCRYPTION")
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
return r.env.Inside(
|
|
||||||
"PIA_ENCRYPTION",
|
|
||||||
[]string{
|
|
||||||
constants.PIAEncryptionPresetNormal,
|
|
||||||
constants.PIAEncryptionPresetStrong,
|
|
||||||
},
|
|
||||||
libparams.Default(constants.PIAEncryptionPresetStrong))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPIARegions obtains the regions for the PIA servers from the
|
|
||||||
// environment variable REGION.
|
|
||||||
func (r *reader) GetPIARegions() (regions []string, err error) {
|
|
||||||
return r.env.CSVInside("REGION", constants.PIAGeoChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPIAPort obtains the port to reach the PIA server on from the
|
|
||||||
// environment variable PORT.
|
|
||||||
func (r *reader) GetPIAPort() (port uint16, err error) {
|
|
||||||
n, err := r.env.IntRange("PORT", 0, 65535, libparams.Default("0"))
|
|
||||||
return uint16(n), err
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetPrivadoHostnames obtains the hostnames for the Privado server from the
|
|
||||||
// environment variable SERVER_HOSTNAME.
|
|
||||||
func (r *reader) GetPrivadoHostnames() (hosts []string, err error) {
|
|
||||||
return r.env.CSVInside("SERVER_HOSTNAME",
|
|
||||||
constants.PrivadoHostnameChoices(),
|
|
||||||
libparams.RetroKeys([]string{"HOSTNAME"}, r.onRetroActive))
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetPublicIPPeriod obtains the period to fetch the IP address periodically.
|
|
||||||
// Set to 0 to disable.
|
|
||||||
func (r *reader) GetPublicIPPeriod() (period time.Duration, err error) {
|
|
||||||
s, err := r.env.Get("PUBLICIP_PERIOD", libparams.Default("12h"))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return time.ParseDuration(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPublicIPFilepath obtains the public IP filepath
|
|
||||||
// from the environment variable PUBLICIP_FILE with retro-compatible
|
|
||||||
// environment variable IP_STATUS_FILE.
|
|
||||||
func (r *reader) GetPublicIPFilepath() (filepath models.Filepath, err error) {
|
|
||||||
filepathStr, err := r.env.Path("PUBLICIP_FILE",
|
|
||||||
libparams.RetroKeys([]string{"IP_STATUS_FILE"}, r.onRetroActive),
|
|
||||||
libparams.Default("/tmp/gluetun/ip"), libparams.CaseSensitiveValue())
|
|
||||||
return models.Filepath(filepathStr), err
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetPurevpnRegions obtains the regions (continents) for the PureVPN servers from the
|
|
||||||
// environment variable REGION.
|
|
||||||
func (r *reader) GetPurevpnRegions() (regions []string, err error) {
|
|
||||||
return r.env.CSVInside("REGION", constants.PurevpnRegionChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPurevpnCountries obtains the countries for the PureVPN servers from the
|
|
||||||
// environment variable COUNTRY.
|
|
||||||
func (r *reader) GetPurevpnCountries() (countries []string, err error) {
|
|
||||||
return r.env.CSVInside("COUNTRY", constants.PurevpnCountryChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPurevpnCities obtains the cities for the PureVPN servers from the
|
|
||||||
// environment variable CITY.
|
|
||||||
func (r *reader) GetPurevpnCities() (cities []string, err error) {
|
|
||||||
return r.env.CSVInside("CITY", constants.PurevpnCityChoices())
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetOutboundSubnets obtains the CIDR subnets from the comma separated list of the
|
|
||||||
// environment variable FIREWALL_OUTBOUND_SUBNETS.
|
|
||||||
func (r *reader) GetOutboundSubnets() (outboundSubnets []net.IPNet, err error) {
|
|
||||||
const key = "FIREWALL_OUTBOUND_SUBNETS"
|
|
||||||
retroOption := libparams.RetroKeys(
|
|
||||||
[]string{"EXTRA_SUBNETS"},
|
|
||||||
r.onRetroActive,
|
|
||||||
)
|
|
||||||
s, err := r.env.Get(key, retroOption)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if s == "" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
subnets := strings.Split(s, ",")
|
|
||||||
for _, subnet := range subnets {
|
|
||||||
_, cidr, err := net.ParseCIDR(subnet)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot parse outbound subnet %q from environment variable with key %s: %w", subnet, key, err)
|
|
||||||
} else if cidr == nil {
|
|
||||||
return nil, fmt.Errorf("cannot parse outbound subnet %q from environment variable with key %s: subnet is nil",
|
|
||||||
subnet, key)
|
|
||||||
}
|
|
||||||
outboundSubnets = append(outboundSubnets, *cidr)
|
|
||||||
}
|
|
||||||
return outboundSubnets, nil
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r *reader) GetControlServerPort() (port uint16, warning string, err error) {
|
|
||||||
return r.env.ListeningPort("HTTP_CONTROL_SERVER_PORT", libparams.Default("8000"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reader) GetControlServerLog() (enabled bool, err error) {
|
|
||||||
return r.env.OnOff("HTTP_CONTROL_SERVER_LOG", libparams.Default("on"))
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetShadowSocks obtains if ShadowSocks is on from the environment variable
|
|
||||||
// SHADOWSOCKS.
|
|
||||||
func (r *reader) GetShadowSocks() (activated bool, err error) {
|
|
||||||
return r.env.OnOff("SHADOWSOCKS", libparams.Default("off"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetShadowSocksLog obtains the ShadowSocks log level from the environment variable
|
|
||||||
// SHADOWSOCKS_LOG.
|
|
||||||
func (r *reader) GetShadowSocksLog() (activated bool, err error) {
|
|
||||||
return r.env.OnOff("SHADOWSOCKS_LOG", libparams.Default("off"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetShadowSocksPort obtains the ShadowSocks listening port from the environment variable
|
|
||||||
// SHADOWSOCKS_PORT.
|
|
||||||
func (r *reader) GetShadowSocksPort() (port uint16, warning string, err error) {
|
|
||||||
return r.env.ListeningPort("SHADOWSOCKS_PORT", libparams.Default("8388"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetShadowSocksPassword obtains the ShadowSocks server password.
|
|
||||||
// It first tries to use the SHADOWSOCKS_PASSWORD environment variable (easier for the end user)
|
|
||||||
// and then tries to read from the secret file shadowsocks_password if nothing was found.
|
|
||||||
func (r *reader) GetShadowSocksPassword() (password string, err error) {
|
|
||||||
const compulsory = false
|
|
||||||
return r.getFromEnvOrSecretFile("SHADOWSOCKS_PASSWORD", compulsory, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetShadowSocksMethod obtains the ShadowSocks method to use from the environment variable
|
|
||||||
// SHADOWSOCKS_METHOD.
|
|
||||||
func (r *reader) GetShadowSocksMethod() (method string, err error) {
|
|
||||||
return r.env.Get("SHADOWSOCKS_METHOD", libparams.Default("chacha20-ietf-poly1305"))
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetSurfsharkRegions obtains the regions for the Surfshark servers from the
|
|
||||||
// environment variable REGION.
|
|
||||||
func (r *reader) GetSurfsharkRegions() (regions []string, err error) {
|
|
||||||
return r.env.CSVInside("REGION", constants.SurfsharkRegionChoices())
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetPUID obtains the user ID to use from the environment variable PUID
|
|
||||||
// with retro compatible variable UID.
|
|
||||||
func (r *reader) GetPUID() (ppuid int, err error) {
|
|
||||||
return r.env.IntRange("PUID", 0, 65535,
|
|
||||||
libparams.Default("1000"),
|
|
||||||
libparams.RetroKeys([]string{"UID"}, r.onRetroActive))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGID obtains the group ID to use from the environment variable PGID
|
|
||||||
// with retro compatible variable PGID.
|
|
||||||
func (r *reader) GetPGID() (pgid int, err error) {
|
|
||||||
return r.env.IntRange("PGID", 0, 65535,
|
|
||||||
libparams.Default("1000"),
|
|
||||||
libparams.RetroKeys([]string{"GID"}, r.onRetroActive))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTZ obtains the timezone from the environment variable TZ.
|
|
||||||
func (r *reader) GetTimezone() (timezone string, err error) {
|
|
||||||
return r.env.Get("TZ")
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetUpdaterPeriod obtains the period to fetch the servers information when the tunnel is up.
|
|
||||||
// Set to 0 to disable.
|
|
||||||
func (r *reader) GetUpdaterPeriod() (period time.Duration, err error) {
|
|
||||||
s, err := r.env.Get("UPDATER_PERIOD", libparams.Default("0"))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return time.ParseDuration(s)
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetVyprvpnRegions obtains the regions for the Vyprvpn servers from the
|
|
||||||
// environment variable REGION.
|
|
||||||
func (r *reader) GetVyprvpnRegions() (regions []string, err error) {
|
|
||||||
return r.env.CSVInside("REGION", constants.VyprvpnRegionChoices())
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
package params
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetWindscribeRegions obtains the regions for the Windscribe servers from the
|
|
||||||
// environment variable REGION.
|
|
||||||
func (r *reader) GetWindscribeRegions() (regions []string, err error) {
|
|
||||||
return r.env.CSVInside("REGION", constants.WindscribeRegionChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWindscribeCities obtains the cities for the Windscribe servers from the
|
|
||||||
// environment variable CITY.
|
|
||||||
func (r *reader) GetWindscribeCities() (cities []string, err error) {
|
|
||||||
return r.env.CSVInside("CITY", constants.WindscribeCityChoices())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWindscribeHostnames obtains the hostnames for the Windscribe servers from the
|
|
||||||
// environment variable SERVER_HOSTNAME.
|
|
||||||
func (r *reader) GetWindscribeHostnames() (hostnames []string, err error) {
|
|
||||||
return r.env.CSVInside("SERVER_HOSTNAME",
|
|
||||||
constants.WindscribeHostnameChoices(),
|
|
||||||
libparams.RetroKeys([]string{"HOSTNAME"}, r.onRetroActive),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWindscribePort obtains the port to reach the Windscribe server on from the
|
|
||||||
// environment variable PORT.
|
|
||||||
//nolint:gomnd
|
|
||||||
func (r *reader) GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error) {
|
|
||||||
n, err := r.env.IntRange("PORT", 0, 65535, libparams.Default("0"))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
switch protocol {
|
|
||||||
case constants.TCP:
|
|
||||||
switch n {
|
|
||||||
case 21, 22, 80, 123, 143, 443, 587, 1194, 3306, 8080, 54783:
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("port %d is not valid for protocol %s", n, protocol)
|
|
||||||
}
|
|
||||||
case constants.UDP:
|
|
||||||
switch n {
|
|
||||||
case 53, 80, 123, 443, 1194, 54783:
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("port %d is not valid for protocol %s", n, protocol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return uint16(n), nil
|
|
||||||
}
|
|
||||||
@@ -9,10 +9,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -41,7 +41,7 @@ func (c *cyberghost) filterServers(regions []string, group string) (servers []mo
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cyberghost) GetOpenVPNConnection(selection models.ServerSelection) (
|
func (c *cyberghost) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
connection models.OpenVPNConnection, err error) {
|
connection models.OpenVPNConnection, err error) {
|
||||||
const httpsPort = 443
|
const httpsPort = 443
|
||||||
if selection.TargetIP != nil {
|
if selection.TargetIP != nil {
|
||||||
@@ -65,7 +65,7 @@ func (c *cyberghost) GetOpenVPNConnection(selection models.ServerSelection) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *cyberghost) BuildConf(connection models.OpenVPNConnection,
|
func (c *cyberghost) BuildConf(connection models.OpenVPNConnection,
|
||||||
username string, settings settings.OpenVPN) (lines []string) {
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
if len(settings.Cipher) == 0 {
|
if len(settings.Cipher) == 0 {
|
||||||
settings.Cipher = aes256cbc
|
settings.Cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -43,7 +43,7 @@ func (m *mullvad) filterServers(countries, cities, isps []string, owned bool) (s
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mullvad) GetOpenVPNConnection(selection models.ServerSelection) (
|
func (m *mullvad) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
connection models.OpenVPNConnection, err error) {
|
connection models.OpenVPNConnection, err error) {
|
||||||
var defaultPort uint16 = 1194
|
var defaultPort uint16 = 1194
|
||||||
if selection.Protocol == constants.TCP {
|
if selection.Protocol == constants.TCP {
|
||||||
@@ -75,7 +75,7 @@ func (m *mullvad) GetOpenVPNConnection(selection models.ServerSelection) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mullvad) BuildConf(connection models.OpenVPNConnection,
|
func (m *mullvad) BuildConf(connection models.OpenVPNConnection,
|
||||||
username string, settings settings.OpenVPN) (lines []string) {
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
if len(settings.Cipher) == 0 {
|
if len(settings.Cipher) == 0 {
|
||||||
settings.Cipher = aes256cbc
|
settings.Cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -49,7 +49,7 @@ func (n *nordvpn) filterServers(regions []string, protocol models.NetworkProtoco
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *nordvpn) GetOpenVPNConnection(selection models.ServerSelection) (
|
func (n *nordvpn) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
connection models.OpenVPNConnection, err error) {
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
@@ -80,7 +80,7 @@ func (n *nordvpn) GetOpenVPNConnection(selection models.ServerSelection) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *nordvpn) BuildConf(connection models.OpenVPNConnection,
|
func (n *nordvpn) BuildConf(connection models.OpenVPNConnection,
|
||||||
username string, settings settings.OpenVPN) (lines []string) {
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
if len(settings.Cipher) == 0 {
|
if len(settings.Cipher) == 0 {
|
||||||
settings.Cipher = aes256cbc
|
settings.Cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
gluetunLog "github.com/qdm12/gluetun/internal/logging"
|
gluetunLog "github.com/qdm12/gluetun/internal/logging"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -45,7 +45,7 @@ var (
|
|||||||
ErrInvalidPort = errors.New("invalid port number")
|
ErrInvalidPort = errors.New("invalid port number")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *pia) getPort(selection models.ServerSelection) (port uint16, err error) {
|
func (p *pia) getPort(selection configuration.ServerSelection) (port uint16, err error) {
|
||||||
if selection.CustomPort == 0 {
|
if selection.CustomPort == 0 {
|
||||||
switch selection.Protocol {
|
switch selection.Protocol {
|
||||||
case constants.TCP:
|
case constants.TCP:
|
||||||
@@ -93,7 +93,7 @@ func (p *pia) getPort(selection models.ServerSelection) (port uint16, err error)
|
|||||||
return port, nil
|
return port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pia) GetOpenVPNConnection(selection models.ServerSelection) (
|
func (p *pia) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
connection models.OpenVPNConnection, err error) {
|
connection models.OpenVPNConnection, err error) {
|
||||||
port, err := p.getPort(selection)
|
port, err := p.getPort(selection)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -131,7 +131,7 @@ func (p *pia) GetOpenVPNConnection(selection models.ServerSelection) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *pia) BuildConf(connection models.OpenVPNConnection,
|
func (p *pia) BuildConf(connection models.OpenVPNConnection,
|
||||||
username string, settings settings.OpenVPN) (lines []string) {
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
var X509CRL, certificate string
|
var X509CRL, certificate string
|
||||||
var defaultCipher, defaultAuth string
|
var defaultCipher, defaultAuth string
|
||||||
if settings.Provider.ExtraConfigOptions.EncryptionPreset == constants.PIAEncryptionPresetNormal {
|
if settings.Provider.ExtraConfigOptions.EncryptionPreset == constants.PIAEncryptionPresetNormal {
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -39,7 +39,7 @@ func (s *privado) filterServers(hostnames []string) (servers []models.PrivadoSer
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *privado) GetOpenVPNConnection(selection models.ServerSelection) (
|
func (s *privado) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
connection models.OpenVPNConnection, err error) {
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16 = 1194
|
var port uint16 = 1194
|
||||||
switch selection.Protocol {
|
switch selection.Protocol {
|
||||||
@@ -73,7 +73,7 @@ func (s *privado) GetOpenVPNConnection(selection models.ServerSelection) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *privado) BuildConf(connection models.OpenVPNConnection,
|
func (s *privado) BuildConf(connection models.OpenVPNConnection,
|
||||||
username string, settings settings.OpenVPN) (lines []string) {
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
if len(settings.Cipher) == 0 {
|
if len(settings.Cipher) == 0 {
|
||||||
settings.Cipher = aes256cbc
|
settings.Cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,18 +5,18 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provider contains methods to read and modify the openvpn configuration to connect as a client.
|
// Provider contains methods to read and modify the openvpn configuration to connect as a client.
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error)
|
GetOpenVPNConnection(selection configuration.ServerSelection) (connection models.OpenVPNConnection, err error)
|
||||||
BuildConf(connection models.OpenVPNConnection, username string, settings settings.OpenVPN) (lines []string)
|
BuildConf(connection models.OpenVPNConnection, username string, settings configuration.OpenVPN) (lines []string)
|
||||||
PortForward(ctx context.Context, client *http.Client,
|
PortForward(ctx context.Context, client *http.Client,
|
||||||
openFile os.OpenFileFunc, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,
|
openFile os.OpenFileFunc, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,
|
||||||
syncState func(port uint16) (pfFilepath models.Filepath))
|
syncState func(port uint16) (pfFilepath models.Filepath))
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -42,7 +42,7 @@ func (p *purevpn) filterServers(regions, countries, cities []string) (servers []
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *purevpn) GetOpenVPNConnection(selection models.ServerSelection) (
|
func (p *purevpn) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
connection models.OpenVPNConnection, err error) {
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
@@ -75,7 +75,7 @@ func (p *purevpn) GetOpenVPNConnection(selection models.ServerSelection) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *purevpn) BuildConf(connection models.OpenVPNConnection,
|
func (p *purevpn) BuildConf(connection models.OpenVPNConnection,
|
||||||
username string, settings settings.OpenVPN) (lines []string) {
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
if len(settings.Cipher) == 0 {
|
if len(settings.Cipher) == 0 {
|
||||||
settings.Cipher = aes256cbc
|
settings.Cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -40,7 +40,7 @@ func (s *surfshark) filterServers(regions []string) (servers []models.SurfsharkS
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *surfshark) GetOpenVPNConnection(selection models.ServerSelection) (
|
func (s *surfshark) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
connection models.OpenVPNConnection, err error) {
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
@@ -76,7 +76,7 @@ func (s *surfshark) GetOpenVPNConnection(selection models.ServerSelection) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *surfshark) BuildConf(connection models.OpenVPNConnection,
|
func (s *surfshark) BuildConf(connection models.OpenVPNConnection,
|
||||||
username string, settings settings.OpenVPN) (lines []string) {
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
if len(settings.Cipher) == 0 {
|
if len(settings.Cipher) == 0 {
|
||||||
settings.Cipher = aes256cbc
|
settings.Cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -40,7 +40,7 @@ func (v *vyprvpn) filterServers(regions []string) (servers []models.VyprvpnServe
|
|||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vyprvpn) GetOpenVPNConnection(selection models.ServerSelection) (
|
func (v *vyprvpn) GetOpenVPNConnection(selection configuration.ServerSelection) (
|
||||||
connection models.OpenVPNConnection, err error) {
|
connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
@@ -72,7 +72,7 @@ func (v *vyprvpn) GetOpenVPNConnection(selection models.ServerSelection) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *vyprvpn) BuildConf(connection models.OpenVPNConnection,
|
func (v *vyprvpn) BuildConf(connection models.OpenVPNConnection,
|
||||||
username string, settings settings.OpenVPN) (lines []string) {
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
if len(settings.Cipher) == 0 {
|
if len(settings.Cipher) == 0 {
|
||||||
settings.Cipher = aes256cbc
|
settings.Cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/firewall"
|
"github.com/qdm12/gluetun/internal/firewall"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -44,7 +44,7 @@ func (w *windscribe) filterServers(regions, cities, hostnames []string) (servers
|
|||||||
}
|
}
|
||||||
|
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
func (w *windscribe) GetOpenVPNConnection(selection models.ServerSelection) (connection models.OpenVPNConnection, err error) {
|
func (w *windscribe) GetOpenVPNConnection(selection configuration.ServerSelection) (connection models.OpenVPNConnection, err error) {
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
case selection.CustomPort > 0:
|
case selection.CustomPort > 0:
|
||||||
@@ -75,7 +75,7 @@ func (w *windscribe) GetOpenVPNConnection(selection models.ServerSelection) (con
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *windscribe) BuildConf(connection models.OpenVPNConnection,
|
func (w *windscribe) BuildConf(connection models.OpenVPNConnection,
|
||||||
username string, settings settings.OpenVPN) (lines []string) {
|
username string, settings configuration.OpenVPN) (lines []string) {
|
||||||
if len(settings.Cipher) == 0 {
|
if len(settings.Cipher) == 0 {
|
||||||
settings.Cipher = aes256cbc
|
settings.Cipher = aes256cbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -19,8 +19,8 @@ type Looper interface {
|
|||||||
RunRestartTicker(ctx context.Context, wg *sync.WaitGroup)
|
RunRestartTicker(ctx context.Context, wg *sync.WaitGroup)
|
||||||
GetStatus() (status models.LoopStatus)
|
GetStatus() (status models.LoopStatus)
|
||||||
SetStatus(status models.LoopStatus) (outcome string, err error)
|
SetStatus(status models.LoopStatus) (outcome string, err error)
|
||||||
GetSettings() (settings settings.PublicIP)
|
GetSettings() (settings configuration.PublicIP)
|
||||||
SetSettings(settings settings.PublicIP) (outcome string)
|
SetSettings(settings configuration.PublicIP) (outcome string)
|
||||||
GetPublicIP() (publicIP net.IP)
|
GetPublicIP() (publicIP net.IP)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ type looper struct {
|
|||||||
const defaultBackoffTime = 5 * time.Second
|
const defaultBackoffTime = 5 * time.Second
|
||||||
|
|
||||||
func NewLooper(client *http.Client, logger logging.Logger,
|
func NewLooper(client *http.Client, logger logging.Logger,
|
||||||
settings settings.PublicIP, puid, pgid int,
|
settings configuration.PublicIP, puid, pgid int,
|
||||||
os os.OS) Looper {
|
os os.OS) Looper {
|
||||||
return &looper{
|
return &looper{
|
||||||
state: state{
|
state: state{
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type state struct {
|
type state struct {
|
||||||
status models.LoopStatus
|
status models.LoopStatus
|
||||||
settings settings.PublicIP
|
settings configuration.PublicIP
|
||||||
ip net.IP
|
ip net.IP
|
||||||
statusMu sync.RWMutex
|
statusMu sync.RWMutex
|
||||||
settingsMu sync.RWMutex
|
settingsMu sync.RWMutex
|
||||||
@@ -72,13 +72,13 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) GetSettings() (settings settings.PublicIP) {
|
func (l *looper) GetSettings() (settings configuration.PublicIP) {
|
||||||
l.state.settingsMu.RLock()
|
l.state.settingsMu.RLock()
|
||||||
defer l.state.settingsMu.RUnlock()
|
defer l.state.settingsMu.RUnlock()
|
||||||
return l.state.settings
|
return l.state.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) SetSettings(settings settings.PublicIP) (outcome string) {
|
func (l *looper) SetSettings(settings configuration.PublicIP) (outcome string) {
|
||||||
l.state.settingsMu.Lock()
|
l.state.settingsMu.Lock()
|
||||||
defer l.state.settingsMu.Unlock()
|
defer l.state.settingsMu.Unlock()
|
||||||
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
|
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
|
||||||
|
|||||||
@@ -1,191 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
unboundmodels "github.com/qdm12/dns/pkg/models"
|
|
||||||
unbound "github.com/qdm12/dns/pkg/unbound"
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DNS contains settings to configure Unbound for DNS over TLS operation.
|
|
||||||
type DNS struct { //nolint:maligned
|
|
||||||
Enabled bool
|
|
||||||
PlaintextAddress net.IP
|
|
||||||
KeepNameserver bool
|
|
||||||
BlockMalicious bool
|
|
||||||
BlockAds bool
|
|
||||||
BlockSurveillance bool
|
|
||||||
UpdatePeriod time.Duration
|
|
||||||
Unbound unboundmodels.Settings
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNS) String() string {
|
|
||||||
return strings.Join(d.lines(), "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
subIndent = " |--"
|
|
||||||
indent = " " // used if lines already contain the subIndent
|
|
||||||
)
|
|
||||||
|
|
||||||
func (d *DNS) lines() (lines []string) {
|
|
||||||
lines = append(lines, subIndent+"DNS:")
|
|
||||||
if d.PlaintextAddress != nil {
|
|
||||||
lines = append(lines, indent+subIndent+"Plaintext address: "+d.PlaintextAddress.String())
|
|
||||||
}
|
|
||||||
keepNameserver := "no"
|
|
||||||
if d.KeepNameserver {
|
|
||||||
keepNameserver = "yes"
|
|
||||||
}
|
|
||||||
lines = append(lines,
|
|
||||||
indent+subIndent+"Keep nameserver (disabled blocking): "+keepNameserver)
|
|
||||||
if !d.Enabled {
|
|
||||||
lines = append(lines, indent+subIndent+"DNS over TLS: disabled")
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
lines = append(lines, indent+subIndent+"DNS over TLS:")
|
|
||||||
|
|
||||||
lines = append(lines, indent+indent+subIndent+"Unbound:")
|
|
||||||
for _, line := range d.Unbound.Lines() {
|
|
||||||
lines = append(lines, indent+indent+indent+line)
|
|
||||||
}
|
|
||||||
|
|
||||||
blockMalicious := disabled
|
|
||||||
if d.BlockMalicious {
|
|
||||||
blockMalicious = enabled
|
|
||||||
}
|
|
||||||
lines = append(lines, indent+indent+subIndent+"Block malicious: "+blockMalicious)
|
|
||||||
|
|
||||||
blockAds := disabled
|
|
||||||
if d.BlockAds {
|
|
||||||
blockAds = enabled
|
|
||||||
}
|
|
||||||
lines = append(lines, indent+indent+subIndent+"Block ads: "+blockAds)
|
|
||||||
|
|
||||||
blockSurveillance := disabled
|
|
||||||
if d.BlockSurveillance {
|
|
||||||
blockSurveillance = enabled
|
|
||||||
}
|
|
||||||
lines = append(lines, indent+indent+subIndent+"Block surveillance: "+blockSurveillance)
|
|
||||||
|
|
||||||
update := "deactivated"
|
|
||||||
if d.UpdatePeriod > 0 {
|
|
||||||
update = "every " + d.UpdatePeriod.String()
|
|
||||||
}
|
|
||||||
lines = append(lines, indent+indent+subIndent+"Update: "+update)
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDNSSettings obtains DNS over TLS settings from environment variables using the params package.
|
|
||||||
func GetDNSSettings(paramsReader params.Reader) (settings DNS, err error) {
|
|
||||||
settings.Enabled, err = paramsReader.GetDNSOverTLS()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plain DNS settings
|
|
||||||
settings.PlaintextAddress, err = paramsReader.GetDNSPlaintext()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.KeepNameserver, err = paramsReader.GetDNSKeepNameserver()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// DNS over TLS external settings
|
|
||||||
settings.BlockMalicious, err = paramsReader.GetDNSMaliciousBlocking()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.BlockSurveillance, err = paramsReader.GetDNSSurveillanceBlocking()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.BlockAds, err = paramsReader.GetDNSAdsBlocking()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.UpdatePeriod, err = paramsReader.GetDNSUpdatePeriod()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unbound specific settings
|
|
||||||
settings.Unbound, err = getUnboundSettings(paramsReader)
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consistency check
|
|
||||||
IPv6Support := false
|
|
||||||
for _, provider := range settings.Unbound.Providers {
|
|
||||||
providerData, ok := unbound.GetProviderData(provider)
|
|
||||||
switch {
|
|
||||||
case !ok:
|
|
||||||
return settings, fmt.Errorf("DNS provider %q does not have associated data", provider)
|
|
||||||
case !providerData.SupportsTLS:
|
|
||||||
return settings, fmt.Errorf("DNS provider %q does not support DNS over TLS", provider)
|
|
||||||
case providerData.SupportsIPv6:
|
|
||||||
IPv6Support = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if settings.Unbound.IPv6 && !IPv6Support {
|
|
||||||
return settings, fmt.Errorf("None of the DNS over TLS provider(s) set support IPv6")
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUnboundSettings(reader params.Reader) (settings unboundmodels.Settings, err error) {
|
|
||||||
settings.Providers, err = reader.GetDNSOverTLSProviders()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ListeningPort = 53
|
|
||||||
settings.Caching, err = reader.GetDNSOverTLSCaching()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.IPv4 = true
|
|
||||||
settings.IPv6, err = reader.GetDNSOverTLSIPv6()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.VerbosityLevel, err = reader.GetDNSOverTLSVerbosity()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.VerbosityDetailsLevel, err = reader.GetDNSOverTLSVerbosityDetails()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ValidationLogLevel, err = reader.GetDNSOverTLSValidationLogLevel()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.BlockedHostnames = []string{}
|
|
||||||
settings.BlockedIPs, err = reader.GetDNSOverTLSPrivateAddresses()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.AllowedHostnames, err = reader.GetDNSUnblockedHostnames()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.AccessControl.Allowed = []net.IPNet{
|
|
||||||
{
|
|
||||||
IP: net.IPv4zero,
|
|
||||||
Mask: net.IPv4Mask(0, 0, 0, 0),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
IP: net.IPv6zero,
|
|
||||||
Mask: net.IPMask{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/qdm12/dns/pkg/models"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_DNS_Lines(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
testCases := map[string]struct {
|
|
||||||
settings DNS
|
|
||||||
lines []string
|
|
||||||
}{
|
|
||||||
"disabled DOT": {
|
|
||||||
settings: DNS{
|
|
||||||
PlaintextAddress: net.IP{1, 1, 1, 1},
|
|
||||||
},
|
|
||||||
lines: []string{
|
|
||||||
" |--DNS:",
|
|
||||||
" |--Plaintext address: 1.1.1.1",
|
|
||||||
" |--Keep nameserver (disabled blocking): no",
|
|
||||||
" |--DNS over TLS: disabled",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"enabled DOT": {
|
|
||||||
settings: DNS{
|
|
||||||
Enabled: true,
|
|
||||||
KeepNameserver: true,
|
|
||||||
Unbound: models.Settings{
|
|
||||||
Providers: []string{"cloudflare"},
|
|
||||||
},
|
|
||||||
BlockMalicious: true,
|
|
||||||
BlockAds: true,
|
|
||||||
BlockSurveillance: true,
|
|
||||||
UpdatePeriod: time.Hour,
|
|
||||||
},
|
|
||||||
lines: []string{
|
|
||||||
" |--DNS:",
|
|
||||||
" |--Keep nameserver (disabled blocking): yes",
|
|
||||||
" |--DNS over TLS:",
|
|
||||||
" |--Unbound:",
|
|
||||||
" |--DNS over TLS providers:",
|
|
||||||
" |--cloudflare",
|
|
||||||
" |--Listening port: 0",
|
|
||||||
" |--Access control:",
|
|
||||||
" |--Allowed:",
|
|
||||||
" |--Caching: disabled",
|
|
||||||
" |--IPv4 resolution: disabled",
|
|
||||||
" |--IPv6 resolution: disabled",
|
|
||||||
" |--Verbosity level: 0/5",
|
|
||||||
" |--Verbosity details level: 0/4",
|
|
||||||
" |--Validation log level: 0/2",
|
|
||||||
" |--Blocked hostnames:",
|
|
||||||
" |--Blocked IP addresses:",
|
|
||||||
" |--Allowed hostnames:",
|
|
||||||
" |--Block malicious: enabled",
|
|
||||||
" |--Block ads: enabled",
|
|
||||||
" |--Block surveillance: enabled",
|
|
||||||
" |--Update: every 1h0m0s",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for name, testCase := range testCases {
|
|
||||||
testCase := testCase
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
lines := testCase.settings.lines()
|
|
||||||
assert.Equal(t, testCase.lines, lines)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Firewall contains settings to customize the firewall operation.
|
|
||||||
type Firewall struct {
|
|
||||||
VPNInputPorts []uint16
|
|
||||||
InputPorts []uint16
|
|
||||||
OutboundSubnets []net.IPNet
|
|
||||||
Enabled bool
|
|
||||||
Debug bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Firewall) String() string {
|
|
||||||
if !f.Enabled {
|
|
||||||
return "Firewall settings: disabled"
|
|
||||||
}
|
|
||||||
vpnInputPorts := make([]string, len(f.VPNInputPorts))
|
|
||||||
for i, port := range f.VPNInputPorts {
|
|
||||||
vpnInputPorts[i] = fmt.Sprintf("%d", port)
|
|
||||||
}
|
|
||||||
inputPorts := make([]string, len(f.InputPorts))
|
|
||||||
for i, port := range f.InputPorts {
|
|
||||||
inputPorts[i] = fmt.Sprintf("%d", port)
|
|
||||||
}
|
|
||||||
outboundSubnets := make([]string, len(f.OutboundSubnets))
|
|
||||||
for i := range f.OutboundSubnets {
|
|
||||||
outboundSubnets[i] = f.OutboundSubnets[i].String()
|
|
||||||
}
|
|
||||||
|
|
||||||
settingsList := []string{
|
|
||||||
"Firewall settings:",
|
|
||||||
"VPN input ports: " + strings.Join(vpnInputPorts, ", "),
|
|
||||||
"Input ports: " + strings.Join(inputPorts, ", "),
|
|
||||||
"Outbound subnets: " + strings.Join(outboundSubnets, ", "),
|
|
||||||
}
|
|
||||||
if f.Debug {
|
|
||||||
settingsList = append(settingsList, "Debug: on")
|
|
||||||
}
|
|
||||||
return strings.Join(settingsList, "\n |--")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFirewallSettings obtains firewall settings from environment variables using the params package.
|
|
||||||
func GetFirewallSettings(paramsReader params.Reader) (settings Firewall, err error) {
|
|
||||||
settings.VPNInputPorts, err = paramsReader.GetVPNInputPorts()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.InputPorts, err = paramsReader.GetInputPorts()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.OutboundSubnets, err = paramsReader.GetOutboundSubnets()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.Enabled, err = paramsReader.GetFirewall()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.Debug, err = paramsReader.GetFirewallDebug()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HTTPProxy contains settings to configure the HTTP proxy.
|
|
||||||
type HTTPProxy struct {
|
|
||||||
User string
|
|
||||||
Password string
|
|
||||||
Port uint16
|
|
||||||
Enabled bool
|
|
||||||
Stealth bool
|
|
||||||
Log bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HTTPProxy) String() string {
|
|
||||||
if !h.Enabled {
|
|
||||||
return "HTTP Proxy settings: disabled"
|
|
||||||
}
|
|
||||||
auth, log, stealth := disabled, disabled, disabled
|
|
||||||
if h.User != "" {
|
|
||||||
auth = enabled
|
|
||||||
}
|
|
||||||
if h.Log {
|
|
||||||
log = enabled
|
|
||||||
}
|
|
||||||
if h.Stealth {
|
|
||||||
stealth = enabled
|
|
||||||
}
|
|
||||||
settingsList := []string{
|
|
||||||
"HTTP proxy settings:",
|
|
||||||
fmt.Sprintf("Port: %d", h.Port),
|
|
||||||
"Authentication: " + auth,
|
|
||||||
"Stealth: " + stealth,
|
|
||||||
"Log: " + log,
|
|
||||||
}
|
|
||||||
return strings.Join(settingsList, "\n |--")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPProxySettings obtains HTTPProxy settings from environment variables using the params package.
|
|
||||||
func GetHTTPProxySettings(paramsReader params.Reader) (settings HTTPProxy, warning string, err error) {
|
|
||||||
settings.Enabled, err = paramsReader.GetHTTPProxy()
|
|
||||||
if err != nil || !settings.Enabled {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.User, err = paramsReader.GetHTTPProxyUser()
|
|
||||||
if err != nil {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.Password, err = paramsReader.GetHTTPProxyPassword()
|
|
||||||
if err != nil {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.Stealth, err = paramsReader.GetHTTPProxyStealth()
|
|
||||||
if err != nil {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.Log, err = paramsReader.GetHTTPProxyLog()
|
|
||||||
if err != nil {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.Port, warning, err = paramsReader.GetHTTPProxyPort()
|
|
||||||
if err != nil {
|
|
||||||
return settings, warning, err
|
|
||||||
}
|
|
||||||
return settings, warning, nil
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OpenVPN contains settings to configure the OpenVPN client.
|
|
||||||
type OpenVPN struct {
|
|
||||||
User string `json:"user"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
Verbosity int `json:"verbosity"`
|
|
||||||
MSSFix uint16 `json:"mssfix"`
|
|
||||||
Root bool `json:"run_as_root"`
|
|
||||||
Cipher string `json:"cipher"`
|
|
||||||
Auth string `json:"auth"`
|
|
||||||
Provider models.ProviderSettings `json:"provider"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
// Remove spaces in user ID to simplify user's life, thanks @JeordyR
|
|
||||||
settings.User = strings.ReplaceAll(settings.User, " ", "")
|
|
||||||
if vpnProvider == constants.Mullvad {
|
|
||||||
settings.Password = "m"
|
|
||||||
} else {
|
|
||||||
settings.Password, err = paramsReader.GetPassword()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
settings.Verbosity, err = paramsReader.GetOpenVPNVerbosity()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.Root, err = paramsReader.GetOpenVPNRoot()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.Cipher, err = paramsReader.GetOpenVPNCipher()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.Auth, err = paramsReader.GetOpenVPNAuth()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.MSSFix, err = paramsReader.GetOpenVPNMSSFix()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
switch vpnProvider {
|
|
||||||
case constants.PrivateInternetAccess:
|
|
||||||
settings.Provider, err = GetPIASettings(paramsReader)
|
|
||||||
case constants.Mullvad:
|
|
||||||
settings.Provider, err = GetMullvadSettings(paramsReader)
|
|
||||||
case constants.Windscribe:
|
|
||||||
settings.Provider, err = GetWindscribeSettings(paramsReader)
|
|
||||||
case constants.Surfshark:
|
|
||||||
settings.Provider, err = GetSurfsharkSettings(paramsReader)
|
|
||||||
case constants.Cyberghost:
|
|
||||||
settings.Provider, err = GetCyberghostSettings(paramsReader)
|
|
||||||
case constants.Vyprvpn:
|
|
||||||
settings.Provider, err = GetVyprvpnSettings(paramsReader)
|
|
||||||
case constants.Nordvpn:
|
|
||||||
settings.Provider, err = GetNordvpnSettings(paramsReader)
|
|
||||||
case constants.Purevpn:
|
|
||||||
settings.Provider, err = GetPurevpnSettings(paramsReader)
|
|
||||||
case constants.Privado:
|
|
||||||
settings.Provider, err = GetPrivadoSettings(paramsReader)
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("VPN service provider %q is not valid", vpnProvider)
|
|
||||||
}
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *OpenVPN) String() string {
|
|
||||||
runAsRoot := "no"
|
|
||||||
if o.Root {
|
|
||||||
runAsRoot = "yes"
|
|
||||||
}
|
|
||||||
settingsList := []string{
|
|
||||||
"OpenVPN settings:",
|
|
||||||
"User: [redacted]",
|
|
||||||
"Password: [redacted]",
|
|
||||||
"Verbosity level: " + fmt.Sprintf("%d", o.Verbosity),
|
|
||||||
"Run as root: " + runAsRoot,
|
|
||||||
o.Provider.String(),
|
|
||||||
}
|
|
||||||
if len(o.Cipher) > 0 {
|
|
||||||
settingsList = append(settingsList, "Custom cipher: "+o.Cipher)
|
|
||||||
}
|
|
||||||
if len(o.Auth) > 0 {
|
|
||||||
settingsList = append(settingsList, "Custom auth algorithm: "+o.Auth)
|
|
||||||
}
|
|
||||||
return strings.Join(settingsList, "\n|--")
|
|
||||||
}
|
|
||||||
@@ -1,260 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetPIASettings obtains PIA settings from environment variables using the params package.
|
|
||||||
func GetPIASettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
|
||||||
settings.Name = constants.PrivateInternetAccess
|
|
||||||
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
encryptionPreset, err := paramsReader.GetPIAEncryptionPreset()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.EncryptionPreset = encryptionPreset
|
|
||||||
settings.ExtraConfigOptions.EncryptionPreset = encryptionPreset
|
|
||||||
settings.ServerSelection.Regions, err = paramsReader.GetPIARegions()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.CustomPort, err = paramsReader.GetPIAPort()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.PortForwarding.Enabled, err = paramsReader.GetPortForwarding()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
if settings.PortForwarding.Enabled {
|
|
||||||
settings.PortForwarding.Filepath, err = paramsReader.GetPortForwardingStatusFilepath()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMullvadSettings obtains Mullvad settings from environment variables using the params package.
|
|
||||||
func GetMullvadSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
|
||||||
settings.Name = constants.Mullvad
|
|
||||||
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Countries, err = paramsReader.GetMullvadCountries()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Cities, err = paramsReader.GetMullvadCities()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.ISPs, err = paramsReader.GetMullvadISPs()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.CustomPort, err = paramsReader.GetMullvadPort()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
if settings.ServerSelection.Protocol == constants.TCP {
|
|
||||||
switch settings.ServerSelection.CustomPort {
|
|
||||||
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: //nolint:gomnd
|
|
||||||
default:
|
|
||||||
return settings, fmt.Errorf("port %d is not valid for UDP protocol", settings.ServerSelection.CustomPort)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Owned, err = paramsReader.GetMullvadOwned()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ExtraConfigOptions.OpenVPNIPv6, err = paramsReader.GetOpenVPNIPv6()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWindscribeSettings obtains Windscribe settings from environment variables using the params package.
|
|
||||||
func GetWindscribeSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
|
||||||
settings.Name = constants.Windscribe
|
|
||||||
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Regions, err = paramsReader.GetWindscribeRegions()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Cities, err = paramsReader.GetWindscribeCities()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Hostnames, err = paramsReader.GetWindscribeHostnames()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.CustomPort, err = paramsReader.GetWindscribePort(settings.ServerSelection.Protocol)
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSurfsharkSettings obtains Surfshark settings from environment variables using the params package.
|
|
||||||
func GetSurfsharkSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
|
||||||
settings.Name = constants.Surfshark
|
|
||||||
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Regions, err = paramsReader.GetSurfsharkRegions()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCyberghostSettings obtains Cyberghost settings from environment variables using the params package.
|
|
||||||
func GetCyberghostSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
|
||||||
settings.Name = constants.Cyberghost
|
|
||||||
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ExtraConfigOptions.ClientKey, err = paramsReader.GetCyberghostClientKey()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ExtraConfigOptions.ClientCertificate, err = paramsReader.GetCyberghostClientCertificate()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Group, err = paramsReader.GetCyberghostGroup()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Regions, err = paramsReader.GetCyberghostRegions()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetVyprvpnSettings obtains Vyprvpn settings from environment variables using the params package.
|
|
||||||
func GetVyprvpnSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
|
||||||
settings.Name = constants.Vyprvpn
|
|
||||||
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Regions, err = paramsReader.GetVyprvpnRegions()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetNordvpnSettings obtains NordVPN settings from environment variables using the params package.
|
|
||||||
func GetNordvpnSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
|
||||||
settings.Name = constants.Nordvpn
|
|
||||||
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Regions, err = paramsReader.GetNordvpnRegions()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Numbers, err = paramsReader.GetNordvpnNumbers()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPurevpnSettings obtains Purevpn settings from environment variables using the params package.
|
|
||||||
func GetPurevpnSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
|
||||||
settings.Name = constants.Purevpn
|
|
||||||
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Regions, err = paramsReader.GetPurevpnRegions()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Countries, err = paramsReader.GetPurevpnCountries()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Cities, err = paramsReader.GetPurevpnCities()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPrivadoSettings obtains Privado settings from environment variables using the params package.
|
|
||||||
func GetPrivadoSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
|
||||||
settings.Name = constants.Privado
|
|
||||||
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.ServerSelection.Hostnames, err = paramsReader.GetPrivadoHostnames()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PublicIP struct {
|
|
||||||
Period time.Duration `json:"period"`
|
|
||||||
IPFilepath models.Filepath `json:"ip_filepath"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPublicIPSettings(paramsReader params.Reader) (settings PublicIP, err error) {
|
|
||||||
settings.Period, err = paramsReader.GetPublicIPPeriod()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.IPFilepath, err = paramsReader.GetPublicIPFilepath()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PublicIP) String() string {
|
|
||||||
if s.Period == 0 {
|
|
||||||
return "Public IP getter settings: disabled"
|
|
||||||
}
|
|
||||||
settingsList := []string{
|
|
||||||
"Public IP getter settings:",
|
|
||||||
fmt.Sprintf("Period: %s", s.Period),
|
|
||||||
fmt.Sprintf("IP file: %s", s.IPFilepath),
|
|
||||||
}
|
|
||||||
return strings.Join(settingsList, "\n|--")
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ControlServer contains settings to customize the control server operation.
|
|
||||||
type ControlServer struct {
|
|
||||||
Port uint16
|
|
||||||
Log bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ControlServer) String() string {
|
|
||||||
settingsList := []string{
|
|
||||||
"HTTP Control server:",
|
|
||||||
fmt.Sprintf("Listening port: %d", c.Port),
|
|
||||||
fmt.Sprintf("Logging: %t", c.Log),
|
|
||||||
}
|
|
||||||
return strings.Join(settingsList, "\n |--")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetControlServerSettings obtains the HTTP control server settings from
|
|
||||||
// environment variables using the params package.
|
|
||||||
func GetControlServerSettings(paramsReader params.Reader) (settings ControlServer, warning string, err error) {
|
|
||||||
settings.Log, err = paramsReader.GetControlServerLog()
|
|
||||||
if err != nil {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.Port, warning, err = paramsReader.GetControlServerPort()
|
|
||||||
if err != nil {
|
|
||||||
return settings, warning, err
|
|
||||||
}
|
|
||||||
return settings, warning, nil
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
enabled = "enabled"
|
|
||||||
disabled = "disabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Settings contains all settings for the program to run.
|
|
||||||
type Settings struct {
|
|
||||||
VPNSP models.VPNProvider
|
|
||||||
OpenVPN OpenVPN
|
|
||||||
System System
|
|
||||||
DNS DNS
|
|
||||||
Firewall Firewall
|
|
||||||
HTTPProxy HTTPProxy
|
|
||||||
ShadowSocks ShadowSocks
|
|
||||||
Updater Updater
|
|
||||||
PublicIP PublicIP
|
|
||||||
VersionInformation bool
|
|
||||||
ControlServer ControlServer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Settings) String() string {
|
|
||||||
versionInformation := disabled
|
|
||||||
if s.VersionInformation {
|
|
||||||
versionInformation = enabled
|
|
||||||
}
|
|
||||||
return strings.Join([]string{
|
|
||||||
"Settings summary below:",
|
|
||||||
s.OpenVPN.String(),
|
|
||||||
s.System.String(),
|
|
||||||
s.DNS.String(),
|
|
||||||
s.Firewall.String(),
|
|
||||||
s.HTTPProxy.String(),
|
|
||||||
s.ShadowSocks.String(),
|
|
||||||
s.ControlServer.String(),
|
|
||||||
s.Updater.String(),
|
|
||||||
s.PublicIP.String(),
|
|
||||||
"Version information: " + versionInformation,
|
|
||||||
"", // new line at the end
|
|
||||||
}, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllSettings obtains all settings for the program and returns an error as soon
|
|
||||||
// as an error is encountered reading them.
|
|
||||||
func GetAllSettings(paramsReader params.Reader) (settings Settings, warnings []string, err error) {
|
|
||||||
settings.VPNSP, err = paramsReader.GetVPNSP()
|
|
||||||
if err != nil {
|
|
||||||
return settings, nil, err
|
|
||||||
}
|
|
||||||
settings.OpenVPN, err = GetOpenVPNSettings(paramsReader, settings.VPNSP)
|
|
||||||
if err != nil {
|
|
||||||
return settings, nil, err
|
|
||||||
}
|
|
||||||
settings.DNS, err = GetDNSSettings(paramsReader)
|
|
||||||
if err != nil {
|
|
||||||
return settings, nil, err
|
|
||||||
}
|
|
||||||
settings.Firewall, err = GetFirewallSettings(paramsReader)
|
|
||||||
if err != nil {
|
|
||||||
return settings, nil, err
|
|
||||||
}
|
|
||||||
settings.System, err = GetSystemSettings(paramsReader)
|
|
||||||
if err != nil {
|
|
||||||
return settings, nil, err
|
|
||||||
}
|
|
||||||
settings.PublicIP, err = getPublicIPSettings(paramsReader)
|
|
||||||
if err != nil {
|
|
||||||
return settings, nil, err
|
|
||||||
}
|
|
||||||
settings.VersionInformation, err = paramsReader.GetVersionInformation()
|
|
||||||
if err != nil {
|
|
||||||
return settings, nil, err
|
|
||||||
}
|
|
||||||
settings.Updater, err = GetUpdaterSettings(paramsReader)
|
|
||||||
if err != nil {
|
|
||||||
return settings, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var warning string
|
|
||||||
settings.HTTPProxy, warning, err = GetHTTPProxySettings(paramsReader)
|
|
||||||
if warning != "" {
|
|
||||||
warnings = append(warnings, warning)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return settings, warnings, err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ShadowSocks, warning, err = GetShadowSocksSettings(paramsReader)
|
|
||||||
if warning != "" {
|
|
||||||
warnings = append(warnings, warning)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return settings, warnings, err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ControlServer, warning, err = GetControlServerSettings(paramsReader)
|
|
||||||
if warning != "" {
|
|
||||||
warnings = append(warnings, warning)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return settings, warnings, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return settings, warnings, nil
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ShadowSocks contains settings to configure the Shadowsocks server.
|
|
||||||
type ShadowSocks struct {
|
|
||||||
Method string
|
|
||||||
Password string
|
|
||||||
Port uint16
|
|
||||||
Enabled bool
|
|
||||||
Log bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ShadowSocks) String() string {
|
|
||||||
if !s.Enabled {
|
|
||||||
return "ShadowSocks settings: disabled"
|
|
||||||
}
|
|
||||||
log := disabled
|
|
||||||
if s.Log {
|
|
||||||
log = enabled
|
|
||||||
}
|
|
||||||
settingsList := []string{
|
|
||||||
"ShadowSocks settings:",
|
|
||||||
"Password: [redacted]",
|
|
||||||
"Log: " + log,
|
|
||||||
fmt.Sprintf("Port: %d", s.Port),
|
|
||||||
"Method: " + s.Method,
|
|
||||||
}
|
|
||||||
return strings.Join(settingsList, "\n |--")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetShadowSocksSettings obtains ShadowSocks settings from environment variables using the params package.
|
|
||||||
func GetShadowSocksSettings(paramsReader params.Reader) (settings ShadowSocks, warning string, err error) {
|
|
||||||
settings.Enabled, err = paramsReader.GetShadowSocks()
|
|
||||||
if err != nil || !settings.Enabled {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.Password, err = paramsReader.GetShadowSocksPassword()
|
|
||||||
if err != nil {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.Log, err = paramsReader.GetShadowSocksLog()
|
|
||||||
if err != nil {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.Method, err = paramsReader.GetShadowSocksMethod()
|
|
||||||
if err != nil {
|
|
||||||
return settings, "", err
|
|
||||||
}
|
|
||||||
settings.Port, warning, err = paramsReader.GetShadowSocksPort()
|
|
||||||
if err != nil {
|
|
||||||
return settings, warning, err
|
|
||||||
}
|
|
||||||
return settings, warning, nil
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// System contains settings to configure system related elements.
|
|
||||||
type System struct {
|
|
||||||
PUID int
|
|
||||||
PGID int
|
|
||||||
Timezone string
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSystemSettings obtains the System settings using the params functions.
|
|
||||||
func GetSystemSettings(paramsReader params.Reader) (settings System, err error) {
|
|
||||||
settings.PUID, err = paramsReader.GetPUID()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.PGID, err = paramsReader.GetPGID()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
settings.Timezone, err = paramsReader.GetTimezone()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *System) String() string {
|
|
||||||
settingsList := []string{
|
|
||||||
"System settings:",
|
|
||||||
fmt.Sprintf("Process user ID: %d", s.PUID),
|
|
||||||
fmt.Sprintf("Process group ID: %d", s.PGID),
|
|
||||||
fmt.Sprintf("Timezone: %s", s.Timezone),
|
|
||||||
}
|
|
||||||
return strings.Join(settingsList, "\n|--")
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Updater struct {
|
|
||||||
Period time.Duration `json:"period"`
|
|
||||||
DNSAddress string `json:"dns_address"`
|
|
||||||
Cyberghost bool `json:"cyberghost"`
|
|
||||||
Mullvad bool `json:"mullvad"`
|
|
||||||
Nordvpn bool `json:"nordvpn"`
|
|
||||||
PIA bool `json:"pia"`
|
|
||||||
Privado bool `json:"privado"`
|
|
||||||
Purevpn bool `json:"purevpn"`
|
|
||||||
Surfshark bool `json:"surfshark"`
|
|
||||||
Vyprvpn bool `json:"vyprvpn"`
|
|
||||||
Windscribe bool `json:"windscribe"`
|
|
||||||
// The two below should be used in CLI mode only
|
|
||||||
Stdout bool `json:"-"` // in order to update constants file (maintainer side)
|
|
||||||
CLI bool `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUpdaterSettings obtains the server updater settings using the params functions.
|
|
||||||
func GetUpdaterSettings(paramsReader params.Reader) (settings Updater, err error) {
|
|
||||||
settings = Updater{
|
|
||||||
Cyberghost: true,
|
|
||||||
Mullvad: true,
|
|
||||||
Nordvpn: true,
|
|
||||||
PIA: true,
|
|
||||||
Purevpn: true,
|
|
||||||
Surfshark: true,
|
|
||||||
Vyprvpn: true,
|
|
||||||
Windscribe: true,
|
|
||||||
Stdout: false,
|
|
||||||
CLI: false,
|
|
||||||
DNSAddress: "127.0.0.1",
|
|
||||||
}
|
|
||||||
settings.Period, err = paramsReader.GetUpdaterPeriod()
|
|
||||||
if err != nil {
|
|
||||||
return settings, err
|
|
||||||
}
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Updater) String() string {
|
|
||||||
if s.Period == 0 {
|
|
||||||
return "Server updater settings: disabled"
|
|
||||||
}
|
|
||||||
settingsList := []string{
|
|
||||||
"Server updater settings:",
|
|
||||||
fmt.Sprintf("Period: %s", s.Period),
|
|
||||||
}
|
|
||||||
return strings.Join(settingsList, "\n|--")
|
|
||||||
}
|
|
||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
shadowsockslib "github.com/qdm12/ss-server/pkg"
|
shadowsockslib "github.com/qdm12/ss-server/pkg"
|
||||||
)
|
)
|
||||||
@@ -17,8 +17,8 @@ type Looper interface {
|
|||||||
Run(ctx context.Context, wg *sync.WaitGroup)
|
Run(ctx context.Context, wg *sync.WaitGroup)
|
||||||
SetStatus(status models.LoopStatus) (outcome string, err error)
|
SetStatus(status models.LoopStatus) (outcome string, err error)
|
||||||
GetStatus() (status models.LoopStatus)
|
GetStatus() (status models.LoopStatus)
|
||||||
GetSettings() (settings settings.ShadowSocks)
|
GetSettings() (settings configuration.ShadowSocks)
|
||||||
SetSettings(settings settings.ShadowSocks) (outcome string)
|
SetSettings(settings configuration.ShadowSocks) (outcome string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type looper struct {
|
type looper struct {
|
||||||
@@ -51,7 +51,7 @@ func (l *looper) logAndWait(ctx context.Context, err error) {
|
|||||||
|
|
||||||
const defaultBackoffTime = 10 * time.Second
|
const defaultBackoffTime = 10 * time.Second
|
||||||
|
|
||||||
func NewLooper(settings settings.ShadowSocks, logger logging.Logger) Looper {
|
func NewLooper(settings configuration.ShadowSocks, logger logging.Logger) Looper {
|
||||||
return &looper{
|
return &looper{
|
||||||
state: state{
|
state: state{
|
||||||
status: constants.Stopped,
|
status: constants.Stopped,
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type state struct {
|
type state struct {
|
||||||
status models.LoopStatus
|
status models.LoopStatus
|
||||||
settings settings.ShadowSocks
|
settings configuration.ShadowSocks
|
||||||
statusMu sync.RWMutex
|
statusMu sync.RWMutex
|
||||||
settingsMu sync.RWMutex
|
settingsMu sync.RWMutex
|
||||||
}
|
}
|
||||||
@@ -69,13 +69,13 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) GetSettings() (settings settings.ShadowSocks) {
|
func (l *looper) GetSettings() (settings configuration.ShadowSocks) {
|
||||||
l.state.settingsMu.RLock()
|
l.state.settingsMu.RLock()
|
||||||
defer l.state.settingsMu.RUnlock()
|
defer l.state.settingsMu.RUnlock()
|
||||||
return l.state.settings
|
return l.state.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) SetSettings(settings settings.ShadowSocks) (outcome string) {
|
func (l *looper) SetSettings(settings configuration.ShadowSocks) (outcome string) {
|
||||||
l.state.settingsMu.Lock()
|
l.state.settingsMu.Lock()
|
||||||
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
|
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
|
||||||
if settingsUnchanged {
|
if settingsUnchanged {
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/gluetun/internal/storage"
|
"github.com/qdm12/gluetun/internal/storage"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
@@ -18,8 +18,8 @@ type Looper interface {
|
|||||||
RunRestartTicker(ctx context.Context, wg *sync.WaitGroup)
|
RunRestartTicker(ctx context.Context, wg *sync.WaitGroup)
|
||||||
GetStatus() (status models.LoopStatus)
|
GetStatus() (status models.LoopStatus)
|
||||||
SetStatus(status models.LoopStatus) (outcome string, err error)
|
SetStatus(status models.LoopStatus) (outcome string, err error)
|
||||||
GetSettings() (settings settings.Updater)
|
GetSettings() (settings configuration.Updater)
|
||||||
SetSettings(settings settings.Updater) (outcome string)
|
SetSettings(settings configuration.Updater) (outcome string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type looper struct {
|
type looper struct {
|
||||||
@@ -44,7 +44,7 @@ type looper struct {
|
|||||||
|
|
||||||
const defaultBackoffTime = 5 * time.Second
|
const defaultBackoffTime = 5 * time.Second
|
||||||
|
|
||||||
func NewLooper(settings settings.Updater, currentServers models.AllServers,
|
func NewLooper(settings configuration.Updater, currentServers models.AllServers,
|
||||||
storage storage.Storage, setAllServers func(allServers models.AllServers),
|
storage storage.Storage, setAllServers func(allServers models.AllServers),
|
||||||
client *http.Client, logger logging.Logger) Looper {
|
client *http.Client, logger logging.Logger) Looper {
|
||||||
loggerWithPrefix := logger.WithPrefix("updater: ")
|
loggerWithPrefix := logger.WithPrefix("updater: ")
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type state struct {
|
type state struct {
|
||||||
status models.LoopStatus
|
status models.LoopStatus
|
||||||
settings settings.Updater
|
settings configuration.Updater
|
||||||
statusMu sync.RWMutex
|
statusMu sync.RWMutex
|
||||||
periodMu sync.RWMutex
|
periodMu sync.RWMutex
|
||||||
}
|
}
|
||||||
@@ -69,13 +69,13 @@ func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) GetSettings() (settings settings.Updater) {
|
func (l *looper) GetSettings() (settings configuration.Updater) {
|
||||||
l.state.periodMu.RLock()
|
l.state.periodMu.RLock()
|
||||||
defer l.state.periodMu.RUnlock()
|
defer l.state.periodMu.RUnlock()
|
||||||
return l.state.settings
|
return l.state.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) SetSettings(settings settings.Updater) (outcome string) {
|
func (l *looper) SetSettings(settings configuration.Updater) (outcome string) {
|
||||||
l.state.periodMu.Lock()
|
l.state.periodMu.Lock()
|
||||||
defer l.state.periodMu.Unlock()
|
defer l.state.periodMu.Unlock()
|
||||||
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
|
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/network"
|
"github.com/qdm12/golibs/network"
|
||||||
)
|
)
|
||||||
@@ -18,7 +18,7 @@ type Updater interface {
|
|||||||
|
|
||||||
type updater struct {
|
type updater struct {
|
||||||
// configuration
|
// configuration
|
||||||
options settings.Updater
|
options configuration.Updater
|
||||||
|
|
||||||
// state
|
// state
|
||||||
servers models.AllServers
|
servers models.AllServers
|
||||||
@@ -31,7 +31,7 @@ type updater struct {
|
|||||||
client network.Client
|
client network.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(settings settings.Updater, httpClient *http.Client,
|
func New(settings configuration.Updater, httpClient *http.Client,
|
||||||
currentServers models.AllServers, logger logging.Logger) Updater {
|
currentServers models.AllServers, logger logging.Logger) Updater {
|
||||||
if len(settings.DNSAddress) == 0 {
|
if len(settings.DNSAddress) == 0 {
|
||||||
settings.DNSAddress = "1.1.1.1"
|
settings.DNSAddress = "1.1.1.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user