diff --git a/Stormancer.NetProxy/Program.cs b/Stormancer.NetProxy/Program.cs index 697912d..8bf70af 100644 --- a/Stormancer.NetProxy/Program.cs +++ b/Stormancer.NetProxy/Program.cs @@ -35,6 +35,7 @@ private static IEnumerable ProxyFromConfig(string proxyName, ProxyConfig p var forwardIp = proxyConfig.forwardIp; var localIp = proxyConfig.localIp; var protocol = proxyConfig.protocol; + var forwardTls = proxyConfig.forwardTls; try { if (forwardIp == null) @@ -68,7 +69,7 @@ private static IEnumerable ProxyFromConfig(string proxyName, ProxyConfig p try { var proxy = new UdpProxy(); - task = proxy.Start(forwardIp, forwardPort.Value, localPort.Value, localIp); + task = proxy.Start(forwardIp, forwardPort.Value, localPort.Value, localIp, forwardTls); } catch (Exception ex) { @@ -86,7 +87,7 @@ private static IEnumerable ProxyFromConfig(string proxyName, ProxyConfig p try { var proxy = new TcpProxy(); - task = proxy.Start(forwardIp, forwardPort.Value, localPort.Value, localIp); + task = proxy.Start(forwardIp, forwardPort.Value, localPort.Value, localIp, forwardTls); } catch (Exception ex) { @@ -111,10 +112,12 @@ public class ProxyConfig public string? localIp { get; set; } public string? forwardIp { get; set; } public ushort? forwardPort { get; set; } + + public bool forwardTls { get; set; } } internal interface IProxy { - Task Start(string remoteServerHostNameOrAddress, ushort remoteServerPort, ushort localPort, string? localIp = null); + Task Start(string remoteServerHostNameOrAddress, ushort remoteServerPort, ushort localPort, string? localIp = null, bool remoteTls = false); } -} \ No newline at end of file +} diff --git a/Stormancer.NetProxy/TcpProxy.cs b/Stormancer.NetProxy/TcpProxy.cs index 496558a..4b1bf57 100644 --- a/Stormancer.NetProxy/TcpProxy.cs +++ b/Stormancer.NetProxy/TcpProxy.cs @@ -4,8 +4,12 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; +using System.Net.Security; using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; @@ -18,7 +22,7 @@ internal class TcpProxy : IProxy /// public int ConnectionTimeout { get; set; } = (4 * 60 * 1000); - public async Task Start(string remoteServerHostNameOrAddress, ushort remoteServerPort, ushort localPort, string? localIp) + public async Task Start(string remoteServerHostNameOrAddress, ushort remoteServerPort, ushort localPort, string? localIp, bool remoteTls) { var connections = new ConcurrentBag(); @@ -62,7 +66,7 @@ public async Task Start(string remoteServerHostNameOrAddress, ushort remoteServe var ips = await Dns.GetHostAddressesAsync(remoteServerHostNameOrAddress).ConfigureAwait(false); var tcpConnection = await TcpConnection.AcceptTcpClientAsync(localServer, - new IPEndPoint(ips[0], remoteServerPort)) + new IPEndPoint(ips[0], remoteServerPort), remoteTls) .ConfigureAwait(false); tcpConnection.Run(); connections.Add(tcpConnection); @@ -88,16 +92,17 @@ internal class TcpConnection private EndPoint? _forwardLocalEndpoint; private long _totalBytesForwarded; private long _totalBytesResponded; + private bool _remoteTls; public long LastActivity { get; private set; } = Environment.TickCount64; - public static async Task AcceptTcpClientAsync(TcpListener tcpListener, IPEndPoint remoteEndpoint) + public static async Task AcceptTcpClientAsync(TcpListener tcpListener, IPEndPoint remoteEndpoint, bool remoteTls) { var localServerConnection = await tcpListener.AcceptTcpClientAsync().ConfigureAwait(false); localServerConnection.NoDelay = true; - return new TcpConnection(localServerConnection, remoteEndpoint); + return new TcpConnection(localServerConnection, remoteEndpoint, remoteTls); } - private TcpConnection(TcpClient localServerConnection, IPEndPoint remoteEndpoint) + private TcpConnection(TcpClient localServerConnection, IPEndPoint remoteEndpoint, bool remoteTls) { _localServerConnection = localServerConnection; _remoteEndpoint = remoteEndpoint; @@ -106,6 +111,7 @@ private TcpConnection(TcpClient localServerConnection, IPEndPoint remoteEndpoint _sourceEndpoint = _localServerConnection.Client.RemoteEndPoint; _serverLocalEndpoint = _localServerConnection.Client.LocalEndPoint; + _remoteTls = remoteTls; } public void Run() @@ -145,12 +151,19 @@ private void RunInternal(CancellationToken cancellationToken) { serverStream.Close(); clientStream.Close(); - }, true)) - { - await Task.WhenAny( - CopyToAsync(clientStream, serverStream, 81920, Direction.Forward, cancellationToken), - CopyToAsync(serverStream, clientStream, 81920, Direction.Responding, cancellationToken) - ).ConfigureAwait(false); + }, true)) { + Stream wrappedServerStream; + if (_remoteTls) { + wrappedServerStream = new SslStream(serverStream, true, (sender, certificate, chain, errors) => true); + await ((SslStream)wrappedServerStream).AuthenticateAsClientAsync("localhost", new X509Certificate2Collection(), SslProtocols.Tls12, false); + } else + wrappedServerStream = serverStream; + try { + await Task.WhenAny(CopyToAsync(clientStream, wrappedServerStream, 81920, Direction.Forward, cancellationToken), CopyToAsync(wrappedServerStream, clientStream, 81920, Direction.Responding, cancellationToken)).ConfigureAwait(false); + } finally { + if (wrappedServerStream != serverStream) + wrappedServerStream.Dispose(); + } } } } diff --git a/Stormancer.NetProxy/UdpProxy.cs b/Stormancer.NetProxy/UdpProxy.cs index 15618fd..bcd10f2 100644 --- a/Stormancer.NetProxy/UdpProxy.cs +++ b/Stormancer.NetProxy/UdpProxy.cs @@ -15,9 +15,11 @@ internal class UdpProxy : IProxy /// public int ConnectionTimeout { get; set; } = (4 * 60 * 1000); - public async Task Start(string remoteServerHostNameOrAddress, ushort remoteServerPort, ushort localPort, string? localIp = null) + public async Task Start(string remoteServerHostNameOrAddress, ushort remoteServerPort, ushort localPort, string? localIp = null, bool remoteTls = false) { var connections = new ConcurrentDictionary(); + if (remoteTls) + throw new ArgumentException("UDP connections cannot be wrapped in TLS", nameof(remoteTls)); // TCP will lookup every time while this is only once. var ips = await Dns.GetHostAddressesAsync(remoteServerHostNameOrAddress).ConfigureAwait(false); diff --git a/Stormancer.NetProxy/config.json b/Stormancer.NetProxy/config.json index 159e13f..0143692 100644 --- a/Stormancer.NetProxy/config.json +++ b/Stormancer.NetProxy/config.json @@ -1,32 +1,16 @@ { - "testUdp": { - "localPort": 7777, - "protocol": "udp", - "forwardIp": "35.187.92.120", - "forwardPort": 7777 - }, - "http": { - "localPort": 80, + "clickhouse-tls": { + "localPort": 19000, "protocol": "tcp", - "forwardIp": "149.56.107.33", - "forwardPort": 81 - }, - "https": { - "localPort": 8443, - "protocol": "any", - "forwardIp": "35.187.92.120", - "forwardPort": 443 + "forwardIp": "127.0.0.1", + "forwardPort": 9440, + "forwardTls": true }, - "raknet1": { - "localPort": 30000, - "protocol": "udp", - "forwardIp": "35.187.92.120", - "forwardPort": 30000 - }, - "raknet2": { - "localPort": 30001, - "protocol": "udp", - "forwardIp": "35.187.92.120", - "forwardPort": 30001 + "clickhouse": { + "localPort": 19001, + "protocol": "tcp", + "forwardIp": "127.0.0.1", + "forwardPort": 9000, + "forwardTls": false } }