feat(perfectprivacy): port forwarding support (#2378)
This commit is contained in:
43
internal/provider/perfectprivacy/portforward.go
Normal file
43
internal/provider/perfectprivacy/portforward.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package perfectprivacy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
// PortForward calculates and returns the VPN server side ports forwarded.
|
||||
func (p *Provider) PortForward(_ context.Context,
|
||||
objects utils.PortForwardObjects) (ports []uint16, err error) {
|
||||
if !objects.InternalIP.IsValid() {
|
||||
panic("internal ip is not set")
|
||||
}
|
||||
|
||||
return internalIPToPorts(objects.InternalIP), nil
|
||||
}
|
||||
|
||||
func (p *Provider) KeepPortForward(ctx context.Context,
|
||||
_ utils.PortForwardObjects) (err error) {
|
||||
<-ctx.Done()
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
// See https://www.perfect-privacy.com/en/faq section
|
||||
// How are the default forwarding ports being calculated?
|
||||
func internalIPToPorts(internalIP netip.Addr) (ports []uint16) {
|
||||
internalIPBytes := internalIP.AsSlice()
|
||||
// Convert the internal IP address to a bit string
|
||||
// and keep only the last 12 bits
|
||||
last16Bits := internalIPBytes[len(internalIPBytes)-2:]
|
||||
last12Bits := []byte{
|
||||
last16Bits[0] & 0b00001111, // only keep 4 bits
|
||||
last16Bits[1],
|
||||
}
|
||||
basePort := uint16(last12Bits[0])<<8 + uint16(last12Bits[1]) //nolint:gomnd
|
||||
return []uint16{
|
||||
10000 + basePort,
|
||||
20000 + basePort,
|
||||
30000 + basePort,
|
||||
}
|
||||
}
|
||||
33
internal/provider/perfectprivacy/portforward_test.go
Normal file
33
internal/provider/perfectprivacy/portforward_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package perfectprivacy
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_internalIPToPorts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
internalIP netip.Addr
|
||||
ports []uint16
|
||||
}{
|
||||
"example_case": {
|
||||
internalIP: netip.AddrFrom4([4]byte{10, 0, 203, 88}),
|
||||
ports: []uint16{12904, 22904, 32904},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ports := internalIPToPorts(testCase.internalIP)
|
||||
|
||||
assert.Equal(t, testCase.ports, ports)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ type PortForwardObjects struct {
|
||||
// Gateway is the VPN gateway IP address, used by Private Internet Access
|
||||
// and ProtonVPN.
|
||||
Gateway netip.Addr
|
||||
// InternalIP is the VPN internal IP address assigned, used by Perfect Privacy.
|
||||
InternalIP netip.Addr
|
||||
// Client is used to query the VPN gateway for Private Internet Access.
|
||||
Client *http.Client
|
||||
// ServerName is used by Private Internet Access for port forwarding.
|
||||
|
||||
Reference in New Issue
Block a user