Documentation
¶
Overview ¶
Package h2tunnel provides an embeddable, authenticated, resumable tunnel over HTTP/2, HTTP/3, WebTransport, MASQUE, and gRPC transports.
A Client acts as a concurrent net.Conn dialer. A Server authenticates every request and delegates target authorization and connection establishment to a mandatory TargetDialer. NewClient and NewServer perform no network I/O.
Minimal end-to-end setup (development TLS, closed-by-default service registry):
tlsConfig, _ := h2tunnel.SelfSignedTLSConfig("localhost")
auth, _ := h2tunnel.NewTokenAuthenticator("long-random-token")
dialer, _ := h2tunnel.NewStaticServiceDialer(map[string]h2tunnel.Service{
"ssh": {Network: h2tunnel.NetworkTCP, Address: "127.0.0.1:22"},
}, nil)
server, _ := h2tunnel.NewServer(h2tunnel.ServerOptions{
Transports: []h2tunnel.Transport{h2tunnel.TransportH2},
TLSConfig: tlsConfig,
Authenticator: auth,
Dialer: dialer,
})
go server.ListenAndServe(":8443")
client, _ := h2tunnel.NewClient(h2tunnel.ClientOptions{
Endpoint: "https://localhost:8443",
Credentials: credentials, // h2tunnel.NewTokenCredentials(...)
TLSConfig: &tls.Config{InsecureSkipVerify: true}, // self-signed dev cert
})
conn, _ := client.DialContext(ctx, h2tunnel.NetworkTCP, "ssh")
// conn is a net.Conn over the tunnel; use it like any TCP connection.
Dial errors match the exported sentinels: errors.Is(err, h2tunnel.ErrUnauthenticated) means the token was rejected (HTTP 407/401) and errors.Is(err, h2tunnel.ErrForbidden) means the target was denied (HTTP 403). See the README for production deployment guidance (CDN topology, token hygiene, and logical service registries).
Index ¶
- Constants
- Variables
- func PprofHandler() http.Handler
- func SelfSignedTLSConfig(host string) (*tls.Config, error)
- func Version() string
- type Authenticator
- type Client
- func (c *Client) Close() error
- func (c *Client) DialContext(ctx context.Context, network, target string) (net.Conn, error)
- func (c *Client) DialPacketContext(ctx context.Context, network, target string) (PacketConn, error)
- func (c *Client) ForceReconnect()
- func (c *Client) SetEventHandler(h ClientEventHandler)
- func (c *Client) Shutdown(ctx context.Context) error
- func (c *Client) Start(ctx context.Context) error
- func (c *Client) Stats() *ClientStats
- type ClientDialer
- type ClientEvent
- type ClientEventHandler
- type ClientEventKind
- type ClientOptions
- type ClientStats
- type ClientTuning
- type CredentialProvider
- type DialKind
- type DialRequest
- type Listeners
- type Network
- type PacketConn
- type PaddingTuning
- type Principal
- type QUICDialer
- type Server
- func (s *Server) Close() error
- func (s *Server) Handler() http.Handler
- func (s *Server) ListenAndServe(address string) error
- func (s *Server) Listeners() Listeners
- func (s *Server) Serve(listeners Listeners) error
- func (s *Server) SetEventHandler(h ServerEventHandler)
- func (s *Server) Shutdown(ctx context.Context) error
- func (s *Server) Stats() *ServerStats
- type ServerEvent
- type ServerEventHandler
- type ServerEventKind
- type ServerOptions
- type ServerStats
- type ServerTuning
- type Service
- type TargetDialer
- type Transport
- type TunnelError
Examples ¶
Constants ¶
const ( NetworkTCP = "tcp" NetworkUDP = "udp" )
const ( // TunnelDeathMaxRetries: redials exhausted, session abandoned. TunnelDeathMaxRetries = "max retries" // TunnelDeathAuthRejected: server authentication rejected (407/401). TunnelDeathAuthRejected = "auth rejected" // TunnelDeathPeerFIN: peer ended normally (EOF/END frame). TunnelDeathPeerFIN = "peer FIN" // TunnelDeathDataGap: the downlink seq gap is unrecoverable (the server-side // session may have been reclaimed by idle timeout or its window overwritten). TunnelDeathDataGap = "data gap" // TunnelDeathCanceled: the caller's context was canceled or the Client closed. TunnelDeathCanceled = "canceled" )
Client tunnel death reasons (common values of ClientEvent.Reason).
Variables ¶
Functions ¶
func PprofHandler ¶
PprofHandler returns a handler exposing the standard net/http/pprof endpoints (Go runtime CPU/heap/goroutine/block/mutex profiles). Zero configuration: it is safe to reuse with no arguments.
Note: these endpoints can dump process memory and goroutine stacks — expose them only on a trusted network surface (an admin port, a localhost reverse proxy, or behind authentication).
func SelfSignedTLSConfig ¶
SelfSignedTLSConfig returns a TLS config carrying a freshly generated self-signed certificate. The certificate is valid for host (default "localhost") and always for 127.0.0.1 / ::1, so clients can verify the connection when dialing loopback with a normal TLS config. Intended for development and protected origin links — use a publicly trusted certificate in production.
Types ¶
type Authenticator ¶
Authenticator authenticates an incoming tunnel request. Implementations must treat request headers as read-only and return a stable, non-empty Principal.ID.
func NewTokenAuthenticator ¶
func NewTokenAuthenticator(token string) (Authenticator, error)
NewTokenAuthenticator creates a constant-time pre-shared-token authenticator. Both the canonical Authorization header and the CDN-safe X-Auth-Token header are accepted.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an embeddable tunnel dialer. A Client may be used concurrently.
Example ¶
ExampleClient demonstrates embedding the client and dialing a logical service through the tunnel.
package main
import ()
func main() {
// credentials, _ := h2tunnel.NewTokenCredentials("long-random-token")
// client, _ := h2tunnel.NewClient(h2tunnel.ClientOptions{
// Endpoint: "https://tunnel.example.com",
// Credentials: credentials,
// })
// _ = client.Start(context.Background())
// conn, err := client.DialContext(context.Background(), h2tunnel.NetworkTCP, "ssh")
// if err != nil {
// if errors.Is(err, h2tunnel.ErrUnauthenticated) {
// // token rejected → switch to another token
// } else if errors.Is(err, h2tunnel.ErrForbidden) {
// // target rejected → change target or request authorization
// }
// }
// _ = conn
}
Output:
func NewClient ¶
func NewClient(options ClientOptions) (*Client, error)
NewClient validates options without performing network I/O.
func (*Client) DialContext ¶
DialContext establishes a TCP tunnel and returns only after the remote target and resume/2 handshake are ready.
network accepts "", "tcp", "tcp4", and "tcp6"; the address family only governs the local side of the API contract — the server dials the target with its own TargetDialer and may resolve it differently.
Dial errors match the exported sentinels via errors.Is: ErrUnauthenticated (HTTP 407/401, token rejected) and ErrForbidden (HTTP 403, target denied by policy).
func (*Client) DialPacketContext ¶
DialPacketContext establishes a connected UDP tunnel.
func (*Client) ForceReconnect ¶
func (c *Client) ForceReconnect()
ForceReconnect forces every active tunnel to abandon its current stream and redial immediately (session id and recovery window are preserved; the peer is unaware). Embedders call it proactively when a network-change event (NotifyAddrChange / NWPathMonitor / ConnectivityManager) arrives, skipping the passive latency of waiting for a heartbeat timeout. Whether a session actually terminates is still governed by AutoRedial / the redial cap.
func (*Client) SetEventHandler ¶
func (c *Client) SetEventHandler(h ClientEventHandler)
SetEventHandler registers the client event callback (replacing the previous one; passing nil stops dispatch). The callback runs on its own goroutine and panics are recovered, so it never affects the tunnel engine — but it should return quickly. See the dispatch constraints in events.go.
func (*Client) Shutdown ¶
Shutdown rejects new dials and waits for active tunnels to close naturally. When ctx expires the remaining tunnels keep draining in the background; call Close to force-close them (the internal waiter terminates once Close runs, since Close tears down every active tunnel).
func (*Client) Start ¶
Start initializes and verifies the transport. It is safe to call concurrently and is also invoked lazily by DialContext/DialPacketContext. A failed Start releases all transport resources and returns the error; the Client may be retried (state resets so Start can run again).
func (*Client) Stats ¶
func (c *Client) Stats() *ClientStats
Example ¶
ExampleClient_Stats demonstrates collecting tunnel stats (can be pushed to a monitoring system periodically).
package main
import ()
func main() {
// var client *h2tunnel.Client
// stats := client.Stats()
// promActiveTunnels.Set(float64(stats.ActiveDials.Load()))
// promUplinkBytes.Add(float64(stats.UplinkBytes.Load()))
}
Output:
type ClientDialer ¶
ClientDialer and QUICDialer let embedding applications control the underlying sockets (for example interface binding or Android VPN protect). Nil values keep the standard library / quic-go dialers.
type ClientEvent ¶
type ClientEvent struct {
Kind ClientEventKind
Target string // logical target at dial time
Network Network // tcp / udp
Transport Transport
// Attempt is meaningful only for Reconnecting events: the upcoming redial
// ordinal (1-based).
Attempt int
// Reason is a human-readable cause: for TunnelDied see the TunnelDeath*
// constants; for Reconnecting it is the underlying error text; empty otherwise.
Reason string
// Err is the underlying error (may be nil).
Err error
}
ClientEvent is the client event payload.
type ClientEventHandler ¶
type ClientEventHandler func(ClientEvent)
ClientEventHandler is the client event callback. It is invoked on its own goroutine; panics are recovered and never affect the tunnel engine. But the callback should return quickly — if you need blocking work (writing to a metrics queue, etc.), make it asynchronous yourself.
type ClientEventKind ¶
type ClientEventKind string
ClientEventKind identifies a client event type.
const ( // EventTunnelEstablished: the tunnel is ready (handshake done, target dialed). EventTunnelEstablished ClientEventKind = "tunnel_established" // EventTunnelDied: the tunnel died. Reason explains why (see the // TunnelDeath* constants and the ClientEvent.Reason docs). EventTunnelDied ClientEventKind = "tunnel_died" // EventReconnecting: after a stream break, redial the same session (resumable). EventReconnecting ClientEventKind = "reconnecting" // EventTargetDenied: the server denied the target with 403 (policy/registry lacks the service). EventTargetDenied ClientEventKind = "target_denied" )
type ClientOptions ¶
type ClientOptions struct {
// Server address (with scheme). https pairs with h2/h3/wt/masque, http with
// h2c; when Transport is empty it is inferred from the scheme.
Endpoint string
// Tunnel HTTP path (default "/"). MASQUE endpoints are nested under it:
// <path>.well-known/masque/{tcp,udp}/<host>/<port>/.
Path string
// Transport protocol; empty = inferred from the Endpoint scheme (https→h2, http→h2c).
Transport Transport
// Overrides the HTTP Host header (CDN multi-tenant origin-fetch scenarios).
Host string
// TLS config; used after a Clone so callers can safely reuse theirs. Not
// allowed with an http endpoint.
TLSConfig *tls.Config
// UtlxFingerprint enables utls fingerprint disguise: rewrites the TLS
// ClientHello into a real browser's shape (chrome/firefox/edge/safari/ios/qq)
// to resist JA3/JA4-based TLS fingerprinting. Empty = Go native crypto/tls.
// Only applies to h2/grpc (TLS over TCP): the TLS for h3/wt/masque is done
// inside quic-go and cannot be injected, so configuring it there errors in
// NewClient; the http endpoint (h2c) likewise.
UtlxFingerprint string
// Per-request authentication callback (typically from NewTokenCredentials).
Credentials CredentialProvider
Tuning ClientTuning
// Event callback (optional, injected at construction; or SetEventHandler at runtime).
EventHandler ClientEventHandler
Logger *slog.Logger
// Underlying TCP socket dialer (interface binding / VPN protect); nil = stdlib.
Dialer ClientDialer
// Underlying QUIC dialer (for h3/wt/masque); nil = quic-go default.
QUICDialer QUICDialer
}
ClientOptions configures an embeddable tunnel client. It intentionally has no local listen address or default target: callers pass the target per dial. ClientEventHandler is an optional client event callback (TunnelEstablished, TunnelDied, Reconnecting, TargetDenied), dispatched on its own goroutine with panics recovered. It can also be registered at runtime via Client.SetEventHandler.
type ClientStats ¶
type ClientStats struct {
// DialAttempts: number of dials initiated (TCP DialContext + UDP DialPacketContext).
DialAttempts atomic.Int64
// DialFailures: number of failed dials (handshake not ready, server rejected, etc.).
DialFailures atomic.Int64
// UplinkBytes: bytes the client sent (uplink through the tunnel).
UplinkBytes atomic.Int64
// DownlinkBytes: bytes the client received (downlink through the tunnel).
DownlinkBytes atomic.Int64
// ResumeReconnects: number of TCP/UDP session reconnects (same-session redial).
ResumeReconnects atomic.Int64
// ActiveDials: number of dials currently in progress.
ActiveDials atomic.Int64
}
ClientStats holds cumulative client statistics.
type ClientTuning ¶
type ClientTuning struct {
// Session-recovery ring window size (bytes). 0 = default 256KB, capped at
// 64MB (larger errors). Outage-recovery note: outage duration × downlink rate
// > window ⇒ the gap is unrecoverable and the session terminates. Raise it for
// long outages or high throughput.
SessionWindowBytes int
// CDN two-way heartbeat interval. 0 = default 25s; negative = disable the
// heartbeat entirely (only for direct origin links, no CDN/reverse proxy in
// between); positive values are clamped to [5s, 5min].
HeartbeatInterval time.Duration
// Backup-lane KEEPALIVE interval. 0 = default 15s; valid range 1s–1h, larger errors.
KeepaliveInterval time.Duration
// Data-plane handshake HANDSHAKE-ACK timeout. 0 = default 3s; valid range
// 1ms–30s, larger errors.
HandshakeTimeout time.Duration
// Number of hot standby connections (0 = disabled; unsupported by WT, must be 0).
StandbyConnections int
// UDP datagram uplink queue depth. 0 = default 200; valid range 0–65536,
// larger errors. When full, writes block until the write deadline (CLI drops);
// raising it absorbs bursts at the cost of memory.
DatagramQueueSize int
// Network-change self-heal: after redials exhaust (16), reset the retry
// counter and keep dialing (infinite revival), fitting mobile networks where
// "disconnected, waiting for the network to return"; false = terminate on
// exhaustion and dispatch a TunnelDied(max retries) event for the caller to
// decide whether to redial. Default false.
AutoRedial bool
// Per-attempt dial budget. 0 = unlimited (rely on the transport timeout); a
// positive value bounds only each attempt's connect + handshake phase (the
// timer stops once the tunnel is ready, so established streams are not
// bounded), used to tighten the give-up cadence during an outage (e.g. 10s,
// so 16 redials exhaust in ~3 minutes).
RedialBudget time.Duration
// Padding controls application-layer tunnel record shaping. Padding is
// removed by the peer and is never forwarded to the TCP or UDP target.
// The zero value disables padding.
Padding PaddingTuning
// MASQUE carrier selection (only valid with Transport=masque): "h3" = QUIC/UDP
// only; "h2" = TCP extended CONNECT only (the server must enable extended
// CONNECT, see the ClientTuning docs / README GODEBUG note); empty = automatic
// (h3 first, automatically pinned to h2 if the h3 dial fails). On UDP-blocked
// deployments, explicitly setting "h2" skips the first-connection QUIC handshake timeout.
MasqueALPN string
}
ClientTuning contains the small set of knobs that materially affect CDN reliability or per-session memory. Zero values select safe defaults.
type CredentialProvider ¶
CredentialProvider adds authentication data to one outgoing tunnel request. Protocol-owned headers are restored after this callback returns and therefore cannot be overridden by a credential provider.
func NewTokenCredentials ¶
func NewTokenCredentials(token string) (CredentialProvider, error)
NewTokenCredentials creates CDN-safe client token credentials.
type DialRequest ¶
type DialRequest struct {
Network Network
Target string
Transport Transport
Principal Principal
// Kind distinguishes why a dial happens. DialKindProbe is the handshake of a
// probe/warm-up lane: the server never establishes a real connection for it
// (probe lanes never dial); Target is only for authorization logging.
// Business tunnels are always DialKindBusiness.
Kind DialKind
}
DialRequest is passed to the server's policy-aware target dialer.
type Listeners ¶
type Listeners struct {
TCP net.Listener
QUIC net.PacketConn
}
Listeners groups the stream and QUIC listeners owned by Server.Serve.
type Network ¶
type Network string
Network identifies the application network transported through the tunnel.
type PacketConn ¶
type PacketConn interface {
net.Conn
net.PacketConn
}
PacketConn is a connected datagram tunnel that can be consumed as either a net.Conn or net.PacketConn.
type PaddingTuning ¶
type PaddingTuning struct {
// MinRecordBytes enables padding when greater than zero. It must be larger
// than the 16-byte resume record header and leave room for the random range.
MinRecordBytes int `json:"min_record_bytes"`
// MaxRecordBytes is the inclusive random upper bound. Zero derives a
// default 25% above MinRecordBytes. It must not exceed 65535.
MaxRecordBytes int `json:"max_record_bytes"`
}
PaddingTuning controls application-layer record shaping. When enabled, each stream record is randomly sized between MinRecordBytes and MaxRecordBytes. Datagram boundaries are preserved: small datagrams are padded, while a datagram already larger than MaxRecordBytes is sent as one intact record.
This does not promise a minimum IP packet size. TLS, HTTP/2, HTTP/3, QUIC, TCP segmentation, acknowledgements, retransmissions, CDNs, and the path MTU may split or coalesce application records after h2tunnel writes them.
type QUICDialer ¶
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is an embeddable, single-lifecycle tunnel server.
Example ¶
ExampleServer demonstrates embedding a tunnel server with a closed service registry.
package main
import ()
func main() {
// tlsConfig, _ := h2tunnel.SelfSignedTLSConfig("localhost")
// auth, _ := h2tunnel.NewTokenAuthenticator("long-random-token")
// dialer, _ := h2tunnel.NewStaticServiceDialer(map[string]h2tunnel.Service{
// "ssh": {Network: h2tunnel.NetworkTCP, Address: "127.0.0.1:22"},
// }, nil)
// server, _ := h2tunnel.NewServer(h2tunnel.ServerOptions{
// Transports: []h2tunnel.Transport{h2tunnel.TransportH2},
// TLSConfig: tlsConfig,
// Authenticator: auth,
// Dialer: dialer,
// })
// _ = server.ListenAndServe(":8443")
}
Output:
func NewServer ¶
func NewServer(options ServerOptions) (*Server, error)
NewServer validates options and creates a server without opening sockets or starting goroutines.
func (*Server) Handler ¶
Handler returns the tunnel handler for embedding in an existing HTTP server.
func (*Server) ListenAndServe ¶
ListenAndServe opens the listeners required by the configured transports. TCP and QUIC use the same numeric port, including when address uses port 0.
func (*Server) Listeners ¶
Listeners returns the listeners currently bound by Serve. Before Serve is called both members are nil; the QUIC member can report its actual port via LocalAddr() when port 0 is used (a WT-only server has no TCP listener, so this is the only way to discover the port). The return value is an internal reference for reading addresses only; callers must not close the listeners (ownership belongs to Serve).
func (*Server) Serve ¶
Serve owns the supplied listeners and blocks until all enabled transports stop. A failure in one listener stops its sibling before Serve returns.
func (*Server) SetEventHandler ¶
func (s *Server) SetEventHandler(h ServerEventHandler)
SetEventHandler registers the server event callback (replacing the previous one; passing nil stops dispatch).
func (*Server) Shutdown ¶
Shutdown stops new requests and waits for owned HTTP/QUIC servers to drain.
func (*Server) Stats ¶
func (s *Server) Stats() *ServerStats
type ServerEvent ¶
type ServerEvent struct {
Kind ServerEventKind
SessionID string
Target string // logical target; empty for AuthRejected events
Network Network // tcp / udp
Transport Transport
Principal Principal // request identity on successful auth; zero value for AuthRejected
RemoteAddr string // client source IP (clientIP fallback chain, spoofable, for logging only)
Reason string
Err error
}
ServerEvent is the server event payload.
type ServerEventHandler ¶
type ServerEventHandler func(ServerEvent)
ServerEventHandler is the server event callback. Invocation semantics match ClientEventHandler.
type ServerEventKind ¶
type ServerEventKind string
ServerEventKind identifies a server event type.
const ( // ServerEventSessionOpened: a new session was established (first join of a new session id). ServerEventSessionOpened ServerEventKind = "session_opened" // ServerEventSessionResumed: an existing session reconnected and resumed. ServerEventSessionResumed ServerEventKind = "session_resumed" // ServerEventSessionClosed: the session closed (peer END, idle reclaim, or server shutdown). ServerEventSessionClosed ServerEventKind = "session_closed" // ServerEventAuthRejected: authentication failed (valuable to SIEM: possible credential brute-force). ServerEventAuthRejected ServerEventKind = "auth_rejected" // ServerEventTargetDenied: the target was denied by policy (403 / unsupported network). ServerEventTargetDenied ServerEventKind = "target_denied" // ServerEventReplayDropped: the downlink replay gap is unrecoverable (the // replay window was overwritten; the client was disconnected too long); the // session's downlink coordinate is broken and the client will reopen it. ServerEventReplayDropped ServerEventKind = "replay_dropped" )
type ServerOptions ¶
type ServerOptions struct {
EventHandler ServerEventHandler
// Tunnel HTTP path (default "/"). MASQUE endpoints are nested under it:
// <path>.well-known/masque/{tcp,udp}/<host>/<port>/.
Path string
Transports []Transport
Networks []Network
TLSConfig *tls.Config
Authenticator Authenticator
Dialer TargetDialer
Tuning ServerTuning
Logger *slog.Logger
}
ServerOptions configures an embeddable tunnel server. Authenticator and Dialer are mandatory so a library server never becomes an open proxy by accident. ServerEventHandler is an optional server event callback (Session*, AuthRejected, TargetDenied, ReplayDropped), dispatched on its own goroutine with panics recovered. It can also be registered at runtime via Server.SetEventHandler.
type ServerStats ¶
type ServerStats struct {
// SessionsCreated: number of tunnel sessions established (new session id).
SessionsCreated atomic.Int64
// SessionsResumed: number of session resumptions (an existing session id rejoined).
SessionsResumed atomic.Int64
// SessionsActive: number of currently active sessions (approximate at read time).
SessionsActive atomic.Int64
// UplinkBytes: bytes the server received from clients (written to target).
UplinkBytes atomic.Int64
// DownlinkBytes: bytes the server sent to clients (from target).
DownlinkBytes atomic.Int64
// AuthFailures: number of failed-authentication requests.
AuthFailures atomic.Int64
}
ServerStats holds cumulative server statistics.
type ServerTuning ¶
type ServerTuning struct {
// Session-recovery ring window size (bytes). 0 = default 256KB, capped at
// 64MB (larger errors).
SessionWindowBytes int
// Session idle reclaim time. 0 = default 60s (a session with no active stream
// closes after this timeout).
SessionIdleTimeout time.Duration
// Padding controls server-to-client application-layer tunnel records.
// Configure both client and server to shape both traffic directions.
Padding PaddingTuning
}
Server performance tuning. Zero values select safe defaults.
type TargetDialer ¶
TargetDialer authorizes, resolves, and connects one requested target. For UDP it must return a connected datagram net.Conn (normally *net.UDPConn).
Probe/warm-up lanes (DialKindProbe) only appear in authorization logs; the server never calls Dialer for them — an implementation can skip establishing connections for probe-kind requests.
func NewStaticServiceDialer ¶
NewStaticServiceDialer creates a closed-by-default logical service registry. The input map and role slices are copied. Unknown services and role failures return ErrForbidden without revealing whether a service exists.
type Transport ¶
type Transport string
Transport identifies the HTTP transport carrying a tunnel stream.
type TunnelError ¶
type TunnelError struct {
// contains filtered or unexported fields
}
TunnelError means the server rejected tunnel establishment with an HTTP status code. Beyond the public sentinels, embedders can use errors.As(*TunnelError) to recover the original status for fine-grained handling.
func (*TunnelError) Error ¶
func (e *TunnelError) Error() string
func (*TunnelError) HTTPStatus ¶
func (e *TunnelError) HTTPStatus() int
HTTPStatus returns the HTTP status the server rejected with.
func (*TunnelError) Unwrap ¶
func (e *TunnelError) Unwrap() error
Source Files
¶
- api_types.go
- backup.go
- cert_gen.go
- client.go
- client_api.go
- client_resume.go
- client_resume_udp.go
- config.go
- connmanager.go
- doc.go
- events.go
- handshake.go
- packet_conn.go
- padding.go
- pool.go
- pprof.go
- protocol.go
- resumeframe.go
- ring.go
- routing.go
- server.go
- server_api.go
- session.go
- sharecrypto.go
- stats.go
- transport_grpc.go
- transport_h2.go
- transport_h3.go
- transport_masque.go
- transport_masque_client.go
- transport_wt.go
- uri.go
- utls_client.go