The visitor system enables client-to-client connections in frp, allowing one frpc instance (the "visitor") to connect to services exposed by another frpc instance (the "server" side proxy). This architecture supports three visitor types: STCP (Secure TCP), XTCP (P2P TCP with NAT traversal), and SUDP (Secure UDP). Visitors work in conjunction with corresponding proxy types to establish authenticated, optionally encrypted connections between clients.
For information about the server-side proxy configurations that visitors connect to, see Secure Proxies (STCP/SUDP). For details on the NAT hole punching mechanism used by XTCP, see NAT Traversal and XTCP.
The visitor system consists of visitor instances that connect to the frps server, authenticate using a shared secret key, and establish tunnels to target proxies. Unlike traditional proxies that expose local services to external users, visitors consume services from other frpc instances.
Visitor Architecture Diagram
Sources: client/visitor/visitor.go54-58 client/visitor/visitor_manager.go34-47 server/controller/resource.go28-64 server/visitor/visitor.go37-41
All visitor types implement the Visitor interface defined in client/visitor/visitor.go54-58:
| Method | Purpose |
|---|---|
Run() error | Starts the visitor, listening for user connections |
AcceptConn(net.Conn) error | Accepts a connection transferred from another visitor or plugin |
Close() | Stops the visitor and cleans up resources |
The BaseVisitor struct client/visitor/visitor.go115-124 provides common functionality:
ClientCommonConfigHelper interface providing server connection and message transportbindPort > 0)netpkg.InternalListener for connection redirectionHelper Interface Diagram
Sources: client/visitor/visitor.go39-51 client/visitor/visitor_manager.go202-228
STCPVisitor establishes secure TCP connections through the frps server. It listens on a local port and forwards connections to the target STCP proxy after authentication.
STCP Connection Flow
Sources: client/visitor/stcp.go27-85 client/visitor/visitor.go154-190
Key Implementation Details:
dialRawVisitorConn to reach the server and wrapVisitorConn for transport features.msg.NewVisitorConn handshake, including the generation of the SignKey using util.GetAuthKey(cfg.SecretKey, now).XTCPVisitor uses NAT hole punching to establish peer-to-peer connections, bypassing the server for data transfer. It supports both KCP and QUIC protocols.
XTCP P2P Connection Establishment
Sources: client/visitor/xtcp.go44-111 client/visitor/xtcp.go252-280
Tunnel Session Types:
Key Implementation Details:
KeepTunnelOpen is enabled, this goroutine periodically checks the tunnel health using a rate.Limiter to prevent excessive retry attempts.nathole.PreCheck and address exchange via the server.FallbackTo is configured and the P2P tunnel fails within FallbackTimeoutMs, the visitor transfers the connection to a fallback visitor (typically STCP).SUDPVisitor provides secure UDP forwarding through the server.
SUDP Architecture
Sources: client/visitor/sudp.go33-43 client/visitor/sudp.go70-111
The SUDP visitor operates as follows:
dispatcher.sendCh, then calls getNewVisitorConn() to establish a tunnel to the server.workConnReaderFn: Reads msg.UDPPacket or msg.Ping from the tunnel.workConnSenderFn: Writes packets from the local sendCh to the tunnel.The server maintains a Manager to handle incoming visitor connections and route them to the appropriate proxy listeners.
Server Visitor Manager
| Entity | Role | Source |
|---|---|---|
Manager | Manages listenerBundle maps indexed by proxy name. | server/visitor/visitor.go37-41 |
listenerBundle | Stores the InternalListener, secret key, and allowed users. | server/visitor/visitor.go30-34 |
NewConn() | Validates authentication and puts the connection into the listener. | server/visitor/visitor.go66-104 |
Wire Protocol Support:
Incoming connections are wrapped in a wireProtocolConn server/visitor/visitor.go106-113 which preserves the wireProtocol version (v1 or v2) for the underlying proxy to handle correctly.
Sources: server/visitor/visitor.go49-64 server/visitor/visitor.go66-104
The client-side Manager handles the lifecycle of all configured visitors.
Manager Logic
net.Conn to its AcceptConn method.Sources: client/visitor/visitor_manager.go34-47 client/visitor/visitor_manager.go134-182
Visitors use wrapVisitorConn client/visitor/visitor.go192-206 to apply transport-layer features before bridging data:
UseEncryption is true, it wraps the connection using libio.WithEncryption with the SecretKey.UseCompression is true, it wraps the connection using libio.WithCompressionFromPool.SUDP Protocol Bridging:
When the proxy and visitor use different wire protocol versions (e.g., Proxy v1 and Visitor v2), the server performs transcoding of msg.UDPPacket and msg.Ping messages.
Sources: server/proxy/sudp_test.go29-52 server/proxy/sudp_test.go54-77