checker-stun-turn/README.md
Pierre-Olivier Mercier 7c7706fe3f Initial commit
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.
2026-04-26 19:55:05 +07:00

4 KiB

checker-stun-turn

happyDomain checker that probes STUN and TURN servers end-to-end: DNS / SRV discovery, TCP/UDP reachability, TLS / DTLS handshake, STUN binding, open-relay check, authenticated TURN Allocate (long-term creds or REST API shared secret), relay address sanity, and a CreatePermission + Send round-trip through the relay.

Backed by github.com/pion/stun + github.com/pion/turn.

Tests performed per endpoint

Test What it proves
dial:<transport> DNS resolves, port is reachable, TLS/DTLS handshake succeeds.
tls / dtls Records TLS version + cipher + peer cert CN.
stun_binding Server answers RFC 5389 Binding Request; measures RTT.
stun_reflexive_public Server returned a public XOR-MAPPED address (not RFC1918).
turn_open_relay_check Unauthenticated Allocate is rejected with 401 + REALM/NONCE.
turn_allocate_auth Authenticated Allocate succeeds; relay address returned.
turn_relay_public Relay address is publicly routable.
turn_relay_echo CreatePermission + Send to the probe peer succeed.
turn_channel_bind (optional) ChannelBind exercised via the relay conn.

Most common failures surfaced with a fix

Each failing sub-test carries a Fix field that is rendered prominently in the HTML report (yellow callout at the top of the card and inline with each row). Mapping:

  • UDP/TCP dial timeouts → firewall/NAT guidance
  • TLS handshake errors → certificate reissue guidance (coturn cert=/pkey=)
  • STUN binding returns RFC1918 → external-ip= for coturn
  • Unauthenticated Allocate accepted → enable lt-cred-mech, close the open relay
  • Allocate 401 loop → check NTP (TURN nonces are time-sensitive)
  • Allocate 441 → wrong username/password or wrong REST shared secret
  • Allocate 442 → try different transport or enable it server-side
  • Allocate 486/508 → quota / port-range issues on the server
  • Relay address is private → set relay-ip= to a public IP
  • Relay echo fails → min-port/max-port range not publicly reachable

Usage

Build and run:

make           # standalone binary
make plugin    # .so plugin for happyDomain
./checker-stun-turn -listen :8080

Trigger a check:

curl -sX POST localhost:8080/collect -H 'content-type: application/json' -d '{
  "options": {
    "zone": "example.com",
    "serverURI": "turns:turn.example.com:5349?transport=tcp",
    "mode": "turn",
    "username": "alice",
    "credential": "s3cret",
    "transports": "udp,tcp,tls",
    "probePeer": "1.1.1.1:53",
    "timeout": 5
  }
}' | jq .

Options

Scope Option Type Default Notes
run zone string (auto-filled) used for _stun._udp / _turn._udp / _turns._tcp SRV discovery
run serverURI string explicit URI, RFC 7064/7065
run mode choice auto stun, turn, auto
user username string long-term credentials
user credential secret long-term credentials
user sharedSecret secret REST-API auth (draft-uberti), takes precedence
user realm string optional explicit realm
user transports string udp,tcp,tls comma-separated among udp,tcp,tls,dtls
user probePeer string 1.1.1.1:53 target for the relay echo test
user testChannelBind bool false
user warningRTT uint 200 ms
user criticalRTT uint 1000 ms
user timeout uint 5 s per-probe

License

MIT (see LICENSE).