feat(healthcheck): combination of ICMP and TCP+TLS checks (#2923)
- New option: `HEALTH_ICMP_TARGET_IP` defaults to `0.0.0.0` meaning use the VPN server public IP address. - Options removed: `HEALTH_VPN_INITIAL_DURATION` and `HEALTH_VPN_ADDITIONAL_DURATION` - times and retries are handpicked and hardcoded. - Less aggressive checks and less false positive detection
This commit is contained in:
@@ -2,6 +2,7 @@ package settings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@@ -24,16 +25,13 @@ type Health struct {
|
||||
// HTTP server. It defaults to 500 milliseconds.
|
||||
ReadTimeout time.Duration
|
||||
// TargetAddress is the address (host or host:port)
|
||||
// to TCP dial to periodically for the health check.
|
||||
// to TCP TLS dial to periodically for the health check.
|
||||
// It cannot be the empty string in the internal state.
|
||||
TargetAddress string
|
||||
// SuccessWait is the duration to wait to re-run the
|
||||
// healthcheck after a successful healthcheck.
|
||||
// It defaults to 5 seconds and cannot be zero in
|
||||
// the internal state.
|
||||
SuccessWait time.Duration
|
||||
// VPN has health settings specific to the VPN loop.
|
||||
VPN HealthyWait
|
||||
// ICMPTargetIP is the IP address to use for ICMP echo requests
|
||||
// in the health checker. It can be set to an unspecified address
|
||||
// such that the VPN server IP is used, which is also the default behavior.
|
||||
ICMPTargetIP netip.Addr
|
||||
}
|
||||
|
||||
func (h Health) Validate() (err error) {
|
||||
@@ -42,11 +40,6 @@ func (h Health) Validate() (err error) {
|
||||
return fmt.Errorf("server listening address is not valid: %w", err)
|
||||
}
|
||||
|
||||
err = h.VPN.validate()
|
||||
if err != nil {
|
||||
return fmt.Errorf("health VPN settings: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -56,8 +49,7 @@ func (h *Health) copy() (copied Health) {
|
||||
ReadHeaderTimeout: h.ReadHeaderTimeout,
|
||||
ReadTimeout: h.ReadTimeout,
|
||||
TargetAddress: h.TargetAddress,
|
||||
SuccessWait: h.SuccessWait,
|
||||
VPN: h.VPN.copy(),
|
||||
ICMPTargetIP: h.ICMPTargetIP,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +61,7 @@ func (h *Health) OverrideWith(other Health) {
|
||||
h.ReadHeaderTimeout = gosettings.OverrideWithComparable(h.ReadHeaderTimeout, other.ReadHeaderTimeout)
|
||||
h.ReadTimeout = gosettings.OverrideWithComparable(h.ReadTimeout, other.ReadTimeout)
|
||||
h.TargetAddress = gosettings.OverrideWithComparable(h.TargetAddress, other.TargetAddress)
|
||||
h.SuccessWait = gosettings.OverrideWithComparable(h.SuccessWait, other.SuccessWait)
|
||||
h.VPN.overrideWith(other.VPN)
|
||||
h.ICMPTargetIP = gosettings.OverrideWithComparable(h.ICMPTargetIP, other.ICMPTargetIP)
|
||||
}
|
||||
|
||||
func (h *Health) SetDefaults() {
|
||||
@@ -80,9 +71,7 @@ func (h *Health) SetDefaults() {
|
||||
const defaultReadTimeout = 500 * time.Millisecond
|
||||
h.ReadTimeout = gosettings.DefaultComparable(h.ReadTimeout, defaultReadTimeout)
|
||||
h.TargetAddress = gosettings.DefaultComparable(h.TargetAddress, "cloudflare.com:443")
|
||||
const defaultSuccessWait = 5 * time.Second
|
||||
h.SuccessWait = gosettings.DefaultComparable(h.SuccessWait, defaultSuccessWait)
|
||||
h.VPN.setDefaults()
|
||||
h.ICMPTargetIP = gosettings.DefaultComparable(h.ICMPTargetIP, netip.IPv4Unspecified()) // use the VPN server IP
|
||||
}
|
||||
|
||||
func (h Health) String() string {
|
||||
@@ -93,10 +82,11 @@ func (h Health) toLinesNode() (node *gotree.Node) {
|
||||
node = gotree.New("Health settings:")
|
||||
node.Appendf("Server listening address: %s", h.ServerAddress)
|
||||
node.Appendf("Target address: %s", h.TargetAddress)
|
||||
node.Appendf("Duration to wait after success: %s", h.SuccessWait)
|
||||
node.Appendf("Read header timeout: %s", h.ReadHeaderTimeout)
|
||||
node.Appendf("Read timeout: %s", h.ReadTimeout)
|
||||
node.AppendNode(h.VPN.toLinesNode("VPN"))
|
||||
icmpTarget := "VPN server IP"
|
||||
if !h.ICMPTargetIP.IsUnspecified() {
|
||||
icmpTarget = h.ICMPTargetIP.String()
|
||||
}
|
||||
node.Appendf("ICMP target IP: %s", icmpTarget)
|
||||
return node
|
||||
}
|
||||
|
||||
@@ -104,16 +94,9 @@ func (h *Health) Read(r *reader.Reader) (err error) {
|
||||
h.ServerAddress = r.String("HEALTH_SERVER_ADDRESS")
|
||||
h.TargetAddress = r.String("HEALTH_TARGET_ADDRESS",
|
||||
reader.RetroKeys("HEALTH_ADDRESS_TO_PING"))
|
||||
|
||||
h.SuccessWait, err = r.Duration("HEALTH_SUCCESS_WAIT_DURATION")
|
||||
h.ICMPTargetIP, err = r.NetipAddr("HEALTH_ICMP_TARGET_IP")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = h.VPN.read(r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("VPN health settings: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user