This commit is contained in:
SpringHgui 2021-08-01 18:32:32 +08:00
parent d98b7fea76
commit 3e5020b890
60 changed files with 1085 additions and 288 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ publish
/SuiDao.Client/Properties/PublishProfiles/FolderProfile.pubxml /SuiDao.Client/Properties/PublishProfiles/FolderProfile.pubxml
/FastTunnel.Core/*.user /FastTunnel.Core/*.user
/build /build
/FastTunnel.Server/.config

View File

@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging;
using FastTunnel.Core.Extensions; using FastTunnel.Core.Extensions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using FastTunnel.Core.Client; using FastTunnel.Core.Client;
using System;
namespace FastTunnel.Client namespace FastTunnel.Client
{ {
@ -10,7 +11,14 @@ namespace FastTunnel.Client
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
CreateHostBuilder(args).Build().Run(); try
{
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
} }
public static IHostBuilder CreateHostBuilder(string[] args) => public static IHostBuilder CreateHostBuilder(string[] args) =>

View File

@ -13,7 +13,7 @@
//"ServerAddr": "my.com", //"ServerAddr": "my.com",
"ServerAddr": "127.0.0.1", "ServerAddr": "127.0.0.1",
// //
"ServerPort": 1271 "ServerPort": 1270
}, },
"Webs": [ "Webs": [
{ {
@ -37,11 +37,12 @@
], ],
/** /**
* ssh穿ssh访/mysql/erp/ *
* 访/mysql/erp/TCP
* linux#ssh -oPort=12701 {root}@{ServerAddr} ServerAddr iproot * linux#ssh -oPort=12701 {root}@{ServerAddr} ServerAddr iproot
* 访访 * 访访
*/ */
"SSH": [ "Forward": [
{ {
"LocalIp": "127.0.0.1", "LocalIp": "127.0.0.1",
"LocalPort": 8090, "LocalPort": 8090,

View File

@ -1,6 +1,4 @@
using Newtonsoft.Json; using FastTunnel.Core.Config;
using Newtonsoft.Json.Linq;
using FastTunnel.Core.Config;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using System; using System;
using System.Net.Sockets; using System.Net.Sockets;
@ -15,12 +13,15 @@ using Microsoft.Extensions.Configuration;
using FastTunnel.Core.Server; using FastTunnel.Core.Server;
using FastTunnel.Core.Sockets; using FastTunnel.Core.Sockets;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Net.WebSockets;
using System.Text.Json;
namespace FastTunnel.Core.Client namespace FastTunnel.Core.Client
{ {
public class FastTunnelClient : IFastTunnelClient public class FastTunnelClient : IFastTunnelClient
{ {
Socket _client; //Socket _client;
private IFastTunnelClientSocket socket;
protected ILogger<FastTunnelClient> _logger; protected ILogger<FastTunnelClient> _logger;
@ -31,19 +32,19 @@ namespace FastTunnel.Core.Client
int reTrySpan = 10 * 1000; // 登陆失败后重试间隔 int reTrySpan = 10 * 1000; // 登陆失败后重试间隔
HttpRequestHandler _newCustomerHandler; HttpRequestHandler _newCustomerHandler;
NewSSHHandler _newSSHHandler; NewForwardHandler _newSSHHandler;
LogHandler _logHandler; LogHandler _logHandler;
ClientHeartHandler _clientHeartHandler; ClientHeartHandler _clientHeartHandler;
Func<Socket> lastLogin;
Message<LogInMassage> loginMsg; Message<LogInMassage> loginMsg;
protected readonly IOptionsMonitor<DefaultClientConfig> _configuration; protected readonly IOptionsMonitor<DefaultClientConfig> _configuration;
private readonly CancellationTokenSource cancellationTokenSource = new();
public SuiDaoServer Server { get; protected set; } public SuiDaoServer Server { get; protected set; }
public FastTunnelClient( public FastTunnelClient(
ILogger<FastTunnelClient> logger, ILogger<FastTunnelClient> logger,
HttpRequestHandler newCustomerHandler, HttpRequestHandler newCustomerHandler,
NewSSHHandler newSSHHandler, LogHandler logHandler, NewForwardHandler newSSHHandler, LogHandler logHandler,
IOptionsMonitor<DefaultClientConfig> configuration, IOptionsMonitor<DefaultClientConfig> configuration,
ClientHeartHandler clientHeartHandler) ClientHeartHandler clientHeartHandler)
{ {
@ -60,7 +61,7 @@ namespace FastTunnel.Core.Client
timer_heart.Elapsed += HeartElapsed; timer_heart.Elapsed += HeartElapsed;
} }
private void reConn() private async Task reConnAsync()
{ {
Close(); Close();
@ -71,7 +72,7 @@ namespace FastTunnel.Core.Client
Thread.Sleep(reTrySpan); Thread.Sleep(reTrySpan);
_logger.LogInformation("登录重试..."); _logger.LogInformation("登录重试...");
_client = lastLogin.Invoke(); socket = await loginAsync(CancellationToken.None);
break; break;
} }
@ -90,12 +91,12 @@ namespace FastTunnel.Core.Client
try try
{ {
_client.SendCmd(new Message<HeartMassage> { MessageType = MessageType.Heart, Content = null }); socket.SendAsync(new Message<HeartMassage> { MessageType = MessageType.Heart, Content = null }, cancellationTokenSource.Token).Wait();
} }
catch (Exception) catch (Exception)
{ {
// 与服务端断开连接 // 与服务端断开连接
reConn(); reConnAsync();
} }
finally finally
{ {
@ -108,43 +109,77 @@ namespace FastTunnel.Core.Client
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="customLoginMsg">自定义登录信息,可进行扩展业务</param> /// <param name="customLoginMsg">自定义登录信息,可进行扩展业务</param>
public void Start() public async Task StartAsync(CancellationToken cancellationToken)
{ {
_logger.LogInformation("===== FastTunnel Client Start ====="); CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, this.cancellationTokenSource.Token);
lastLogin = login; _logger.LogInformation("===== FastTunnel Client Start =====");
try try
{ {
_client = lastLogin.Invoke(); socket = await loginAsync(cancellationToken);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex.Message); _logger.LogError(ex.Message);
reConn(); reConnAsync();
return; return;
} }
_ = connSuccessAsync(); _ = connSuccessAsync();
} }
//protected virtual Socket login()
//{
// Server = _configuration.CurrentValue.Server;
protected virtual Socket login() // DnsSocket _client = null;
// _logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}");
// try
// {
// // 连接到的目标IP
// if (_client == null)
// {
// _client = new DnsSocket(Server.ServerAddr, Server.ServerPort);
// }
// _client.Connect();
// _logger.LogInformation("连接成功");
// }
// catch (Exception)
// {
// throw;
// }
// loginMsg = new Message<LogInMassage>
// {
// MessageType = MessageType.C_LogIn,
// Content = new LogInMassage
// {
// Webs = _configuration.CurrentValue.Webs,
// SSH = _configuration.CurrentValue.SSH,
// },
// };
// // 登录
// _client.Send(loginMsg);
// return _client.Socket;
//}
protected virtual async Task<IFastTunnelClientSocket> loginAsync(CancellationToken cancellationToken)
{ {
Server = _configuration.CurrentValue.Server; Server = _configuration.CurrentValue.Server;
DnsSocket _client = null;
_logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}"); _logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}");
try try
{ {
// 连接到的目标IP // 连接到的目标IP
if (_client == null) socket = new DefultClientSocket();
{
_client = new DnsSocket(Server.ServerAddr, Server.ServerPort);
}
_client.Connect(); await socket.ConnectAsync(
new Uri($"ws://{_configuration.CurrentValue.Server.ServerAddr}:{_configuration.CurrentValue.Server.ServerPort}"), cancellationToken);
_logger.LogInformation("连接成功"); _logger.LogInformation("连接成功");
} }
@ -159,29 +194,19 @@ namespace FastTunnel.Core.Client
Content = new LogInMassage Content = new LogInMassage
{ {
Webs = _configuration.CurrentValue.Webs, Webs = _configuration.CurrentValue.Webs,
SSH = _configuration.CurrentValue.SSH, SSH = _configuration.CurrentValue.Forwards,
}, },
}; };
// 登录 // 登录
_client.Send(loginMsg); await socket.SendAsync(loginMsg, cancellationToken);
return socket;
return _client.Socket;
} }
void Close() void Close()
{ {
timer_heart.Stop(); timer_heart.Stop();
socket.CloseAsync();
try
{
_client?.Shutdown(SocketShutdown.Both);
}
catch (Exception)
{
}
_client?.Close();
} }
private async Task connSuccessAsync() private async Task connSuccessAsync()
@ -192,7 +217,7 @@ namespace FastTunnel.Core.Client
timer_heart.Start(); timer_heart.Start();
var th = new Thread(ReceiveServer); var th = new Thread(ReceiveServer);
th.Start(_client); th.Start(socket);
// await new PipeHepler(_client, ProceccLine).ProcessLinesAsync(); // await new PipeHepler(_client, ProceccLine).ProcessLinesAsync();
} }
@ -205,7 +230,7 @@ namespace FastTunnel.Core.Client
private void ReceiveServer(object obj) private void ReceiveServer(object obj)
{ {
var client = obj as Socket; var client = obj as IFastTunnelClientSocket;
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
string lastBuffer = string.Empty; string lastBuffer = string.Empty;
@ -215,10 +240,10 @@ namespace FastTunnel.Core.Client
{ {
try try
{ {
n = client.Receive(buffer); n = client.ReceiveAsync(buffer, cancellationTokenSource.Token).GetAwaiter().GetResult();
if (n == 0) if (n == 0)
{ {
client.Shutdown(SocketShutdown.Both); client.CloseAsync();
break; break;
} }
} }
@ -290,36 +315,38 @@ namespace FastTunnel.Core.Client
_logger.LogInformation("stop receive from server"); _logger.LogInformation("stop receive from server");
} }
private void HandleServerRequest(string words) private void HandleServerRequest(string lineCmd)
{ {
Task.Run(() => Task.Run(() =>
{ {
var Msg = JsonConvert.DeserializeObject<Message<JObject>>(words); var cmds = lineCmd.Split("||");
if (Msg.MessageType != MessageType.Heart) var type = cmds[0];
{
_logger.LogDebug($"HandleServerRequest {words}");
}
TunnelMassage msg = null;
IClientHandler handler; IClientHandler handler;
switch (Msg.MessageType) switch (type)
{ {
case MessageType.Heart: case "Heart":
handler = _clientHeartHandler; handler = _clientHeartHandler;
msg = JsonSerializer.Deserialize<HeartMassage>(cmds[1]);
break; break;
case MessageType.S_NewCustomer: case "S_NewCustomer":
handler = _newCustomerHandler; handler = _newCustomerHandler;
msg = JsonSerializer.Deserialize<NewCustomerMassage>(cmds[1]);
break; break;
case MessageType.S_NewSSH: case "S_NewSSH":
handler = _newSSHHandler; handler = _newSSHHandler;
msg = JsonSerializer.Deserialize<NewForwardMessage>(cmds[1]);
break; break;
case MessageType.Log: case "Log":
handler = _logHandler; handler = _logHandler;
msg = JsonSerializer.Deserialize<LogMassage>(cmds[1]);
break; break;
default: default:
throw new Exception($"未处理的消息:{Msg.MessageType} {Msg.Content}"); throw new Exception($"未处理的消息:{lineCmd}");
} }
handler.HandlerMsg(this, Msg); handler.HandlerMsgAsync(this, msg);
}); });
} }
} }

View File

@ -27,35 +27,37 @@ namespace FastTunnel.Core.Client
public ConcurrentDictionary<string, WebInfo> WebList { get; private set; } public ConcurrentDictionary<string, WebInfo> WebList { get; private set; }
= new ConcurrentDictionary<string, WebInfo>(); = new ConcurrentDictionary<string, WebInfo>();
public ConcurrentDictionary<int, SSHInfo<SSHHandlerArg>> SSHList { get; private set; } public ConcurrentDictionary<int, ForwardInfo<ForwardHandlerArg>> SSHList { get; private set; }
= new ConcurrentDictionary<int, SSHInfo<SSHHandlerArg>>(); = new ConcurrentDictionary<int, ForwardInfo<ForwardHandlerArg>>();
readonly ILogger _logger; readonly ILogger _logger;
readonly ClientListenerV2 clientListener; //readonly ClientListenerV2 clientListener;
readonly HttpListenerV2 http_listener; //readonly HttpListenerV2 http_listener;
public readonly IOptionsMonitor<DefaultServerConfig> serverOption; public readonly IOptionsMonitor<DefaultServerConfig> serverOption;
public IProxyConfigProvider proxyConfig;
public FastTunnelServer(ILogger<FastTunnelServer> logger, IProxyConfigProvider proxyConfig, IOptionsMonitor<DefaultServerConfig> serverSettings) public FastTunnelServer(ILogger<FastTunnelServer> logger, IProxyConfigProvider proxyConfig, IOptionsMonitor<DefaultServerConfig> serverSettings)
{ {
_logger = logger; _logger = logger;
serverOption = serverSettings; serverOption = serverSettings;
this.proxyConfig = proxyConfig;
clientListener = new ClientListenerV2(this, proxyConfig, "0.0.0.0", serverOption.CurrentValue.BindPort, _logger); // clientListener = new ClientListenerV2(this, proxyConfig, "0.0.0.0", serverOption.CurrentValue.BindPort, _logger);
http_listener = new HttpListenerV2("0.0.0.0", serverOption.CurrentValue.WebProxyPort, _logger); // http_listener = new HttpListenerV2("0.0.0.0", serverOption.CurrentValue.WebProxyPort, _logger);
} }
public void Run() public void Run()
{ {
_logger.LogInformation("===== FastTunnel Server Starting ====="); _logger.LogInformation("===== FastTunnel Server Starting =====");
listenClient(); // listenClient();
//listenHttp(); // listenHttp();
} }
private void listenClient() //private void listenClient()
{ //{
clientListener.Start(); // clientListener.Start();
} //}
//private void listenHttp() //private void listenHttp()
//{ //{
@ -66,8 +68,8 @@ namespace FastTunnel.Core.Client
{ {
_logger.LogInformation("===== FastTunnel Server Stoping ====="); _logger.LogInformation("===== FastTunnel Server Stoping =====");
clientListener.Stop(); //clientListener.Stop();
http_listener.Stop(); //http_listener.Stop();
} }
} }
} }

