relay

package
v0.9.77 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 6, 2026 License: GPL-3.0 Imports: 25 Imported by: 0

Documentation

Overview

Package relay wraps a pion/turn/v5 TURN server with ggscale's tenant + player identity model. Credentials are issued via the standard TURN REST API (RFC draft-uberti-rtcweb-turn-rest-00) so any client SDK can consume them; the server-side AuthHandler reconstructs the HMAC password for incoming TURN auth checks.

The username embeds a short key id so multiple shared secrets can be accepted at once: the active (first) secret signs new credentials while older secrets stay valid, giving a zero-downtime rotation window equal to the credential TTL.

Index

Constants

This section is empty.

Variables

View Source
var ErrCredentialsExpired = errors.New("relay: credentials expired")

ErrCredentialsExpired is returned by Verify when the encoded expiry has already elapsed.

View Source
var ErrCredentialsInvalid = errors.New("relay: credentials invalid")

ErrCredentialsInvalid is returned by Verify on any other failure (unparseable username, unknown key id, HMAC mismatch).

Functions

func ValidateTURNURI

func ValidateTURNURI(raw string) error

ValidateTURNURI accepts the turn:/turns: URI forms clients dial. TURN URIs are opaque (turn:host:port?transport=udp), so the host lands in Opaque rather than Host after url.Parse.

Types

type Credentials

type Credentials struct {
	Username   string   `json:"username" example:"1767225600:3:42:k1"`
	Password   string   `json:"password" example:"dGVzdC1obWFjLXNhbXBsZS12YWx1ZQ=="`
	TTLSeconds int64    `json:"ttl" example:"600"`
	Realm      string   `json:"realm" example:"ggscale"`
	URLs       []string `json:"urls,omitempty" example:"turn:relay.example.com:3478?transport=udp"`
	Region     string   `json:"region" example:"us-east"`
	STUNURLs   []string `json:"stun_urls,omitempty" example:"stun:stun.example.com:3478"`
}

Credentials are the values returned to a client. URLs are the TURN URIs of the relay nodes the client should dial, and Region is the region they were chosen from, or "" when they span regions. The API server fills both from the relay node registry; Issue leaves them empty.

type Issuer

type Issuer struct {
	// contains filtered or unexported fields
}

Issuer mints and verifies short-lived TURN-REST credentials. One Issuer per process; safe for concurrent use once constructed.

func NewIssuer

func NewIssuer(secret, realm string, ttl time.Duration) *Issuer

NewIssuer returns an Issuer with a single shared secret and realm. ttl is the validity window encoded into each issued username; the server-side AuthHandler rejects requests after this elapses.

func NewIssuerWithSecrets

func NewIssuerWithSecrets(secrets []string, realm string, ttl time.Duration) *Issuer

NewIssuerWithSecrets returns an Issuer whose first secret signs new credentials and every non-empty secret is accepted for verification. This backs zero-downtime rotation: configure old + new together, promote the new secret to first, then drop the old one after a credential-TTL overlap.

func (*Issuer) Issue

func (i *Issuer) Issue(tenantID, playerID int64) (*Credentials, error)

Issue returns a fresh credential pair scoped to (tenantID, playerID), signed by the active secret and tagged with its key id.

func (*Issuer) SetSTUNURLs

func (i *Issuer) SetSTUNURLs(urls []string)

SetSTUNURLs sets the discovery-only STUN URIs returned alongside TURN credentials so WebRTC clients can gather direct server-reflexive candidates.

func (*Issuer) Verify

func (i *Issuer) Verify(username, password string) (int64, int64, error)

Verify checks the username + password pair against every accepted secret, returning the embedded (tenantID, playerID) on success. The in-process TURN server authenticates via authForUsername (pion recomputes and compares the HMAC key itself); Verify is the standalone entrypoint for verifying a credential pair out of band — e.g. an external relay or a conformance test.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server wraps pion/turn/v5. One Server per process. It owns every listener it opens (UDP packet conns + TCP/TLS listeners); Close releases them all.

