94 lines
3 KiB
Go
94 lines
3 KiB
Go
package checker
|
|
|
|
import (
|
|
"context"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
// c2sReachableRule verifies that at least one client-to-server endpoint
|
|
// is reachable (TCP + TLS) and that no discovered c2s endpoint is down.
|
|
type c2sReachableRule struct{}
|
|
|
|
func (r *c2sReachableRule) Name() string { return "xmpp.c2s_reachable" }
|
|
func (r *c2sReachableRule) Description() string {
|
|
return "Verifies that at least one client-to-server endpoint accepts TCP and completes TLS."
|
|
}
|
|
|
|
func (r *c2sReachableRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
|
|
return evaluateReachable(ctx, obs, opts, ModeClient)
|
|
}
|
|
|
|
// s2sReachableRule is the s2s counterpart.
|
|
type s2sReachableRule struct{}
|
|
|
|
func (r *s2sReachableRule) Name() string { return "xmpp.s2s_reachable" }
|
|
func (r *s2sReachableRule) Description() string {
|
|
return "Verifies that at least one server-to-server endpoint accepts TCP and completes TLS."
|
|
}
|
|
|
|
func (r *s2sReachableRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
|
|
return evaluateReachable(ctx, obs, opts, ModeServer)
|
|
}
|
|
|
|
func evaluateReachable(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions, mode XMPPMode) []sdk.CheckState {
|
|
data, errSt := loadXMPPData(ctx, obs)
|
|
if errSt != nil {
|
|
return []sdk.CheckState{*errSt}
|
|
}
|
|
wantC2S, wantS2S := wantsFromOpts(opts)
|
|
if mode == ModeClient && !wantC2S {
|
|
return []sdk.CheckState{notTestedState("xmpp.c2s_reachable.skipped", "c2s not in scope for the selected mode.")}
|
|
}
|
|
if mode == ModeServer && !wantS2S {
|
|
return []sdk.CheckState{notTestedState("xmpp.s2s_reachable.skipped", "s2s not in scope for the selected mode.")}
|
|
}
|
|
|
|
// Per-endpoint TCP unreachable states for this mode.
|
|
var states []sdk.CheckState
|
|
anyForMode := false
|
|
for _, ep := range data.Endpoints {
|
|
if ep.Mode != mode {
|
|
continue
|
|
}
|
|
anyForMode = true
|
|
if !ep.TCPConnected && ep.Error != "" {
|
|
states = append(states, sdk.CheckState{
|
|
Status: sdk.StatusWarn,
|
|
Message: "Cannot reach " + ep.Address + ": " + ep.Error + ".",
|
|
Code: CodeTCPUnreachable,
|
|
Subject: ep.Address,
|
|
Meta: map[string]any{"fix": "Verify firewall rules and that the XMPP server is listening on this address."},
|
|
})
|
|
}
|
|
}
|
|
|
|
if !anyForMode {
|
|
return []sdk.CheckState{{
|
|
Status: sdk.StatusCrit,
|
|
Message: "No " + string(mode) + " endpoint discovered to probe.",
|
|
Code: CodeNoSRV,
|
|
}}
|
|
}
|
|
|
|
working := data.Coverage.WorkingC2S
|
|
if mode == ModeServer {
|
|
working = data.Coverage.WorkingS2S
|
|
}
|
|
if !working {
|
|
states = append(states, sdk.CheckState{
|
|
Status: sdk.StatusCrit,
|
|
Message: "No working " + string(mode) + " endpoint (TCP + TLS).",
|
|
Code: CodeAllEndpointsDown,
|
|
})
|
|
}
|
|
|
|
if len(states) == 0 {
|
|
code := "xmpp.c2s_reachable.ok"
|
|
if mode == ModeServer {
|
|
code = "xmpp.s2s_reachable.ok"
|
|
}
|
|
return []sdk.CheckState{passState(code, "At least one "+string(mode)+" endpoint is reachable and completes TLS.")}
|
|
}
|
|
return states
|
|
}
|