135 lines
4.7 KiB
Go
135 lines
4.7 KiB
Go
// Package checker implements the XMPP server checker for happyDomain.
|
|
//
|
|
// It probes a domain's XMPP deployment (SRV discovery, STARTTLS,
|
|
// stream features, SASL mechanisms, dialback / SASL EXTERNAL,
|
|
// XEP-0368 direct TLS) and reports actionable findings.
|
|
//
|
|
// TLS certificate chain / SAN / expiry / cipher posture is intentionally
|
|
// out of scope; a dedicated TLS checker covers that.
|
|
package checker
|
|
|
|
import (
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
const ObservationKeyXMPP sdk.ObservationKey = "xmpp"
|
|
|
|
type XMPPMode string
|
|
|
|
const (
|
|
ModeClient XMPPMode = "c2s"
|
|
ModeServer XMPPMode = "s2s"
|
|
ModeBoth XMPPMode = "both"
|
|
)
|
|
|
|
var validModes = []string{string(ModeClient), string(ModeServer), string(ModeBoth)}
|
|
|
|
// XMPPData is the full observation stored per run.
|
|
type XMPPData struct {
|
|
Domain string `json:"domain"`
|
|
RunAt string `json:"run_at"`
|
|
SRV SRVLookup `json:"srv"`
|
|
Endpoints []EndpointProbe `json:"endpoints"`
|
|
Coverage ReachabilitySpan `json:"coverage"`
|
|
Issues []Issue `json:"issues"`
|
|
}
|
|
|
|
type SRVLookup struct {
|
|
Client []SRVRecord `json:"client,omitempty"`
|
|
Server []SRVRecord `json:"server,omitempty"`
|
|
ClientSecure []SRVRecord `json:"client_secure,omitempty"`
|
|
ServerSecure []SRVRecord `json:"server_secure,omitempty"`
|
|
Jabber []SRVRecord `json:"jabber,omitempty"`
|
|
// Errors per-set (keyed by record type like "_xmpp-client._tcp").
|
|
Errors map[string]string `json:"errors,omitempty"`
|
|
// FallbackProbed is true when no SRV was published and we probed the bare domain.
|
|
FallbackProbed bool `json:"fallback_probed,omitempty"`
|
|
}
|
|
|
|
type SRVRecord struct {
|
|
Target string `json:"target"`
|
|
Port uint16 `json:"port"`
|
|
Priority uint16 `json:"priority"`
|
|
Weight uint16 `json:"weight"`
|
|
// IPv4 and IPv6 addresses resolved for the target (at probe time).
|
|
IPv4 []string `json:"ipv4,omitempty"`
|
|
IPv6 []string `json:"ipv6,omitempty"`
|
|
}
|
|
|
|
// EndpointProbe is the result of probing one (mode, host, port, address) tuple.
|
|
type EndpointProbe struct {
|
|
Mode XMPPMode `json:"mode"`
|
|
SRVPrefix string `json:"srv_prefix"`
|
|
Target string `json:"target"`
|
|
Port uint16 `json:"port"`
|
|
Address string `json:"address"`
|
|
IsIPv6 bool `json:"is_ipv6,omitempty"`
|
|
DirectTLS bool `json:"direct_tls,omitempty"`
|
|
|
|
// What happened.
|
|
TCPConnected bool `json:"tcp_connected"`
|
|
StreamOpened bool `json:"stream_opened"`
|
|
|
|
STARTTLSOffered bool `json:"starttls_offered"`
|
|
STARTTLSRequired bool `json:"starttls_required"`
|
|
STARTTLSUpgraded bool `json:"starttls_upgraded"`
|
|
|
|
TLSVersion string `json:"tls_version,omitempty"`
|
|
TLSCipher string `json:"tls_cipher,omitempty"`
|
|
|
|
// Post-TLS features.
|
|
FeaturesRead bool `json:"features_read,omitempty"`
|
|
SASLMechanisms []string `json:"sasl_mechanisms,omitempty"`
|
|
DialbackOffered bool `json:"dialback_offered,omitempty"`
|
|
SASLExternal bool `json:"sasl_external,omitempty"`
|
|
|
|
StreamFrom string `json:"stream_from,omitempty"`
|
|
|
|
ElapsedMS int64 `json:"elapsed_ms"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
type ReachabilitySpan struct {
|
|
HasIPv4 bool `json:"has_ipv4"`
|
|
HasIPv6 bool `json:"has_ipv6"`
|
|
// WorkingC2S is true when at least one c2s endpoint completed TLS + advertised SASL.
|
|
WorkingC2S bool `json:"working_c2s"`
|
|
// WorkingS2S is true when at least one s2s endpoint completed TLS + advertised dialback or SASL EXTERNAL.
|
|
WorkingS2S bool `json:"working_s2s"`
|
|
}
|
|
|
|
// Issue is a structured finding attached to the observation so the rule and
|
|
// the HTML report can both consume them without re-deriving logic.
|
|
type Issue struct {
|
|
Code string `json:"code"`
|
|
Severity string `json:"severity"` // "info" | "warn" | "crit"
|
|
Message string `json:"message"`
|
|
Fix string `json:"fix,omitempty"`
|
|
Endpoint string `json:"endpoint,omitempty"`
|
|
}
|
|
|
|
// Severities (string for stable JSON, independent of sdk.Status numeric values).
|
|
const (
|
|
SeverityInfo = "info"
|
|
SeverityWarn = "warn"
|
|
SeverityCrit = "crit"
|
|
)
|
|
|
|
// Issue codes.
|
|
const (
|
|
CodeNoSRV = "xmpp.no_srv"
|
|
CodeSRVServfail = "xmpp.srv.servfail"
|
|
CodeStartTLSMissing = "xmpp.starttls.missing"
|
|
CodeStartTLSNotRequired = "xmpp.starttls.not_required"
|
|
CodeStartTLSFailed = "xmpp.starttls.handshake_failed"
|
|
CodeTCPUnreachable = "xmpp.tcp.unreachable"
|
|
CodeSASLPlainOnly = "xmpp.sasl.plain_only"
|
|
CodeSASLNoSCRAM = "xmpp.sasl.no_scram"
|
|
CodeSASLNoSCRAMPlus = "xmpp.sasl.no_scram_plus"
|
|
CodeS2SNoAuth = "xmpp.s2s.no_auth"
|
|
CodeS2SProbeIncomplete = "xmpp.s2s.probe_incomplete"
|
|
CodeLegacyJabber = "xmpp.legacy_jabber"
|
|
CodeNoIPv6 = "xmpp.no_ipv6"
|
|
CodeNoDirectTLS = "xmpp.no_direct_tls"
|
|
CodeAllEndpointsDown = "xmpp.all_endpoints_down"
|
|
)
|