GSproxy
GSproxy is a standalone Perl tool that reads a CSV list of remote targets and keeps a working SOCKS proxy alive for each of them. It brings up remote SOCKS servers over an MCP shell bridge, starts local gs-netcat SOCKS clients, watches every proxy, and exposes a single gateway SOCKS port that always points at the first healthy proxy.
Overview
The tool turns a list of endpoint,secret,port rows into a self-healing set of SOCKS proxies. For each row it does three things:
- Brings up a remote SOCKS server through an MCP
Tools_Shell_Commandcall, using a gs-netcat listener wrapped to look likepython. - Starts a local gs-netcat SOCKS client bound to
127.0.0.1on the row's port. - Monitors the local SOCKS proxy and logs every status change.
It then listens on a gateway SOCKS port and relays each incoming connection to the first proxy that is currently alive.
The whole tool is written with core Perl modules only, so it runs without extra installs.
Features
- CSV driven config, one proxy per row.
- Remote bring-up through an MCP shell call, reusing the gs-netcat listener command shape.
- Local gs-netcat SOCKS client launched per row.
- Continuous monitoring with configurable interval and per-check timeout.
- Automatic re-bring-up of dead proxies in the background.
- A gateway SOCKS port that follows the first alive proxy.
- Daemon mode with pidfile, status, and stop commands.
- Remote and local teardown that kills leftover gs-netcat processes.
- Offline self-tests that cover config parsing, command building, and the SOCKS handshake.
Requirements
- Perl 5 with the core modules
Getopt::Long,IO::Socket::INET,IO::Select,POSIX,HTTP::Tiny,JSON::PP,Time::HiRes,File::Spec,Errno, andFile::Basename. - The
gs-netcatbinary inPATH, or a path supplied with--gs-netcat. - Network access from the MCP endpoint so the remote bring-up command can download and run gs-netcat.
- A reachable MCP endpoint that exposes the
Tools_Shell_Commandtool.
Installation
- Copy
gsproxy.plsomewhere on the host and make it executable withchmod +x gsproxy.pl. - Make sure
gs-netcatis installed and on thePATH. - Create a
gsproxy.csvnext to the script, or point--configat another file.
Configuration
The config file is CSV. Each non-empty, non-comment line has the form:
endpoint,secret,port[,label]
endpointis the base URL of the MCP server that exposesTools_Shell_Command.secretis the gs-netcat shared secret used by both the remote listener and the local client.portis the local SOCKS port for that row. It must be a number from 1 to 65535.labelis an optional friendly name. When missing it defaults torowplus the line number.
Blank lines and lines starting with # are ignored. A header line such as endpoint,secret,port,label is detected and skipped when the third field is not a number. Invalid rows are reported on standard error and skipped.
Example:
endpoint,secret,port,label
https://mcp.example.org,sekret123,20001,alpha
https://mcp.other.org,topsecret9,20002,beta
The endpoint may be a base URL or a full MCP URL. If it does not already end in /gradio_api/mcp or /mcp, the value of --mcp-path is appended.
Usage
Run the tool as a daemon:
./gsproxy.pl
Run one monitor pass and exit:
./gsproxy.pl --once
Run in the foreground:
./gsproxy.pl --no-daemon
Options
The script accepts these command line options:
--config FILEsets the CSV config path. The default isgsproxy.csvnext to the script.--gateway-port PORTsets the gateway SOCKS port. The default is1080.--bind ADDRsets the address the gateway listens on. The default is0.0.0.0.--interval SECsets the monitor interval in seconds. The default is30.--timeout SECsets the per-check timeout in seconds. The default is10.--mcp-timeout SECsets the MCP shell command timeout in seconds. The default is60.--test-host HOSTsets the host probed through each SOCKS proxy. The default iswww.google.com.--test-port PORTsets the port probed through each SOCKS proxy. The default is443.--workdir DIRsets the remote working directory for the MCP call. The default is..--gs-netcat PATHsets the gs-netcat binary. The default isgs-netcatfromPATH.--log FILEsets the log file. The default isgsproxy.lognext to the script.--pidfile FILEsets the pidfile. The default isgsproxy.pidnext to the script.--state FILEsets the runtime state file. The default isgsproxy.statenext to the script.--insecuredisables TLS certificate checks for the MCP endpoint.--no-mcpskips the remote MCP bring-up call.--no-localskips the local gs-netcat client start.--no-bringupruns monitor only and never restarts proxies.--no-daemonruns in the foreground.--onceruns one monitor pass and then exits.--listparses the config, prints the rows, and exits.--statusreports whether the daemon is running.--stopstops a running daemon and tears down proxies.--selftestruns the offline self-tests.-h, --helpshows the help text.
The --daemon option is a negatable boolean and defaults to on. --verbose and -v increase logging to standard error.
How it works
gsproxy has four moving parts: the remote bring-up, the local client, the monitor, and the gateway.
- Remote bring-up downloads a gs-netcat build with
curl, unpacks it, and runs a gs-netcat listener with-lSD -s SECRET. The listening process is renamed topythonso it blends into the host. - The local client runs
gs-netcat -D -p PORT -s SECRET, which opens a SOCKS listener on127.0.0.1at the row's port. - The monitor performs a full SOCKS5 handshake against each local port, testing a real CONNECT to a probe host and port. A passing handshake marks the proxy alive.
- The gateway accepts SOCKS5 connections on
--bind:--gateway-portand relays them to the first alive proxy listed in the state file.
MCP bring-up
The remote call is an MCP JSON-RPC exchange over HTTP. The script sends an initialize request, captures the Mcp-Session-Id header, sends the notifications/initialized notification, then calls tools/call with the name Tools_Shell_Command. Responses may be plain JSON or server-sent events, so the body is parsed for the last data: line before decoding. Requests are retried up to three times on transport failures.
Monitoring and state
On every interval the monitor checks each proxy, logs only status changes, and writes the list of alive ports to the state file. The first alive port from that list is the current gateway target. When a proxy is found dead, the tool forks a background bring-up unless --no-bringup is set. In --once mode the bring-up runs inline instead of forking.
Gateway relay
The gateway listens, forks per connection, and reads the target port from the state file. It opens a TCP connection to that port and copies bytes in both directions with IO::Select, shutting down each direction as its side closes. If the state file has no valid port, the connection is dropped.
Teardown
Stopping the tool cleans up both sides. Locally it scans /proc for gs-netcat processes that match the -D -p PORT shape and sends them TERM. Remotely it runs a shell command over MCP that scans /proc for processes whose environment contains GSOCKET_ARGS=-lSD -s SECRET and kills them.
Command reference
- Start as a daemon:
./gsproxy.pl - Start and stop:
./gsproxy.pl --stop - Check status:
./gsproxy.pl --status - List config rows:
./gsproxy.pl --list - One pass, foreground:
./gsproxy.pl --once --no-daemon - Run self-tests:
./gsproxy.pl --selftest
Files
gsproxy.csvis the default config file.gsproxy.logis the append-only log, one UTC-stamped line per event.gsproxy.pidholds the daemon and gateway process ids.gsproxy.stateholds the first alive port on the first line and all alive ports on the second.
Logging
Every event is written with a UTC timestamp in the form [YYYY-MM-DDTHH:MM:SSZ] message. Bring-up, MCP results, status changes, gateway startup, and teardown are all logged. The log is appended, never truncated, so it grows over time. With --verbose, log lines are also printed to standard error.
Gateway behavior
- The gateway always targets the first alive proxy in listing order.
- It re-reads the state file on every new connection, so failover is immediate.
- A dead or missing target port causes the connection to be dropped without reply.
- Each connection is handled by a forked child, keeping the listener responsive.
Self-tests
The --selftest mode runs offline checks and prints PASS or FAIL per case. It writes a temporary CSV, a temporary state file, and a temporary log under /tmp. It covers config parsing, command string quoting, gs-netcat process discovery, live and dead SOCKS detection, and a full gateway relay against a fake SOCKS server. It exits non-zero if any check fails.
Security notes
- Secrets are masked in logs and list output, so only the first two characters appear.
- The remote process is deliberately renamed to
pythonto hide on the target host. - The
--insecureflag turns off TLS verification and should be used only when the MCP endpoint is trusted. - The gateway binds to
0.0.0.0by default. Restrict--bindif the host should not expose the proxy to the network. - Anyone who can reach the gateway SOCKS port can route through the current proxy, so the port should be firewalled.
Troubleshooting
- If the script reports no usable rows, check that the CSV has valid
endpoint,secret,portfields and a numeric port. - If the daemon will not start, run
--statusto see whether it is already running, then use--stopfirst. - If MCP bring-up fails, confirm the endpoint exposes
Tools_Shell_Commandand try--insecureonly if the certificate is the problem. - If no proxy becomes alive, run
--listto confirm the rows and check thatgs-netcatis on thePATH. - If the gateway has no target, watch the log for
SOCKS ... is deadlines to see which proxies are failing.
Credits
Created by Luxferre in 2026, released into the public domain with no warranties.