func NewServer

func NewServer(cfg ServerConfig) (*Server, error)

NewServer binds the configured listeners and starts the underlying pion server. The returned Server owns the listeners; callers must invoke Close to release the ports.

func (*Server) ActiveAllocations

func (s *Server) ActiveAllocations() int64

ActiveAllocations reports the number of currently-live relay allocations.

func (*Server) ActiveWork

func (s *Server) ActiveWork() int64

ActiveWork reports the work a drain waits on: every Allocate admitted through the drain gate, from admission until its relayed socket closes.

func (*Server) AllocThrottled

func (s *Server) AllocThrottled() int64

AllocThrottled reports the cumulative count of authenticated allocations refused by the per-player rate limit.

func (*Server) AuthFailures

func (s *Server) AuthFailures() int64

AuthFailures reports the cumulative count of rejected TURN auth attempts.

func (*Server) BeginDrain

func (s *Server) BeginDrain()

BeginDrain refuses new TURN Allocate requests. Existing allocations keep refreshing, binding permissions, and relaying data.

func (*Server) Close

func (s *Server) Close() error

Close stops the TURN server and releases every listener.

func (*Server) EndDrain

func (s *Server) EndDrain()

EndDrain accepts new TURN Allocate requests again.

func (*Server) PeerRejected

func (s *Server) PeerRejected() int64

PeerRejected reports the cumulative count of CreatePermission/ChannelBind attempts refused because the peer address was private and private peers are disallowed.

func (*Server) PublicIP

func (s *Server) PublicIP() string

PublicIP reports the address peers reach this relay on.

func (*Server) RefusedWork

func (s *Server) RefusedWork() int64

RefusedWork reports the cumulative count of Allocate requests refused while draining.

func (*Server) RejectedAllocations

func (s *Server) RejectedAllocations() int64

RejectedAllocations reports the cumulative count of allocations refused because the node allocation cap was reached.

func (*Server) Transports

func (s *Server) Transports() []string

Transports lists the client transports this relay listens on: "udp", then "tcp" and "tls" when enabled.

type ServerConfig

type ServerConfig struct {
	PublicIP    string
	BindAddr    string // host portion of the bind address; empty -> 0.0.0.0
	BindPort    int    // UDP port
	TCPPort     int    // TURN-over-TCP port; 0 disables
	TLSPort     int    // TURNS (TLS) port; 0 disables
	TLSCertFile string // required when TLSPort != 0
	TLSKeyFile  string // required when TLSPort != 0
	// RelayMinPort/RelayMaxPort bound the UDP ports allocated for relayed
	// media. Both 0 (the default) allocates from the OS ephemeral range;
	// setting a range lets the firewall open only those ports. The range width
	// caps the number of concurrent relay allocations.
	RelayMinPort int
	RelayMaxPort int
	// MaxAllocations caps concurrently-live relay allocations node-wide,
	// bounding port-range exhaustion from a single credential. 0 = unlimited.
	MaxAllocations int
	// PlayerAllocPerMinute/PlayerAllocBurst throttle authenticated allocations
	// per player so one credential can't monopolise the global pool. <=0 disables.
	PlayerAllocPerMinute int
	PlayerAllocBurst     int
	// AllowPrivatePeers lets clients relay to loopback/RFC1918/link-local/ULA
	// peer addresses. Default false: the relay refuses to proxy into private
	// space, so a valid credential can't turn the node into an SSRF hop to
	// internal services. Set true only for a self-host relay that legitimately
	// bridges private peers on a trusted network.
	AllowPrivatePeers bool
	// Logger receives the pion server's internal events; nil uses slog.Default.
	Logger *slog.Logger
	Issuer *Issuer
}

ServerConfig wires NewServer. PublicIP is the address peers connect to; BindPort is the local UDP port the listener binds (default 3478). TCPPort and TLSPort are optional TURN/TCP and TURNS/TLS transports (0 = off) so clients behind UDP-blocking firewalls can still reach the relay.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
⌂ 换网址