Adds a happyDomain checker that probes STUN/TURN servers end-to-end:
DNS/SRV discovery, UDP/TCP/TLS/DTLS dial, STUN binding + reflexive-addr
sanity, open-relay detection, authenticated TURN Allocate (long-term
creds or REST-API HMAC), public-relay check, CreatePermission + Send
round-trip through the relay, and optional ChannelBind.
Failing sub-tests carry a remediation string (`Fix`) that the HTML
report surfaces as a yellow headline callout and inline next to each
row. Mapping covers the most common coturn misconfigurations
(external-ip, relay-ip, lt-cred-mech, min-port/max-port, cert issues,
401 nonce drift, 441/442/486/508 allocation errors).
Implements sdk.EndpointDiscoverer (checker/discovery.go): every
stuns:/turns:/DTLS endpoint observed during Collect is published as a
DiscoveredEndpoint{Type: "tls"|"dtls"} so a downstream TLS checker can
verify certificates without re-parsing the observation.
Backed by pion/stun/v3 + pion/turn/v4 + pion/dtls/v3; SDK pinned to a
local replace until the EndpointDiscoverer interface ships in a tagged
release.
51 lines
1.4 KiB
Go
51 lines
1.4 KiB
Go
package checker
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
tlsct "git.happydns.org/checker-tls/contract"
|
|
)
|
|
|
|
// DiscoverEntries implements sdk.DiscoveryPublisher.
|
|
//
|
|
// stuns:/turns: (RFC 7064/7065) speak TLS immediately after the TCP
|
|
// handshake, so every secure TCP-based endpoint we observed is published
|
|
// under the tls.endpoint.v1 contract for checker-tls to pick up.
|
|
//
|
|
// DTLS is intentionally omitted: the current checker-tls consumer uses
|
|
// crypto/tls and would not probe a datagram-TLS endpoint correctly. Emitting
|
|
// a DTLS entry today would only produce orphan lineage.
|
|
//
|
|
// SNI is left empty (= Host); no STARTTLS upgrade applies; the scheme
|
|
// mandates direct TLS on the wire.
|
|
func (p *stunTurnProvider) DiscoverEntries(data any) ([]sdk.DiscoveryEntry, error) {
|
|
d, ok := data.(*StunTurnData)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected data type %T", data)
|
|
}
|
|
seen := make(map[string]struct{})
|
|
var out []sdk.DiscoveryEntry
|
|
for _, ep := range d.Endpoints {
|
|
if !ep.Dial.OK {
|
|
continue
|
|
}
|
|
if !ep.Endpoint.Secure || ep.Endpoint.Transport == TransportDTLS {
|
|
continue
|
|
}
|
|
key := fmt.Sprintf("%s|%d", ep.Endpoint.Host, ep.Endpoint.Port)
|
|
if _, dup := seen[key]; dup {
|
|
continue
|
|
}
|
|
seen[key] = struct{}{}
|
|
entry, err := tlsct.NewEntry(tlsct.TLSEndpoint{
|
|
Host: ep.Endpoint.Host,
|
|
Port: ep.Endpoint.Port,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out = append(out, entry)
|
|
}
|
|
return out, nil
|
|
}
|