TutoProxy.Server - inbound server that accepts connections from tunneling clients (TutoProxy.Client) via SignalR and listens for incoming TCP/UDP traffic from external clients.
Command line arguments:
| Argument | Required | Description |
|---|---|---|
<host> |
Yes | Server binding address with port. Example: http://0.0.0.0:8088 or http://200.100.10.1:8088 |
--tcp <ports> |
No* | TCP ports to listen on. Supports individual ports and ranges. Example: --tcp=80,443,8000-8100 |
--udp <ports> |
No* | UDP ports to listen on. Supports individual ports and ranges. Example: --udp=5000-5010,65500 |
--clients <list> |
No | Comma-separated list of allowed client IDs. If omitted, all clients are allowed |
--daemon |
No | Run in daemon mode without terminal GUI, reduces CPU overhead |
*At least one of --tcp or --udp must be specified.
Example - start server with 50 TCP/UDP ports for 3 specific clients:
TutoProxy.Server http://200.100.10.1:8088 \
--tcp=3389,8071-8073,10000-10010,20000-20010 \
--udp=5000-5010,7000-7010 \
--clients=Client0Linux,ClientSecLinux,Client3WinTutoProxy.Client - tunneling client that connects to TutoProxy.Server via SignalR and forwards traffic to the target host.
Command line arguments:
| Argument | Required | Description |
|---|---|---|
<server> |
Yes | TutoProxy.Server address. Example: http://200.100.10.1:8088 |
<sendto> |
Yes | Target host IP where traffic will be forwarded. Example: 127.0.0.1 or 192.168.1.100 |
--id <id> |
No | Unique client identifier. Must match allowed clients on server if restriction is enabled |
--tcp <ports> |
No* | TCP ports to handle. Must be subset of server's TCP ports. Example: --tcp=80,443 |
--udp <ports> |
No* | UDP ports to handle. Must be subset of server's UDP ports. Example: --udp=5000-5005 |
--protocol <mode> |
No | Transport protocol: Auto (default), Http, WebSocket. WebSocket mode skips negotiation for faster connection |
--parallel <count> |
No | Number of parallel SignalR connections (1-8, default: 1). Multiple connections increase throughput by distributing TCP sessions across channels |
--daemon |
No | Run in daemon mode without terminal GUI, reduces CPU overhead |
*At least one of --tcp or --udp must be specified.
Example - start client forwarding 5 TCP and 3 UDP ports:
TutoProxy.Client http://200.100.10.1:8088 127.0.0.1 \
--tcp=8071,10000,20004-20006 \
--udp=7000-7002 \
--id=Client0LinuxExample - start client with 4 parallel SignalR connections for higher throughput:
TutoProxy.Client http://200.100.10.1:8088 127.0.0.1 \
--tcp=8071-8080 \
--id=Client0Linux \
--protocol=WebSocket \
--parallel=4Important: Ports of different TutoProxy.Client instances must not overlap. Each client serves a unique set of ports.
TutoProxy.Client supports multiple parallel SignalR connections to increase throughput. When --parallel=N is specified:
- Client creates N
SignalRConnectioninstances to the server - Server groups these connections into a
ClientGroup - New TCP sessions are distributed across connections using round-robin
- Each TCP session maintains affinity to its assigned connection (session stickiness)
- UDP traffic is distributed across connections using round-robin
TutoProxy.Server side:
- External Client connects to
TcpServer.Listen()/UdpServer TcpServercallsDataTransferService.ConnectTcp()to establish sessionDataTransferServiceselects connection viaHubClientsService.GetConnectionIdForTcp()(round-robin)DataTransferServiceregisters session affinity viaHubClientsService.RegisterTcpSession()DataTransferServiceinvokesConnectTcpon selectedSignalRConnection- On data receive,
TcpClient.ReceivingStream()callsDataTransferService.SendTcpRequest() DataTransferServiceusesHubClientsService.GetConnectionIdForTcpSession()for session affinityDataTransferServiceinvokesTcpRequeston the same connection
TutoProxy.Client side:
ClientReceiver.ConnectTcp()receives connection requestClientsService.AddTcpClient()createsTcpClientwith specificITcpDataChannelTcpClient.Connect()establishes socket to Target HostClientReceiver.TcpRequest()receives data, passes toTcpClient.SendRequest()TcpClientsends data to Target Host via socket
TutoProxy.Client side:
- Target Host sends response data
TcpClient.ReceivingStream()receives data from socketTcpClientcallsITcpDataChannel.SendTcpResponse()(bound to specificSignalRConnection)SignalRConnection.SendTcpResponse()invokeshubProxy.TcpResponse()
TutoProxy.Server side:
SignalRHub.TcpResponse()receives response withContext.ConnectionIdSignalRHubcallsDataTransferService.HandleTcpResponse()DataTransferServicecallsHubClientsService.GetClient()to findHubClientHubClient.SendTcpResponse()findsTcpServerby portTcpServer.SendResponse()findsTcpClientby origin portTcpClient.SendDataAsync()sends response via socket to External Client
TutoProxy.Server:
SignalRHub- SignalR hub, handlesTcpResponse,UdpResponse,DisconnectTcp,DisconnectUdpHubClientsService- managesClientGroupinstances, handles parallel connections, round-robin distribution, session affinityClientGroup- groups SignalR connections from same client, containsHubClientand connection listDataTransferService- routes data between SignalRHub and HubClients, manages session registrationHubClient- represents connected TutoProxy.Client, containsTcpServer/UdpServerinstancesTcpServer/UdpServer- listen on ports, manageTcpClient/UdpClientsessionsTcpClient/UdpClient- handle individual external client socket sessions
TutoProxy.Client:
SignalRClient- manages multipleSignalRConnectioninstances for parallel connectionsSignalRConnection- implementsITcpDataChannel, wrapsHubConnection, handles TCP session affinityClientReceiver- implementsIClientReceiver, handles incomingTcpRequest,UdpRequest,ConnectTcpTcpClient/UdpClient- connect to target host, send requests, receive responses via boundITcpDataChannelClientsService- manages activeTcpClient/UdpClientinstances
The project includes a performance testing script that measures tunnel throughput using iperf3 and Docker.
┌─────────────────────────────────────────────────────────────────┐
│ localhost │
│ │
│ ┌─────────────┐ ┌──────────────────┐ ┌────────────┐ │
│ │ iperf3 │ │ TutoProxy.Server │ │ TutoProxy. │ │
│ │ -c localhost│─────▶│ :5201 │─────▶│ Client │ │
│ │ -p 5201 │ TCP │ (SignalR :5088) │SignalR │ │
│ └─────────────┘ └──────────────────┘ └─────┬──────┘ │
│ │ │
└───────────────────────────────────────────────────────┼─────────┘
│ TCP
▼
┌───────────────────────────────────────────────────────────────┐
│ Docker Network │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ iperf3-server (172.17.0.X:5201) │ │
│ └─────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
- Docker
- iperf3 (
sudo apt install iperf3) - .NET SDK
# Full TCP test (Auto + Http + WebSocket protocols)
./Projects/TutoProxy/scripts/perf-test.sh full
./Projects/TutoProxy/scripts/perf-test.sh full-reverse
# WebSocket protocol test (fastest)
./Projects/TutoProxy/scripts/perf-test.sh websocket -d 10
./Projects/TutoProxy/scripts/perf-test.sh websocket-reverse -d 10
# Parallel connections test (4 iperf streams over 4 SignalR connections)
./Projects/TutoProxy/scripts/perf-test.sh websocket -d 10 -p 4 -s 4
# Full UDP test (Auto + Http + WebSocket protocols)
./Projects/TutoProxy/scripts/perf-test.sh udp-full -d 10 -b 1000M
./Projects/TutoProxy/scripts/perf-test.sh udp-full-reverse -d 10 -b 1000MPerformance tests can also be run from VSCode: Ctrl+Shift+P → "Tasks: Run Task" → select a perf test
