Documentation
¶
Overview ¶
Package wsbind implements a WireGuard conn.Bind that transports WireGuard datagrams as binary WebSocket messages, with an optional upgrade to UDP relay for better performance.
Architecture:
WireGuard device ←→ wsBind ←→ WebSocket (or UDP) ←→ Hub relay
Transport modes:
- WebSocket (default) -- works through any HTTP proxy / Cloudflare.
- UDP relay (upgrade) -- eliminates TCP-over-TCP. Hub relays raw UDP datagrams tagged with an 8-byte session token.
Thread safety:
- WebSocket sends serialized via writeMu.
- UDP sends are inherently goroutine-safe (single socket).
- Receives from both transports merge into RecvCh.
- Close is idempotent; bind supports Close→Open cycles.
Index ¶
- type Bind
- func (b *Bind) AttemptDirect(peerAddrStr string) error
- func (b *Bind) BatchSize() int
- func (b *Bind) Close() error
- func (b *Bind) DirectActive() bool
- func (b *Bind) Open(port uint16) ([]conn.ReceiveFunc, uint16, error)
- func (b *Bind) ParseEndpoint(s string) (conn.Endpoint, error)
- func (b *Bind) PeerIP() string
- func (b *Bind) STUNDiscover() (string, error)
- func (b *Bind) Send(bufs [][]byte, ep conn.Endpoint) error
- func (b *Bind) SendControlFrame(payload []byte) error
- func (b *Bind) SendText(data []byte) error
- func (b *Bind) SetMark(mark uint32) error
- func (b *Bind) StartDataKeepalive(interval time.Duration) func()
- func (b *Bind) StartSessionKeepalive(closeFn func()) (chan<- struct{}, func())
- func (b *Bind) UDPActive() bool
- func (b *Bind) UpgradeUDP(hubHost string, hubPort int, token []byte) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Bind ¶
type Bind struct {
RecvCh chan []byte // binary WG datagrams from the reader goroutine(s)
// contains filtered or unexported fields
}
Bind implements conn.Bind for WireGuard-over-WebSocket transport with optional UDP relay upgrade.
WireGuard calls Close() then Open() during device state transitions (e.g. Up). The bind must support this cycle -- Close/Open are re-entrant and reset the receive path each time.
func New ¶
New creates a Bind using the given WebSocket connection. bufSize controls the receive channel buffer depth. A random session ID is generated for v1 relay frame headers.
func (*Bind) AttemptDirect ¶
AttemptDirect initiates UDP hole punching to the given peer address. It sends probe packets and waits for a response from the peer. On success, the bind routes WG datagrams directly to the peer. On failure, returns an error and the bind continues using UDP relay or WebSocket.
func (*Bind) Close ¶
Close signals all receiveFunc goroutines to stop and closes the UDP socket if active. Safe to call multiple times.
func (*Bind) DirectActive ¶
DirectActive reports whether the bind is using a direct peer-to-peer path.
func (*Bind) Open ¶
Open returns the receive function. WireGuard calls Open after Close during state transitions, so this resets the closed channel to allow receiveFunc to work again.
func (*Bind) ParseEndpoint ¶
ParseEndpoint returns a static endpoint -- there's only one peer per bind.
func (*Bind) PeerIP ¶ added in v0.7.0
PeerIP returns the IP address of the WebSocket peer (the hub). This is the actual TCP peer address, which may differ from the hostname used to connect (e.g. resolved LAN IP vs public hostname).
func (*Bind) STUNDiscover ¶
STUNDiscover performs a STUN Binding Request (RFC 5389) on the existing UDP socket and returns the server-reflexive address (public IP:port). This must be called after UpgradeUDP succeeds.
func (*Bind) SendControlFrame ¶ added in v0.6.0
SendControlFrame builds and sends a CONTROL relay frame through the WebSocket, serialized with other writes via writeMu.
func (*Bind) SendText ¶
SendText sends a text (JSON control) message through the WebSocket, serialized with WireGuard datagram sends to avoid concurrent writes.
func (*Bind) SetMark ¶
SetMark is a no-op (SO_MARK is irrelevant for WebSocket/UDP relay transport).
func (*Bind) StartDataKeepalive ¶ added in v0.3.73
StartDataKeepalive sends a periodic text-frame keepalive over the WebSocket to prevent intermediate proxies (e.g., Cloudflare) from closing the connection due to inactivity. When the tunnel upgrades to UDP relay, no data frames flow over the WebSocket, and some proxies do not count ping/pong control frames as activity. The keepalive message is a small JSON text frame that the hub relays to the peer, where it is silently ignored. Returns a stop function to cancel the keepalive goroutine.
func (*Bind) StartSessionKeepalive ¶ added in v0.6.0
func (b *Bind) StartSessionKeepalive(closeFn func()) (chan<- struct{}, func())
StartSessionKeepalive starts a goroutine that sends periodic in-band session keepalive requests (CONTROL frame, payload 0x01) and calls closeFn if no response arrives within relay.KeepaliveTimeout.
Returns (respCh, stop):
- respCh: the caller sends on this channel when a keepalive response (0x02) is received.
- stop: call to cancel the keepalive goroutine.
func (*Bind) UpgradeUDP ¶
UpgradeUDP attempts to switch from WebSocket to UDP relay. hubHost is the hub's hostname, hubPort is the UDP port, and token is the 8-byte session token assigned by the hub.
Returns nil on success (UDP is now active). On failure, returns an error and the bind continues using WebSocket transparently.