A self-hosted, automated proxy core written in Rust. Designed for "seamless proxying" with automatic speed testing, clustering, switching, and self-healing.
- Multi-protocol Support: Shadowsocks (AEAD, AEAD-2022)
- Smart Routing: Domain/IP-based rules with external ruleset support
- Auto Failover: Automatic node switching on failure with health tracking
- Auto Clustering: Latency-based node grouping for optimal selection
- Happy Eyeballs: Concurrent connection attempts for faster establishment
- DNS Integration: Built-in DNS server with domain-IP mapping
# Build
cargo build --release
# Run with config
./target/release/proxy-core -c config.ymlFull documentation available at: https://perishcode.github.io/RustProxyCore/
listen: "127.0.0.1:7890"
mode: rule # direct | global | rule | auto
dns:
listen: "127.0.0.1:5353"
upstream: system
subscriptions:
- key: airport-1
url: https://airport.com/sub
rules:
- [DOMAIN-SUFFIX, google.com, PROXY]
- [DOMAIN-SUFFIX, baidu.com, DIRECT]
- [FINAL, "", PROXY]| Mode | Description |
|---|---|
direct |
All traffic connects directly |
global |
All traffic through proxy |
rule |
Route based on rules (default) |
auto |
Smart mode with clustering and learning |
src/
├── main.rs # CLI entry point
├── lib.rs # Module exports
│
├── core/ # Foundation layer (no business deps)
│ ├── error.rs # Unified error types
│ ├── config/ # Configuration parsing
│ │ ├── mod.rs # Config, Settings
│ │ ├── mode.rs # ProxyMode
│ │ ├── outbound.rs # OutboundConfig
│ │ ├── health.rs # HealthConfig
│ │ └── pool.rs # PoolConfig
│ └── types/ # Data types
│ ├── address.rs # Address
│ ├── proxy.rs # Proxy
│ └── rule.rs # MatchRule, MatchContext
│
├── protocol/ # Protocol layer
│ ├── subscription.rs # SS subscription parsing
│ └── sniffer/ # Protocol sniffing
│ ├── tls.rs # TLS SNI extraction
│ └── http.rs # HTTP Host extraction
│
├── dns/ # DNS layer
│ ├── server.rs # UDP DNS server
│ ├── mapping.rs # IP-domain mapping
│ └── resolver.rs # Domain resolver
│
├── node/ # Node layer
│ ├── registry.rs # Global node registry
│ └── health.rs # Node health cache
│
├── rule/ # Rule layer
│ ├── engine.rs # Rule matching engine
│ ├── loader.rs # Ruleset loader
│ └── learned.rs # Dynamic learned rules
│
├── outbound/ # Outbound layer (pure implementations)
│ ├── traits.rs # Outbound trait, BoxedStream
│ ├── direct.rs # DirectOutbound
│ ├── shadowsocks.rs # ShadowsocksOutbound
│ ├── group.rs # GroupOutbound
│ └── reject.rs # RejectOutbound
│
├── relay/ # Relay layer
│ └── mod.rs # relay(), relay_with_validation()
│
├── routing/ # Routing layer
│ ├── manager.rs # OutboundManager
│ └── happy_eyeballs.rs # Concurrent connection
│
├── learning/ # Learning layer (auto mode)
│ ├── event.rs # Event definitions + EventEmitter
│ ├── state.rs # Learning state structures
│ ├── reader.rs # StateReader (read-only)
│ ├── manager.rs # StateManager, LearningSystem
│ ├── fingerprint.rs # Node stable fingerprint
│ ├── persistence.rs # SQLite persistence
│ ├── exception.rs # Service exception definitions
│ ├── health.rs # System health detection
│ └── probe.rs # Recovery probe runner
│
├── inbound/ # Inbound layer
│ └── socks5.rs # SOCKS5 protocol handler
│
└── runtime/ # Runtime configuration
└── mod.rs
┌─────────────────────────────────────────────────────────────────┐
│ Business Layer (emit events) │
│ Socks5Handler / OutboundManager / ProbeTask │
└─────────────────────────────────────────────────────────────────┘
│ emit() │ read()
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ EventEmitter │ StateReader │ StateManager │
│ (send events) │ (read-only) │ (single writer) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ LearnedState │
│ (domain_node_map, node_health, failure_correlations) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ SQLite Persistence │
│ (domain_mapping, node_health, correlation) │
└─────────────────────────────────────────────────────────────────┘
Key Features:
- Event-driven learning from actual connection results
- Failure correlation analysis (skip related failing nodes)
- SQLite persistence (survive restarts)
- Recovery probe for cooldown nodes
- Service exception feedback (no healthy nodes, subscription stale, etc.)
┌─────────────────┐ ┌──────────────┐ ┌────────────────┐
│ SOCKS5 Client │────▶│ Socks5 In │────▶│ RuleEngine │
└─────────────────┘ └──────────────┘ └────────────────┘
│
┌────────────────────────────┼────────────────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ DIRECT │ │ GROUP │ │ REJECT │
└─────────────┘ └──────────────┘ └──────────────┘
│ │
│ ┌────────┴────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Target │ │ SS Node 1 │ │ SS Node 2 │
└─────────────┘ └─────────────┘ └─────────────┘
| Component | Technology |
|---|---|
| Core | Rust + Tokio |
| Protocol | shadowsocks-rust |
| DNS | hickory-dns |
| Storage | rusqlite |
| E2E Test | pnpm + vitest |
- Rust 1.75+
- pnpm 10+
- Node.js 20+ (for E2E tests)
# Build
cargo build
# Run tests
cargo test
# Run with debug logging
RUST_LOG=debug cargo run -- -c config.yml
# Format code
cargo fmt
# Lint
cargo clippy
# E2E tests
pnpm test
# E2E tests with real network
PROXY_E2E_REAL=1 pnpm test- Rust Edition: 2021
- Max Line Width: 100 characters
- Indentation: 4 spaces
- Lints: clippy pedantic + nursery enabled
- Error Handling: Typed errors (
ProxyError,ConnectionError, etc.) - Async Runtime: Tokio
[lints.rust]
unsafe_code = "forbid"
[lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }-
Module Organization
core/- Foundation layer (error, config, types)protocol/- Protocol parsing (subscription, sniffer)inbound/- Incoming connection handlersoutbound/- Outgoing connection handlersrelay/- Bidirectional data relayrouting/- Route decision (OutboundManager, Happy Eyeballs)learning/- Smart learning system (auto mode)node/- Node management and health trackingrule/- Rule matching enginedns/- DNS server and resolution
-
Error Handling
- Use typed errors from
src/core/error.rs - Avoid
anyhow::bail!in library code - Let callers decide presentation
- Use typed errors from
-
Configuration
- All runtime constants should be configurable
- Use
Arc<Runtime>for shared configuration - Defaults defined in
types/config/
-
Testing
- Unit tests:
cargo test - E2E tests:
pnpm test(vitest) - Real network tests require
PROXY_E2E_REAL=1
- Unit tests:
MIT