Documentation
¶
Overview ¶
Package p2p implements a peer-to-peer tunnel host: it exposes gRPC tunnels to a peer and bridges each one to a local target, using a DERP relay for rendezvous and, optionally, a hole-punched direct path.
It runs in two modes. With Config.Derp set, peers are addressed by base64 curve25519 public key and the relay/hole-punch engine carries the tunnel; with it empty ("stub" mode) the peer is a plain host:port dialled directly.
The package is a library. The standalone binary lives in cmd/p2p and is only a flag/config front end over New. An embedder that wants tunnels without a separate process uses:
host, err := p2p.New(&p2p.Config{Derp: url, KeyHex: hexKey})
if err != nil {
return err
}
defer host.Close()
if err := host.Connect(); err != nil { // engine + configured forwards
return err
}
conn, err := host.Provider().OpenTunnelStream(ctx, "tcp", peerKey)
Provider opens tunnels in-process over an in-memory stream; the gRPC control plane (Start/Serve) is only needed by out-of-process clients. Both paths run the same data-plane code, so tunnel semantics do not depend on the carrier.
Index ¶
- type Config
- type Engine
- type ForwardConfig
- type Host
- func (h *Host) AddForward(listen, peerKey string) error
- func (h *Host) Addr() string
- func (h *Host) Close() error
- func (h *Host) Connect() error
- func (h *Host) Provider() *Provider
- func (h *Host) PublicKey() string
- func (h *Host) Serve(ln net.Listener) error
- func (h *Host) Start() (string, error)
- func (h *Host) Status(ctx context.Context) (*proto.StatusReply, error)
- type LogConfig
- type LogRotationConfig
- type Option
- type Provider
- type SmuxTimeouts
- type TLSConfig
- type TimeoutsConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
Addr string `yaml:"addr,omitempty"`
Token string `yaml:"token,omitempty"`
Derp string `yaml:"derp,omitempty"`
Key string `yaml:"key,omitempty"`
KeyHex string `yaml:"keyHex,omitempty"`
Target string `yaml:"target,omitempty"`
Targets []string `yaml:"targets,omitempty"`
Stun string `yaml:"stun,omitempty"`
Direct *bool `yaml:"direct,omitempty"`
TLS *TLSConfig `yaml:"tls,omitempty"`
Log *LogConfig `yaml:"log,omitempty"`
Timeouts *TimeoutsConfig `yaml:"timeouts,omitempty"`
Forwards []ForwardConfig `yaml:"forwards,omitempty"`
}
Config is the optional YAML configuration file. Every field mirrors a command-line flag (the flag name without the leading "--"); a config value supplies the default and an explicitly-set flag overrides it.
func LoadConfig ¶
LoadConfig reads and parses a YAML config file.
func (*Config) TargetList ¶
TargetList merges the legacy scalar `target` with the `targets` list, scalar first, into the raw spec list the engine parses.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine connects the host to a DERP rendezvous/relay server and turns relayed packets into one smux session per peer. The peer address is the base64 (raw URL) encoding of its 32-byte curve25519 public key — the same string GOST passes to OpenTunnel as "peer".
Data path: every OpenStream on the session is one tunnel; the local endpoint listener bridges onto it exactly like the stub bridges onto a dialed TCP conn. Both peers keep an accept loop and pipe inbound streams to the local --target, so either side can open tunnels.
Session role (smux.Client vs smux.Server) is decided by public-key ordering so both ends always agree on exactly one session per pair regardless of who dials first. smux allows either side to open streams.
func (*Engine) Connect ¶
Connect dials the relay eagerly (used at startup so inbound tunnels work immediately instead of waiting for the reconnect ticker).
func (*Engine) OpenStream ¶
OpenStream opens a tunnel stream to the peer, establishing the DERP connection and mux session on first use. An established direct (hole-punched) session is preferred; on any failure it falls back to the relay session. The returned connection is tagged with the transport it uses ("direct" or "derp") so the caller can log which path the tunnel took.
type ForwardConfig ¶
type ForwardConfig struct {
Listen string `yaml:"listen,omitempty"`
Peer string `yaml:"peer,omitempty"`
}
ForwardConfig is a pre-configured static port forward: bind Listen and bridge accepted connections to the peer's public key.
type Host ¶
type Host struct {
// contains filtered or unexported fields
}
Host is a p2p endpoint. It owns the DERP engine (when a relay URL is configured), the gRPC control plane, and the tunnel bookkeeping. It can run standalone as the CLI does (Start + Close) or be embedded in-process (Connect + Provider).
func New ¶
New builds a Host from cfg. It performs no network I/O: the DERP connection is deferred to Connect, and all listeners are bound by Connect/Start.
func (*Host) AddForward ¶
AddForward binds a static endpoint and bridges it to peer (DERP mode only). listen is the local address, peerKey a base64 public key.
func (*Host) Close ¶
Close shuts the host down: the gRPC server and listener, the static forward listeners, the DERP engine, and the pending-tunnel GC. It is idempotent.
func (*Host) Connect ¶
Connect establishes the DERP engine connection and applies the configured static forwards. It is idempotent: only the first call performs work and its error is remembered.
A failed DERP connection is not fatal — the engine retries in the background and inbound tunnels stay unreachable until it connects — so Start logs it and continues. Embedding callers that need strict startup can check the error.
type LogConfig ¶
type LogConfig struct {
Level string `yaml:"level,omitempty"`
Format string `yaml:"format,omitempty"`
Output string `yaml:"output,omitempty"`
Rotation *LogRotationConfig `yaml:"rotation,omitempty"`
}
LogConfig mirrors the --log.* flags plus file rotation.
type LogRotationConfig ¶
type LogRotationConfig struct {
MaxSize int `yaml:"maxSize,omitempty"`
MaxAge int `yaml:"maxAge,omitempty"`
MaxBackups int `yaml:"maxBackups,omitempty"`
LocalTime bool `yaml:"localTime,omitempty"`
Compress bool `yaml:"compress,omitempty"`
}
LogRotationConfig configures lumberjack file rotation for a file output. Zero values fall back to lumberjack's defaults (100 MB, keep all, UTC, no compression).
type Option ¶
type Option func(*Host)
Option configures a Host.
func WithLogger ¶
WithLogger sets the logger used by the host, its engine, and its server. Defaults to slog.Default().
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider exposes a Host as a tunnel provider for in-process use: it opens tunnels without a loopback gRPC control plane.
Close stops the provider from accepting new tunnels; it does not tear down the Host or any already-open tunnel. Those end with their own connections, exactly as the gRPC path's streams do.
func (*Provider) OpenTunnelStream ¶
OpenTunnelStream opens a tunnel to peer and returns its local end. network is normalized here (udp/udp4/udp6 -> udp), so callers may pass any dialer network. peer carries the same meaning as on the gRPC path: a base64 public key in DERP mode, a host:port in stub mode.
ctx only bounds the call itself (allocation); the tunnel outlives it. The peer dial runs in the tunnel's serve goroutine, so the returned conn — not ctx — is the cancellation handle: closing it tears the tunnel down.
type SmuxTimeouts ¶
type SmuxTimeouts struct {
Interval time.Duration `yaml:"interval,omitempty"`
Timeout time.Duration `yaml:"timeout,omitempty"`
}
SmuxTimeouts tunes the smux keepalive shared by the relay and direct sessions. Timeout must be >= 2x Interval (validated in applyTimeouts).
type TLSConfig ¶
type TLSConfig struct {
Secure *bool `yaml:"secure,omitempty"`
CAFile string `yaml:"caFile,omitempty"`
}
TLSConfig mirrors the --tls.* flags. Secure is a pointer so an omitted "secure" (default true) is distinguishable from an explicit "secure: false".
type TimeoutsConfig ¶
type TimeoutsConfig struct {
PunchWait time.Duration `yaml:"punchWait,omitempty"`
Punch time.Duration `yaml:"punch,omitempty"`
Seed time.Duration `yaml:"seed,omitempty"`
Backoff time.Duration `yaml:"backoff,omitempty"`
DerpKeepAlive time.Duration `yaml:"derpKeepAlive,omitempty"`
Smux *SmuxTimeouts `yaml:"smux,omitempty"`
}
TimeoutsConfig tunes deployment-dependent timings. Zero values keep the built-in defaults; internal mechanism timeouts stay hardcoded.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
p2p
command
Command p2p runs the p2p host standalone: a gRPC control plane that opens tunnels to peer hosts over a DERP relay (or, in stub mode, bridges to a direct host:port).
|
Command p2p runs the p2p host standalone: a gRPC control plane that opens tunnels to peer hosts over a DERP relay (or, in stub mode, bridges to a direct host:port). |
|
internal
|
|
|
derpclient
Package derpclient implements the minimal client side of the DERP protocol (Tailscale's Designated Encrypted Relay for Packets) over the WebSocket transport, enough to act as a p2p rendezvous/relay client against the official derper binary.
|
Package derpclient implements the minimal client side of the DERP protocol (Tailscale's Designated Encrypted Relay for Packets) over the WebSocket transport, enough to act as a p2p rendezvous/relay client against the official derper binary. |
|
stun
Package stun implements the minimal client side of STUN (RFC 5389): a single binding request, enough to learn the public NAT mapping of a UDP socket for UDP hole punching.
|
Package stun implements the minimal client side of STUN (RFC 5389): a single binding request, enough to learn the public NAT mapping of a UDP socket for UDP hole punching. |
|
tests
|
|
|
e2e/helper
command
Command helper is the e2e suite's sidecar: the pieces a shell script would otherwise need extra tooling for.
|
Command helper is the e2e suite's sidecar: the pieces a shell script would otherwise need extra tooling for. |