Assimilate PIA v4 as PIA in code

This commit is contained in:
Quentin McGaw
2020-11-10 13:35:49 +00:00
parent f48392064e
commit aef14a9f6d
9 changed files with 82 additions and 96 deletions

View File

@@ -415,7 +415,7 @@ func routeReadyEvents(ctx context.Context, wg *sync.WaitGroup, tunnelReadyCh, dn
logger.Info("VPN routing IP address: %s", vpnDestination) logger.Info("VPN routing IP address: %s", vpnDestination)
} }
if portForwardingEnabled { if portForwardingEnabled {
// vpnGateway required only for PIA v4 // vpnGateway required only for PIA
vpnGateway, err := routing.VPNLocalGatewayIP() vpnGateway, err := routing.VPNLocalGatewayIP()
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)

View File

@@ -15,7 +15,7 @@ const (
OpenVPNAuthConf models.Filepath = "/etc/openvpn/auth.conf" OpenVPNAuthConf models.Filepath = "/etc/openvpn/auth.conf"
// OpenVPNConf is the file path to the OpenVPN client configuration file. // OpenVPNConf is the file path to the OpenVPN client configuration file.
OpenVPNConf models.Filepath = "/etc/openvpn/target.ovpn" OpenVPNConf models.Filepath = "/etc/openvpn/target.ovpn"
// PIAPortForward is the file path to the port forwarding JSON information for PIA v4 servers. // PIAPortForward is the file path to the port forwarding JSON information for PIA servers.
PIAPortForward models.Filepath = "/gluetun/piaportforward.json" PIAPortForward models.Filepath = "/gluetun/piaportforward.json"
// TunnelDevice is the file path to tun device. // TunnelDevice is the file path to tun device.
TunnelDevice models.Filepath = "/dev/net/tun" TunnelDevice models.Filepath = "/dev/net/tun"

View File

@@ -44,7 +44,7 @@ func PostProcessLine(s string) (filtered string, level logging.Level) {
case s == "openvpn: Initialization Sequence Completed": case s == "openvpn: Initialization Sequence Completed":
return color.HiGreenString(s), logging.InfoLevel return color.HiGreenString(s), logging.InfoLevel
case s == "openvpn: AUTH: Received control message: AUTH_FAILED": case s == "openvpn: AUTH: Received control message: AUTH_FAILED":
filtered = s + "\n\n (IF YOU ARE USING PIA V4 servers, MAYBE CHECK OUT https://github.com/qdm12/gluetun/issues/265)\n" //nolint:lll filtered = s + "\n\n (IF YOU ARE USING PIA servers, MAYBE CHECK OUT https://github.com/qdm12/gluetun/issues/265)\n" //nolint:lll
level = logging.ErrorLevel level = logging.ErrorLevel
default: default:
filtered = s filtered = s

View File

@@ -62,7 +62,7 @@ func Test_PostProcessLine(t *testing.T) {
logging.InfoLevel}, logging.InfoLevel},
"openvpn auth failed": { "openvpn auth failed": {
"openvpn: AUTH: Received control message: AUTH_FAILED", "openvpn: AUTH: Received control message: AUTH_FAILED",
"openvpn: AUTH: Received control message: AUTH_FAILED\n\n (IF YOU ARE USING PIA V4 servers, MAYBE CHECK OUT https://github.com/qdm12/gluetun/issues/265)\n", //nolint:lll "openvpn: AUTH: Received control message: AUTH_FAILED\n\n (IF YOU ARE USING PIA servers, MAYBE CHECK OUT https://github.com/qdm12/gluetun/issues/265)\n", //nolint:lll
logging.ErrorLevel}, logging.ErrorLevel},
} }
for name, tc := range tests { for name, tc := range tests {

View File

@@ -1,81 +0,0 @@
package provider
import (
"fmt"
"strings"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models"
)
func buildPIAConf(connection models.OpenVPNConnection, verbosity int, root bool, cipher, auth string,
extras models.ExtraConfigOptions) (lines []string) {
var X509CRL, certificate string
var defaultCipher, defaultAuth string
if extras.EncryptionPreset == constants.PIAEncryptionPresetNormal {
defaultCipher = "aes-128-cbc"
defaultAuth = "sha1"
X509CRL = constants.PiaX509CRLNormal
certificate = constants.PIACertificateNormal
} else { // strong encryption
defaultCipher = aes256cbc
defaultAuth = "sha256"
X509CRL = constants.PiaX509CRLStrong
certificate = constants.PIACertificateStrong
}
if len(cipher) == 0 {
cipher = defaultCipher
}
if len(auth) == 0 {
auth = defaultAuth
}
lines = []string{
"client",
"dev tun",
"nobind",
"persist-key",
"remote-cert-tls server",
// PIA specific
"ping 300", // Ping every 5 minutes to prevent a timeout error
"reneg-sec 0",
"compress", // allow PIA server to choose the compression to use
// Added constant values
"auth-nocache",
"mute-replay-warnings",
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
"auth-retry nointeract",
"suppress-timestamps",
// Modified variables
fmt.Sprintf("verb %d", verbosity),
fmt.Sprintf("auth-user-pass %s", constants.OpenVPNAuthConf),
fmt.Sprintf("proto %s", connection.Protocol),
fmt.Sprintf("remote %s %d", connection.IP, connection.Port),
fmt.Sprintf("cipher %s", cipher),
fmt.Sprintf("auth %s", auth),
}
if strings.HasSuffix(cipher, "-gcm") {
lines = append(lines, "ncp-disable")
}
if !root {
lines = append(lines, "user nonrootuser")
}
lines = append(lines, []string{
"<crl-verify>",
"-----BEGIN X509 CRL-----",
X509CRL,
"-----END X509 CRL-----",
"</crl-verify>",
}...)
lines = append(lines, []string{
"<ca>",
"-----BEGIN CERTIFICATE-----",
certificate,
"-----END CERTIFICATE-----",
"</ca>",
"",
}...)
return lines
}

View File

@@ -23,7 +23,7 @@ import (
"github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/logging"
) )
type piaV4 struct { type pia struct {
servers []models.PIAServer servers []models.PIAServer
timeNow timeNowFunc timeNow timeNowFunc
randSource rand.Source randSource rand.Source
@@ -31,15 +31,15 @@ type piaV4 struct {
activeProtocol models.NetworkProtocol activeProtocol models.NetworkProtocol
} }
func newPrivateInternetAccessV4(servers []models.PIAServer, timeNow timeNowFunc) *piaV4 { func newPrivateInternetAccess(servers []models.PIAServer, timeNow timeNowFunc) *pia {
return &piaV4{ return &pia{
servers: servers, servers: servers,
timeNow: timeNow, timeNow: timeNow,
randSource: rand.NewSource(timeNow().UnixNano()), randSource: rand.NewSource(timeNow().UnixNano()),
} }
} }
func (p *piaV4) GetOpenVPNConnection(selection models.ServerSelection) ( func (p *pia) GetOpenVPNConnection(selection models.ServerSelection) (
connection models.OpenVPNConnection, err error) { connection models.OpenVPNConnection, err error) {
var port uint16 var port uint16
switch selection.Protocol { switch selection.Protocol {
@@ -109,13 +109,80 @@ func (p *piaV4) GetOpenVPNConnection(selection models.ServerSelection) (
return connection, nil return connection, nil
} }
func (p *piaV4) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, func (p *pia) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool,
cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
return buildPIAConf(connection, verbosity, root, cipher, auth, extras) var X509CRL, certificate string
var defaultCipher, defaultAuth string
if extras.EncryptionPreset == constants.PIAEncryptionPresetNormal {
defaultCipher = "aes-128-cbc"
defaultAuth = "sha1"
X509CRL = constants.PiaX509CRLNormal
certificate = constants.PIACertificateNormal
} else { // strong encryption
defaultCipher = aes256cbc
defaultAuth = "sha256"
X509CRL = constants.PiaX509CRLStrong
certificate = constants.PIACertificateStrong
}
if len(cipher) == 0 {
cipher = defaultCipher
}
if len(auth) == 0 {
auth = defaultAuth
}
lines = []string{
"client",
"dev tun",
"nobind",
"persist-key",
"remote-cert-tls server",
// PIA specific
"ping 300", // Ping every 5 minutes to prevent a timeout error
"reneg-sec 0",
"compress", // allow PIA server to choose the compression to use
// Added constant values
"auth-nocache",
"mute-replay-warnings",
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
"auth-retry nointeract",
"suppress-timestamps",
// Modified variables
fmt.Sprintf("verb %d", verbosity),
fmt.Sprintf("auth-user-pass %s", constants.OpenVPNAuthConf),
fmt.Sprintf("proto %s", connection.Protocol),
fmt.Sprintf("remote %s %d", connection.IP, connection.Port),
fmt.Sprintf("cipher %s", cipher),
fmt.Sprintf("auth %s", auth),
}
if strings.HasSuffix(cipher, "-gcm") {
lines = append(lines, "ncp-disable")
}
if !root {
lines = append(lines, "user nonrootuser")
}
lines = append(lines, []string{
"<crl-verify>",
"-----BEGIN X509 CRL-----",
X509CRL,
"-----END X509 CRL-----",
"</crl-verify>",
}...)
lines = append(lines, []string{
"<ca>",
"-----BEGIN CERTIFICATE-----",
certificate,
"-----END CERTIFICATE-----",
"</ca>",
"",
}...)
return lines
} }
//nolint:gocognit //nolint:gocognit
func (p *piaV4) PortForward(ctx context.Context, client *http.Client, func (p *pia) PortForward(ctx context.Context, client *http.Client,
fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator, fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,
syncState func(port uint16) (pfFilepath models.Filepath)) { syncState func(port uint16) (pfFilepath models.Filepath)) {
if !p.activeServer.PortForward { if !p.activeServer.PortForward {
@@ -130,7 +197,7 @@ func (p *piaV4) PortForward(ctx context.Context, client *http.Client,
if p.activeProtocol == constants.TCP { if p.activeProtocol == constants.TCP {
commonName = p.activeServer.OpenvpnTCP.CN commonName = p.activeServer.OpenvpnTCP.CN
} }
client, err := newPIAv4HTTPClient(commonName) client, err := newPIAHTTPClient(commonName)
if err != nil { if err != nil {
pfLogger.Error("aborting because: %s", err) pfLogger.Error("aborting because: %s", err)
return return
@@ -260,7 +327,7 @@ func filterPIAServers(servers []models.PIAServer, regions []string) (filtered []
return filtered return filtered
} }
func newPIAv4HTTPClient(serverName string) (client *http.Client, err error) { func newPIAHTTPClient(serverName string) (client *http.Client, err error) {
certificateBytes, err := base64.StdEncoding.DecodeString(constants.PIACertificateStrong) certificateBytes, err := base64.StdEncoding.DecodeString(constants.PIACertificateStrong)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot decode PIA root certificate: %w", err) return nil, fmt.Errorf("cannot decode PIA root certificate: %w", err)

View File

@@ -25,7 +25,7 @@ type Provider interface {
func New(provider models.VPNProvider, allServers models.AllServers, timeNow timeNowFunc) Provider { func New(provider models.VPNProvider, allServers models.AllServers, timeNow timeNowFunc) Provider {
switch provider { switch provider {
case constants.PrivateInternetAccess: case constants.PrivateInternetAccess:
return newPrivateInternetAccessV4(allServers.Pia.Servers, timeNow) return newPrivateInternetAccess(allServers.Pia.Servers, timeNow)
case constants.Mullvad: case constants.Mullvad:
return newMullvad(allServers.Mullvad.Servers, timeNow) return newMullvad(allServers.Mullvad.Servers, timeNow)
case constants.Windscribe: case constants.Windscribe:

View File

@@ -81,7 +81,7 @@ func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServe
} }
if u.options.PIA { if u.options.PIA {
u.logger.Info("updating Private Internet Access (v4) servers...") u.logger.Info("updating Private Internet Access servers...")
if err := u.updatePIA(ctx); err != nil { if err := u.updatePIA(ctx); err != nil {
u.logger.Error(err) u.logger.Error(err)
} }