Skip to content

Commit

Permalink
PIA port forwarding final fixes (#259)
Browse files Browse the repository at this point in the history
- Returns an error if the server does not support port forwarding
- TLS verification using the server common name obtained through the API
- Updated readme
- Fixes #236
  • Loading branch information
qdm12 authored Oct 16, 2020
1 parent 98f778c commit 0d2ca37
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 16 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,6 @@ RUN apk add -q --progress --no-cache --update openvpn ca-certificates iptables i
deluser tinyproxy && \
deluser unbound && \
mkdir /gluetun
# TODO remove once SAN is added to PIA servers certificates, see https://github.com/pia-foss/manual-connections/issues/10
ENV GODEBUG=x509ignoreCN=0
COPY --from=builder /tmp/gobuild/entrypoint /entrypoint
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,11 +352,11 @@ There are various ways to achieve this, depending on your use case.
## Private Internet Access port forwarding
Note that [not all regions support port forwarding](https://www.privateinternetaccess.com/helpdesk/kb/articles/how-do-i-enable-port-forwarding-on-my-vpn).
When `PORT_FORWARDING=on`, a port will be forwarded on the VPN server side and written to the file specified by `PORT_FORWARDING_STATUS_FILE=/forwarded_port`.
When `PORT_FORWARDING=on`, a port will be forwarded on the VPN server side and written to the file specified by `PORT_FORWARDING_STATUS_FILE=/tmp/gluetun/forwarded_port`.
It can be useful to mount this file as a volume to read it from other containers, for example to configure a torrenting client.
For `VPNSP=private internet access` (default), you will keep the same forwarded port for 60 days as long as you bind mount the `/gluetun` directory.
You can also use the HTTP control server (see below) to get the port forwarded.
## HTTP control server
Expand Down
55 changes: 42 additions & 13 deletions internal/provider/piav4.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import (
)

type piaV4 struct {
servers []models.PIAServer
timeNow timeNowFunc
randSource rand.Source
servers []models.PIAServer
timeNow timeNowFunc
randSource rand.Source
activeServer models.PIAServer
activeProtocol models.NetworkProtocol
}

func newPrivateInternetAccessV4(servers []models.PIAServer, timeNow timeNowFunc) *piaV4 {
Expand Down Expand Up @@ -79,7 +81,29 @@ func (p *piaV4) GetOpenVPNConnection(selection models.ServerSelection) (connecti
}
}

return pickRandomConnection(connections, p.randSource), nil
connection = pickRandomConnection(connections, p.randSource)

// Reverse lookup server from picked connection
found := false
for _, server := range servers {
IPs := server.OpenvpnUDP.IPs
if selection.Protocol == constants.TCP {
IPs = server.OpenvpnTCP.IPs
}
for _, IP := range IPs {
if connection.IP.Equal(IP) {
p.activeServer = server
found = true
break
}
}
if found {
break
}
}
p.activeProtocol = selection.Protocol

return connection, nil
}

func (p *piaV4) BuildConf(connection models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
Expand All @@ -90,11 +114,19 @@ func (p *piaV4) BuildConf(connection models.OpenVPNConnection, verbosity, uid, g
func (p *piaV4) PortForward(ctx context.Context, client *http.Client,
fileManager files.FileManager, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator,
syncState func(port uint16) (pfFilepath models.Filepath)) {
if !p.activeServer.PortForward {
pfLogger.Error("The server %s does not support port forwarding", p.activeServer.Region)
return
}
if gateway == nil {
pfLogger.Error("aborting because: VPN gateway IP address was not found")
return
}
client, err := newPIAv4HTTPClient()
commonName := p.activeServer.OpenvpnUDP.CN
if p.activeProtocol == constants.TCP {
commonName = p.activeServer.OpenvpnTCP.CN
}
client, err := newPIAv4HTTPClient(commonName)
if err != nil {
pfLogger.Error("aborting because: %s", err)
return
Expand Down Expand Up @@ -225,7 +257,7 @@ func filterPIAServers(servers []models.PIAServer, region string) (filtered []mod
return nil
}

func newPIAv4HTTPClient() (client *http.Client, err error) {
func newPIAv4HTTPClient(serverName string) (client *http.Client, err error) {
certificateBytes, err := base64.StdEncoding.DecodeString(constants.PIACertificateStrong)
if err != nil {
return nil, fmt.Errorf("cannot decode PIA root certificate: %w", err)
Expand All @@ -237,10 +269,10 @@ func newPIAv4HTTPClient() (client *http.Client, err error) {
rootCAs := x509.NewCertPool()
rootCAs.AddCert(certificate)
TLSClientConfig := &tls.Config{
RootCAs: rootCAs,
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: true, //nolint:gosec
} // TODO fix and remove InsecureSkipVerify
RootCAs: rootCAs,
MinVersion: tls.VersionTLS12,
ServerName: serverName,
}
transport := http.Transport{
TLSClientConfig: TLSClientConfig,
Proxy: http.ProxyFromEnvironment,
Expand All @@ -267,9 +299,6 @@ func refreshPIAPortForwardData(client *http.Client, gateway net.IP, fileManager
}
data.Port, data.Signature, data.Expiration, err = fetchPIAPortForwardData(client, gateway, data.Token)
if err != nil {
if strings.HasSuffix(err.Error(), "connection refused") {
return data, fmt.Errorf("cannot obtain port forwarding data: connection was refused, are you sure the region you are using supports port forwarding ;)")
}
return data, fmt.Errorf("cannot obtain port forwarding data: %w", err)
}
if err := writePIAPortForwardData(fileManager, data); err != nil {
Expand Down

0 comments on commit 0d2ca37

Please sign in to comment.