scorpiox-frp

Pure C FRP tunneling client — compatible with frps v0.52+. TCP, HTTP, HTTPS, STCP proxy types with Yamux multiplexing, AES-128-CFB encryption, and auto-reconnect. No Go, no OpenSSL.

FRP TCP HTTP HTTPS STCP TLS Port 7000

Overview

scorpiox-frp is a pure C implementation of an FRP (Fast Reverse Proxy) client. It speaks the native FRP wire protocol — JSON messages over length-prefixed binary frames — and connects to any standard frps server v0.52 or later. Unlike the official Go client, scorpiox-frp compiles to a single static binary with zero runtime dependencies. It uses mbedTLS for AES-128-CFB encryption on the control channel and implements Yamux session multiplexing for efficient connection handling.

Source Files

source layoutscorpiox/scorpiox-frp.c # CLI entry point, arg parsing, proxy config scorpiox/libsxnet/sx_frp.c # FRP protocol engine, Yamux, auth, crypto scorpiox/libsxnet/sx_frp.h # Public API and data structures

Protocol Support

scorpiox-frp supports six protocol types for tunneling traffic through a remote frps server. Each proxy type handles a different traffic pattern.

Protocol Description Use Case
TCP Raw TCP port forwarding SSH, databases, custom services
HTTP HTTP reverse proxy with virtual hosting Web apps, APIs, dev servers
HTTPS TLS-terminated HTTPS proxy Secure web services
STCP Secret TCP — visitor must know secret key Private services, peer-to-peer
TLS Optional TLS wrap on control channel to frps Secure control plane
FRP Native wire protocol (JSON + length-prefixed frames) Internal frps communication

Architecture

The client establishes a single control connection to frps, authenticates with MD5-hashed token, then multiplexes all proxy traffic over Yamux sessions through that connection.

┌─────────────────┐ ┌──────────────────┐ │ Local Service │ │ Remote User │ │ (localhost:80) │ │ (internet) │ └────────┬────────┘ └────────┬─────────┘ ┌─────────────────┐ AES-128-CFB ┌──────────────────┐ │ scorpiox-frp │════════════════════│ frps │ │ (frpc client) │ Yamux mux │ (v0.52+ server) │ └─────────────────┘ Port 7000 └──────────────────┘ Control flow: 1. TCP connect to frps:7000 2. Send TypeLogin with MD5(token + timestamp) 3. Receive TypeLoginResp — session established 4. Start heartbeat goroutine (30s interval) 5. Register proxies: TypeNewProxy for each config 6. On TypeReqWorkConn: open Yamux stream → connect local

Yamux Multiplexing

All traffic shares a single TCP connection to frps. Yamux (Yet another Multiplexer) creates virtual streams over this connection, each identified by a 32-bit stream ID. This avoids the overhead of separate TCP connections per proxy while maintaining flow control per stream.

Wire Protocol

Each FRP message is a length-prefixed JSON frame:

frp frame format┌──────────┬──────────┬─────────────────────────┐ type (1B) len (8B) JSON payload (len bytes) └──────────┴──────────┴─────────────────────────┘ # Message types: TypeLogin = 'o' # Client login request TypeLoginResp = '1' # Server login response TypeNewProxy = 'p' # Register a proxy TypeNewProxyResp = '2' # Proxy registration ack TypeReqWorkConn = 'r' # Server requests work connection TypeNewWorkConn = 'w' # Client opens work connection TypePing = 'h' # Heartbeat ping TypePong = '4' # Heartbeat pong

Features

FRP Wire Protocol

JSON over length-prefixed frames. Native frps v0.52+ compatibility without the Go runtime.

MD5 Auth

Token + timestamp hashed with MD5 for frps authentication. Same algorithm as the official client.

AES-128-CFB Crypto

Control stream encryption via mbedTLS. No OpenSSL dependency — bundled at compile time.

Yamux Multiplexing

Session multiplexing over a single TCP connection. Efficient stream management with flow control.

4 Proxy Types

TCP, HTTP, HTTPS, STCP — custom domains, subdomains, secret keys.

Auto-Reconnect

Exponential backoff reconnection. Survives network interruptions without manual restart.

