77 lines
2.2 KiB
Go
77 lines
2.2 KiB
Go
package prober
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"net"
|
|
"strconv"
|
|
"time"
|
|
|
|
"git.ipng.ch/ipng/vpp-maglev/internal/health"
|
|
)
|
|
|
|
// TCPProbe performs a TCP connect to cfg.Target:cfg.Port inside the healthcheck
|
|
// netns. If cfg.TCP.SSL is true a TLS handshake is performed after connect,
|
|
// making this an L6 check (useful for smtps, imaps, etc.).
|
|
// Plain connect returns L4OK/L4TOUT/L4CON.
|
|
// TLS handshake returns L6OK/L6TOUT/L6RSP (on top of an L4OK connect).
|
|
func TCPProbe(ctx context.Context, cfg ProbeConfig) health.ProbeResult {
|
|
port := cfg.Port
|
|
if port == 0 {
|
|
port = 80
|
|
}
|
|
addr := net.JoinHostPort(cfg.Target.String(), strconv.Itoa(int(port)))
|
|
|
|
doTLS := cfg.TCP != nil && cfg.TCP.SSL
|
|
var serverName string
|
|
var insecureSkipVerify bool
|
|
if cfg.TCP != nil {
|
|
serverName = cfg.TCP.ServerName
|
|
insecureSkipVerify = cfg.TCP.InsecureSkipVerify
|
|
}
|
|
|
|
var result health.ProbeResult
|
|
err := inNetns(cfg.HealthCheckNetns, func() error {
|
|
dialer := &net.Dialer{Timeout: cfg.Timeout}
|
|
if cfg.ProbeSrc != nil {
|
|
dialer.LocalAddr = &net.TCPAddr{IP: cfg.ProbeSrc}
|
|
}
|
|
conn, err := dialer.DialContext(ctx, "tcp", addr)
|
|
if err != nil {
|
|
if isTimeout(err) {
|
|
result = health.ProbeResult{OK: false, Layer: health.LayerL4, Code: "L4TOUT", Detail: err.Error()}
|
|
} else {
|
|
result = health.ProbeResult{OK: false, Layer: health.LayerL4, Code: "L4CON", Detail: err.Error()}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if !doTLS {
|
|
conn.Close()
|
|
result = health.ProbeResult{OK: true, Layer: health.LayerL4, Code: "L4OK"}
|
|
return nil
|
|
}
|
|
|
|
// TLS handshake.
|
|
tlsConn := tls.Client(conn, tlsConfig(serverName, insecureSkipVerify))
|
|
tlsConn.SetDeadline(time.Now().Add(cfg.Timeout)) //nolint:errcheck
|
|
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
|
tlsConn.Close()
|
|
if isTimeout(err) {
|
|
result = health.ProbeResult{OK: false, Layer: health.LayerL6, Code: "L6TOUT", Detail: err.Error()}
|
|
} else {
|
|
result = health.ProbeResult{OK: false, Layer: health.LayerL6, Code: "L6RSP", Detail: err.Error()}
|
|
}
|
|
return nil
|
|
}
|
|
tlsConn.Close()
|
|
result = health.ProbeResult{OK: true, Layer: health.LayerL6, Code: "L6OK"}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return health.ProbeResult{OK: false, Layer: health.LayerL4, Code: "L4CON", Detail: err.Error()}
|
|
}
|
|
return result
|
|
}
|