121 lines
2.9 KiB
Go
121 lines
2.9 KiB
Go
package checker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
func Rule() sdk.CheckRule {
|
|
return &sipRule{}
|
|
}
|
|
|
|
type sipRule struct{}
|
|
|
|
func (r *sipRule) Name() string {
|
|
return "sip_server"
|
|
}
|
|
|
|
func (r *sipRule) Description() string {
|
|
return "Checks DNS resolution, reachability and OPTIONS response of a SIP/VoIP server"
|
|
}
|
|
|
|
func (r *sipRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) sdk.CheckState {
|
|
var data SIPData
|
|
if err := obs.Get(ctx, ObservationKeySIP, &data); err != nil {
|
|
return sdk.CheckState{
|
|
Status: sdk.StatusError,
|
|
Message: fmt.Sprintf("failed to load SIP observation: %v", err),
|
|
Code: "sip.observation_error",
|
|
}
|
|
}
|
|
|
|
issues := append([]Issue(nil), data.Issues...)
|
|
|
|
// Fold in related TLS observations so cert issues surface on the
|
|
// SIP page without requiring a separate glance at the TLS report.
|
|
related, _ := obs.GetRelated(ctx, TLSRelatedKey)
|
|
issues = append(issues, tlsIssuesFromRelated(related)...)
|
|
|
|
worst := sdk.StatusOK
|
|
critMsgs, warnMsgs := []string{}, []string{}
|
|
var firstCritCode, firstWarnCode string
|
|
|
|
for _, is := range issues {
|
|
switch is.Severity {
|
|
case SeverityCrit:
|
|
if worst < sdk.StatusCrit {
|
|
worst = sdk.StatusCrit
|
|
}
|
|
if firstCritCode == "" {
|
|
firstCritCode = is.Code
|
|
}
|
|
critMsgs = append(critMsgs, is.Message)
|
|
case SeverityWarn:
|
|
if worst < sdk.StatusWarn {
|
|
worst = sdk.StatusWarn
|
|
}
|
|
if firstWarnCode == "" {
|
|
firstWarnCode = is.Code
|
|
}
|
|
warnMsgs = append(warnMsgs, is.Message)
|
|
}
|
|
}
|
|
|
|
transports := []string{}
|
|
if data.Coverage.WorkingUDP {
|
|
transports = append(transports, "udp")
|
|
}
|
|
if data.Coverage.WorkingTCP {
|
|
transports = append(transports, "tcp")
|
|
}
|
|
if data.Coverage.WorkingTLS {
|
|
transports = append(transports, "tls")
|
|
}
|
|
|
|
meta := map[string]any{
|
|
"working_udp": data.Coverage.WorkingUDP,
|
|
"working_tcp": data.Coverage.WorkingTCP,
|
|
"working_tls": data.Coverage.WorkingTLS,
|
|
"has_ipv4": data.Coverage.HasIPv4,
|
|
"has_ipv6": data.Coverage.HasIPv6,
|
|
"endpoints": len(data.Endpoints),
|
|
"issue_count": len(data.Issues),
|
|
}
|
|
|
|
switch worst {
|
|
case sdk.StatusOK:
|
|
return sdk.CheckState{
|
|
Status: sdk.StatusOK,
|
|
Message: fmt.Sprintf("SIP operational (%s, %d endpoints)", strings.Join(transports, "+"), len(data.Endpoints)),
|
|
Code: "sip.ok",
|
|
Meta: meta,
|
|
}
|
|
case sdk.StatusWarn:
|
|
return sdk.CheckState{
|
|
Status: sdk.StatusWarn,
|
|
Message: "SIP works with warnings: " + joinTop(warnMsgs, 2),
|
|
Code: firstWarnCode,
|
|
Meta: meta,
|
|
}
|
|
default:
|
|
return sdk.CheckState{
|
|
Status: sdk.StatusCrit,
|
|
Message: "SIP broken: " + joinTop(critMsgs, 2),
|
|
Code: firstCritCode,
|
|
Meta: meta,
|
|
}
|
|
}
|
|
}
|
|
|
|
func joinTop(msgs []string, n int) string {
|
|
if len(msgs) == 0 {
|
|
return ""
|
|
}
|
|
if len(msgs) <= n {
|
|
return strings.Join(msgs, "; ")
|
|
}
|
|
return strings.Join(msgs[:n], "; ") + fmt.Sprintf(" (+%d more)", len(msgs)-n)
|
|
}
|