Heartbeat Keep-Alive

Periodic ping/pong with frps. Detects dead connections and triggers auto-reconnect.

Optional TLS Transport

Wrap the entire control connection in TLS for frps servers that require encrypted transport.

Connection Pooling

Pre-established work connections reduce latency for new proxy requests from frps.

Custom Domains

Route HTTP/HTTPS traffic by domain name. Use custom_domains or subdomain configuration.

Zero Dependencies

Pure C with mbedTLS compiled in. Single static binary — no Go, no OpenSSL, no runtime.

Static Binary

Cross-compiled for Linux, macOS, Windows. Drop in and run — no installation required.

Usage Examples

Expose a local web server via HTTP

http proxyscorpiox-frp --server your-server.com:7000 --token my-secret-token --type http --local-port 8080 --custom-domain app.example.com

Forward SSH access through NAT

tcp proxy — sshscorpiox-frp --server frps.example.com:7000 --token my-secret-token --type tcp --local-port 22 --remote-port 6022 # Then connect from anywhere: ssh -p 6022 user@frps.example.com

HTTPS proxy with subdomain

https proxyscorpiox-frp --server frps.example.com:7000 --token my-secret-token --type https --local-port 443 --subdomain myapp # Accessible at: https://myapp.frps.example.com

Secret TCP (peer-to-peer)

stcp proxy# Server side (machine behind NAT): scorpiox-frp --server frps.example.com:7000 --token my-secret-token --type stcp --local-port 3306 --sk shared-secret-key --name my-database # Visitor side (connect without frps exposing a port): # Uses the same --sk to authenticate with frps relay

TLS-wrapped control connection

tls transportscorpiox-frp --server frps-secure.example.com:7000 --token my-secret-token --tls --type tcp --local-port 80 --remote-port 8080

Configuration

scorpiox-frp reads configuration from CLI flags. All flags can also be set as environment variables with the SCORPIOX_FRP_ prefix.

Flag Default Description
--server 127.0.0.1:7000 frps server address (host:port)
--token Authentication token (shared with frps)
--type tcp Proxy type: tcp, http, https, stcp
--local-port Local service port to expose
--local-ip 127.0.0.1 Local bind address for the proxied service
--remote-port Remote port on frps (TCP proxy type only)
--custom-domain Custom domain for HTTP/HTTPS proxies
--subdomain Subdomain for HTTP/HTTPS proxies
--name auto Proxy name (must be unique on frps)
--sk Secret key for STCP proxy type
--tls off Enable TLS on control connection
--pool-count 1 Number of pre-established work connections

Security

Authentication

scorpiox-frp authenticates with frps using the same MD5 scheme as the official client. The token is hashed with the current timestamp: MD5(token + timestamp). This prevents replay attacks since the timestamp window is validated server-side.

Encryption

The control stream is encrypted with AES-128-CFB using a key derived from the shared token. This is implemented via mbedTLS, compiled statically into the binary. The encryption covers all control messages (login, proxy registration, heartbeats) but not the data stream — that's handled by the application-layer protocol (e.g., HTTPS, SSH).

encryption flowtoken = "my-secret-token" key = MD5(token) # 16 bytes → AES-128 key iv = MD5(key) # 16 bytes → CFB IV cipher = AES-128-CFB(key, iv) # Stream cipher on control channel

TLS Transport

When --tls is enabled, the entire connection (control + data) is wrapped in TLS before the FRP protocol layer. This provides end-to-end encryption including work connections. Use this when the network between scorpiox-frp and frps is untrusted.

vs. Official Go Client

Aspect scorpiox-frp (C) Official frpc (Go)
Language Pure C Go
Binary size ~200 KB static ~15 MB
Memory usage ~2 MB RSS ~20 MB RSS
Dependencies Zero (mbedTLS embedded) Go runtime, modules
Startup time <1 ms ~50 ms
TLS library mbedTLS (static) Go crypto/tls
Multiplexing Yamux Yamux
Proxy types TCP, HTTP, HTTPS, STCP TCP, HTTP, HTTPS, STCP, SUDP, XTCP, TCPMUX
Config format CLI flags TOML / CLI
frps compatibility v0.52+ v0.52+