package checker import ( "net" "strconv" sdk "git.happydns.org/checker-sdk-go/checker" tlsct "git.happydns.org/checker-tls/contract" ) func Provider() sdk.ObservationProvider { return &xmppProvider{} } type xmppProvider struct{} func (p *xmppProvider) Key() sdk.ObservationKey { return ObservationKeyXMPP } // Definition implements sdk.CheckerDefinitionProvider. func (p *xmppProvider) Definition() *sdk.CheckerDefinition { return Definition() } // DiscoverEntries implements sdk.DiscoveryPublisher. // // It publishes TLS endpoint contract entries for every SRV target we found, // so a downstream TLS checker can verify the certificate chain / SAN / // expiry on each one without re-doing the SRV lookup. The XMPP checker // itself does not perform certificate verification; that posture lives in // the TLS checker. // // SNI is set to the bare JID domain rather than the SRV target, because XMPP // certificates must be valid for the source domain (RFC 6120 ยง13.7.2.1), // which is typically different from the SRV target hostname. func (p *xmppProvider) DiscoverEntries(data any) ([]sdk.DiscoveryEntry, error) { d, ok := data.(*XMPPData) if !ok || d == nil { return nil, nil } // Carry over the STARTTLS-required posture observed during probing. starttlsRequired := map[string]bool{} for _, ep := range d.Endpoints { if ep.STARTTLSRequired { starttlsRequired[endpointKey(ep.Target, ep.Port)] = true } } var out []sdk.DiscoveryEntry emit := func(proto string, recs []SRVRecord, directTLS bool) error { for _, r := range recs { ep := tlsct.TLSEndpoint{ Host: r.Target, Port: r.Port, SNI: d.Domain, } if !directTLS { ep.STARTTLS = proto ep.RequireSTARTTLS = starttlsRequired[endpointKey(r.Target, r.Port)] } entry, err := tlsct.NewEntry(ep) if err != nil { return err } out = append(out, entry) } return nil } if err := emit("xmpp-client", d.SRV.Client, false); err != nil { return nil, err } if err := emit("xmpp-server", d.SRV.Server, false); err != nil { return nil, err } if err := emit("", d.SRV.ClientSecure, true); err != nil { return nil, err } if err := emit("", d.SRV.ServerSecure, true); err != nil { return nil, err } return out, nil } func endpointKey(host string, port uint16) string { return net.JoinHostPort(host, strconv.FormatUint(uint64(port), 10)) }