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.
This commit is contained in:
commit
7c7706fe3f
29 changed files with 2794 additions and 0 deletions
77
checker/interactive.go
Normal file
77
checker/interactive.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//go:build standalone
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
sdk "git.happydns.org/checker-sdk-go/checker"
|
||||
)
|
||||
|
||||
// RenderForm exposes the inputs needed to drive a STUN/TURN check from
|
||||
// the standalone HTML form. The fields mirror the canonical option
|
||||
// documentation in Definition() (RunOpts then UserOpts) so the form
|
||||
// stays in lock-step with the JSON schema served at /definition.
|
||||
func (p *stunTurnProvider) RenderForm() []sdk.CheckerOptionField {
|
||||
def := p.Definition()
|
||||
fields := make([]sdk.CheckerOptionField, 0, len(def.Options.RunOpts)+len(def.Options.UserOpts))
|
||||
fields = append(fields, def.Options.RunOpts...)
|
||||
fields = append(fields, def.Options.UserOpts...)
|
||||
return fields
|
||||
}
|
||||
|
||||
// ParseForm turns the submitted form into a CheckerOptions. At least one
|
||||
// of zone or serverURI must be provided so discoverEndpoints has
|
||||
// something to work with.
|
||||
func (p *stunTurnProvider) ParseForm(r *http.Request) (sdk.CheckerOptions, error) {
|
||||
zone := strings.TrimSpace(r.FormValue("zone"))
|
||||
zone = strings.TrimSuffix(zone, ".")
|
||||
uri := strings.TrimSpace(r.FormValue("serverURI"))
|
||||
if zone == "" && uri == "" {
|
||||
return nil, errors.New("either zone or serverURI is required")
|
||||
}
|
||||
|
||||
opts := sdk.CheckerOptions{}
|
||||
if zone != "" {
|
||||
opts["zone"] = zone
|
||||
}
|
||||
if uri != "" {
|
||||
opts["serverURI"] = uri
|
||||
}
|
||||
|
||||
if v := strings.TrimSpace(r.FormValue("mode")); v != "" {
|
||||
switch v {
|
||||
case "auto", "stun", "turn":
|
||||
opts["mode"] = v
|
||||
default:
|
||||
return nil, errors.New("mode must be one of: auto, stun, turn")
|
||||
}
|
||||
}
|
||||
|
||||
for _, k := range []string{"username", "credential", "sharedSecret", "realm", "transports", "probePeer"} {
|
||||
if v := strings.TrimSpace(r.FormValue(k)); v != "" {
|
||||
opts[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if v := r.FormValue("testChannelBind"); v != "" {
|
||||
opts["testChannelBind"] = v == "true" || v == "on" || v == "1"
|
||||
}
|
||||
|
||||
for _, k := range []string{"warningRTT", "criticalRTT", "timeout"} {
|
||||
v := strings.TrimSpace(r.FormValue(k))
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
n, err := strconv.ParseUint(v, 10, 32)
|
||||
if err != nil {
|
||||
return nil, errors.New(k + " must be a non-negative integer")
|
||||
}
|
||||
opts[k] = int(n)
|
||||
}
|
||||
|
||||
return opts, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue