From 976d5e4f0686854cbc56dc674423c5c5a92afd71 Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Sat, 18 Jul 2026 04:52:26 -0700 Subject: [PATCH] fix(healthcheck): guard periodic checks against divide-by-zero when config is cleared --- internal/healthcheck/checker.go | 14 +++++++++++++- internal/healthcheck/checker_test.go | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/internal/healthcheck/checker.go b/internal/healthcheck/checker.go index 5d36f58d0..4ddc23de8 100644 --- a/internal/healthcheck/checker.go +++ b/internal/healthcheck/checker.go @@ -159,6 +159,8 @@ func (c *Checker) Start(ctx context.Context) (runError <-chan error, err error) func (c *Checker) Stop() error { c.stop() <-c.done + c.configMutex.Lock() + defer c.configMutex.Unlock() c.tlsDialAddrs = nil c.icmpTargetIPs = nil c.smallCheckType = "" @@ -170,6 +172,9 @@ func (c *Checker) smallPeriodicCheck(ctx context.Context) error { icmpTargetIPs := make([]netip.Addr, len(c.icmpTargetIPs)) copy(icmpTargetIPs, c.icmpTargetIPs) c.configMutex.Unlock() + if c.smallCheckType != smallCheckDNS && len(icmpTargetIPs) == 0 { + return nil + } tryTimeouts := []time.Duration{ 5 * time.Second, 5 * time.Second, @@ -202,11 +207,18 @@ func (c *Checker) smallPeriodicCheck(ctx context.Context) error { } func (c *Checker) fullPeriodicCheck(ctx context.Context) error { + c.configMutex.Lock() + tlsDialAddrs := make([]string, len(c.tlsDialAddrs)) + copy(tlsDialAddrs, c.tlsDialAddrs) + c.configMutex.Unlock() + if len(tlsDialAddrs) == 0 { + return nil + } // 20s timeout in case the connection is under stress // See https://github.com/qdm12/gluetun/issues/2270 tryTimeouts := []time.Duration{10 * time.Second, 15 * time.Second, 30 * time.Second} check := func(ctx context.Context, try int) error { - tlsDialAddr := c.tlsDialAddrs[try%len(c.tlsDialAddrs)] + tlsDialAddr := tlsDialAddrs[try%len(tlsDialAddrs)] return tcpTLSCheck(ctx, c.dialer, tlsDialAddr) } return withRetries(ctx, tryTimeouts, c.logger, "TCP+TLS dial", check) diff --git a/internal/healthcheck/checker_test.go b/internal/healthcheck/checker_test.go index f6241f768..a4709bb65 100644 --- a/internal/healthcheck/checker_test.go +++ b/internal/healthcheck/checker_test.go @@ -61,6 +61,20 @@ func Test_Checker_fullcheck(t *testing.T) { }) } +func Test_Checker_periodicCheckEmptyTargets(t *testing.T) { + t.Parallel() + + checker := &Checker{smallCheckType: smallCheckICMP} + + err := checker.fullPeriodicCheck(context.Background()) + + assert.NoError(t, err) + + err = checker.smallPeriodicCheck(context.Background()) + + assert.NoError(t, err) +} + func Test_makeAddressToDial(t *testing.T) { t.Parallel()