hotfix(portforward): log both external and internal ports when they diverge

- useful for ProtonVPN only
- clarify things up for the user
This commit is contained in:
Quentin McGaw
2026-05-21 14:34:39 +00:00
parent 8f012014d6
commit f8a677a424
3 changed files with 71 additions and 5 deletions
+29
View File
@@ -2,6 +2,10 @@ package service
import (
"fmt"
"maps"
"slices"
"sort"
"strconv"
"strings"
)
@@ -20,3 +24,28 @@ func portsToString(ports []uint16) (s string) {
" and " + portStrings[len(portStrings)-1]
}
}
func portPairsToString(internalToExternalPort map[uint16]uint16) (s string) {
switch len(internalToExternalPort) {
case 0:
return "no port forwarded"
case 1:
internal := slices.Collect(maps.Keys(internalToExternalPort))[0]
return "port forwarded is " + portPairToString(internal, internalToExternalPort[internal])
default:
portStrings := make([]string, 0, len(internalToExternalPort))
for internal, external := range internalToExternalPort {
portStrings = append(portStrings, portPairToString(internal, external))
}
sort.StringSlice(portStrings).Sort()
return "ports forwarded are " + strings.Join(portStrings[:len(portStrings)-1], ", ") +
" and " + portStrings[len(portStrings)-1]
}
}
func portPairToString(internal, external uint16) string {
if internal == external {
return strconv.FormatUint(uint64(external), 10)
}
return fmt.Sprintf("%d (internal port %d)", external, internal)
}
@@ -40,3 +40,42 @@ func Test_portsToString(t *testing.T) {
})
}
}
func Test_externalInternalPortsToString(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
internalToExternalPort map[uint16]uint16
s string
}{
"no_port": {
s: "no port forwarded",
},
"one_port": {
internalToExternalPort: map[uint16]uint16{123: 123},
s: "port forwarded is 123",
},
"two_ports": {
internalToExternalPort: map[uint16]uint16{123: 123, 456: 456},
s: "ports forwarded are 123 and 456",
},
"two_ports_different_internal_external": {
internalToExternalPort: map[uint16]uint16{123: 124, 456: 457},
s: "ports forwarded are 124 (internal port 123) and 457 (internal port 456)",
},
"three_ports": {
internalToExternalPort: map[uint16]uint16{123: 123, 456: 456, 789: 789},
s: "ports forwarded are 123, 456 and 789",
},
}
for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
t.Parallel()
s := portPairsToString(testCase.internalToExternalPort)
assert.Equal(t, testCase.s, s)
})
}
}
+3 -5
View File
@@ -89,6 +89,9 @@ func (s *Service) Start(ctx context.Context) (runError <-chan error, err error)
}
func (s *Service) onNewPorts(ctx context.Context, internalToExternalPorts map[uint16]uint16) (err error) {
s.logger.Info(portPairsToString(internalToExternalPorts))
externalPorts := slices.Collect(maps.Values(internalToExternalPorts))
autoRedirectionNeeded := false
externalToInternalPorts := make(map[uint16]uint16, len(internalToExternalPorts))
for internal, external := range internalToExternalPorts {
@@ -97,12 +100,7 @@ func (s *Service) onNewPorts(ctx context.Context, internalToExternalPorts map[ui
autoRedirectionNeeded = true
}
}
externalPorts := slices.Collect(maps.Keys(externalToInternalPorts))
slices.Sort(externalPorts)
s.logger.Info(portsToString(externalPorts))
userRedirectionEnabled := !slices.Equal(s.settings.ListeningPorts, []uint16{0})
for i, port := range externalPorts {
internalPort := externalToInternalPorts[port]