RepoPilotOpen in app →

eycorsican/leaf

A versatile and efficient proxy framework.

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 2w ago
  • 7 active contributors
  • Apache-2.0 licensed
Show all 6 evidence items →
  • CI configured
  • Tests present
  • Single-maintainer risk — top contributor 93% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/eycorsican/leaf)](https://repopilot.app/r/eycorsican/leaf)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/eycorsican/leaf on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: eycorsican/leaf

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/eycorsican/leaf shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 2w ago
  • 7 active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Single-maintainer risk — top contributor 93% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live eycorsican/leaf repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/eycorsican/leaf.

What it runs against: a local clone of eycorsican/leaf — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in eycorsican/leaf | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 41 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>eycorsican/leaf</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of eycorsican/leaf. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/eycorsican/leaf.git
#   cd leaf
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of eycorsican/leaf and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "eycorsican/leaf(\\.git)?\\b" \\
  && ok "origin remote is eycorsican/leaf" \\
  || miss "origin remote is not eycorsican/leaf (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "leaf/src/app/mod.rs" \\
  && ok "leaf/src/app/mod.rs" \\
  || miss "missing critical file: leaf/src/app/mod.rs"
test -f "leaf/src/app/dispatcher.rs" \\
  && ok "leaf/src/app/dispatcher.rs" \\
  || miss "missing critical file: leaf/src/app/dispatcher.rs"
test -f "leaf/src/proxy/chain/mod.rs" \\
  && ok "leaf/src/proxy/chain/mod.rs" \\
  || miss "missing critical file: leaf/src/proxy/chain/mod.rs"
test -f "leaf/src/config/mod.rs" \\
  && ok "leaf/src/config/mod.rs" \\
  || miss "missing critical file: leaf/src/config/mod.rs"
test -f "leaf/src/app/inbound/mod.rs" \\
  && ok "leaf/src/app/inbound/mod.rs" \\
  || miss "missing critical file: leaf/src/app/inbound/mod.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 41 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~11d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/eycorsican/leaf"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Leaf is a Rust-based proxy framework that handles inbound and outbound traffic routing across multiple protocols (SOCKS5, Shadowsocks, Trojan, VMess, Vless) and transports (TLS, QUIC, WebSocket, AMux). It provides transparent proxying via TUN interfaces on Linux/macOS/Windows/iOS/Android and includes traffic control features like proxy chaining, failover with health checks, and a custom Multi-path Transport Protocol (MPTP) for traffic aggregation. Monorepo with workspace members: leaf/ is the core framework (src/app/ contains dispatcher, inbound/outbound managers, DNS client, TUN listener, API server); leaf-cli/ wraps it as a CLI tool; leaf-ffi/ exposes C bindings; leaf-plugins/shadowsocks/ is a protocol plugin. Core routing logic lives in leaf/src/app/dispatcher.rs, transport negotiation in leaf/src/app/inbound/ and leaf/src/app/outbound/.

👥Who it's for

Network engineers and security researchers building privacy/anti-censorship infrastructure, plus developers integrating proxy functionality into applications via the C FFI bindings in leaf-ffi. Users need flexibility across multiple proxy protocols and transport layers without proprietary lock-in.

🌱Maturity & risk

Actively maintained with CI/CD pipelines (GitHub Actions in .github/workflows/ci.yml and release.yml), comprehensive protocol support, and a monorepo structure suggesting production use. The 1.4M lines of Rust code and dual leaf-cli + leaf-ffi packages indicate maturity, though commit recency should be verified via git history.

Single maintainer (eycorsican) creates succession risk. The codebase spans 6 workspace members and multiple transport layers (TLS, QUIC, custom MPTP), increasing surface area. Cross-compilation via Cross.toml and platform-specific code (TUN for 5 OSes, NF for Windows) requires deep testing. Dependencies on cryptographic protocols (Shadowsocks, Trojan, Reality) demand security updates.

Active areas of work

Active development on MPTP (Multi-path Transport Protocol) with dedicated architecture and usage docs in docs/mptp_*.md. Workspace includes a Shadowsocks plugin indicating protocol-as-plugin architecture. CI runs on every commit; release pipeline is automated. No specific PR/issue data visible, but structure suggests ongoing protocol and transport layer expansion.

🚀Get running

git clone https://github.com/eycorsican/leaf.git
cd leaf
cargo build -p leaf-cli --release
./target/release/leaf --help

Daily commands:

# Build CLI
cargo build -p leaf-cli --release

# Run with config (config format inferred from app/mod.rs)
./target/release/leaf -c config.json

# Check help
./target/release/leaf --help

# Build FFI for C integration
cargo build -p leaf-ffi --release

🗺️Map of the codebase

  • leaf/src/app/mod.rs — Core application runtime and initialization; every contributor must understand how the proxy framework bootstraps and manages the main event loop
  • leaf/src/app/dispatcher.rs — Central request router that directs traffic through inbound/outbound chains; essential for understanding request flow and policy application
  • leaf/src/proxy/chain/mod.rs — Proxy chain abstraction that sequences protocol handlers; critical for implementing protocol pipelines and transport layering
  • leaf/src/config/mod.rs — Configuration system that parses and validates proxy rules, routes, and protocol stacks; all feature flags and policy logic originate here
  • leaf/src/app/inbound/mod.rs — Inbound listener management; handles socket acceptance and protocol negotiation for incoming connections
  • leaf/src/app/outbound/mod.rs — Outbound connection pooling and selector logic; manages protocol instantiation and failover behavior
  • Cargo.toml — Workspace manifest defining feature gates, optional protocol implementations, and platform-specific dependencies

🛠️How to make changes

Add a New Proxy Protocol (e.g., new inbound handler)

  1. Create protocol-specific handler directory under leaf/src/proxy/ (e.g., leaf/src/proxy/newprotocol/inbound/mod.rs) implementing the protocol's stream/datagram traits (leaf/src/proxy/newprotocol/inbound/mod.rs)
  2. Register the new inbound handler factory in the inbound manager's build logic (leaf/src/app/inbound/mod.rs)
  3. Add configuration schema entry to support the new protocol in JSON/TOML config files (leaf/src/config/json/config.rs)
  4. Add feature gate in Cargo.toml if the protocol should be optional (Cargo.toml)

Add a New Routing Rule Type

  1. Extend the rule matcher enum in the router module to support the new rule criterion (leaf/src/app/router.rs)
  2. Implement the matching logic (domain, IP, port, country, etc.) in the router's evaluate function (leaf/src/app/router.rs)
  3. Update the configuration schema to accept the new rule syntax in JSON format (leaf/src/config/json/config.rs)

Add a New Transport Layer (e.g., WebSocket, QUIC variant)

  1. Create transport module under leaf/src/proxy/ with separate inbound and outbound implementations (leaf/src/proxy/newtransport/inbound/mod.rs)
  2. Implement the transport wrapper trait that composes with existing protocol handlers (leaf/src/proxy/newtransport/mod.rs)
  3. Register transport factory in both inbound and outbound managers (leaf/src/app/inbound/mod.rs)
  4. Add transport configuration options to JSON schema (leaf/src/config/json/config.rs)

Add a New Statistics or Monitoring Metric

  1. Define metric structure in the stat manager module (leaf/src/app/stat_manager.rs)
  2. Instrument key code paths (dispatcher, chain handlers) to record measurements (leaf/src/app/dispatcher.rs)
  3. Expose metrics through the API server endpoint (leaf/src/app/api/api_server.rs)

🔧Why these technologies

  • Tokio async runtime (Rust) — Enables efficient handling of thousands of concurrent connections with minimal thread overhead; necessary for proxy workloads with high concurrency and low latency sensitivity
  • Protocol Buffers (protobuf) — Compact serialization for geosite databases and selector cache persistence; enables efficient rule evaluation and failover state management
  • OpenSSL / rustls — Required for TLS/QUIC transport layers supporting Trojan, VLESS, and other encrypted protocols; rustls provides pure-Rust alternative where available
  • Tun/TAP (lwip, smolt) — Transparent proxying via fake IP layer; essential for system-wide traffic interception on Linux, macOS, and mobile platforms without per-app configuration
  • FFI bindings (C interface) — Enables embedding leaf in mobile apps (iOS/Android) and other language ecosystems without rewriting core logic

⚖️Trade-offs already made

  • Chain-based architecture vs. monolithic protocol handlers

    • Why: Allows mixing arbitrary protocol layers (SOCKS5 → TLS → QUIC → Shadowsocks) without exponential code duplication
    • Consequence: Slightly higher latency per hop and complex state management; mitigated by zero-copy design and protocol pipelining
  • Async/await Rust vs. sync thread pools

    • Why: Rust futures provide memory safety guarantees and avoid callback hell; single thread per core scales better for I/O workloads
    • Consequence: Steeper learning curve for contributors; all I/O must use async APIs, cannot use blocking system calls in hot paths
  • Rule-based routing (domain/IP/geo) vs. flow inspection

    • Why: Sim
    • Consequence: undefined

🪤Traps & gotchas

Config format: No JSON schema visible in repo; infer from app/mod.rs parsing logic. TUN permissions: Linux/macOS/Windows/iOS require elevated privileges; test on actual device. Cross-compilation: Cross.toml needed for non-native targets; cargo build alone may not work for ARM. Plugin loading: Plugins are compiled as separate crates; dynamic loading path not explicit—check leaf-plugins/ structure. DNS race condition: leaf/src/app/dns/client/tests.rs exists but coverage unknown; concurrent resolution may have edge cases.

🏗️Architecture

💡Concepts to learn

  • TUN Device / Transparent Proxying — Leaf's killer feature is system-wide traffic interception via leaf/src/app/inbound/tun_listener.rs; understanding TUN vs. TPROXY vs. NetFilter is critical to using Leaf effectively on different OSes.
  • SOCKS5 Protocol — Core inbound/outbound protocol in Leaf; the abstraction layer in leaf/src/app/inbound/ and leaf/src/app/outbound/ assumes SOCKS5-compatible semantics for address/port routing.
  • Multi-path Transport Protocol (MPTP) — Leaf's proprietary aggregation protocol documented in docs/mptp_architecture.md and docs/mptp_usage.md; enables bandwidth bonding across multiple transports for higher throughput.
  • Protocol Plugins / Trait-based Abstraction — Leaf uses Rust traits for inbound/outbound handlers, allowing plugins like leaf-plugins/shadowsocks/ to extend without core changes; critical for understanding how to add new protocols.
  • Async/Await with Tokio — All I/O in Leaf is async (tokio runtime); understanding async fn, spawn, and select! is required to modify dispatcher, DNS client, or listener code.
  • gRPC & Protocol Buffers — Leaf exposes runtime control via gRPC in leaf/src/app/api/api_server.rs and uses .proto files (e.g., selector_cache.proto); needed for API extensions or monitoring integrations.
  • Health Check & Failover — Leaf's outbound manager implements health checks and failover routing (leaf/src/app/outbound/selector.rs); understanding ICMP/TCP probes and weighted selection is key to configuring reliable proxy chains.
  • shadowsocks/shadowsocks-rust — Foundational Shadowsocks implementation in Rust; Leaf's Shadowsocks plugin likely builds on or parallels this
  • v2ray/v2ray-core — Similar multi-protocol proxy framework (Go); competitor with VMess/Vless support that Leaf partially implements
  • trojan-gfw/trojan — Original Trojan protocol reference implementation; Leaf's Trojan inbound/outbound comply with this spec
  • xray-project/xray-core — V2Ray fork with Reality obfuscation; Leaf lists Reality as unsupported outbound, so this shows the protocol Leaf may add
  • gVisor/gvisor — Lightweight userspace network stack (netstack); Leaf uses similar patterns for TUN packet handling via lwip/smoltcp

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for DNS client and resolver components

The DNS subsystem (leaf/src/app/dns/client.rs, leaf/src/app/dns/client/types.rs, and leaf/src/common/resolver.rs) has a test file at leaf/src/app/dns/client/tests.rs but lacks comprehensive integration tests. Given DNS is critical for routing decisions and domain-based filtering, adding tests for DNS caching, failure handling, and interaction with fake_dns.rs would improve reliability and catch regressions.

  • [ ] Examine existing tests in leaf/src/app/dns/client/tests.rs to understand current coverage
  • [ ] Add tests for DNS query timeouts and retry logic in leaf/src/app/dns/client.rs
  • [ ] Add tests for fake DNS integration between leaf/src/app/fake_dns.rs and the resolver
  • [ ] Test DNS sniffing behavior in leaf/src/common/dns_sniff.rs
  • [ ] Add end-to-end test for DNS client with different resolver configurations

Add protocol-specific fuzz tests for inbound handlers

The inbound listeners (leaf/src/app/inbound/network_listener.rs, tun_listener.rs, cat_listener.rs) handle multiple proxy protocols (HTTP, SOCKS5, Shadowsocks, Trojan). There are no apparent fuzzing tests for parsing malformed protocol data. Adding fuzz tests would catch crashes and edge cases in protocol parsing before they reach production.

  • [ ] Set up cargo-fuzz in the leaf crate with fuzzing dependencies
  • [ ] Create fuzz targets for SOCKS5 protocol parsing in leaf/src/app/inbound/
  • [ ] Create fuzz targets for Shadowsocks protocol parsing (leaf-plugins/shadowsocks/src/lib.rs)
  • [ ] Create fuzz targets for HTTP header parsing in inbound handlers
  • [ ] Document fuzzing setup in a new docs/fuzzing.md file

Document and add CI validation for MPTP multi-path transport feature

The MPTP (Multi-path Transport Protocol) feature has architecture and usage docs (docs/mptp_architecture.md, docs/mptp_usage.md) but .github/workflows/ci.yml appears not to have specific MPTP integration tests. Additionally, there's no validation that the MPTP configuration examples in the docs actually work. Adding CI tests would ensure the documented feature doesn't regress.

  • [ ] Review docs/mptp_architecture.md and docs/mptp_usage.md for configuration examples
  • [ ] Create a test fixture directory with working MPTP configuration files
  • [ ] Add a new CI workflow step in .github/workflows/ci.yml to compile and validate MPTP configurations
  • [ ] Add integration test in leaf/src/app/ that creates an MPTP outbound and verifies multi-path aggregation behavior
  • [ ] Document MPTP testing in docs/mptp_usage.md with troubleshooting section

🌿Good first issues

  • Add integration tests for the DNS client's failover logic in leaf/src/app/dns/client/tests.rs—currently only unit tests visible, no end-to-end failover scenarios.
  • Document the config.json schema and add example configs for each listener type (TUN, CAT, network) in a new docs/config-examples/ directory with real working examples.
  • Implement health check reporting in the API layer (leaf/src/app/api/api_server.rs) to expose real-time failover status via gRPC for external monitoring.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • a897152 — Add MPTP usage (eycorsican)
  • d5ed615 — fix(mptp): make inbound CID session registration atomic under single write lock (eycorsican)
  • 291af8b — Refactor DNS client (eycorsican)
  • 26d17f9 — Add a DNS selector (eycorsican)
  • eea1f5a — Skip invalid DNS server (eycorsican)
  • a5e4d2a — Use aws-lc-rs (eycorsican)
  • f576d34 — Fix build and test (eycorsican)
  • 019bdea — Improve openssl backend ECH handling (eycorsican)
  • 309f9e9 — Improve ring backend ECH handling (eycorsican)
  • b14e2e3 — Support DoH (eycorsican)

🔒Security observations

  • High · Unsafe Symbol Stripping in Release Build — Cargo.toml - [profile.release] section. The Cargo.toml release profile uses strip = "symbols" which removes debugging symbols from the binary. While this reduces binary size, combined with panic = "abort", it can make debugging security issues and crashes more difficult. For a proxy framework handling sensitive data, this reduces observability into security-related failures. Fix: Consider keeping symbols for security-sensitive binaries or only strip non-critical symbols. Alternatively, maintain separate debug symbols for post-incident analysis.
  • High · Potential Cryptographic Implementation Risks — leaf/src/common/crypto.rs. The codebase includes custom cryptographic implementations in leaf/src/common/crypto.rs. Custom crypto is a high-risk area and prone to implementation vulnerabilities. The file structure suggests crypto handling for multiple protocols (Shadowsocks, Trojan, VMess, etc.) Fix: Conduct a thorough security audit of all cryptographic implementations. Prefer well-tested cryptographic libraries (e.g., ring, sodiumoxide) over custom implementations. Document the cryptographic assumptions and threat models.
  • High · TUN/TAP Interface Handling — leaf/src/app/inbound/tun_listener.rs. The presence of leaf/src/app/inbound/tun_listener.rs indicates direct system network interface manipulation. TUN/TAP interfaces require elevated privileges and can be a vector for privilege escalation or system compromise if not properly validated. Fix: Implement strict input validation for TUN configuration. Document privilege requirements. Implement capability dropping after initialization. Consider running TUN handler in a sandboxed process with minimal privileges.
  • High · FFI Boundary Security — leaf-ffi/src/lib.rs and leaf/src/mobile/bindings.rs. The leaf-ffi module exposes Rust functionality through C FFI bindings. FFI boundaries are common sources of memory safety issues and security vulnerabilities when called from untrusted code or with unexpected inputs. Fix: Implement comprehensive input validation at all FFI boundaries. Use repr(C) types carefully. Audit all unsafe blocks. Consider using safer FFI libraries like safer-ffi or cbindgen-generated validations.
  • Medium · DNS Protocol Implementation Risks — leaf/src/app/dns/client.rs and leaf/src/common/dns_sniff.rs. Custom DNS client implementation exists (leaf/src/app/dns/client.rs) along with DNS sniffing capabilities (leaf/src/common/dns_sniff.rs). DNS is a critical protocol and custom implementations may miss security considerations like DNS spoofing, cache poisoning, or DoS attacks. Fix: Use well-tested DNS libraries where possible. Implement DNSSEC validation. Add rate limiting and request validation. Implement cache poisoning protections. Add comprehensive logging for DNS queries.
  • Medium · Hardcoded or Unvalidated Configuration Paths — leaf/src/config/ directory (all format parsers). The presence of multiple configuration format parsers (JSON, TOML, Protobuf) without visible explicit path validation suggests potential path traversal or configuration injection risks. Fix: Implement strict validation of all configuration file paths. Use canonical path resolution. Implement file permission checks (configuration should not be world-writable). Validate all parsed configuration values before use.
  • Medium · API Server Exposure — leaf/src/app/api/api_server.rs. The presence of leaf/src/app/api/api_server.rs indicates a management API. API servers for proxy applications can become attack vectors if not properly secured with authentication and authorization. Fix: Implement robust authentication (mTLS or strong API keys). Use authorization for all endpoints. Implement rate limiting. Never expose the API to untrusted networks. Validate all API inputs. Use HTTPS/TLS only.
  • Medium · Plugin System Security — leaf/src/app/outbound/plugin.rs. The presence of leaf/src/app/outbound/plugin.rs indicates a plugin loading mechanism. Dynamic plugin loading can be exploited to execute arbitrary code if plugins are loaded from untrusted sources. Fix: Implement cryptographic verification of plugins (signatures). Only load plugins from

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · eycorsican/leaf — RepoPilot