View File

@ -2,12 +2,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FastTunnel.Core.Client namespace FastTunnel.Core.Client
{ {
public interface IFastTunnelClient public interface IFastTunnelClient
{ {
void Start(); Task StartAsync(CancellationToken cancellationToken);
} }
} }

View File

@ -12,6 +12,6 @@ namespace FastTunnel.Core.Config
public IEnumerable<WebConfig> Webs { get; set; } public IEnumerable<WebConfig> Webs { get; set; }
public IEnumerable<SSHConfig> SSH { get; set; } public IEnumerable<ForwardConfig> Forwards { get; set; }
} }
} }

View File

@ -7,7 +7,7 @@ namespace FastTunnel.Core.Config
{ {
public class DefaultServerConfig : IServerConfig public class DefaultServerConfig : IServerConfig
{ {
public int BindPort { get; set; } // public int BindPort { get; set; }
public string WebDomain { get; set; } public string WebDomain { get; set; }
@ -17,6 +17,6 @@ namespace FastTunnel.Core.Config
public bool WebHasNginxProxy { get; set; } = false; public bool WebHasNginxProxy { get; set; } = false;
public bool SSHEnabled { get; set; } = false; public bool EnableForward { get; set; } = false;
} }
} }

View File

@ -13,7 +13,7 @@ namespace FastTunnel.Core.Config
public IEnumerable<WebConfig> Webs { get; set; } public IEnumerable<WebConfig> Webs { get; set; }
public IEnumerable<SSHConfig> SSH { get; set; } public IEnumerable<ForwardConfig> Forwards { get; set; }
} }
public class SuiDaoServer public class SuiDaoServer

View File

@ -6,7 +6,7 @@ namespace FastTunnel.Core.Config
{ {
public interface IServerConfig public interface IServerConfig
{ {
int BindPort { get; set; } // int BindPort { get; set; }
#region Web相关配置 #region Web相关配置
@ -28,6 +28,6 @@ namespace FastTunnel.Core.Config
#endregion #endregion
bool SSHEnabled { get; set; } bool EnableForward { get; set; }
} }
} }

View File

@ -6,27 +6,31 @@ using FastTunnel.Core.Server;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FastTunnel.Core.Dispatchers namespace FastTunnel.Core.Dispatchers
{ {
public class SSHDispatcher : IListenerDispatcher public class ForwardDispatcher : IListenerDispatcher
{ {
private FastTunnelServer _server; private FastTunnelServer _server;
private Socket _client; private WebSocket _client;
private SSHConfig _config; private ForwardConfig _config;
public SSHDispatcher(FastTunnelServer server, Socket client, SSHConfig config) public ForwardDispatcher(FastTunnelServer server, WebSocket client, ForwardConfig config)
{ {
_server = server; _server = server;
_client = client; _client = client;
_config = config; _config = config;
} }
public void Dispatch(Socket _socket) public async Task DispatchAsync(Socket _socket)
{ {
var msgid = Guid.NewGuid().ToString(); var msgid = Guid.NewGuid().ToString();
_client.SendCmd(new Message<NewSSHRequest> { MessageType = MessageType.S_NewSSH, Content = new NewSSHRequest { MsgId = msgid, SSHConfig = _config } }); await _client.SendCmdAsync(new Message<NewForwardMessage> { MessageType = MessageType.S_NewSSH, Content = new NewForwardMessage { MsgId = msgid, SSHConfig = _config } });
_server.RequestTemp.TryAdd(msgid, new NewRequest _server.RequestTemp.TryAdd(msgid, new NewRequest
{ {
CustomerClient = _socket, CustomerClient = _socket,

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Dispatchers namespace FastTunnel.Core.Dispatchers
{ {
@ -10,6 +11,6 @@ namespace FastTunnel.Core.Dispatchers
{ {
void Dispatch(AsyncUserToken token, string words); void Dispatch(AsyncUserToken token, string words);
void Dispatch(Socket httpClient); Task DispatchAsync(Socket httpClient);
} }
} }

View File

@ -1,12 +0,0 @@
using Newtonsoft.Json;
using FastTunnel.Core.Models;
using System;
using System.Collections.Generic;
using System.Text;
namespace FastTunnel.Core.Extensions
{
public static class MessageExtension
{
}
}

View File

@ -1,7 +1,7 @@
using Newtonsoft.Json; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Text.Json;
namespace FastTunnel.Core.Extensions namespace FastTunnel.Core.Extensions
{ {
@ -9,7 +9,13 @@ namespace FastTunnel.Core.Extensions
{ {
public static string ToJson(this object message) public static string ToJson(this object message)
{ {
return JsonConvert.SerializeObject(message, Formatting.None); if (message == null)
{
return null;
}
var jsonOptions = new JsonSerializerOptions { WriteIndented = false };
return JsonSerializer.Serialize(message, message.GetType(), jsonOptions);
} }
} }
} }

View File

@ -37,7 +37,7 @@ namespace FastTunnel.Core.Extensions
.AddSingleton<ClientHeartHandler>() .AddSingleton<ClientHeartHandler>()
.AddSingleton<LogHandler>() .AddSingleton<LogHandler>()
.AddSingleton<HttpRequestHandler>() .AddSingleton<HttpRequestHandler>()
.AddSingleton<NewSSHHandler>(); .AddSingleton<NewForwardHandler>();
services.AddHostedService<ServiceFastTunnelClient>(); services.AddHostedService<ServiceFastTunnelClient>();
} }

View File

@ -0,0 +1,30 @@
using FastTunnel.Core.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FastTunnel.Core.Extensions
{
public static class WebSocketExtension
{
public static async Task SendCmdAsync<T>(this WebSocket socket, Message<T> message,
WebSocketMessageType webSocketMessage, bool end, CancellationToken cancellationToken)
where T : TunnelMassage
{
var msg = Encoding.UTF8.GetBytes($"{message.MessageType.ToString()}||{message.Content.ToJson()}\n");
await socket.SendAsync(msg, webSocketMessage, end, cancellationToken);
}
public static async Task SendCmdAsync<T>(this WebSocket socket, Message<T> message)
where T : TunnelMassage
{
var msg = Encoding.UTF8.GetBytes($"{message.MessageType.ToString()}||{message.Content.ToJson()}\n");
await socket.SendAsync(msg, WebSocketMessageType.Binary, false, CancellationToken.None);
}
}
}

View File

@ -22,14 +22,17 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="Client\FastTunnelClient - Copy.cs" />
<Compile Remove="Client\SuiDaoServer.cs.BASE.cs" /> <Compile Remove="Client\SuiDaoServer.cs.BASE.cs" />
<Compile Remove="Client\SuiDaoServer.cs.LOCAL.cs" /> <Compile Remove="Client\SuiDaoServer.cs.LOCAL.cs" />
<Compile Remove="Client\SuiDaoServer.cs.REMOTE.cs" /> <Compile Remove="Client\SuiDaoServer.cs.REMOTE.cs" />
<Compile Remove="Dispatchers\ClientDispatcher.cs" /> <Compile Remove="Dispatchers\ClientDispatcher.cs" />
<Compile Remove="Dispatchers\HttpDispatcher.cs" /> <Compile Remove="Dispatchers\HttpDispatcher.cs" />
<Compile Remove="Dispatchers\HttpDispatcherV2.cs" /> <Compile Remove="Dispatchers\HttpDispatcherV2.cs" />
<Compile Remove="Handlers\Server\SwapMessageHandler.cs" />
<Compile Remove="Listener.cs" /> <Compile Remove="Listener.cs" />
<Compile Remove="Listener\ClientListener.cs" /> <Compile Remove="Listener\ClientListener.cs" />
<Compile Remove="Listener\ClientListenerV2.cs" />
<Compile Remove="Listener\HttpListener.cs" /> <Compile Remove="Listener\HttpListener.cs" />
<Compile Remove="Server.cs" /> <Compile Remove="Server.cs" />
<Compile Remove="Sockets\AsyncSocketSwap.cs" /> <Compile Remove="Sockets\AsyncSocketSwap.cs" />
@ -39,7 +42,7 @@
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0-preview.6.21352.12" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0-preview.6.21352.12" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.0.16-alpha" />
<PackageReference Include="Yarp.ReverseProxy" Version="1.0.0-preview.12.21328.2" /> <PackageReference Include="Yarp.ReverseProxy" Version="1.0.0-preview.12.21328.2" />
</ItemGroup> </ItemGroup>

View File

@ -2,7 +2,6 @@
using FastTunnel.Core.Extensions; using FastTunnel.Core.Extensions;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@ -53,7 +52,6 @@ namespace FastTunnel.Core.Forwarder
public async ValueTask<Stream> proxyAsync(string host, CancellationToken cancellation) public async ValueTask<Stream> proxyAsync(string host, CancellationToken cancellation)
{ {
WebInfo web; WebInfo web;
if (!_fastTunnelServer.WebList.TryGetValue(host, out web)) if (!_fastTunnelServer.WebList.TryGetValue(host, out web))
{ {
@ -63,16 +61,18 @@ namespace FastTunnel.Core.Forwarder
try try
{ {
var RequestId = Guid.NewGuid().ToString().Replace("-", ""); var RequestId = Guid.NewGuid().ToString().Replace("-", "");
_logger.LogDebug($"[send swap]:{RequestId}"); _logger.LogInformation($"[发送swap指令]:{RequestId}");
// 发送指令给客户端,等待建立隧道 // 发送指令给客户端,等待建立隧道
web.Socket.SendCmd(new Message<NewCustomerMassage> { MessageType = MessageType.S_NewCustomer, Content = new NewCustomerMassage { MsgId = RequestId, WebConfig = web.WebConfig } }); await web.Socket.SendCmdAsync(new Message<NewCustomerMassage> { MessageType = MessageType.S_NewCustomer, Content = new NewCustomerMassage { MsgId = RequestId, WebConfig = web.WebConfig } });
// TODO:超时处理 // TODO:超时处理
TaskCompletionSource<Stream> task = new(cancellation); TaskCompletionSource<Stream> task = new(cancellation);
_fastTunnelServer.ResponseTasks.TryAdd(RequestId, task); _fastTunnelServer.ResponseTasks.TryAdd(RequestId, task);
return await task.Task;
var res = await task.Task;
_logger.LogInformation($"[收到swap指令]:{RequestId}");
return res;
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Forwarder
{
public interface IReadWriteStream
{
int Read(byte[] buffer);
void Write(byte[] buffer, int index, int num);
}
}

View File

@ -1,24 +1,103 @@
using Microsoft.AspNetCore.Http; using FastTunnel.Core.Client;
using FastTunnel.Core.Forwarder;
using FastTunnel.Core.Models;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Yarp.ReverseProxy.Configuration;
namespace FastTunnel.Core.MiddleWares namespace FastTunnel.Core.MiddleWares
{ {
public class FastTunnelClientHandler public class FastTunnelClientHandler
{ {
public static async Task Handle(HttpContext context, Func<Task> next) ILogger<FastTunnelClientHandler> logger;
FastTunnelServer fastTunnelServer;
public FastTunnelClientHandler(ILogger<FastTunnelClientHandler> logger, FastTunnelServer fastTunnelServer)
{ {
if (!context.WebSockets.IsWebSocketRequest) this.logger = logger;
this.fastTunnelServer = fastTunnelServer;
}
public async Task Handle(HttpContext context, Func<Task> next)
{
if (!context.WebSockets.IsWebSocketRequest
|| !context.Request.Headers.TryGetValue(HeaderConst.FASTTUNNEL_FLAG, out var version)
|| !context.Request.Headers.TryGetValue(HeaderConst.FASTTUNNEL_TYPE, out var type))
{ {
await next(); await next();
return; return;
}; };
if (HeaderConst.TYPE_CLIENT.Equals(type))
{
await Client(context, next);
}
else if (HeaderConst.TYPE_SWAP.Equals(type))
{
await Swap(context, next);
}
else
{
logger.LogError($"参数异常ConnectionType类型为{type}");
}
}
private async Task Swap(HttpContext context, Func<Task> next)
{
var requestId = context.Request.Path.Value.Trim('/');
if (!fastTunnelServer.ResponseTasks.TryGetValue(requestId, out var response))
{
logger.LogError($"requestId不存在:{requestId}");
return;
};
var lifetime = context.Features.Get<IConnectionLifetimeFeature>();
var transport = context.Features.Get<IConnectionTransportFeature>();
if (lifetime == null || transport == null)
{
await next();
return;
}
using var stream = new WebSocketStream(lifetime, transport);
response.TrySetResult(stream);
logger.LogInformation($"Swap Set {requestId}");
var closedAwaiter = new TaskCompletionSource();
lifetime.ConnectionClosed.Register((task) => { (task as TaskCompletionSource).SetResult(); }, closedAwaiter);
await closedAwaiter.Task;
logger.LogInformation($"Swap Completion {requestId}");
}
private async Task Client(HttpContext context, Func<Task> next)
{
using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
var client = new TunnelClient(logger, webSocket, fastTunnelServer);
this.logger.LogInformation($"{client} 客户端连接成功");
try
{
await client.ReviceAsync();
}
catch (Exception ex)
{
logger.LogError(ex, "通信异常");
}
this.logger.LogInformation($"{client} 客户端断开连接");
} }
} }
} }

View File

@ -0,0 +1,60 @@
using FastTunnel.Core.Client;
using FastTunnel.Core.MiddleWares;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Forwarder.MiddleWare
{
public class FastTunnelSwapHandler
{
ILogger<FastTunnelClientHandler> logger;
FastTunnelServer fastTunnelServer;
public FastTunnelSwapHandler(ILogger<FastTunnelClientHandler> logger, FastTunnelServer fastTunnelServer)
{
this.logger = logger;
this.fastTunnelServer = fastTunnelServer;
}
public async Task Handle(HttpContext context, Func<Task> next)
{
if (context.Request.Method != "PROXY")
{
await next();
return;
}
var requestId = context.Request.Path.Value.Trim('/');
if (!fastTunnelServer.ResponseTasks.TryRemove(requestId, out var responseAwaiter))
{
logger.LogError($"requestId不存在:{requestId}");
return;
};
var lifetime = context.Features.Get<IConnectionLifetimeFeature>();
var transport = context.Features.Get<IConnectionTransportFeature>();
if (lifetime == null || transport == null)
{
await next();
return;
}
logger.LogInformation($"Swap Set {requestId}");
using var reverseConnection = new WebSocketStream(lifetime, transport);
responseAwaiter.TrySetResult(reverseConnection);
var closedAwaiter = new TaskCompletionSource<object>();
lifetime.ConnectionClosed.Register((task) => { (task as TaskCompletionSource<object>).SetResult(null); }, closedAwaiter);
await closedAwaiter.Task;
logger.LogInformation($"Swap close {requestId}");
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Forwarder
{
public class SocketReadWriteStream : IReadWriteStream
{
Socket socket;
public SocketReadWriteStream(Socket socket)
{
this.socket = socket;
}
public int Read(byte[] buffer)
{
return socket.Receive(buffer);
}
public void Write(byte[] buffer, int index, int num)
{
socket.Send(buffer, index, num, SocketFlags.None);
}
}
}

View File

@ -0,0 +1,112 @@
using Microsoft;
using Microsoft.AspNetCore.Connections.Features;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FastTunnel.Core.Forwarder
{
sealed class WebSocketStream : Stream
{
private readonly Stream readStream;
private readonly Stream wirteStream;
private readonly IConnectionLifetimeFeature lifetimeFeature;
public WebSocketStream(IConnectionLifetimeFeature lifetimeFeature, IConnectionTransportFeature transportFeature)
{
this.readStream = transportFeature.Transport.Input.AsStream();
this.wirteStream = transportFeature.Transport.Output.AsStream();
this.lifetimeFeature = lifetimeFeature;
}
public WebSocketStream(Stream stream)
{
this.readStream = stream;
this.wirteStream = stream;
this.lifetimeFeature = null;
}
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => throw new NotSupportedException();
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
public override void Flush()
{
this.wirteStream.Flush();
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
return this.wirteStream.FlushAsync(cancellationToken);
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
return this.readStream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
this.wirteStream.Write(buffer, offset, count);
}
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
return this.readStream.ReadAsync(buffer, cancellationToken);
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return this.readStream.ReadAsync(buffer, offset, count, cancellationToken);
}
public override void Write(ReadOnlySpan<byte> buffer)
{
this.wirteStream.Write(buffer);
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return this.wirteStream.WriteAsync(buffer, offset, count, cancellationToken);
}
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
await this.wirteStream.WriteAsync(buffer, cancellationToken);
}
protected override void Dispose(bool disposing)
{
this.lifetimeFeature?.Abort();
}
public override ValueTask DisposeAsync()
{
this.lifetimeFeature?.Abort();
return ValueTask.CompletedTask;
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FastTunnel.Core.Forwarder
{
public class WebSocktReadWriteStream : IReadWriteStream
{
WebSocket webSocket;
public WebSocktReadWriteStream(WebSocket webSocket)
{
this.webSocket = webSocket;
}
public int Read(byte[] buffer)
{
if (this.webSocket.CloseStatus.HasValue)
{
return 0;
}
return webSocket.ReceiveAsync(buffer, CancellationToken.None).GetAwaiter().GetResult().Count;
}
public void Write(byte[] buffer, int offset, int count)
{
this.webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, CancellationToken.None);
}
}
}

View File

@ -1,18 +1,19 @@
using FastTunnel.Core.Config; using FastTunnel.Core.Config;
using FastTunnel.Core.Client; using FastTunnel.Core.Client;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Handlers.Client namespace FastTunnel.Core.Handlers.Client
{ {
public class ClientHeartHandler : IClientHandler public class ClientHeartHandler : IClientHandler
{ {
public void HandlerMsg(FastTunnelClient cleint, Message<JObject> Msg) public async Task HandlerMsgAsync<T>(FastTunnelClient cleint, T Msg) where T : TunnelMassage
{ {
cleint.lastHeart = DateTime.Now; cleint.lastHeart = DateTime.Now;
await Task.Yield();
} }
} }
} }

View File

@ -1,7 +1,6 @@
using FastTunnel.Core.Config; using FastTunnel.Core.Config;
using FastTunnel.Core.Client; using FastTunnel.Core.Client;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -12,6 +11,12 @@ using System.Threading.Tasks;
using FastTunnel.Core.Sockets; using FastTunnel.Core.Sockets;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using FastTunnel.Core.Utility.Extensions; using FastTunnel.Core.Utility.Extensions;
using System.Net.WebSockets;
using FastTunnel.Core.Forwarder;
using Microsoft;
using Microsoft.AspNetCore.DataProtection;
using FastTunnel.Core.Server;
using System.Data.Common;
namespace FastTunnel.Core.Handlers.Client namespace FastTunnel.Core.Handlers.Client
{ {
@ -24,9 +29,9 @@ namespace FastTunnel.Core.Handlers.Client
_logger = logger; _logger = logger;
} }
public void HandlerMsg(FastTunnelClient cleint, Message<JObject> Msg) public async Task HandlerMsgAsync<T>(FastTunnelClient cleint, T Msg) where T : TunnelMassage
{ {
var request = Msg.Content.ToObject<NewCustomerMassage>(); var request = Msg as NewCustomerMassage;
if (request.MsgId.Contains("_")) if (request.MsgId.Contains("_"))
{ {
var interval = long.Parse(DateTime.Now.GetChinaTicks()) - long.Parse(request.MsgId.Split('_')[0]); var interval = long.Parse(DateTime.Now.GetChinaTicks()) - long.Parse(request.MsgId.Split('_')[0]);
@ -34,10 +39,25 @@ namespace FastTunnel.Core.Handlers.Client
_logger.LogDebug($"Start SwapMassage {request.MsgId} 服务端耗时:{interval}ms"); _logger.LogDebug($"Start SwapMassage {request.MsgId} 服务端耗时:{interval}ms");
} }
//var webSocket = new ClientWebSocket();
//webSocket.Options.RemoteCertificateValidationCallback = delegate { return true; };
//webSocket.Options.SetRequestHeader(HeaderConst.FASTTUNNEL_FLAG, "2.0.0");
//webSocket.Options.SetRequestHeader(HeaderConst.FASTTUNNEL_TYPE, HeaderConst.TYPE_SWAP);
//var uri = new Uri($"ws://{cleint.Server.ServerAddr}:{cleint.Server.ServerPort}/{request.MsgId}");
//webSocket.ConnectAsync(uri, CancellationToken.None);
await Task.Yield();
var connecter = new DnsSocket(cleint.Server.ServerAddr, cleint.Server.ServerPort); var connecter = new DnsSocket(cleint.Server.ServerAddr, cleint.Server.ServerPort);
connecter.Connect(); connecter.Connect();
// connecter.Send(new Message<SwapMassage> { MessageType = MessageType.C_SwapMsg, Content = new SwapMassage(request.MsgId) });
connecter.Send(new Message<SwapMassage> { MessageType = MessageType.C_SwapMsg, Content = new SwapMassage(request.MsgId) }); Stream serverConn = new NetworkStream(connecter.Socket, ownsSocket: true);
var reverse = $"PROXY /{request.MsgId} HTTP/1.1\r\nHost: {cleint.Server.ServerAddr}:{cleint.Server.ServerPort}\r\n\r\n";
var requestMsg = Encoding.ASCII.GetBytes(reverse);
serverConn.WriteAsync(requestMsg, CancellationToken.None).GetAwaiter().GetResult();
_logger.LogDebug($"连接server成功 {request.MsgId}"); _logger.LogDebug($"连接server成功 {request.MsgId}");
var localConnecter = new DnsSocket(request.WebConfig.LocalIp, request.WebConfig.LocalPort); var localConnecter = new DnsSocket(request.WebConfig.LocalIp, request.WebConfig.LocalPort);
@ -45,28 +65,25 @@ namespace FastTunnel.Core.Handlers.Client
try try
{ {
localConnecter.Connect(); localConnecter.Connect();
_logger.LogDebug($"连接本地成功 {request.MsgId}");
new SocketSwap(connecter.Socket, localConnecter.Socket, _logger, request.MsgId).StartSwap();
} }
catch (SocketException sex) catch (SocketException sex)
{ {
localConnecter.Close();
if (sex.ErrorCode == 10061) if (sex.ErrorCode == 10061)
{ {
_logger.LogInformation($"内网服务不存在:{request.WebConfig.LocalIp}:{request.WebConfig.LocalPort}");
// 内网的站点不存在或无法访问 // 内网的站点不存在或无法访问
string statusLine = "HTTP/1.1 200 OK\r\n"; //string statusLine = "HTTP/1.1 200 OK\r\n";
string responseHeader = "Content-Type: text/html\r\n"; //string responseHeader = "Content-Type: text/html\r\n";
byte[] responseBody; //byte[] responseBody;
responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NoSite); //responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NoSite);
connecter.Send(Encoding.UTF8.GetBytes(statusLine)); //connecter.Send(Encoding.UTF8.GetBytes(statusLine));
connecter.Send(Encoding.UTF8.GetBytes(responseHeader)); //connecter.Send(Encoding.UTF8.GetBytes(responseHeader));
connecter.Send(Encoding.UTF8.GetBytes("\r\n")); //connecter.Send(Encoding.UTF8.GetBytes("\r\n"));
connecter.Send(responseBody); //connecter.Send(responseBody);
connecter.Socket.Disconnect(false); //connecter.Socket.Disconnect(false);
connecter.Socket.Close(); //connecter.Socket.Close();
return; return;
} }
else else
@ -79,6 +96,31 @@ namespace FastTunnel.Core.Handlers.Client
localConnecter.Close(); localConnecter.Close();
throw; throw;
} }
_logger.LogDebug($"连接本地成功 {request.MsgId}");
//var streamServer = new WebSocktReadWriteStream(webSocket);
//var streamLocal = new SocketReadWriteStream(localConnecter.Socket);
var localConn = new NetworkStream(localConnecter.Socket, ownsSocket: true);
_logger.LogDebug($"开始转发 {request.MsgId}");
var taskX = serverConn.CopyToAsync(localConn, CancellationToken.None);
var taskY = localConn.CopyToAsync(serverConn, CancellationToken.None);
await Task.WhenAny(taskX, taskY);
try
{
localConn.Close();
serverConn.Close();
_logger.LogDebug($"转发结束 {request.MsgId}");
}
catch (Exception ex)
{
_logger.LogDebug(ex, $"转发结束 {request.MsgId}");
}
} }
} }
} }

View File

@ -1,15 +1,15 @@
using FastTunnel.Core.Config; using FastTunnel.Core.Config;
using FastTunnel.Core.Client; using FastTunnel.Core.Client;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Handlers.Client namespace FastTunnel.Core.Handlers.Client
{ {
public interface IClientHandler public interface IClientHandler
{ {
public void HandlerMsg(FastTunnelClient cleint, Message<JObject> Msg); Task HandlerMsgAsync<T>(FastTunnelClient cleint, T Msg) where T : TunnelMassage;
} }
} }

View File

@ -1,10 +1,10 @@
using FastTunnel.Core.Config; using FastTunnel.Core.Config;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System; using System;
using FastTunnel.Core.Extensions; using FastTunnel.Core.Extensions;
using FastTunnel.Core.Client; using FastTunnel.Core.Client;
using System.Threading.Tasks;
namespace FastTunnel.Core.Handlers.Client namespace FastTunnel.Core.Handlers.Client
{ {
@ -17,11 +17,13 @@ namespace FastTunnel.Core.Handlers.Client
_logger = logger; _logger = logger;
} }
public void HandlerMsg(FastTunnelClient cleint, Message<JObject> Msg) public async Task HandlerMsgAsync<T>(FastTunnelClient cleint, T Msg)
where T : TunnelMassage
{ {
try try
{ {
var msg = Msg.Content.ToObject<LogMassage>(); await Task.Yield();
var msg = Msg as LogMassage;
switch (msg.MsgType) switch (msg.MsgType)
{ {

View File

@ -1,33 +1,35 @@
using FastTunnel.Core.Config; using FastTunnel.Core.Config;
using FastTunnel.Core.Client; using FastTunnel.Core.Client;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using FastTunnel.Core.Sockets; using FastTunnel.Core.Sockets;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace FastTunnel.Core.Handlers.Client namespace FastTunnel.Core.Handlers.Client
{ {
public class NewSSHHandler : IClientHandler public class NewForwardHandler : IClientHandler
{ {
ILogger<NewSSHHandler> _logger; ILogger<NewForwardHandler> _logger;
public NewSSHHandler(ILogger<NewSSHHandler> logger) public NewForwardHandler(ILogger<NewForwardHandler> logger)
{ {
_logger = logger; _logger = logger;
} }
public void HandlerMsg(FastTunnelClient cleint, Message<JObject> Msg) public async Task HandlerMsgAsync<T>(FastTunnelClient cleint, T Msg)
where T : TunnelMassage
{ {
var request_ssh = Msg.Content.ToObject<NewSSHRequest>(); var request_ssh = Msg as NewForwardMessage;
await Task.Yield();
var connecter_ssh = new DnsSocket(cleint.Server.ServerAddr, cleint.Server.ServerPort); var connecter_ssh = new DnsSocket(cleint.Server.ServerAddr, cleint.Server.ServerPort);
connecter_ssh.Connect(); connecter_ssh.Connect();
connecter_ssh.Send(new Message<SwapMassage> { MessageType = MessageType.C_SwapMsg, Content = new SwapMassage(request_ssh.MsgId) }); connecter_ssh.Send(new Message<SwapMassage> { MessageType = MessageType.C_SwapMsg, Content = new SwapMassage(request_ssh.MsgId) });
var localConnecter_ssh = new DnsSocket(request_ssh.SSHConfig.LocalIp, request_ssh.SSHConfig.LocalPort); var localConnecter_ssh = new DnsSocket(request_ssh.SSHConfig.LocalIp, request_ssh.SSHConfig.LocalPort);
localConnecter_ssh.Connect(); localConnecter_ssh.Connect();
new SocketSwap(connecter_ssh.Socket, localConnecter_ssh.Socket, _logger, request_ssh.MsgId).StartSwap(); new SocketSwap(connecter_ssh.Socket, localConnecter_ssh.Socket, _logger, request_ssh.MsgId).StartSwap();
} }
} }

View File

@ -1,16 +0,0 @@
using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Text;
namespace FastTunnel.Core.Handlers.Server
{
public class ConfigHandler : IConfigHandler
{
public LogInMassage GetConfig(JObject content)
{
return content.ToObject<LogInMassage>();
}
}
}

View File

@ -1,11 +1,12 @@
using FastTunnel.Core.Client; using FastTunnel.Core.Client;
using FastTunnel.Core.Extensions; using FastTunnel.Core.Extensions;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Handlers.Server namespace FastTunnel.Core.Handlers.Server
{ {
@ -13,9 +14,11 @@ namespace FastTunnel.Core.Handlers.Server
{ {
public bool NeedRecive => true; public bool NeedRecive => true;
public void HandlerMsg(FastTunnelServer server, Socket client, Message<JObject> msg) public async Task<bool> HandlerMsg<T>(FastTunnelServer server, WebSocket client, T msg)
where T : TunnelMassage
{ {
client.SendCmd(new Message<HeartMassage>() { MessageType = MessageType.Heart, Content = null }); await client.SendCmdAsync(new Message<HeartMassage>() { MessageType = MessageType.Heart, Content = new HeartMassage { } });
return NeedRecive;
} }
} }
} }

View File

@ -1,10 +1,11 @@
using FastTunnel.Core.Client; using FastTunnel.Core.Client;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Handlers namespace FastTunnel.Core.Handlers
{ {
@ -12,6 +13,8 @@ namespace FastTunnel.Core.Handlers
{ {
Boolean NeedRecive { get; } Boolean NeedRecive { get; }
void HandlerMsg(FastTunnelServer server, Socket client, Message<JObject> msg); Task<bool> HandlerMsg<T>(FastTunnelServer server, WebSocket client, T msg) where T : TunnelMassage;
//void HandlerMsg(FastTunnelServer server, Socket client, Message<JObject> msg);
} }
} }

View File

@ -1,13 +0,0 @@
using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Text;
namespace FastTunnel.Core.Handlers
{
public interface IConfigHandler
{
LogInMassage GetConfig(JObject content);
}
}

View File

@ -7,12 +7,13 @@ using FastTunnel.Core.Handlers.Server;
using FastTunnel.Core.Listener; using FastTunnel.Core.Listener;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading.Tasks;
using Yarp.ReverseProxy.Configuration; using Yarp.ReverseProxy.Configuration;
using Yarp.Sample; using Yarp.Sample;
@ -23,7 +24,6 @@ namespace FastTunnel.Core.Handlers
ILogger _logger; ILogger _logger;
public bool NeedRecive => true; public bool NeedRecive => true;
IConfigHandler _configHandler;
static object _locker = new object(); static object _locker = new object();
IProxyConfigProvider proxyConfig; IProxyConfigProvider proxyConfig;
@ -32,47 +32,12 @@ namespace FastTunnel.Core.Handlers
{ {
this.proxyConfig = proxyConfig; this.proxyConfig = proxyConfig;
this._logger = logger; this._logger = logger;
var custome = FastTunnelGlobal.GetCustomHandler<IConfigHandler>();
this._configHandler = custome == null ? new ConfigHandler() : custome;
} }
public LogInMassage GetConfig(JObject content) private async Task HandleLoginAsync(FastTunnelServer server, WebSocket client, LogInMassage requet)
{
return _configHandler.GetConfig(content);
}
public void HandlerMsg(FastTunnelServer server, Socket client, Message<JObject> msg)
{
lock (_locker)
{
HandleLogin(server, client, GetConfig(msg.Content));
}
}
public void HandleLogin(FastTunnelServer server, Socket client, LogInMassage requet)
{ {
bool hasTunnel = false; bool hasTunnel = false;
var filters = FastTunnelGlobal.GetFilters(typeof(IAuthenticationFilter));
if (filters.Count() > 0)
{
foreach (IAuthenticationFilter item in filters)
{
var result = item.Authentication(server, requet);
if (!result)
{
client.SendCmd(new Message<LogMassage>
{
MessageType = MessageType.Log,
Content = new LogMassage(LogMsgType.Error, "认证失败")
});
return;
}
}
}
var sb = new StringBuilder($"{Environment.NewLine}=====隧道已建立成功,可通过以下方式访问内网服务====={Environment.NewLine}{Environment.NewLine}"); var sb = new StringBuilder($"{Environment.NewLine}=====隧道已建立成功,可通过以下方式访问内网服务====={Environment.NewLine}{Environment.NewLine}");
sb.Append($"穿透协议 | 映射关系(公网=>内网){Environment.NewLine}"); sb.Append($"穿透协议 | 映射关系(公网=>内网){Environment.NewLine}");
if (requet.Webs != null && requet.Webs.Count() > 0) if (requet.Webs != null && requet.Webs.Count() > 0)
@ -114,11 +79,11 @@ namespace FastTunnel.Core.Handlers
{ {
try try
{ {
if (item.RemotePort.Equals(server.serverOption.CurrentValue.BindPort)) //if (item.RemotePort.Equals(server.serverOption.CurrentValue.BindPort))
{ //{
_logger.LogError($"RemotePort can not be same with BindPort: {item.RemotePort}"); // _logger.LogError($"RemotePort can not be same with BindPort: {item.RemotePort}");
continue; // continue;
} //}
if (item.RemotePort.Equals(server.serverOption.CurrentValue.WebProxyPort)) if (item.RemotePort.Equals(server.serverOption.CurrentValue.WebProxyPort))
{ {
@ -126,20 +91,20 @@ namespace FastTunnel.Core.Handlers
continue; continue;
} }
SSHInfo<SSHHandlerArg> old; ForwardInfo<ForwardHandlerArg> old;
if (server.SSHList.TryGetValue(item.RemotePort, out old)) if (server.SSHList.TryGetValue(item.RemotePort, out old))
{ {
_logger.LogDebug($"Remove Listener {old.Listener.ListenIp}:{old.Listener.ListenPort}"); _logger.LogDebug($"Remove Listener {old.Listener.ListenIp}:{old.Listener.ListenPort}");
old.Listener.Stop(); old.Listener.Stop();
server.SSHList.TryRemove(item.RemotePort, out SSHInfo<SSHHandlerArg> _); server.SSHList.TryRemove(item.RemotePort, out ForwardInfo<ForwardHandlerArg> _);
} }
var ls = new PortProxyListener("0.0.0.0", item.RemotePort, _logger); var ls = new PortProxyListener("0.0.0.0", item.RemotePort, _logger);
ls.Start(new SSHDispatcher(server, client, item)); ls.Start(new ForwardDispatcher(server, client, item));
// listen success // listen success
server.SSHList.TryAdd(item.RemotePort, new SSHInfo<SSHHandlerArg> { Listener = ls, Socket = client, SSHConfig = item }); server.SSHList.TryAdd(item.RemotePort, new ForwardInfo<ForwardHandlerArg> { Listener = ls, Socket = client, SSHConfig = item });
_logger.LogDebug($"SSH proxy success: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}"); _logger.LogDebug($"SSH proxy success: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
sb.Append($" TCP | {server.serverOption.CurrentValue.WebDomain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}"); sb.Append($" TCP | {server.serverOption.CurrentValue.WebDomain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
@ -149,7 +114,7 @@ namespace FastTunnel.Core.Handlers
{ {
_logger.LogError($"SSH proxy error: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}"); _logger.LogError($"SSH proxy error: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
_logger.LogError(ex.Message); _logger.LogError(ex.Message);
client.SendCmd(new Message<LogMassage> { MessageType = MessageType.Log, Content = new LogMassage(LogMsgType.Info, ex.Message) }); await client.SendCmdAsync(new Message<LogMassage> { MessageType = MessageType.Log, Content = new LogMassage(LogMsgType.Info, ex.Message) });
continue; continue;
} }
} }
@ -157,13 +122,20 @@ namespace FastTunnel.Core.Handlers
if (!hasTunnel) if (!hasTunnel)
{ {
client.SendCmd(new Message<LogMassage> { MessageType = MessageType.Log, Content = new LogMassage(LogMsgType.Info, TunnelResource.NoTunnel) }); await client.SendCmdAsync(new Message<LogMassage> { MessageType = MessageType.Log, Content = new LogMassage(LogMsgType.Info, TunnelResource.NoTunnel) });
} }
else else
{ {
sb.Append($"{Environment.NewLine}===================================================="); sb.Append($"{Environment.NewLine}====================================================");
client.SendCmd(new Message<LogMassage> { MessageType = MessageType.Log, Content = new LogMassage(LogMsgType.Info, sb.ToString()) }); await client.SendCmdAsync(new Message<LogMassage> { MessageType = MessageType.Log, Content = new LogMassage(LogMsgType.Info, sb.ToString()) });
} }
} }
public async Task<bool> HandlerMsg<T>(FastTunnelServer server, WebSocket client, T msg)
where T : TunnelMassage
{
await HandleLoginAsync(server, client, msg as LogInMassage);
return NeedRecive;
}
} }
} }

View File

@ -8,6 +8,7 @@ using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -38,7 +39,6 @@ namespace FastTunnel.Core.Handlers.Server
server.ResponseTasks.TryRemove(SwapMsg.msgId, out _); server.ResponseTasks.TryRemove(SwapMsg.msgId, out _);
_logger.LogDebug($"SwapMassage{SwapMsg.msgId}"); _logger.LogDebug($"SwapMassage{SwapMsg.msgId}");
response.SetResult(new NetworkStream(client, true)); response.SetResult(new NetworkStream(client, true));
} }
else else
@ -59,5 +59,10 @@ namespace FastTunnel.Core.Handlers.Server
client.Close(); client.Close();
} }
} }
public Task<bool> HandlerMsg(FastTunnelServer server, WebSocket client, Message<JObject> msg)
{
throw new NotImplementedException();
}
} }
} }

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core
{
public class HeaderConst
{
public const string FASTTUNNEL_FLAG = "FASTTUNNEL_VERSION";
public const string FASTTUNNEL_TYPE = "FASTTUNNEL_TYPE";
public const string FASTTUNNEL_MSGID = "FASTTUNNEL_MSGID";
public const string TYPE_CLIENT = "CLIENT";
public const string TYPE_SWAP = "SWAP";
}
}

View File

@ -43,7 +43,7 @@ namespace FastTunnel.Core.Listener
_heartHandler = new HeartMessageHandler(); _heartHandler = new HeartMessageHandler();
_swapMsgHandler = new SwapMessageHandler(_logger); _swapMsgHandler = new SwapMessageHandler(_logger);
server = new Server.Server(2000, 100, false, _logger); server = new Server.Server(10000, 100, false, _logger);
} }
public void Start() public void Start()

View File

@ -108,7 +108,7 @@ namespace FastTunnel.Core.Listener
try try
{ {
// 将此客户端交由Dispatcher进行管理 // 将此客户端交由Dispatcher进行管理
_requestDispatcher.Dispatch(accept); _requestDispatcher.DispatchAsync(accept);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -4,7 +4,7 @@ using System.Text;
namespace FastTunnel.Core.Models namespace FastTunnel.Core.Models
{ {
public class SSHConfig public class ForwardConfig
{ {
/// <summary> /// <summary>
/// 局域网IP地址 /// 局域网IP地址

View File

@ -5,9 +5,9 @@ using System.Text;
namespace FastTunnel.Core.Models namespace FastTunnel.Core.Models
{ {
public class SSHHandlerArg public class ForwardHandlerArg
{ {
public SSHConfig SSHConfig { get; internal set; } public ForwardConfig SSHConfig { get; internal set; }
public Socket LocalClient { get; internal set; } public Socket LocalClient { get; internal set; }
} }

View File

@ -2,15 +2,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text; using System.Text;
namespace FastTunnel.Core.Models namespace FastTunnel.Core.Models
{ {
public class SSHInfo<T> public class ForwardInfo<T>
{ {
public Socket Socket { get; set; } public WebSocket Socket { get; set; }
public SSHConfig SSHConfig { get; set; } public ForwardConfig SSHConfig { get; set; }
public IListener Listener { get; set; } public IListener Listener { get; set; }
} }

View File

@ -6,5 +6,6 @@ namespace FastTunnel.Core.Models
{ {
public class HeartMassage : TunnelMassage public class HeartMassage : TunnelMassage
{ {
public string Time { get; set; }
} }
} }

View File

@ -15,6 +15,6 @@ namespace FastTunnel.Core.Models
/// <summary> /// <summary>
/// 端口转发隧道列表 /// 端口转发隧道列表
/// </summary> /// </summary>
public IEnumerable<SSHConfig> SSH { get; set; } public IEnumerable<ForwardConfig> SSH { get; set; }
} }
} }

View File

@ -4,10 +4,10 @@ using System.Text;
namespace FastTunnel.Core.Models namespace FastTunnel.Core.Models
{ {
public class NewSSHRequest : TunnelMassage public class NewForwardMessage : TunnelMassage
{ {
public string MsgId { get; set; } public string MsgId { get; set; }
public SSHConfig SSHConfig { get; set; } public ForwardConfig SSHConfig { get; set; }
} }
} }

View File

@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FastTunnel.Core.Models
{
public enum Protocol
{
TCP = 0,
}
}

View File

@ -0,0 +1,90 @@
using FastTunnel.Core.Client;
using FastTunnel.Core.Extensions;
using FastTunnel.Core.Handlers;
using FastTunnel.Core.Handlers.Server;
using FastTunnel.Core.Protocol;
using Microsoft.Extensions.Logging;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Yarp.ReverseProxy.Configuration;
namespace FastTunnel.Core.Models
{
public class TunnelClient
{
readonly LoginHandler _loginHandler;
readonly HeartMessageHandler _heartHandler;
//readonly SwapMessageHandler _swapMsgHandler;
FastTunnelServer fastTunnelServer;
ILogger logger;
WebSocket webSocket;
public TunnelClient(ILogger logger, WebSocket webSocket, FastTunnelServer fastTunnelServer)
{
this.webSocket = webSocket;
this.logger = logger;
this.fastTunnelServer = fastTunnelServer;
this._loginHandler = new LoginHandler(logger, fastTunnelServer.proxyConfig);
this._heartHandler = new HeartMessageHandler();
// this._swapMsgHandler = new SwapMessageHandler(logger);
}
public async Task ReviceAsync()
{
var buffer = new byte[512];
var tunnelProtocol = new TunnelProtocol();
while (true)
{
var res = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
var cmds = tunnelProtocol.HandleBuffer(buffer, 0, res.Count);
foreach (var item in cmds)
{
if (!await HandleCmdAsync(webSocket, item))
{
return;
};
}
}
}
private async Task<bool> HandleCmdAsync(WebSocket webSocket, string lineCmd)
{
try
{
logger.LogInformation($"client{lineCmd}");
var cmds = lineCmd.Split("||");
var type = cmds[0];
TunnelMassage msg = null;
IClientMessageHandler handler = null;
switch (type)
{
case "C_LogIn": // 登录
handler = _loginHandler;
msg = JsonSerializer.Deserialize<LogInMassage>(cmds[1]);
break;
case "Heart": // 心跳
handler = _heartHandler;
break;
default:
throw new Exception($"未知的通讯指令 {lineCmd}");
}
return await handler.HandlerMsg(fastTunnelServer, webSocket, msg);
}
catch (Exception ex)
{
logger.LogError(ex, $"处理客户端消息失败cmd={lineCmd}");
return false;
}
}
}
}

View File

@ -1,13 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Sockets; using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text; using System.Text;
namespace FastTunnel.Core.Models namespace FastTunnel.Core.Models
{ {
public class WebInfo public class WebInfo
{ {
public Socket Socket { get; set; } public WebSocket Socket { get; set; }
public WebConfig WebConfig { get; set; } public WebConfig WebConfig { get; set; }
} }
} }

View File

@ -0,0 +1,40 @@
using FastTunnel.Core.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Protocol
{
public class TunnelProtocol
{
string massgeTemp;
string m_sectionFlag = "\n";
public IEnumerable<string> HandleBuffer(byte[] buffer, int offset, int count)
{
var words = buffer.GetString(offset, count);
var sum = massgeTemp + words;
if (sum.Contains(m_sectionFlag))
{
var array = (sum).Split(m_sectionFlag);
massgeTemp = null;
var fullMsg = words.EndsWith(m_sectionFlag);
if (!fullMsg)
{
massgeTemp = array[array.Length - 1];
}
return array.Take(array.Length - 1);
}
else
{
massgeTemp = sum;
return null;
}
}
}
}

View File

@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using System.IO; using System.IO;
@ -31,7 +30,7 @@ namespace FastTunnel.Core.Services
{ {
return Task.Run(() => return Task.Run(() =>
{ {
_fastTunnelClient.Start(); _fastTunnelClient.StartAsync(cancellationToken);
}, cancellationToken); }, cancellationToken);
} }
@ -46,7 +45,6 @@ namespace FastTunnel.Core.Services
try try
{ {
_logger.LogError("【UnhandledException】" + e.ExceptionObject); _logger.LogError("【UnhandledException】" + e.ExceptionObject);
_logger.LogError("【UnhandledException】" + JsonConvert.SerializeObject(e.ExceptionObject));
var type = e.ExceptionObject.GetType(); var type = e.ExceptionObject.GetType();
_logger.LogError("ExceptionObject GetType " + type); _logger.LogError("ExceptionObject GetType " + type);
} }

View File

@ -5,7 +5,6 @@ using FastTunnel.Core.Global;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -40,7 +39,6 @@ namespace FastTunnel.Core.Services
try try
{ {
_logger.LogError("【UnhandledException】" + e.ExceptionObject); _logger.LogError("【UnhandledException】" + e.ExceptionObject);
_logger.LogError("【UnhandledException】" + JsonConvert.SerializeObject(e.ExceptionObject));
var type = e.ExceptionObject.GetType(); var type = e.ExceptionObject.GetType();
_logger.LogError("ExceptionObject GetType " + type); _logger.LogError("ExceptionObject GetType " + type);
} }

View File

@ -0,0 +1,51 @@
using FastTunnel.Core.Extensions;
using FastTunnel.Core.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FastTunnel.Core.Sockets
{
public class DefultClientSocket : IFastTunnelClientSocket
{
ClientWebSocket webSocket;
public DefultClientSocket()
{
webSocket = new ClientWebSocket();
webSocket.Options.RemoteCertificateValidationCallback = delegate { return true; };
webSocket.Options.SetRequestHeader(HeaderConst.FASTTUNNEL_FLAG, "2.0.0");
webSocket.Options.SetRequestHeader(HeaderConst.FASTTUNNEL_TYPE, HeaderConst.TYPE_CLIENT);
}
public async Task ConnectAsync(Uri url, CancellationToken cancellationToken)
{
await webSocket.ConnectAsync(url, cancellationToken);
}
public async Task CloseAsync()
{
if (webSocket.State == WebSocketState.Closed)
return;
await webSocket.CloseAsync(WebSocketCloseStatus.Empty, null, CancellationToken.None);
}
public async Task<int> ReceiveAsync(byte[] buffer, CancellationToken cancellationToken)
{
var res = await webSocket.ReceiveAsync(buffer, cancellationToken);
return res.Count;
}
public async Task SendAsync<T>(Message<T> msg, CancellationToken cancellationToken)
where T : TunnelMassage
{
await webSocket.SendCmdAsync(msg, WebSocketMessageType.Binary, false, cancellationToken);
}
}
}

View File

@ -0,0 +1,22 @@
using FastTunnel.Core.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FastTunnel.Core.Sockets
{
public interface IFastTunnelClientSocket
{
Task<int> ReceiveAsync(byte[] buffer, CancellationToken cancellationToken);
Task SendAsync<T>(Message<T> loginMsg, CancellationToken cancellationToken)
where T : TunnelMassage;
Task ConnectAsync(Uri url, CancellationToken cancellationToken);
Task CloseAsync();
}
}

View File

@ -0,0 +1,99 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Channels;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Sockets;
using FastTunnel.Core.Forwarder;
namespace FastTunnel.Core.Sockets
{
public class ReadWriteStreamSwap
{
IReadWriteStream stream;
IReadWriteStream stream1;
ILogger logger;
string msgId;
public ReadWriteStreamSwap(IReadWriteStream stream, IReadWriteStream stream1, ILogger logger, string msgId)
{
this.stream = stream;
this.stream1 = stream1;
this.logger = logger;
this.msgId = msgId;
}
public async Task StartSwapAsync()
{
logger.LogDebug($"[StartSwapStart] {msgId}");
var task = new Task(() =>
{
work(stream, stream1);
});
var task1 = new Task(() =>
{
work(stream1, stream);
});
await Task.WhenAll(task1, task);
logger.LogDebug($"[StartSwapEnd] {msgId}");
}
private void work(IReadWriteStream streamRevice, IReadWriteStream streamSend)
{
byte[] buffer = new byte[512];
while (true)
{
int num;
try
{
try
{
num = streamRevice.Read(buffer);
Console.WriteLine($"{Encoding.UTF8.GetString(buffer, 0, num)}");
}
catch (Exception)
{
close("Revice Fail");
break;
}
if (num == 0)
{
close("Normal Close");
break;
}
try
{
streamSend.Write(buffer, 0, num);
}
catch (Exception)
{
close("Send Fail");
break;
}
}
catch (Exception ex)
{
logger.LogCritical(ex, "致命异常");
break;
}
}
}
private void close(string msg)
{
logger.LogError($"Sarp Error {msg}");
}
}
}

View File

@ -2,6 +2,7 @@
using FastTunnel.Core.Utility.Extensions; using FastTunnel.Core.Utility.Extensions;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Net.Sockets; using System.Net.Sockets;

View File

@ -0,0 +1,98 @@
using FastTunnel.Core.Handlers.Client;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace FastTunnel.Core.Sockets
{
public class StreamSwap
{
private Stream stream1;
private Stream stream2;
private ILogger<HttpRequestHandler> logger;
private string msgId;
public StreamSwap(Stream serverConnection, NetworkStream localConn, ILogger<HttpRequestHandler> logger, string msgId)
{
this.stream1 = serverConnection;
this.stream2 = localConn;
this.logger = logger;
this.msgId = msgId;
}
public async Task StartSwapAsync()
{
logger.LogDebug($"[StartSwapStart] {msgId}");
var task = new Task(() =>
{
work(stream1, stream2);
});
var task1 = new Task(() =>
{
work(stream2, stream1);
});
await Task.WhenAll(task1, task);
logger.LogDebug($"[StartSwapEnd] {msgId}");
}
private void work(Stream streamRevice, Stream streamSend)
{
byte[] buffer = new byte[512];
while (true)
{
int num;
try
{
try
{
num = streamRevice.Read(buffer);
Console.WriteLine($"{Encoding.UTF8.GetString(buffer, 0, num)}");
}
catch (Exception)
{
close("Revice Fail");
break;
}
if (num == 0)
{
close("Normal Close");
break;
}
try
{
streamSend.Write(buffer, 0, num);
}
catch (Exception)
{
close("Send Fail");
break;
}
}
catch (Exception ex)
{
logger.LogCritical(ex, "致命异常");
break;
}
}
}
private void close(string msg)
{
logger.LogError($"Sarp Error {msg}");
}
}
}

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div style="text-align:center;">Coming soon!</div>
</body>
</html>

View File

@ -1,12 +0,0 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "3.1.9",
"commands": [
"dotnet-ef"
]
}
}
}

View File

@ -21,10 +21,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="卸载服务.bat"> <None Update="uninstall.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="安装服务.bat"> <None Update="install.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>

View File

@ -2,6 +2,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using FastTunnel.Core.Extensions; using FastTunnel.Core.Extensions;
using FastTunnel.Core.Forwarder; using FastTunnel.Core.Forwarder;
using FastTunnel.Core.Forwarder.MiddleWare;
using FastTunnel.Core.MiddleWares;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -35,6 +37,8 @@ namespace FastTunnel.Server
// ------------------------Custom Business------------------------------ // ------------------------Custom Business------------------------------
services.AddSingleton<IForwarderHttpClientFactory, FastTunnelForwarderHttpClientFactory>(); services.AddSingleton<IForwarderHttpClientFactory, FastTunnelForwarderHttpClientFactory>();
services.AddSingleton<FastTunnelClientHandler, FastTunnelClientHandler>();
services.AddSingleton<FastTunnelSwapHandler, FastTunnelSwapHandler>();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -44,6 +48,13 @@ namespace FastTunnel.Server
{ {
} }
app.UseWebSockets();
var swapHandler = app.ApplicationServices.GetRequiredService<FastTunnelSwapHandler>();
var clientHandler = app.ApplicationServices.GetRequiredService<FastTunnelClientHandler>();
app.Use(clientHandler.Handle);
app.Use(swapHandler.Handle);
app.UseRouting(); app.UseRouting();
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>

View File

@ -1,4 +1,5 @@
{ {
"urls": "http://*:1270;", // Http¼àÌýË¿Ú
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
// Trace Debug Information Warning Error // Trace Debug Information Warning Error
@ -10,14 +11,11 @@
"AllowedHosts": "*", "AllowedHosts": "*",
"ServerSettings": { "ServerSettings": {
// //
"BindPort": 1271, //"BindPort": 1271,
// //
"WebDomain": "test.cc", "WebDomain": "test.cc",
// Http, 访url http://{SubDomain}.{WebDomain}:{WebProxyPort}/
"WebProxyPort": 1270,
// ngixn访 // ngixn访
"WebHasNginxProxy": false, "WebHasNginxProxy": false,
@ -25,6 +23,6 @@
"WebAllowAccessIps": [], "WebAllowAccessIps": [],
// SSHSSH.false // SSHSSH.false
"SSHEnabled": true "EnableForward": true
} }
} }