udpsplitr
v0.1.0
Published
UDP proxy that splits client and server traffic across separate ports
Maintainers
Readme
UDPSplitR
UDPSplitR is a UDP proxy that splits outgoing and incoming traffic across different ports. The client sends proxied packets from one local port and listens for server responses on another, while the server receives client packets and forwards them to TARGET_IP:TARGET_PORT.
The tool is useful when a UDP flow needs separate paths for input and output traffic between the client-side proxy and the server-side proxy.
The client side intentionally supports one active local UDP peer at a time. The first peer that sends traffic owns the return path; packets from other peers are rejected so responses are not accidentally delivered to the wrong process.
For deployments behind NAT, the experimental NAT_TRAVERSAL option can make the client response socket send keepalive packets. This lets the server learn the observed return endpoint instead of relying only on the configured CLIENT_RESPONSE_IP and CLIENT_RESPONSE_PORT.
Traffic Schema
outgoing path
┌───────────────┐ CLIENT_PROXY_PORT ┌───────────────────┐ SERVER_PORT ┌───────────────────┐ TARGET_PORT ┌──────────────┐
│ Local UDP app │ ────────────────────> │ UDPSplitR client │ ──────────────> │ UDPSplitR server │ ──────────────> │ Target UDP │
└───────────────┘ └───────────────────┘ └───────────────────┘ └──────────────┘
▲ │ │ │
│ │ │ │
└──────────────────────────────────────┘ <────────────────────────────────┘ <──────────────────────────────┘
CLIENT_RESPONSE_PORT response pathThe important part is that the client-side proxy uses different ports for the two directions: CLIENT_PROXY_PORT for incoming local traffic and CLIENT_RESPONSE_PORT for responses from the server.
In --ping-mode, the client prepends a probe ID to each echo payload and matches responses by that ID. The console output is formatted like standard ping, with a PING ... banner, 1-second probe intervals, and per-probe latency lines.
Configuration
Both the client and server proxies have the following configuration options, which can be set in a .env file:
CLIENT_IP: The IP address to listen for client connections (default:0.0.0.0).CLIENT_PROXY_PORT: The port to listen for client connections (default:27817).CLIENT_RESPONSE_PORT: The port to receive responses from the server (default:27818).SERVER_IP: The IP address of the server to forward data to.SERVER_PORT: The port to forward data to the server (default:27817).TARGET_IP: The IP address of the target server to forward data to.TARGET_PORT: The port to forward data to the target server (default:443).CLIENT_RESPONSE_IP: The IP address of the client to receive responses.CLIENT_RESPONSE_PORT: The port to receive responses from the target server (default:27818).MTU_SIZE: The Maximum Transmission Unit size (default:1450).NAT_TRAVERSAL: Enables client response-port keepalives so the server learns the NAT-mapped return path for responses (default:false).
NAT_TRAVERSAL is an experimental feature. It relies on periodic client keepalives to keep the response-port mapping alive through NAT and firewalls, and behavior will vary by network.
When NAT_TRAVERSAL is enabled, the client response socket periodically sends a small keepalive packet to the server. The server uses the observed source address and port as the return path for responses instead of the static CLIENT_RESPONSE_IP and CLIENT_RESPONSE_PORT values.
Usage
Run With npx
Run the proxy directly from npm without installing it globally.
Generate configuration:
Server Machine
npx udpsplitr server --init-envClient Machine
npx udpsplitr client --init-envThe command copies the packaged env.example file and sets MODE for the selected role. It will not overwrite an existing .env unless --force is passed.
Run the proxy:
Server Machine
npx udpsplitr serverClient Machine
npx udpsplitr clientInstall Globally
Install the command once and run it as udpsplitr:
npm install -g udpsplitrGenerate configuration:
Server Machine
udpsplitr server --init-envClient Machine
udpsplitr client --init-envRun the proxy:
Server Machine
udpsplitr serverClient Machine
udpsplitr clientDocker
Create Configuration
Use a temporary container to generate a local .env file before running Docker examples.
Server Machine
docker run --rm -v "$PWD:/config" -w /config ghcr.io/jstarstech/udpsplitr:latest node app.js server --init-envClient Machine
docker run --rm -v "$PWD:/config" -w /config ghcr.io/jstarstech/udpsplitr:latest node app.js client --init-envTemporary Echo/Ping
Server Machine
docker run -d --rm --env-file .env --name udpsplitr-server ghcr.io/jstarstech/udpsplitr:latest node app.js server --echo-modeClient Machine
docker run -d --rm --env-file .env --name udpsplitr-client ghcr.io/jstarstech/udpsplitr:latest node app.js client --ping-modeDevelopment
Clone Repository
git clone https://github.com/jstarstech/udpsplitr.git
cd udpsplitr
npm installLocal Configuration
Server Machine
node app.js server --init-envClient Machine
node app.js client --init-envLocal Run
Server Machine
node app.js serverClient Machine
node app.js clientChecks And Tests
npm run check
npm testDocker Compose
Copy env.example to .env on each machine:
cp env.example .envSet the mode in .env to match the machine role:
# server machine
MODE=server
# client machine
MODE=clientRun Compose normally on both machines:
docker compose up --build