VPNSP value custom for OpenVPN custom config files (#621)
- Retro-compatibility: `OPENVPN_CUSTOM_CONFIG` set implies `VPNSP=custom` - Change: `up` and `down` options are not filtered out - Change: `OPENVPN_INTERFACE` overrides the network interface defined in the configuration file - Change: `PORT` overrides any port found in the configuration file - Feat: config file is read when building the OpenVPN configuration, so it's effectively reloaded on VPN restarts - Feat: extract values from custom file at start to log out valid settings - Maint: `internal/openvpn/extract` package instead of `internal/openvpn/custom` package - Maint: All providers' `BuildConf` method return an error - Maint: rename `CustomConfig` to `ConfFile` in Settings structures
This commit is contained in:
@@ -34,7 +34,11 @@ func (c *CLI) OpenvpnConfig(logger logging.Logger, env params.Interface) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines := providerConf.BuildConf(connection, allSettings.VPN.OpenVPN)
|
||||
lines, err := providerConf.BuildConf(connection, allSettings.VPN.OpenVPN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(strings.Join(lines, "\n"))
|
||||
return nil
|
||||
}
|
||||
|
||||
53
internal/configuration/custom.go
Normal file
53
internal/configuration/custom.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
var (
|
||||
errCustomNotSupported = errors.New("custom provider is not supported")
|
||||
errCustomExtractFromFile = errors.New("cannot extract configuration from file")
|
||||
)
|
||||
|
||||
func (settings *Provider) readCustom(r reader, vpnType string) (err error) {
|
||||
settings.Name = constants.Custom
|
||||
|
||||
if vpnType != constants.OpenVPN {
|
||||
return fmt.Errorf("%w: for VPN type %s", errCustomNotSupported, vpnType)
|
||||
}
|
||||
|
||||
return settings.readCustomOpenVPN(r)
|
||||
}
|
||||
|
||||
func (settings *Provider) readCustomOpenVPN(r reader) (err error) {
|
||||
configFile, err := r.env.Get("OPENVPN_CUSTOM_CONFIG", params.CaseSensitiveValue(), params.Compulsory())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_CUSTOM_CONFIG: %w", err)
|
||||
}
|
||||
settings.ServerSelection.OpenVPN.ConfFile = configFile
|
||||
|
||||
// For display and consistency purposes only,
|
||||
// these values are not actually used since the file is re-read
|
||||
// before each OpenVPN start.
|
||||
_, connection, err := r.ovpnExt.Data(configFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", errCustomExtractFromFile, err)
|
||||
}
|
||||
settings.ServerSelection.OpenVPN.TCP = connection.Protocol == constants.TCP
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings *OpenVPN) readCustom(r reader) (err error) {
|
||||
settings.ConfFile, err = r.env.Path("OPENVPN_CUSTOM_CONFIG",
|
||||
params.Compulsory(), params.CaseSensitiveValue())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_CUSTOM_CONFIG: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -21,7 +21,7 @@ type OpenVPN struct {
|
||||
Root bool `json:"run_as_root"`
|
||||
Cipher string `json:"cipher"`
|
||||
Auth string `json:"auth"`
|
||||
Config string `json:"custom_config"`
|
||||
ConfFile string `json:"conf_file"`
|
||||
Version string `json:"version"`
|
||||
ClientCrt string `json:"-"` // Cyberghost
|
||||
ClientKey string `json:"-"` // Cyberghost, VPNUnlimited
|
||||
@@ -59,8 +59,8 @@ func (settings *OpenVPN) lines() (lines []string) {
|
||||
lines = append(lines, indent+lastIndent+"Custom auth algorithm: "+settings.Auth)
|
||||
}
|
||||
|
||||
if len(settings.Config) > 0 {
|
||||
lines = append(lines, indent+lastIndent+"Custom configuration: "+settings.Config)
|
||||
if settings.ConfFile != "" {
|
||||
lines = append(lines, indent+lastIndent+"Configuration file: "+settings.ConfFile)
|
||||
}
|
||||
|
||||
if settings.ClientKey != "" {
|
||||
@@ -83,13 +83,14 @@ func (settings *OpenVPN) lines() (lines []string) {
|
||||
}
|
||||
|
||||
func (settings *OpenVPN) read(r reader, serviceProvider string) (err error) {
|
||||
settings.Config, err = r.env.Get("OPENVPN_CUSTOM_CONFIG", params.CaseSensitiveValue())
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_CUSTOM_CONFIG: %w", err)
|
||||
credentialsRequired := false
|
||||
switch serviceProvider {
|
||||
case constants.Custom:
|
||||
case constants.VPNUnlimited:
|
||||
default:
|
||||
credentialsRequired = true
|
||||
}
|
||||
|
||||
credentialsRequired := settings.Config == "" && serviceProvider != constants.VPNUnlimited
|
||||
|
||||
settings.User, err = r.getFromEnvOrSecretFile("OPENVPN_USER", credentialsRequired, []string{"USER"})
|
||||
if err != nil {
|
||||
return fmt.Errorf("environment variable OPENVPN_USER: %w", err)
|
||||
@@ -159,6 +160,8 @@ func (settings *OpenVPN) read(r reader, serviceProvider string) (err error) {
|
||||
}
|
||||
|
||||
switch serviceProvider {
|
||||
case constants.Custom:
|
||||
err = settings.readCustom(r) // read OPENVPN_CUSTOM_CONFIG
|
||||
case constants.Cyberghost:
|
||||
err = settings.readCyberghost(r)
|
||||
case constants.PrivateInternetAccess:
|
||||
|
||||
@@ -25,7 +25,7 @@ func Test_OpenVPN_JSON(t *testing.T) {
|
||||
"run_as_root": true,
|
||||
"cipher": "",
|
||||
"auth": "",
|
||||
"custom_config": "",
|
||||
"conf_file": "",
|
||||
"version": "",
|
||||
"encryption_preset": "",
|
||||
"ipv6": false,
|
||||
|
||||
@@ -49,6 +49,8 @@ func (settings *Provider) read(r reader, vpnType string) error {
|
||||
}
|
||||
|
||||
switch settings.Name {
|
||||
case constants.Custom:
|
||||
err = settings.readCustom(r, vpnType)
|
||||
case constants.Cyberghost:
|
||||
err = settings.readCyberghost(r)
|
||||
case constants.Fastestvpn:
|
||||
@@ -99,6 +101,7 @@ func (settings *Provider) readVPNServiceProvider(r reader, vpnType string) (err
|
||||
switch vpnType {
|
||||
case constants.OpenVPN:
|
||||
allowedVPNServiceProviders = []string{
|
||||
constants.Custom,
|
||||
"cyberghost", "fastestvpn", "hidemyass", "ipvanish", "ivpn", "mullvad", "nordvpn",
|
||||
"privado", "pia", "private internet access", "privatevpn", "protonvpn",
|
||||
"purevpn", "surfshark", "torguard", constants.VPNUnlimited, "vyprvpn", "windscribe"}
|
||||
@@ -115,6 +118,11 @@ func (settings *Provider) readVPNServiceProvider(r reader, vpnType string) (err
|
||||
if vpnsp == "pia" { // retro compatibility
|
||||
vpnsp = "private internet access"
|
||||
}
|
||||
|
||||
if settings.isOpenVPNCustomConfig(r.env) { // retro compatibility
|
||||
vpnsp = constants.Custom
|
||||
}
|
||||
|
||||
settings.Name = vpnsp
|
||||
|
||||
return nil
|
||||
@@ -199,3 +207,12 @@ func portsToString(ports []uint16) string {
|
||||
}
|
||||
return strings.Join(slice, ", ")
|
||||
}
|
||||
|
||||
// isOpenVPNCustomConfig is for retro compatibility to set VPNSP=custom
|
||||
// if OPENVPN_CUSTOM_CONFIG is set.
|
||||
func (settings Provider) isOpenVPNCustomConfig(env params.Interface) (ok bool) {
|
||||
s, _ := env.Get("VPN_TYPE")
|
||||
isOpenVPN := s == constants.OpenVPN
|
||||
s, _ = env.Get("OPENVPN_CUSTOM_CONFIG")
|
||||
return isOpenVPN && s != ""
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
ovpnextract "github.com/qdm12/gluetun/internal/openvpn/extract"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/golibs/verification"
|
||||
@@ -18,6 +19,7 @@ type reader struct {
|
||||
env params.Interface
|
||||
logger logging.Logger
|
||||
regex verification.Regex
|
||||
ovpnExt ovpnextract.Interface
|
||||
}
|
||||
|
||||
func newReader(env params.Interface,
|
||||
@@ -27,6 +29,7 @@ func newReader(env params.Interface,
|
||||
env: env,
|
||||
logger: logger,
|
||||
regex: verification.NewRegex(),
|
||||
ovpnExt: ovpnextract.New(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,22 +51,22 @@ func (r *reader) getFromEnvOrSecretFile(envKey string, compulsory bool, retroKey
|
||||
file, fileErr := os.OpenFile(filepath, os.O_RDONLY, 0)
|
||||
if os.IsNotExist(fileErr) {
|
||||
if compulsory {
|
||||
return "", envErr
|
||||
return "", fmt.Errorf("environment variable %s: %w", envKey, envErr)
|
||||
}
|
||||
return "", nil
|
||||
} else if fileErr != nil {
|
||||
return "", fmt.Errorf("%w: %s", ErrReadSecretFile, fileErr)
|
||||
return "", fmt.Errorf("%w: %s: %s", ErrReadSecretFile, filepath, fileErr)
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %s", ErrReadSecretFile, err)
|
||||
return "", fmt.Errorf("%w: %s: %s", ErrReadSecretFile, filepath, err)
|
||||
}
|
||||
|
||||
value = string(b)
|
||||
value = cleanSuffix(value)
|
||||
if compulsory && value == "" {
|
||||
return "", ErrSecretFileIsEmpty
|
||||
return "", fmt.Errorf("%s: %w", filepath, ErrSecretFileIsEmpty)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
|
||||
@@ -106,6 +106,7 @@ func (selection ServerSelection) toLines() (lines []string) {
|
||||
}
|
||||
|
||||
type OpenVPNSelection struct {
|
||||
ConfFile string `json:"conf_file"` // Custom configuration file path
|
||||
TCP bool `json:"tcp"` // UDP if TCP is false
|
||||
CustomPort uint16 `json:"custom_port"` // HideMyAss, Mullvad, PIA, ProtonVPN, Windscribe
|
||||
EncPreset string `json:"encryption_preset"` // PIA - needed to get the port number
|
||||
@@ -114,6 +115,10 @@ type OpenVPNSelection struct {
|
||||
func (settings *OpenVPNSelection) lines() (lines []string) {
|
||||
lines = append(lines, lastIndent+"OpenVPN selection:")
|
||||
|
||||
if settings.ConfFile != "" {
|
||||
lines = append(lines, indent+lastIndent+"Custom configuration file: "+settings.ConfFile)
|
||||
}
|
||||
|
||||
lines = append(lines, indent+lastIndent+"Protocol: "+protoToString(settings.TCP))
|
||||
|
||||
if settings.CustomPort != 0 {
|
||||
|
||||
@@ -58,10 +58,8 @@ func (settings *VPN) read(r reader) (err error) {
|
||||
}
|
||||
settings.Type = vpnType
|
||||
|
||||
if !settings.isOpenVPNCustomConfig(r.env) {
|
||||
if err := settings.Provider.read(r, vpnType); err != nil {
|
||||
return fmt.Errorf("%w: %s", errReadProviderSettings, err)
|
||||
}
|
||||
if err := settings.Provider.read(r, vpnType); err != nil {
|
||||
return fmt.Errorf("%w: %s", errReadProviderSettings, err)
|
||||
}
|
||||
|
||||
switch settings.Type {
|
||||
@@ -79,19 +77,3 @@ func (settings *VPN) read(r reader) (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (settings VPN) isOpenVPNCustomConfig(env params.Interface) (ok bool) {
|
||||
if settings.Type != constants.OpenVPN {
|
||||
return false
|
||||
}
|
||||
s, err := env.Get("OPENVPN_CUSTOM_CONFIG")
|
||||
return err == nil && s != ""
|
||||
}
|
||||
|
||||
func (settings VPN) VPNInterface() (intf string) {
|
||||
if settings.Type == constants.Wireguard {
|
||||
return settings.Wireguard.Interface
|
||||
}
|
||||
// OpenVPN
|
||||
return settings.OpenVPN.Interface
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
// Custom is the VPN provider name for custom
|
||||
// VPN configurations.
|
||||
Custom = "custom"
|
||||
// Cyberghost is a VPN provider.
|
||||
Cyberghost = "cyberghost"
|
||||
// Fastestvpn is a VPN provider.
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package custom
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrReadCustomConfig = errors.New("cannot read custom configuration file")
|
||||
ErrExtractConnection = errors.New("cannot extract connection from custom configuration file")
|
||||
)
|
||||
|
||||
func BuildConfig(settings configuration.OpenVPN) (
|
||||
lines []string, connection models.Connection, intf string, err error) {
|
||||
lines, err = readCustomConfigLines(settings.Config)
|
||||
if err != nil {
|
||||
return nil, connection, "", fmt.Errorf("%w: %s", ErrReadCustomConfig, err)
|
||||
}
|
||||
|
||||
connection, intf, err = extractDataFromLines(lines)
|
||||
if err != nil {
|
||||
return nil, connection, "", fmt.Errorf("%w: %s", ErrExtractConnection, err)
|
||||
}
|
||||
|
||||
if intf == "" {
|
||||
intf = settings.Interface
|
||||
}
|
||||
|
||||
lines = modifyCustomConfig(lines, settings, connection, intf)
|
||||
|
||||
return lines, connection, intf, nil
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package custom
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_BuildConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
file, err := os.CreateTemp("", "")
|
||||
require.NoError(t, err)
|
||||
defer removeFile(t, file.Name())
|
||||
defer file.Close()
|
||||
|
||||
_, err = file.WriteString("remote 1.9.8.7\nkeep me\ncipher remove")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = file.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
settings := configuration.OpenVPN{
|
||||
Cipher: "cipher",
|
||||
MSSFix: 999,
|
||||
Config: file.Name(),
|
||||
Interface: "tun0",
|
||||
}
|
||||
|
||||
lines, connection, intf, err := BuildConfig(settings)
|
||||
assert.NoError(t, err)
|
||||
|
||||
expectedLines := []string{
|
||||
"keep me",
|
||||
"proto udp",
|
||||
"remote 1.9.8.7 1194",
|
||||
"dev tun0",
|
||||
"mute-replay-warnings",
|
||||
"auth-nocache",
|
||||
"pull-filter ignore \"auth-token\"",
|
||||
"auth-retry nointeract",
|
||||
"suppress-timestamps",
|
||||
"verb 0",
|
||||
"data-ciphers-fallback cipher",
|
||||
"data-ciphers cipher",
|
||||
"mssfix 999",
|
||||
"pull-filter ignore \"route-ipv6\"",
|
||||
"pull-filter ignore \"ifconfig-ipv6\"",
|
||||
"user ",
|
||||
}
|
||||
assert.Equal(t, expectedLines, lines)
|
||||
|
||||
expectedConnection := models.Connection{
|
||||
IP: net.IPv4(1, 9, 8, 7),
|
||||
Port: 1194,
|
||||
Protocol: constants.UDP,
|
||||
}
|
||||
assert.Equal(t, expectedConnection, connection)
|
||||
|
||||
assert.Equal(t, "tun0", intf)
|
||||
}
|
||||
29
internal/openvpn/extract/data.go
Normal file
29
internal/openvpn/extract/data.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package extract
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrRead = errors.New("cannot read file")
|
||||
ErrExtractConnection = errors.New("cannot extract connection from file")
|
||||
)
|
||||
|
||||
// Data extracts the lines and connection from the OpenVPN configuration file.
|
||||
func (e *Extractor) Data(filepath string) (lines []string,
|
||||
connection models.Connection, err error) {
|
||||
lines, err = readCustomConfigLines(filepath)
|
||||
if err != nil {
|
||||
return nil, connection, fmt.Errorf("%w: %s", ErrRead, err)
|
||||
}
|
||||
|
||||
connection, err = extractDataFromLines(lines)
|
||||
if err != nil {
|
||||
return nil, connection, fmt.Errorf("%w: %s", ErrExtractConnection, err)
|
||||
}
|
||||
|
||||
return lines, connection, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package custom
|
||||
package extract
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -16,23 +16,22 @@ var (
|
||||
)
|
||||
|
||||
func extractDataFromLines(lines []string) (
|
||||
connection models.Connection, intf string, err error) {
|
||||
connection models.Connection, err error) {
|
||||
for i, line := range lines {
|
||||
ip, port, protocol, intfFound, err := extractDataFromLine(line)
|
||||
ip, port, protocol, err := extractDataFromLine(line)
|
||||
if err != nil {
|
||||
return connection, "", fmt.Errorf("on line %d: %w", i+1, err)
|
||||
return connection, fmt.Errorf("on line %d: %w", i+1, err)
|
||||
}
|
||||
|
||||
intf = intfFound
|
||||
connection.UpdateEmptyWith(ip, port, protocol)
|
||||
|
||||
if connection.Protocol != "" && connection.IP != nil && intf != "" {
|
||||
if connection.Protocol != "" && connection.IP != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if connection.IP == nil {
|
||||
return connection, "", errRemoteLineNotFound
|
||||
return connection, errRemoteLineNotFound
|
||||
}
|
||||
|
||||
if connection.Protocol == "" {
|
||||
@@ -46,41 +45,33 @@ func extractDataFromLines(lines []string) (
|
||||
}
|
||||
}
|
||||
|
||||
return connection, intf, nil
|
||||
return connection, nil
|
||||
}
|
||||
|
||||
var (
|
||||
errExtractProto = errors.New("failed extracting protocol from proto line")
|
||||
errExtractRemote = errors.New("failed extracting from remote line")
|
||||
errExtractDev = errors.New("failed extracting network interface from dev line")
|
||||
)
|
||||
|
||||
func extractDataFromLine(line string) (
|
||||
ip net.IP, port uint16, protocol, intf string, err error) {
|
||||
ip net.IP, port uint16, protocol string, err error) {
|
||||
switch {
|
||||
case strings.HasPrefix(line, "proto "):
|
||||
protocol, err = extractProto(line)
|
||||
if err != nil {
|
||||
return nil, 0, "", "", fmt.Errorf("%w: %s", errExtractProto, err)
|
||||
return nil, 0, "", fmt.Errorf("%w: %s", errExtractProto, err)
|
||||
}
|
||||
return nil, 0, protocol, "", nil
|
||||
return nil, 0, protocol, nil
|
||||
|
||||
case strings.HasPrefix(line, "remote "):
|
||||
ip, port, protocol, err = extractRemote(line)
|
||||
if err != nil {
|
||||
return nil, 0, "", "", fmt.Errorf("%w: %s", errExtractRemote, err)
|
||||
return nil, 0, "", fmt.Errorf("%w: %s", errExtractRemote, err)
|
||||
}
|
||||
return ip, port, protocol, "", nil
|
||||
|
||||
case strings.HasPrefix(line, "dev "):
|
||||
intf, err = extractInterfaceFromLine(line)
|
||||
if err != nil {
|
||||
return nil, 0, "", "", fmt.Errorf("%w: %s", errExtractDev, err)
|
||||
}
|
||||
return nil, 0, "", intf, nil
|
||||
return ip, port, protocol, nil
|
||||
}
|
||||
|
||||
return nil, 0, "", "", nil
|
||||
return nil, 0, "", nil
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -147,16 +138,3 @@ func extractRemote(line string) (ip net.IP, port uint16,
|
||||
|
||||
return ip, port, protocol, nil
|
||||
}
|
||||
|
||||
var (
|
||||
errDevLineFieldsCount = errors.New("dev line has not 2 fields as expected")
|
||||
)
|
||||
|
||||
func extractInterfaceFromLine(line string) (intf string, err error) {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) != 2 { //nolint:gomnd
|
||||
return "", fmt.Errorf("%w: %s", errDevLineFieldsCount, line)
|
||||
}
|
||||
|
||||
return fields[1], nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package custom
|
||||
package extract
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -17,7 +17,6 @@ func Test_extractDataFromLines(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
lines []string
|
||||
connection models.Connection
|
||||
intf string
|
||||
err error
|
||||
}{
|
||||
"success": {
|
||||
@@ -27,7 +26,6 @@ func Test_extractDataFromLines(t *testing.T) {
|
||||
Port: 1194,
|
||||
Protocol: constants.TCP,
|
||||
},
|
||||
intf: "tun6",
|
||||
},
|
||||
"extraction error": {
|
||||
lines: []string{"bla bla", "proto bad", "remote 1.2.3.4 1194 tcp"},
|
||||
@@ -71,7 +69,7 @@ func Test_extractDataFromLines(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
connection, intf, err := extractDataFromLines(testCase.lines)
|
||||
connection, err := extractDataFromLines(testCase.lines)
|
||||
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
@@ -81,7 +79,6 @@ func Test_extractDataFromLines(t *testing.T) {
|
||||
}
|
||||
|
||||
assert.Equal(t, testCase.connection, connection)
|
||||
assert.Equal(t, testCase.intf, intf)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -94,7 +91,6 @@ func Test_extractDataFromLine(t *testing.T) {
|
||||
ip net.IP
|
||||
port uint16
|
||||
protocol string
|
||||
intf string
|
||||
isErr error
|
||||
}{
|
||||
"irrelevant line": {
|
||||
@@ -108,14 +104,6 @@ func Test_extractDataFromLine(t *testing.T) {
|
||||
line: "proto tcp",
|
||||
protocol: constants.TCP,
|
||||
},
|
||||
"extract intf error": {
|
||||
line: "dev ",
|
||||
isErr: errExtractDev,
|
||||
},
|
||||
"extract intf success": {
|
||||
line: "dev tun3",
|
||||
intf: "tun3",
|
||||
},
|
||||
"extract remote error": {
|
||||
line: "remote bad",
|
||||
isErr: errExtractRemote,
|
||||
@@ -133,7 +121,7 @@ func Test_extractDataFromLine(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ip, port, protocol, intf, err := extractDataFromLine(testCase.line)
|
||||
ip, port, protocol, err := extractDataFromLine(testCase.line)
|
||||
|
||||
if testCase.isErr != nil {
|
||||
assert.ErrorIs(t, err, testCase.isErr)
|
||||
@@ -144,7 +132,6 @@ func Test_extractDataFromLine(t *testing.T) {
|
||||
assert.Equal(t, testCase.ip, ip)
|
||||
assert.Equal(t, testCase.port, port)
|
||||
assert.Equal(t, testCase.protocol, protocol)
|
||||
assert.Equal(t, testCase.intf, intf)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -273,44 +260,3 @@ func Test_extractRemote(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_extractInterface(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
line string
|
||||
intf string
|
||||
err error
|
||||
}{
|
||||
"found": {
|
||||
line: "dev tun3",
|
||||
intf: "tun3",
|
||||
},
|
||||
"not enough fields": {
|
||||
line: "dev ",
|
||||
err: errors.New("dev line has not 2 fields as expected: dev "),
|
||||
},
|
||||
"too many fields": {
|
||||
line: "dev one two",
|
||||
err: errors.New("dev line has not 2 fields as expected: dev one two"),
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
intf, err := extractInterfaceFromLine(testCase.line)
|
||||
|
||||
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.intf, intf)
|
||||
})
|
||||
}
|
||||
}
|
||||
18
internal/openvpn/extract/extractor.go
Normal file
18
internal/openvpn/extract/extractor.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package extract
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
var _ Interface = (*Extractor)(nil)
|
||||
|
||||
type Interface interface {
|
||||
Data(filepath string) (lines []string,
|
||||
connection models.Connection, err error)
|
||||
}
|
||||
|
||||
type Extractor struct{}
|
||||
|
||||
func New() *Extractor {
|
||||
return new(Extractor)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package custom
|
||||
package extract
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -1,4 +1,4 @@
|
||||
package custom
|
||||
package extract
|
||||
|
||||
import (
|
||||
"io"
|
||||
@@ -1,4 +1,4 @@
|
||||
package custom
|
||||
package extract
|
||||
|
||||
import (
|
||||
"os"
|
||||
38
internal/provider/custom/connection.go
Normal file
38
internal/provider/custom/connection.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package custom
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrVPNTypeNotSupported = errors.New("VPN type not supported for custom provider")
|
||||
ErrExtractConnection = errors.New("cannot extract connection")
|
||||
)
|
||||
|
||||
// GetConnection gets the connection from the OpenVPN configuration file.
|
||||
func (p *Provider) GetConnection(selection configuration.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
if selection.VPN != constants.OpenVPN {
|
||||
return connection, fmt.Errorf("%w: %s", ErrVPNTypeNotSupported, selection.VPN)
|
||||
}
|
||||
|
||||
_, connection, err = p.extractor.Data(selection.OpenVPN.ConfFile)
|
||||
if err != nil {
|
||||
return connection, fmt.Errorf("%w: %s", ErrExtractConnection, err)
|
||||
}
|
||||
|
||||
connection.Port = getPort(connection.Port, selection)
|
||||
|
||||
return connection, nil
|
||||
}
|
||||
|
||||
// Port found is overridden by custom port set with `PORT` or `WIREGUARD_PORT`.
|
||||
func getPort(foundPort uint16, selection configuration.ServerSelection) (port uint16) {
|
||||
return utils.GetPort(selection, foundPort, foundPort, foundPort)
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package custom
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -10,13 +12,27 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
func modifyCustomConfig(lines []string, settings configuration.OpenVPN,
|
||||
connection models.Connection, intf string) (modified []string) {
|
||||
var ErrExtractData = errors.New("failed extracting information from custom configuration file")
|
||||
|
||||
func (p *Provider) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
lines, _, err = p.extractor.Data(settings.ConfFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrExtractData, err)
|
||||
}
|
||||
|
||||
lines = modifyConfig(lines, connection, settings)
|
||||
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
func modifyConfig(lines []string, connection models.Connection,
|
||||
settings configuration.OpenVPN) (modified []string) {
|
||||
// Remove some lines
|
||||
for _, line := range lines {
|
||||
switch {
|
||||
case strings.HasPrefix(line, "up "),
|
||||
strings.HasPrefix(line, "down "),
|
||||
case
|
||||
line == "",
|
||||
strings.HasPrefix(line, "verb "),
|
||||
strings.HasPrefix(line, "auth-user-pass "),
|
||||
strings.HasPrefix(line, "user "),
|
||||
@@ -36,7 +52,7 @@ func modifyCustomConfig(lines []string, settings configuration.OpenVPN,
|
||||
// Add values
|
||||
modified = append(modified, connection.OpenVPNProtoLine())
|
||||
modified = append(modified, connection.OpenVPNRemoteLine())
|
||||
modified = append(modified, "dev "+intf)
|
||||
modified = append(modified, "dev "+settings.Interface)
|
||||
modified = append(modified, "mute-replay-warnings")
|
||||
modified = append(modified, "auth-nocache")
|
||||
modified = append(modified, "pull-filter ignore \"auth-token\"") // prevent auth failed loop
|
||||
@@ -63,5 +79,23 @@ func modifyCustomConfig(lines []string, settings configuration.OpenVPN,
|
||||
modified = append(modified, "user "+settings.ProcUser)
|
||||
}
|
||||
|
||||
return modified
|
||||
modified = append(modified, "") // trailing line
|
||||
|
||||
return uniqueLines(modified)
|
||||
}
|
||||
|
||||
func uniqueLines(lines []string) (unique []string) {
|
||||
seen := make(map[string]struct{}, len(lines))
|
||||
unique = make([]string, 0, len(lines))
|
||||
|
||||
for _, line := range lines {
|
||||
_, ok := seen[line]
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
seen[line] = struct{}{}
|
||||
unique = append(unique, line)
|
||||
}
|
||||
|
||||
return unique
|
||||
}
|
||||
@@ -10,14 +10,13 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_modifyCustomConfig(t *testing.T) {
|
||||
func Test_modifyConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
lines []string
|
||||
settings configuration.OpenVPN
|
||||
connection models.Connection
|
||||
intf string
|
||||
modified []string
|
||||
}{
|
||||
"mixed": {
|
||||
@@ -26,24 +25,26 @@ func Test_modifyCustomConfig(t *testing.T) {
|
||||
"proto tcp",
|
||||
"remote 5.5.5.5",
|
||||
"cipher bla",
|
||||
"",
|
||||
"tun-ipv6",
|
||||
"keep me here",
|
||||
"auth bla",
|
||||
},
|
||||
settings: configuration.OpenVPN{
|
||||
User: "user",
|
||||
Cipher: "cipher",
|
||||
Auth: "auth",
|
||||
MSSFix: 1000,
|
||||
ProcUser: "procuser",
|
||||
User: "user",
|
||||
Cipher: "cipher",
|
||||
Auth: "auth",
|
||||
MSSFix: 1000,
|
||||
ProcUser: "procuser",
|
||||
Interface: "tun3",
|
||||
},
|
||||
connection: models.Connection{
|
||||
IP: net.IPv4(1, 2, 3, 4),
|
||||
Port: 1194,
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
intf: "tun3",
|
||||
modified: []string{
|
||||
"up bla",
|
||||
"keep me here",
|
||||
"proto udp",
|
||||
"remote 1.2.3.4 1194",
|
||||
@@ -62,6 +63,7 @@ func Test_modifyCustomConfig(t *testing.T) {
|
||||
"pull-filter ignore \"route-ipv6\"",
|
||||
"pull-filter ignore \"ifconfig-ipv6\"",
|
||||
"user procuser",
|
||||
"",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -71,8 +73,8 @@ func Test_modifyCustomConfig(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
modified := modifyCustomConfig(testCase.lines,
|
||||
testCase.settings, testCase.connection, testCase.intf)
|
||||
modified := modifyConfig(testCase.lines,
|
||||
testCase.connection, testCase.settings)
|
||||
|
||||
assert.Equal(t, testCase.modified, modified)
|
||||
})
|
||||
19
internal/provider/custom/provider.go
Normal file
19
internal/provider/custom/provider.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package custom
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/openvpn/extract"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
extractor extract.Interface
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New() *Provider {
|
||||
return &Provider{
|
||||
extractor: extract.New(),
|
||||
NoPortForwarder: utils.NewNoPortForwarding(constants.Custom),
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func (c *Cyberghost) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -87,5 +87,5 @@ func (c *Cyberghost) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (f *Fastestvpn) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -76,5 +76,5 @@ func (f *Fastestvpn) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (h *HideMyAss) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -75,5 +75,5 @@ func (h *HideMyAss) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (i *Ipvanish) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -68,5 +68,5 @@ func (i *Ipvanish) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func (i *Ivpn) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -77,5 +77,5 @@ func (i *Ivpn) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (m *Mullvad) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -83,5 +83,5 @@ func (m *Mullvad) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (n *Nordvpn) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -81,5 +81,5 @@ func (n *Nordvpn) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (p *Privado) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -70,5 +70,5 @@ func (p *Privado) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (p *PIA) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
var defaultCipher, defaultAuth, X509CRL, certificate string
|
||||
switch settings.EncPreset {
|
||||
case constants.PIAEncryptionPresetNormal:
|
||||
@@ -93,5 +93,5 @@ func (p *PIA) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (p *Privatevpn) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES128gcm
|
||||
}
|
||||
@@ -73,5 +73,5 @@ func (p *Privatevpn) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (p *Protonvpn) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -80,5 +80,5 @@ func (p *Protonvpn) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/custom"
|
||||
"github.com/qdm12/gluetun/internal/provider/cyberghost"
|
||||
"github.com/qdm12/gluetun/internal/provider/fastestvpn"
|
||||
"github.com/qdm12/gluetun/internal/provider/hidemyass"
|
||||
@@ -34,7 +35,7 @@ import (
|
||||
// Provider contains methods to read and modify the openvpn configuration to connect as a client.
|
||||
type Provider interface {
|
||||
GetConnection(selection configuration.ServerSelection) (connection models.Connection, err error)
|
||||
BuildConf(connection models.Connection, settings configuration.OpenVPN) (lines []string)
|
||||
BuildConf(connection models.Connection, settings configuration.OpenVPN) (lines []string, err error)
|
||||
PortForwarder
|
||||
}
|
||||
|
||||
@@ -50,6 +51,8 @@ type PortForwarder interface {
|
||||
func New(provider string, allServers models.AllServers, timeNow func() time.Time) Provider {
|
||||
randSource := rand.NewSource(timeNow().UnixNano())
|
||||
switch provider {
|
||||
case constants.Custom:
|
||||
return custom.New()
|
||||
case constants.Cyberghost:
|
||||
return cyberghost.New(allServers.Cyberghost.Servers, randSource)
|
||||
case constants.Fastestvpn:
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (p *Purevpn) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256gcm
|
||||
}
|
||||
@@ -84,5 +84,5 @@ func (p *Purevpn) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (s *Surfshark) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256gcm
|
||||
}
|
||||
@@ -78,5 +78,5 @@ func (s *Surfshark) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (t *Torguard) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256gcm
|
||||
}
|
||||
@@ -84,5 +84,5 @@ func (t *Torguard) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (p *Provider) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
lines = []string{
|
||||
"client",
|
||||
"dev " + settings.Interface,
|
||||
@@ -71,5 +71,5 @@ func (p *Provider) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (v *Vyprvpn) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -65,5 +65,5 @@ func (v *Vyprvpn) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func (w *Windscribe) BuildConf(connection models.Connection,
|
||||
settings configuration.OpenVPN) (lines []string) {
|
||||
settings configuration.OpenVPN) (lines []string, err error) {
|
||||
if settings.Cipher == "" {
|
||||
settings.Cipher = constants.AES256cbc
|
||||
}
|
||||
@@ -81,5 +81,5 @@ func (w *Windscribe) BuildConf(connection models.Connection,
|
||||
|
||||
lines = append(lines, "")
|
||||
|
||||
return lines
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
@@ -7,15 +7,14 @@ import (
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/firewall"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/openvpn"
|
||||
"github.com/qdm12/gluetun/internal/openvpn/custom"
|
||||
"github.com/qdm12/gluetun/internal/provider"
|
||||
"github.com/qdm12/golibs/command"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
var (
|
||||
errServerConn = errors.New("failed finding a valid server connection")
|
||||
errBuildConfig = errors.New("failed building configuration")
|
||||
errWriteConfig = errors.New("failed writing configuration to file")
|
||||
errWriteAuth = errors.New("failed writing auth to file")
|
||||
@@ -28,18 +27,12 @@ func setupOpenVPN(ctx context.Context, fw firewall.VPNConnectionSetter,
|
||||
openvpnConf openvpn.Interface, providerConf provider.Provider,
|
||||
settings configuration.VPN, starter command.Starter, logger logging.Logger) (
|
||||
runner vpnRunner, serverName string, err error) {
|
||||
var connection models.Connection
|
||||
var netInterface string
|
||||
var lines []string
|
||||
if settings.OpenVPN.Config == "" {
|
||||
netInterface = settings.OpenVPN.Interface
|
||||
connection, err = providerConf.GetConnection(settings.Provider.ServerSelection)
|
||||
if err == nil {
|
||||
lines = providerConf.BuildConf(connection, settings.OpenVPN)
|
||||
}
|
||||
} else {
|
||||
lines, connection, netInterface, err = custom.BuildConfig(settings.OpenVPN)
|
||||
connection, err := providerConf.GetConnection(settings.Provider.ServerSelection)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("%w: %s", errServerConn, err)
|
||||
}
|
||||
|
||||
lines, err := providerConf.BuildConf(connection, settings.OpenVPN)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("%w: %s", errBuildConfig, err)
|
||||
}
|
||||
@@ -55,7 +48,7 @@ func setupOpenVPN(ctx context.Context, fw firewall.VPNConnectionSetter,
|
||||
}
|
||||
}
|
||||
|
||||
if err := fw.SetVPNConnection(ctx, connection, netInterface); err != nil {
|
||||
if err := fw.SetVPNConnection(ctx, connection, settings.OpenVPN.Interface); err != nil {
|
||||
return nil, "", fmt.Errorf("%w: %s", errFirewall, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
- Gluetun entire logs available at control server, maybe in structured format
|
||||
- Authentication with the control server
|
||||
- Get announcement from Github file
|
||||
- Support multiple connections in custom ovpn
|
||||
|
||||
## Gluetun V4
|
||||
|
||||
@@ -47,4 +48,7 @@
|
||||
- Change `VPNSP` to `VPN_SERVICE_PROVIDER`
|
||||
- Change `REGION` (etc.) to `SERVER_REGIONS`
|
||||
- Remove `PUBLICIP_FILE`
|
||||
- Remove retro-compatibility where OPENVPN_CONFIG != "" implies VPNSP = "custom"
|
||||
and set `OPENVPN_CUSTOM_CONFIG` default to `/gluetun/custom.ovpn`
|
||||
- Split servers.json and compress it
|
||||
- Use relative paths everywhere instead of absolute
|
||||
|
||||
Reference in New Issue
Block a user