Initial commit
This commit is contained in:
commit
8f41185302
20 changed files with 2775 additions and 0 deletions
125
checker/rule.go
Normal file
125
checker/rule.go
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package checker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdk "git.happydns.org/checker-sdk-go/checker"
|
||||
)
|
||||
|
||||
func Rule() sdk.CheckRule {
|
||||
return &smtpRule{}
|
||||
}
|
||||
|
||||
type smtpRule struct{}
|
||||
|
||||
func (r *smtpRule) Name() string {
|
||||
return "smtp_server"
|
||||
}
|
||||
|
||||
func (r *smtpRule) Description() string {
|
||||
return "Checks MX discovery, SMTP connectivity, STARTTLS, PTR/FCrDNS and mail-acceptance posture for an email-receiving domain"
|
||||
}
|
||||
|
||||
func (r *smtpRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) sdk.CheckState {
|
||||
var data SMTPData
|
||||
if err := obs.Get(ctx, ObservationKeySMTP, &data); err != nil {
|
||||
return sdk.CheckState{
|
||||
Status: sdk.StatusError,
|
||||
Message: fmt.Sprintf("failed to load SMTP observation: %v", err),
|
||||
Code: "smtp.observation_error",
|
||||
}
|
||||
}
|
||||
|
||||
issues := append([]Issue(nil), data.Issues...)
|
||||
|
||||
// Fold related TLS observations so cert/chain problems show up on the
|
||||
// SMTP service page without requiring the user to open a separate
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// Null-MX is a *declared* refusal of mail; it's an INFO, not a fail.
|
||||
if data.MX.NullMX {
|
||||
return sdk.CheckState{
|
||||
Status: sdk.StatusInfo,
|
||||
Message: "Domain refuses all email via null MX (RFC 7505).",
|
||||
Code: CodeNullMX,
|
||||
Meta: map[string]any{
|
||||
"null_mx": true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
meta := map[string]any{
|
||||
"has_ipv4": data.Coverage.HasIPv4,
|
||||
"has_ipv6": data.Coverage.HasIPv6,
|
||||
"any_starttls": data.Coverage.AnySTARTTLS,
|
||||
"all_starttls": data.Coverage.AllSTARTTLS,
|
||||
"all_accept_mail": data.Coverage.AllAcceptMail,
|
||||
"mx_count": len(data.MX.Records),
|
||||
"endpoint_count": len(data.Endpoints),
|
||||
"native_issues": len(data.Issues),
|
||||
"related_tls_count": len(related),
|
||||
}
|
||||
|
||||
switch worst {
|
||||
case sdk.StatusOK:
|
||||
return sdk.CheckState{
|
||||
Status: sdk.StatusOK,
|
||||
Message: fmt.Sprintf("SMTP operational (%d MX, %d endpoints, TLS=%v)", len(data.MX.Records), len(data.Endpoints), data.Coverage.AllSTARTTLS),
|
||||
Code: "smtp.ok",
|
||||
Meta: meta,
|
||||
}
|
||||
case sdk.StatusWarn:
|
||||
return sdk.CheckState{
|
||||
Status: sdk.StatusWarn,
|
||||
Message: "SMTP works with warnings: " + joinTop(warnMsgs, 2),
|
||||
Code: firstWarnCode,
|
||||
Meta: meta,
|
||||
}
|
||||
default:
|
||||
return sdk.CheckState{
|
||||
Status: sdk.StatusCrit,
|
||||
Message: "SMTP 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)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue