104 lines
2.9 KiB
PowerShell
104 lines
2.9 KiB
PowerShell
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<bool> 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()
|