diff --git a/README.md b/README.md index 077c98a6..af50567a 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ docker run --rm --network=container:pia alpine:3.11 wget -qO- https://ipinfo.io | `OPENVPN_VERBOSITY` | `1` | Openvpn verbosity level from 0 to 6 | | `OPENVPN_ROOT` | `no` | Run OpenVPN as root, `yes` or `no` | | `OPENVPN_TARGET_IP` | | Specify a target VPN server IP address to use, valid for Mullvad and Private Internet Access | +| `OPENVPN_CIPHER` | | Specify a custom cipher to use, use at your own risk. It will also set `ncp-disable` if using AES GCM for PIA | ## Connect to it diff --git a/cmd/main.go b/cmd/main.go index e0e646e7..e4eeb0f2 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -132,12 +132,12 @@ func main() { case "pia": connections, err = piaConf.GetOpenVPNConnections(allSettings.PIA.Region, allSettings.OpenVPN.NetworkProtocol, allSettings.PIA.Encryption, allSettings.OpenVPN.TargetIP) e.FatalOnError(err) - err = piaConf.BuildConf(connections, allSettings.PIA.Encryption, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root) + err = piaConf.BuildConf(connections, allSettings.PIA.Encryption, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root, allSettings.OpenVPN.Cipher) e.FatalOnError(err) case "mullvad": connections, err = mullvadConf.GetOpenVPNConnections(allSettings.Mullvad.Country, allSettings.Mullvad.City, allSettings.Mullvad.ISP, allSettings.OpenVPN.NetworkProtocol, allSettings.Mullvad.Port, allSettings.OpenVPN.TargetIP) e.FatalOnError(err) - err = mullvadConf.BuildConf(connections, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root) + err = mullvadConf.BuildConf(connections, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root, allSettings.OpenVPN.Cipher) e.FatalOnError(err) } diff --git a/internal/mullvad/conf.go b/internal/mullvad/conf.go index b0e8c923..76051211 100644 --- a/internal/mullvad/conf.go +++ b/internal/mullvad/conf.go @@ -35,10 +35,13 @@ func (c *configurator) GetOpenVPNConnections(country models.MullvadCountry, city return connections, nil } -func (c *configurator) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool) (err error) { +func (c *configurator) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher string) (err error) { if len(connections) == 0 { return fmt.Errorf("at least one connection string is expected") } + if len(cipher) == 0 { + cipher = "AES-256-CBC" + } lines := []string{ "client", "dev tun", @@ -53,7 +56,6 @@ func (c *configurator) BuildConf(connections []models.OpenVPNConnection, verbosi // Mullvad specific "sndbuf 524288", "rcvbuf 524288", - "cipher AES-256-CBC", "tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA", // Added constant values @@ -67,6 +69,7 @@ func (c *configurator) BuildConf(connections []models.OpenVPNConnection, verbosi fmt.Sprintf("verb %d", verbosity), fmt.Sprintf("auth-user-pass %s", constants.OpenVPNAuthConf), fmt.Sprintf("proto %s", string(connections[0].Protocol)), + fmt.Sprintf("cipher %s", cipher), } if !root { lines = append(lines, "user nonrootuser") diff --git a/internal/mullvad/mullvad.go b/internal/mullvad/mullvad.go index 655d0495..ebfcef12 100644 --- a/internal/mullvad/mullvad.go +++ b/internal/mullvad/mullvad.go @@ -13,7 +13,7 @@ const logPrefix = "Mullvad configurator" // Configurator contains methods to download, read and modify the openvpn configuration to connect as a client type Configurator interface { GetOpenVPNConnections(country models.MullvadCountry, city models.MullvadCity, provider models.MullvadProvider, protocol models.NetworkProtocol, customPort uint16, targetIP net.IP) (connections []models.OpenVPNConnection, err error) - BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool) (err error) + BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher string) (err error) } type configurator struct { diff --git a/internal/params/openvpn.go b/internal/params/openvpn.go index 8d4ffbf0..4b26a451 100644 --- a/internal/params/openvpn.go +++ b/internal/params/openvpn.go @@ -3,6 +3,7 @@ package params import ( "fmt" "net" + "strings" libparams "github.com/qdm12/golibs/params" "github.com/qdm12/private-internet-access-docker/internal/models" @@ -63,3 +64,10 @@ func (p *paramsReader) GetTargetIP() (ip net.IP, err error) { } return ip, nil } + +// GetOpenVPNCipher obtains a custom cipher to use with OpenVPN +// from the environment variable OPENVPN_CIPHER +func (p *paramsReader) GetOpenVPNCipher() (cipher string, err error) { + cipher, err = p.envParams.GetEnv("OPENVPN_CIPHER") + return strings.ToLower(cipher), err +} diff --git a/internal/params/params.go b/internal/params/params.go index f310d24e..472833c2 100644 --- a/internal/params/params.go +++ b/internal/params/params.go @@ -38,6 +38,7 @@ type ParamsReader interface { GetOpenVPNVerbosity() (verbosity int, err error) GetOpenVPNRoot() (root bool, err error) GetTargetIP() (ip net.IP, err error) + GetOpenVPNCipher() (cipher string, err error) // PIA getters GetPortForwarding() (activated bool, err error) diff --git a/internal/pia/conf.go b/internal/pia/conf.go index 1b56ee46..099fdec9 100644 --- a/internal/pia/conf.go +++ b/internal/pia/conf.go @@ -66,15 +66,19 @@ func (c *configurator) GetOpenVPNConnections(region models.PIARegion, protocol m return connections, nil } -func (c *configurator) BuildConf(connections []models.OpenVPNConnection, encryption models.PIAEncryption, verbosity, uid, gid int, root bool) (err error) { - var X509CRL, certificate, cipherAlgo, authAlgo string +func (c *configurator) BuildConf(connections []models.OpenVPNConnection, encryption models.PIAEncryption, verbosity, uid, gid int, root bool, cipher string) (err error) { + var X509CRL, certificate, authAlgo string if encryption == constants.PIAEncryptionNormal { - cipherAlgo = "aes-128-cbc" + if len(cipher) == 0 { + cipher = "aes-128-cbc" + } authAlgo = "sha1" X509CRL = constants.PIAX509CRL_NORMAL certificate = constants.PIACertificate_NORMAL } else { // strong encryption - cipherAlgo = "aes-256-cbc" + if len(cipher) == 0 { + cipher = "aes-256-cbc" + } authAlgo = "sha256" X509CRL = constants.PIAX509CRL_STRONG certificate = constants.PIACertificate_STRONG @@ -104,9 +108,12 @@ func (c *configurator) BuildConf(connections []models.OpenVPNConnection, encrypt fmt.Sprintf("verb %d", verbosity), fmt.Sprintf("auth-user-pass %s", constants.OpenVPNAuthConf), fmt.Sprintf("proto %s", string(connections[0].Protocol)), - fmt.Sprintf("cipher %s", cipherAlgo), + fmt.Sprintf("cipher %s", cipher), fmt.Sprintf("auth %s", authAlgo), } + if strings.HasSuffix(cipher, "-gcm") { + lines = append(lines, "ncp-disable") + } if !root { lines = append(lines, "user nonrootuser") } diff --git a/internal/pia/pia.go b/internal/pia/pia.go index 392c410d..db077a3b 100644 --- a/internal/pia/pia.go +++ b/internal/pia/pia.go @@ -18,7 +18,7 @@ const logPrefix = "PIA configurator" type Configurator interface { GetOpenVPNConnections(region models.PIARegion, protocol models.NetworkProtocol, encryption models.PIAEncryption, targetIP net.IP) (connections []models.OpenVPNConnection, err error) - BuildConf(connections []models.OpenVPNConnection, encryption models.PIAEncryption, verbosity, uid, gid int, root bool) (err error) + BuildConf(connections []models.OpenVPNConnection, encryption models.PIAEncryption, verbosity, uid, gid int, root bool, cipher string) (err error) GetPortForward() (port uint16, err error) WritePortForward(filepath models.Filepath, port uint16) (err error) AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error) diff --git a/internal/settings/openvpn.go b/internal/settings/openvpn.go index 62b55f98..457f16a5 100644 --- a/internal/settings/openvpn.go +++ b/internal/settings/openvpn.go @@ -15,6 +15,7 @@ type OpenVPN struct { Verbosity int Root bool TargetIP net.IP + Cipher string } // GetOpenVPNSettings obtains the OpenVPN settings using the params functions @@ -35,6 +36,10 @@ func GetOpenVPNSettings(params params.ParamsReader) (settings OpenVPN, err error if err != nil { return settings, err } + settings.Cipher, err = params.GetOpenVPNCipher() + if err != nil { + return settings, err + } return settings, nil } @@ -49,6 +54,7 @@ func (o *OpenVPN) String() string { "Verbosity level: " + fmt.Sprintf("%d", o.Verbosity), "Run as root: " + runAsRoot, "Target IP address: " + o.TargetIP.String(), + "Custom cipher: " + o.Cipher, } return strings.Join(settingsList, "\n|--") }