An asyncio-based SOCKS5 proxy that forwards traffic over a persistent SSH connection and exposes live stats via a Textual TUI.
Note: Over 80% of the code is AI-generated content.
- Local SOCKS5 (CONNECT) listener; traffic forwarded through SSH.
- Single SSH session with per-request channels (asyncssh).
- Metrics (per-connection/global bytes and rates) via
StatsManager. - Full-screen TUI showing status and active connections.
- YAML config with profiles; CLI flags to pick profile and log files.
core/ssh_proxy.py— manages SSH connection and tunnels.core/socks_server.py— minimal SOCKS5 server handing streams to SSHProxy.core/stats.py— metrics collection and snapshots for the UI.ui/tui_app.py— Textual TUI that polls stats and renders a table.config/loader.py— YAML config loader + profiles.config/example.yaml— sample config.main.py— integration entrypoint.tests/test_stats_demo.py— quick stats simulation script.
- Parse CLI args (
main.py). - Load YAML config/profile (
config/loader.py). - Create
StatsManager,SSHProxy,SocksServer. - Start SSH keep-alive and SOCKS listener.
- Launch Textual TUI (pulls
StatsManager.get_snapshot()every second). - On quit, stop TUI → stop SOCKS → close SSH.
- Python 3.10+
- Dependencies:
asyncssh,textual,pyyaml
Install:
pip install asyncssh textual pyyamlSee config/example.yaml:
default_profile: work
profiles:
work:
ssh_host: "work.example.com"
ssh_port: 22
ssh_user: "alice"
ssh_key_path: "~/.ssh/id_rsa"
local_socks_addr: "127.0.0.1:1080"CLI picks config/profile:
python main.py --config config/example.yaml --profile workStart the proxy + TUI (logs go to files by default):
python main.py --config config/example.yaml --log-level INFO --log-file logs/app.log --tui-log logs/textual.logUse your browser/curl with SOCKS5 pointing to local_socks_addr.
Quit the TUI with q.
- Application logs:
--log-file(no console output to avoid TUI flicker). - Textual logs:
--tui-logor setTEXTUAL_LOGenv var.
- Harden error handling/timeouts for production.
- Add auth for SOCKS and richer TUI interactions (filters/reconnect actions).