wsbind

package
v0.11.0-dev.2 Latest Latest
Warning

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

Go to latest
Published: Apr 16, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

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:

  1. WebSocket (default) -- works through any HTTP proxy / Cloudflare.
  2. 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

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

func New(ws *websocket.Conn, bufSize int) *Bind

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

func (b *Bind) AttemptDirect(peerAddrStr string) error

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) BatchSize

func (b *Bind) BatchSize() int

BatchSize returns 1 (no batching).

func (*Bind) Close

func (b *Bind) Close() error

Close signals all receiveFunc goroutines to stop and closes the UDP socket if active. Safe to call multiple times.

func (*Bind) DirectActive

func (b *Bind) DirectActive() bool

DirectActive reports whether the bind is using a direct peer-to-peer path.

func (*Bind) Open

func (b *Bind) Open(port uint16) ([]conn.ReceiveFunc, uint16, error)

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

func (b *Bind) ParseEndpoint(s string) (conn.Endpoint, error)

ParseEndpoint returns a static endpoint -- there's only one peer per bind.

func (*Bind) PeerIP added in v0.7.0

func (b *Bind) PeerIP() string

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

func (b *Bind) STUNDiscover() (string, error)

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) Send

func (b *Bind) Send(bufs [][]byte, ep conn.Endpoint) error

Send writes WireGuard datagrams. Priority: direct → UDP relay → WebSocket.

func (*Bind) SendControlFrame added in v0.6.0

func (b *Bind) SendControlFrame(payload []byte) error

SendControlFrame builds and sends a CONTROL relay frame through the WebSocket, serialized with other writes via writeMu.

func (*Bind) SendText

func (b *Bind) SendText(data []byte) error

SendText sends a text (JSON control) message through the WebSocket, serialized with WireGuard datagram sends to avoid concurrent writes.

func (*Bind) SetMark

func (b *Bind) SetMark(mark uint32) error

SetMark is a no-op (SO_MARK is irrelevant for WebSocket/UDP relay transport).

func (*Bind) StartDataKeepalive added in v0.3.73

func (b *Bind) StartDataKeepalive(interval time.Duration) func()

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) UDPActive

func (b *Bind) UDPActive() bool

UDPActive reports whether the bind is currently using UDP.

func (*Bind) UpgradeUDP

func (b *Bind) UpgradeUDP(hubHost string, hubPort int, token []byte) error

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.

Jump to

Keyboard shortcuts

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