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.
90 lines
4 KiB
Markdown
90 lines
4 KiB
Markdown
# 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`](https://github.com/pion/stun) +
|
|
[`github.com/pion/turn`](https://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).
|