param( [string]$ListenAddress = "0.0.0.0", [Parameter(Mandatory = $true)][int]$ListenPort, [Parameter(Mandatory = $true)][string]$TargetHost, [Parameter(Mandatory = $true)][int]$TargetPort, [int]$IdleExitSeconds = 8 ) $ErrorActionPreference = "Stop" Add-Type -TypeDefinition @" using System; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; public static class PlanetTcpRelay { public static async Task RunAsync(string listenAddress, int listenPort, string targetHost, int targetPort, int idleExitSeconds) { IPAddress address; if (!IPAddress.TryParse(listenAddress, out address)) { address = IPAddress.Any; } var listener = new TcpListener(address, listenPort); listener.Start(); var lastHealthyAt = DateTime.UtcNow; try { while (true) { if (await CanConnectAsync(targetHost, targetPort)) { lastHealthyAt = DateTime.UtcNow; } else if ((DateTime.UtcNow - lastHealthyAt).TotalSeconds >= idleExitSeconds) { break; } while (listener.Pending()) { var client = await listener.AcceptTcpClientAsync(); _ = Task.Run(() => HandleClientAsync(client, targetHost, targetPort)); } await Task.Delay(200); } } finally { listener.Stop(); } } private static async Task CanConnectAsync(string host, int port) { using (var client = new TcpClient()) { var connectTask = client.ConnectAsync(host, port); var completed = await Task.WhenAny(connectTask, Task.Delay(500)); if (completed != connectTask) { return false; } try { await connectTask; return client.Connected; } catch { return false; } } } private static async Task HandleClientAsync(TcpClient client, string targetHost, int targetPort) { using (client) using (var upstream = new TcpClient()) { try { await upstream.ConnectAsync(targetHost, targetPort); var clientStream = client.GetStream(); var upstreamStream = upstream.GetStream(); var toUpstream = clientStream.CopyToAsync(upstreamStream); var toClient = upstreamStream.CopyToAsync(clientStream); await Task.WhenAny(toUpstream, toClient); } catch { } } } } "@ [PlanetTcpRelay]::RunAsync($ListenAddress, $ListenPort, $TargetHost, $TargetPort, $IdleExitSeconds).GetAwaiter().GetResult()