Documentation
¶
Overview ¶
Package relay runs a STUN and TURN server for pipe peers, with per-user throughput plans on the relayed path.
One UDP listener serves both roles: it answers STUN Binding requests, and it answers TURN Allocate requests for authenticated users. An optional TCP listener serves clients whose networks block UDP.
srv, err := relay.Start(relay.Config{
Listen: "127.0.0.1:3478",
Users: map[string]relay.User{"admin": {Password: "admin"}},
})
Users are authenticated either from a static table (Config.Users) or with ephemeral credentials derived from a shared secret (Config.AuthSecret), the mechanism coturn calls use-auth-secret. Every authenticated user maps to a Plan that says how fast its relay sockets may go and how many it may hold at once. That is how a service gives free users a 512 KiB/s relay and paying users a faster one from the same server.
The throughput budget is real congestion, not a reported number: packets are delayed or dropped, so SCTP inside a pipe connection backs off the way it would on a slow link.
Index ¶
- Constants
- func FormatSize(n int64) string
- func IssueCredentials(secret, userID string, ttl time.Duration) (username, password string, err error)
- func ParsePlans(spec string) (map[string]Plan, error)
- func ParsePortRange(spec string) (minPort, maxPort uint16, err error)
- func ParseSize(s string) (int64, error)
- func ParseUsers(spec string) (map[string]User, error)
- func SortedUsers(s Stats) []string
- type Config
- type Plan
- type Server
- func (s *Server) Addr() *net.UDPAddr
- func (s *Server) Close() error
- func (s *Server) IssueCredentials(userID string, ttl time.Duration) (username, password string, err error)
- func (s *Server) Realm() string
- func (s *Server) STUNURL() string
- func (s *Server) Stats() Stats
- func (s *Server) TURNTCPURL() string
- func (s *Server) TURNURL() string
- type Stats
- type User
- type UserStats
Constants ¶
const ( // DefaultRealm is the TURN realm used when none is configured. The realm is // part of the long-term credential digest, so both ends must agree on it. DefaultRealm = "pipe.example" // DefaultMaxDelay bounds how long a relayed packet may be held waiting for // throughput budget before it is dropped instead. DefaultMaxDelay = 20 * time.Millisecond // DefaultCredentialTTL is how long ephemeral credentials issued by // [Server.IssueCredentials] stay valid. DefaultCredentialTTL = 24 * time.Hour )
Defaults for Config.
Variables ¶
This section is empty.
Functions ¶
func FormatSize ¶
FormatSize renders a byte count with a binary suffix.
func IssueCredentials ¶
func IssueCredentials(secret, userID string, ttl time.Duration) (username, password string, err error)
IssueCredentials returns TURN REST API credentials for userID under secret. The username embeds the expiry, so the server needs no database: it recomputes the HMAC and checks the clock. Put the plan in the user ID, for example "alice@paid", and Config.PlanFor's default maps it.
func ParsePlans ¶
ParsePlans parses a "name=rate[/maxallocations],..." list, for example "free=512KiB/4,paid=8MiB". A rate of 0 means unlimited.
func ParsePortRange ¶
ParsePortRange parses "min-max" into an inclusive port range. An empty string means no restriction.
func ParseSize ¶
ParseSize parses a byte count such as 512, 512KiB, 4MiB, or 1MB. Binary and decimal suffixes are both accepted and mean what they say.
func ParseUsers ¶
ParseUsers parses a "user=password[:plan],user2=password2" list.
func SortedUsers ¶
SortedUsers returns the user IDs in stats in a stable order.
Types ¶
type Config ¶
type Config struct {
// Listen is the UDP address to serve STUN and TURN on. Use a zero port to
// let the kernel choose one, then read [Server.Addr].
Listen string
// ListenTCP, when set, is a TCP address on which TURN is also served for
// clients behind UDP-hostile firewalls. STUN over TCP is answered too.
ListenTCP string
// Realm is the TURN realm. It defaults to [DefaultRealm].
Realm string
// Users maps TURN username to credential and plan for static
// authentication.
Users map[string]User
// AuthSecret, when set, enables ephemeral credentials in the TURN REST API
// format: the username is "<unix expiry>:<user id>" and the password is
// the base64 HMAC-SHA1 of the username under the secret. Issue them with
// [Server.IssueCredentials] or [IssueCredentials]. Static Users still work
// alongside.
AuthSecret string
// Plans are the named budgets users may be assigned to.
Plans map[string]Plan
// DefaultPlan applies to users without a plan. Its zero value means an
// unlimited relay.
DefaultPlan Plan
// PlanFor, when set, chooses the plan name for an authenticated user ID.
// The default looks the ID up in Users, then treats a "name@plan" ID as
// selecting plan, and otherwise uses DefaultPlan. Ephemeral credentials
// carry the plan in the user ID that way: "alice@paid".
PlanFor func(userID string) string
// RelayIP is the address handed to clients as their relay address. It
// defaults to the IP of the resolved listen address, which is what a local
// example wants. A server behind NAT must set its public address here.
RelayIP net.IP
// MinPort and MaxPort, when both set, restrict relay sockets to that
// inclusive range, which is what a firewall or a Docker port mapping needs.
// When zero, the kernel picks ephemeral ports.
MinPort, MaxPort uint16
// Logger receives lifecycle events. Credentials are never logged.
Logger *slog.Logger
}
Config configures a Server.
type Plan ¶
type Plan struct {
// Rate limits each allocated relay socket, in bytes per second per
// direction. Zero means unlimited.
Rate int64
// Burst is the token bucket depth in bytes. It defaults to a tenth of a
// second of Rate, and is never smaller than 64 KiB.
Burst int64
// MaxDelay bounds how long an inbound relayed packet may be held waiting for
// budget. Packets that would wait longer are dropped, which is how a
// congested link behaves. It defaults to [DefaultMaxDelay]; a zero-length
// delay is expressed as a negative value.
MaxDelay time.Duration
// MaxAllocations bounds the relay sockets one user may hold at a time. A
// pipe connection uses one allocation per side. Zero means unlimited.
MaxAllocations int
}
Plan is the relay budget granted to a class of users.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is a running STUN and TURN server.
func Start ¶
Start binds the listeners and starts serving. The caller owns the returned server and must Close it.
func (*Server) IssueCredentials ¶
func (s *Server) IssueCredentials(userID string, ttl time.Duration) (username, password string, err error)
IssueCredentials returns ephemeral credentials for userID that expire after ttl, signed with the server's auth secret. It fails when no secret is set.
func (*Server) TURNTCPURL ¶
TURNTCPURL is the URL of the TCP listener, or empty when there is none.
type Stats ¶
type Stats struct {
// Allocations counts relay sockets created since startup.
Allocations int64
// Active counts relay sockets open right now.
Active int64
// SentBytes and SentPackets count traffic from a client toward a peer.
SentBytes, SentPackets int64
// ReceivedBytes and ReceivedPackets count traffic from a peer toward a
// client.
ReceivedBytes, ReceivedPackets int64
// DroppedBytes and DroppedPackets count traffic discarded because it
// exceeded the throughput budget.
DroppedBytes, DroppedPackets int64
// DelayedPackets counts packets held to stay inside the budget.
DelayedPackets int64
// Users breaks the counters down by authenticated user ID.
Users map[string]UserStats
}
Stats is a snapshot of relayed traffic.
type User ¶
type User struct {
// Password is the long-term credential. It is digested at startup and
// never kept in memory afterwards.
Password string
// Plan names an entry in [Config.Plans]. Empty selects
// [Config.DefaultPlan].
Plan string
}
User is one entry in the static credential table.
type UserStats ¶
type UserStats struct {
// Plan is the plan name the user resolved to.
Plan string
// Allocations counts relay sockets created for the user; Active counts
// the ones open right now.
Allocations, Active int64
// SentBytes and ReceivedBytes count relayed traffic in each direction.
SentBytes, ReceivedBytes int64
// DroppedBytes and DroppedPackets count traffic over the plan's budget.
DroppedBytes, DroppedPackets int64
// RejectedAllocations counts Allocate requests refused by the plan's
// MaxAllocations quota.
RejectedAllocations int64
}
UserStats is the traffic of one user.