Compare commits

..

1 Commits

Author SHA1 Message Date
Quentin McGaw 4ff4ff4d90 DEBUG_EXTERNAL_PORT_MISMATCH_CYCLES 2026-08-02 14:44:29 +00:00
@@ -6,6 +6,8 @@ import (
"fmt" "fmt"
"maps" "maps"
"net/netip" "net/netip"
"os"
"strconv"
"strings" "strings"
"time" "time"
@@ -13,6 +15,25 @@ import (
"github.com/qdm12/gluetun/internal/provider/utils" "github.com/qdm12/gluetun/internal/provider/utils"
) )
// debugPortMismatchTriggerCycles is read from the environment variable
// DEBUG_EXTERNAL_PORT_MISMATCH_CYCLES. If set to a value > 0, the port
// forwarding maintain loop will trigger a synthetic external port mismatch
// error after the specified number of successful maintain cycles.
// This is only used for testing/debugging purposes.
//
//nolint:gochecknoglobals // env var read once at init for debug-only synthetic trigger
var debugPortMismatchTriggerCycles = func() uint {
value := os.Getenv("DEBUG_EXTERNAL_PORT_MISMATCH_CYCLES")
if value == "" {
return 0
}
parsed, err := strconv.ParseUint(value, 10, 16)
if err != nil || parsed == 0 {
return 0
}
return uint(parsed)
}()
// PortForward obtains a VPN server side port forwarded from ProtonVPN gateway. // PortForward obtains a VPN server side port forwarded from ProtonVPN gateway.
func (p *Provider) PortForward(ctx context.Context, objects utils.PortForwardObjects) ( func (p *Provider) PortForward(ctx context.Context, objects utils.PortForwardObjects) (
internalToExternalPorts map[uint16]uint16, err error, internalToExternalPorts map[uint16]uint16, err error,
@@ -126,6 +147,7 @@ func (p *Provider) KeepPortForward(ctx context.Context,
const refreshTimeout = 45 * time.Second const refreshTimeout = 45 * time.Second
timer := time.NewTimer(refreshTimeout) timer := time.NewTimer(refreshTimeout)
logger := objects.Logger logger := objects.Logger
maintainCycles := uint(0)
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
@@ -134,6 +156,20 @@ func (p *Provider) KeepPortForward(ctx context.Context,
} }
objects.Logger.Debug("refreshing forwarded ports since 45 seconds have elapsed") objects.Logger.Debug("refreshing forwarded ports since 45 seconds have elapsed")
// DEBUG: trigger synthetic port mismatch after N maintain cycles.
if debugPortMismatchTriggerCycles > 0 {
maintainCycles++
if maintainCycles == debugPortMismatchTriggerCycles {
fakeExternalPort := uint16(65535) //nolint:mnd // arbitrary port to trigger mismatch error
objects.Logger.Error(fmt.Sprintf(
"DEBUG: triggering synthetic external port mismatch after %d maintain cycles",
maintainCycles))
return fmt.Errorf("refreshing port mapping: TCP external port requested as %d but received %d",
uint16(1), fakeExternalPort)
}
}
const lifetime = 60 * time.Second const lifetime = 60 * time.Second
for internalPort, externalPort := range p.internalToExternalPorts { for internalPort, externalPort := range p.internalToExternalPorts {
_, _, err := addPortMappingTCPUDP(ctx, client, logger, objects.Gateway, internalPort, externalPort, lifetime) _, _, err := addPortMappingTCPUDP(ctx, client, logger, objects.Gateway, internalPort, externalPort, lifetime)