mirror of
https://github.com/FastTunnel/FastTunnel.git
synced 2025-02-08 02:39:29 +08:00
11
This commit is contained in:
parent
d98b7fea76
commit
3e5020b890
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -12,3 +12,4 @@ publish
|
|||
/SuiDao.Client/Properties/PublishProfiles/FolderProfile.pubxml
|
||||
/FastTunnel.Core/*.user
|
||||
/build
|
||||
/FastTunnel.Server/.config
|
||||
|
|
|
@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging;
|
|||
using FastTunnel.Core.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using FastTunnel.Core.Client;
|
||||
using System;
|
||||
|
||||
namespace FastTunnel.Client
|
||||
{
|
||||
|
@ -10,7 +11,14 @@ namespace FastTunnel.Client
|
|||
{
|
||||
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) =>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//"ServerAddr": "my.com",
|
||||
"ServerAddr": "127.0.0.1",
|
||||
// 服务端监听的通信端口
|
||||
"ServerPort": 1271
|
||||
"ServerPort": 1270
|
||||
},
|
||||
"Webs": [
|
||||
{
|
||||
|
@ -37,11 +37,12 @@
|
|||
],
|
||||
|
||||
/**
|
||||
* ssh穿透,ssh访问内网主机/mysql/erp/等任何服务
|
||||
* 端口转发
|
||||
* 访问内网主机/mysql/erp/等任何TCP协议服务
|
||||
* 远程linux示例:#ssh -oPort=12701 {root}@{ServerAddr} ServerAddr 填入服务端ip,root对应内网用户名
|
||||
* 通过服务端返回的访问方式进行访问即可
|
||||
*/
|
||||
"SSH": [
|
||||
"Forward": [
|
||||
{
|
||||
"LocalIp": "127.0.0.1",
|
||||
"LocalPort": 8090,
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Models;
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
|
@ -15,12 +13,15 @@ using Microsoft.Extensions.Configuration;
|
|||
using FastTunnel.Core.Server;
|
||||
using FastTunnel.Core.Sockets;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FastTunnel.Core.Client
|
||||
{
|
||||
public class FastTunnelClient : IFastTunnelClient
|
||||
{
|
||||
Socket _client;
|
||||
//Socket _client;
|
||||
private IFastTunnelClientSocket socket;
|
||||
|
||||
protected ILogger<FastTunnelClient> _logger;
|
||||
|
||||
|
@ -31,19 +32,19 @@ namespace FastTunnel.Core.Client
|
|||
|
||||
int reTrySpan = 10 * 1000; // 登陆失败后重试间隔
|
||||
HttpRequestHandler _newCustomerHandler;
|
||||
NewSSHHandler _newSSHHandler;
|
||||
NewForwardHandler _newSSHHandler;
|
||||
LogHandler _logHandler;
|
||||
ClientHeartHandler _clientHeartHandler;
|
||||
Func<Socket> lastLogin;
|
||||
Message<LogInMassage> loginMsg;
|
||||
protected readonly IOptionsMonitor<DefaultClientConfig> _configuration;
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new();
|
||||
|
||||
public SuiDaoServer Server { get; protected set; }
|
||||
|
||||
public FastTunnelClient(
|
||||
ILogger<FastTunnelClient> logger,
|
||||
HttpRequestHandler newCustomerHandler,
|
||||
NewSSHHandler newSSHHandler, LogHandler logHandler,
|
||||
NewForwardHandler newSSHHandler, LogHandler logHandler,
|
||||
IOptionsMonitor<DefaultClientConfig> configuration,
|
||||
ClientHeartHandler clientHeartHandler)
|
||||
{
|
||||
|
@ -60,7 +61,7 @@ namespace FastTunnel.Core.Client
|
|||
timer_heart.Elapsed += HeartElapsed;
|
||||
}
|
||||
|
||||
private void reConn()
|
||||
private async Task reConnAsync()
|
||||
{
|
||||
Close();
|
||||
|
||||
|
@ -71,7 +72,7 @@ namespace FastTunnel.Core.Client
|
|||
Thread.Sleep(reTrySpan);
|
||||
|
||||
_logger.LogInformation("登录重试...");
|
||||
_client = lastLogin.Invoke();
|
||||
socket = await loginAsync(CancellationToken.None);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -90,12 +91,12 @@ namespace FastTunnel.Core.Client
|
|||
|
||||
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)
|
||||
{
|
||||
// 与服务端断开连接
|
||||
reConn();
|
||||
reConnAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -108,43 +109,77 @@ namespace FastTunnel.Core.Client
|
|||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <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
|
||||
{
|
||||
_client = lastLogin.Invoke();
|
||||
socket = await loginAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
|
||||
reConn();
|
||||
reConnAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
_ = 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;
|
||||
|
||||
DnsSocket _client = null;
|
||||
_logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}");
|
||||
|
||||
try
|
||||
{
|
||||
// 连接到的目标IP
|
||||
if (_client == null)
|
||||
{
|
||||
_client = new DnsSocket(Server.ServerAddr, Server.ServerPort);
|
||||
}
|
||||
socket = new DefultClientSocket();
|
||||
|
||||
_client.Connect();
|
||||
await socket.ConnectAsync(
|
||||
new Uri($"ws://{_configuration.CurrentValue.Server.ServerAddr}:{_configuration.CurrentValue.Server.ServerPort}"), cancellationToken);
|
||||
|
||||
_logger.LogInformation("连接成功");
|
||||
}
|
||||
|
@ -159,29 +194,19 @@ namespace FastTunnel.Core.Client
|
|||
Content = new LogInMassage
|
||||
{
|
||||
Webs = _configuration.CurrentValue.Webs,
|
||||
SSH = _configuration.CurrentValue.SSH,
|
||||
SSH = _configuration.CurrentValue.Forwards,
|
||||
},
|
||||
};
|
||||
|
||||
// 登录
|
||||
_client.Send(loginMsg);
|
||||
|
||||
return _client.Socket;
|
||||
await socket.SendAsync(loginMsg, cancellationToken);
|
||||
return socket;
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
timer_heart.Stop();
|
||||
|
||||
try
|
||||
{
|
||||
_client?.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
_client?.Close();
|
||||
socket.CloseAsync();
|
||||
}
|
||||
|
||||
private async Task connSuccessAsync()
|
||||
|
@ -192,7 +217,7 @@ namespace FastTunnel.Core.Client
|
|||
timer_heart.Start();
|
||||
|
||||
var th = new Thread(ReceiveServer);
|
||||
th.Start(_client);
|
||||
th.Start(socket);
|
||||
// await new PipeHepler(_client, ProceccLine).ProcessLinesAsync();
|
||||
}
|
||||
|
||||
|
@ -205,7 +230,7 @@ namespace FastTunnel.Core.Client
|
|||
|
||||
private void ReceiveServer(object obj)
|
||||
{
|
||||
var client = obj as Socket;
|
||||
var client = obj as IFastTunnelClientSocket;
|
||||
byte[] buffer = new byte[1024];
|
||||
|
||||
string lastBuffer = string.Empty;
|
||||
|
@ -215,10 +240,10 @@ namespace FastTunnel.Core.Client
|
|||
{
|
||||
try
|
||||
{
|
||||
n = client.Receive(buffer);
|
||||
n = client.ReceiveAsync(buffer, cancellationTokenSource.Token).GetAwaiter().GetResult();
|
||||
if (n == 0)
|
||||
{
|
||||
client.Shutdown(SocketShutdown.Both);
|
||||
client.CloseAsync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -290,36 +315,38 @@ namespace FastTunnel.Core.Client
|
|||
_logger.LogInformation("stop receive from server");
|
||||
}
|
||||
|
||||
private void HandleServerRequest(string words)
|
||||
private void HandleServerRequest(string lineCmd)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
var Msg = JsonConvert.DeserializeObject<Message<JObject>>(words);
|
||||
if (Msg.MessageType != MessageType.Heart)
|
||||
{
|
||||
_logger.LogDebug($"HandleServerRequest {words}");
|
||||
}
|
||||
var cmds = lineCmd.Split("||");
|
||||
var type = cmds[0];
|
||||
|
||||
TunnelMassage msg = null;
|
||||
IClientHandler handler;
|
||||
switch (Msg.MessageType)
|
||||
switch (type)
|
||||
{
|
||||
case MessageType.Heart:
|
||||
case "Heart":
|
||||
handler = _clientHeartHandler;
|
||||
msg = JsonSerializer.Deserialize<HeartMassage>(cmds[1]);
|
||||
break;
|
||||
case MessageType.S_NewCustomer:
|
||||
case "S_NewCustomer":
|
||||
handler = _newCustomerHandler;
|
||||
msg = JsonSerializer.Deserialize<NewCustomerMassage>(cmds[1]);
|
||||
break;
|
||||
case MessageType.S_NewSSH:
|
||||
case "S_NewSSH":
|
||||
handler = _newSSHHandler;
|
||||
msg = JsonSerializer.Deserialize<NewForwardMessage>(cmds[1]);
|
||||
break;
|
||||
case MessageType.Log:
|
||||
case "Log":
|
||||
handler = _logHandler;
|
||||
msg = JsonSerializer.Deserialize<LogMassage>(cmds[1]);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"未处理的消息:{Msg.MessageType} {Msg.Content}");
|
||||
throw new Exception($"未处理的消息:{lineCmd}");
|
||||
}
|
||||
|
||||
handler.HandlerMsg(this, Msg);
|
||||
handler.HandlerMsgAsync(this, msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,35 +27,37 @@ namespace FastTunnel.Core.Client
|
|||
public ConcurrentDictionary<string, WebInfo> WebList { get; private set; }
|
||||
= new ConcurrentDictionary<string, WebInfo>();
|
||||
|
||||
public ConcurrentDictionary<int, SSHInfo<SSHHandlerArg>> SSHList { get; private set; }
|
||||
= new ConcurrentDictionary<int, SSHInfo<SSHHandlerArg>>();
|
||||
public ConcurrentDictionary<int, ForwardInfo<ForwardHandlerArg>> SSHList { get; private set; }
|
||||
= new ConcurrentDictionary<int, ForwardInfo<ForwardHandlerArg>>();
|
||||
|
||||
readonly ILogger _logger;
|
||||
readonly ClientListenerV2 clientListener;
|
||||
readonly HttpListenerV2 http_listener;
|
||||
//readonly ClientListenerV2 clientListener;
|
||||
//readonly HttpListenerV2 http_listener;
|
||||
public readonly IOptionsMonitor<DefaultServerConfig> serverOption;
|
||||
public IProxyConfigProvider proxyConfig;
|
||||
|
||||
public FastTunnelServer(ILogger<FastTunnelServer> logger, IProxyConfigProvider proxyConfig, IOptionsMonitor<DefaultServerConfig> serverSettings)
|
||||
{
|
||||
_logger = logger;
|
||||
serverOption = serverSettings;
|
||||
this.proxyConfig = proxyConfig;
|
||||
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
_logger.LogInformation("===== FastTunnel Server Starting =====");
|
||||
|
||||
listenClient();
|
||||
//listenHttp();
|
||||
// listenClient();
|
||||
// listenHttp();
|
||||
}
|
||||
|
||||
private void listenClient()
|
||||
{
|
||||
clientListener.Start();
|
||||
}
|
||||
//private void listenClient()
|
||||
//{
|
||||
// clientListener.Start();
|
||||
//}
|
||||
|
||||
//private void listenHttp()
|
||||
//{
|
||||
|
@ -66,8 +68,8 @@ namespace FastTunnel.Core.Client
|
|||
{
|
||||
_logger.LogInformation("===== FastTunnel Server Stoping =====");
|
||||
|
||||
clientListener.Stop();
|
||||
http_listener.Stop();
|
||||
//clientListener.Stop();
|
||||
//http_listener.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Client
|
||||
{
|
||||
public interface IFastTunnelClient
|
||||
{
|
||||
void Start();
|
||||
Task StartAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@ namespace FastTunnel.Core.Config
|
|||
|
||||
public IEnumerable<WebConfig> Webs { get; set; }
|
||||
|
||||
public IEnumerable<SSHConfig> SSH { get; set; }
|
||||
public IEnumerable<ForwardConfig> Forwards { get; set; }
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ namespace FastTunnel.Core.Config
|
|||
{
|
||||
public class DefaultServerConfig : IServerConfig
|
||||
{
|
||||
public int BindPort { get; set; }
|
||||
// public int BindPort { get; set; }
|
||||
|
||||
public string WebDomain { get; set; }
|
||||
|
||||
|
@ -17,6 +17,6 @@ namespace FastTunnel.Core.Config
|
|||
|
||||
public bool WebHasNginxProxy { get; set; } = false;
|
||||
|
||||
public bool SSHEnabled { get; set; } = false;
|
||||
public bool EnableForward { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace FastTunnel.Core.Config
|
|||
|
||||
public IEnumerable<WebConfig> Webs { get; set; }
|
||||
|
||||
public IEnumerable<SSHConfig> SSH { get; set; }
|
||||
public IEnumerable<ForwardConfig> Forwards { get; set; }
|
||||
}
|
||||
|
||||
public class SuiDaoServer
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace FastTunnel.Core.Config
|
|||
{
|
||||
public interface IServerConfig
|
||||
{
|
||||
int BindPort { get; set; }
|
||||
// int BindPort { get; set; }
|
||||
|
||||
#region Web相关配置
|
||||
|
||||
|
@ -28,6 +28,6 @@ namespace FastTunnel.Core.Config
|
|||
|
||||
#endregion
|
||||
|
||||
bool SSHEnabled { get; set; }
|
||||
bool EnableForward { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,27 +6,31 @@ using FastTunnel.Core.Server;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Dispatchers
|
||||
{
|
||||
public class SSHDispatcher : IListenerDispatcher
|
||||
public class ForwardDispatcher : IListenerDispatcher
|
||||
{
|
||||
private FastTunnelServer _server;
|
||||
private Socket _client;
|
||||
private SSHConfig _config;
|
||||
private WebSocket _client;
|
||||
private ForwardConfig _config;
|
||||
|
||||
public SSHDispatcher(FastTunnelServer server, Socket client, SSHConfig config)
|
||||
public ForwardDispatcher(FastTunnelServer server, WebSocket client, ForwardConfig config)
|
||||
{
|
||||
_server = server;
|
||||
_client = client;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public void Dispatch(Socket _socket)
|
||||
public async Task DispatchAsync(Socket _socket)
|
||||
{
|
||||
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
|
||||
{
|
||||
CustomerClient = _socket,
|
|
@ -3,6 +3,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Dispatchers
|
||||
{
|
||||
|
@ -10,6 +11,6 @@ namespace FastTunnel.Core.Dispatchers
|
|||
{
|
||||
void Dispatch(AsyncUserToken token, string words);
|
||||
|
||||
void Dispatch(Socket httpClient);
|
||||
Task DispatchAsync(Socket httpClient);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FastTunnel.Core.Extensions
|
||||
{
|
||||
|
@ -9,7 +9,13 @@ namespace FastTunnel.Core.Extensions
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace FastTunnel.Core.Extensions
|
|||
.AddSingleton<ClientHeartHandler>()
|
||||
.AddSingleton<LogHandler>()
|
||||
.AddSingleton<HttpRequestHandler>()
|
||||
.AddSingleton<NewSSHHandler>();
|
||||
.AddSingleton<NewForwardHandler>();
|
||||
|
||||
services.AddHostedService<ServiceFastTunnelClient>();
|
||||
}
|
||||
|
|
30
FastTunnel.Core/Extensions/WebSocketExtension.cs
Normal file
30
FastTunnel.Core/Extensions/WebSocketExtension.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,14 +22,17 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Client\FastTunnelClient - Copy.cs" />
|
||||
<Compile Remove="Client\SuiDaoServer.cs.BASE.cs" />
|
||||
<Compile Remove="Client\SuiDaoServer.cs.LOCAL.cs" />
|
||||
<Compile Remove="Client\SuiDaoServer.cs.REMOTE.cs" />
|
||||
<Compile Remove="Dispatchers\ClientDispatcher.cs" />
|
||||
<Compile Remove="Dispatchers\HttpDispatcher.cs" />
|
||||
<Compile Remove="Dispatchers\HttpDispatcherV2.cs" />
|
||||
<Compile Remove="Handlers\Server\SwapMessageHandler.cs" />
|
||||
<Compile Remove="Listener.cs" />
|
||||
<Compile Remove="Listener\ClientListener.cs" />
|
||||
<Compile Remove="Listener\ClientListenerV2.cs" />
|
||||
<Compile Remove="Listener\HttpListener.cs" />
|
||||
<Compile Remove="Server.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.Logging.Abstractions" 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" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -53,7 +52,6 @@ namespace FastTunnel.Core.Forwarder
|
|||
|
||||
public async ValueTask<Stream> proxyAsync(string host, CancellationToken cancellation)
|
||||
{
|
||||
|
||||
WebInfo web;
|
||||
if (!_fastTunnelServer.WebList.TryGetValue(host, out web))
|
||||
{
|
||||
|
@ -63,16 +61,18 @@ namespace FastTunnel.Core.Forwarder
|
|||
try
|
||||
{
|
||||
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:超时处理
|
||||
TaskCompletionSource<Stream> task = new(cancellation);
|
||||
|
||||
_fastTunnelServer.ResponseTasks.TryAdd(RequestId, task);
|
||||
return await task.Task;
|
||||
|
||||
var res = await task.Task;
|
||||
_logger.LogInformation($"[收到swap指令]:{RequestId}");
|
||||
return res;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
15
FastTunnel.Core/Forwarder/IReadWriteStream.cs
Normal file
15
FastTunnel.Core/Forwarder/IReadWriteStream.cs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Yarp.ReverseProxy.Configuration;
|
||||
|
||||
namespace FastTunnel.Core.MiddleWares
|
||||
{
|
||||
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();
|
||||
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} 客户端断开连接");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
28
FastTunnel.Core/Forwarder/SocketReadWriteStream.cs
Normal file
28
FastTunnel.Core/Forwarder/SocketReadWriteStream.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
112
FastTunnel.Core/Forwarder/WebSocketStream.cs
Normal file
112
FastTunnel.Core/Forwarder/WebSocketStream.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
35
FastTunnel.Core/Forwarder/WebSocktReadWriteStream.cs
Normal file
35
FastTunnel.Core/Forwarder/WebSocktReadWriteStream.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,19 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Client
|
||||
{
|
||||
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;
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -12,6 +11,12 @@ using System.Threading.Tasks;
|
|||
using FastTunnel.Core.Sockets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
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
|
||||
{
|
||||
|
@ -24,9 +29,9 @@ namespace FastTunnel.Core.Handlers.Client
|
|||
_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("_"))
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
//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);
|
||||
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}");
|
||||
var localConnecter = new DnsSocket(request.WebConfig.LocalIp, request.WebConfig.LocalPort);
|
||||
|
@ -45,28 +65,25 @@ namespace FastTunnel.Core.Handlers.Client
|
|||
try
|
||||
{
|
||||
localConnecter.Connect();
|
||||
_logger.LogDebug($"连接本地成功 {request.MsgId}");
|
||||
|
||||
new SocketSwap(connecter.Socket, localConnecter.Socket, _logger, request.MsgId).StartSwap();
|
||||
}
|
||||
catch (SocketException sex)
|
||||
{
|
||||
localConnecter.Close();
|
||||
if (sex.ErrorCode == 10061)
|
||||
{
|
||||
_logger.LogInformation($"内网服务不存在:{request.WebConfig.LocalIp}:{request.WebConfig.LocalPort}");
|
||||
// 内网的站点不存在或无法访问
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
byte[] responseBody;
|
||||
responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NoSite);
|
||||
//string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
//string responseHeader = "Content-Type: text/html\r\n";
|
||||
//byte[] responseBody;
|
||||
//responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NoSite);
|
||||
|
||||
connecter.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
connecter.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
connecter.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
connecter.Send(responseBody);
|
||||
//connecter.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
//connecter.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
//connecter.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
//connecter.Send(responseBody);
|
||||
|
||||
connecter.Socket.Disconnect(false);
|
||||
connecter.Socket.Close();
|
||||
//connecter.Socket.Disconnect(false);
|
||||
//connecter.Socket.Close();
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -79,6 +96,31 @@ namespace FastTunnel.Core.Handlers.Client
|
|||
localConnecter.Close();
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Client
|
||||
{
|
||||
public interface IClientHandler
|
||||
{
|
||||
public void HandlerMsg(FastTunnelClient cleint, Message<JObject> Msg);
|
||||
Task HandlerMsgAsync<T>(FastTunnelClient cleint, T Msg) where T : TunnelMassage;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Client;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Client
|
||||
{
|
||||
|
@ -17,11 +17,13 @@ namespace FastTunnel.Core.Handlers.Client
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public void HandlerMsg(FastTunnelClient cleint, Message<JObject> Msg)
|
||||
public async Task HandlerMsgAsync<T>(FastTunnelClient cleint, T Msg)
|
||||
where T : TunnelMassage
|
||||
{
|
||||
try
|
||||
{
|
||||
var msg = Msg.Content.ToObject<LogMassage>();
|
||||
await Task.Yield();
|
||||
var msg = Msg as LogMassage;
|
||||
|
||||
switch (msg.MsgType)
|
||||
{
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using FastTunnel.Core.Sockets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Client
|
||||
{
|
||||
public class NewSSHHandler : IClientHandler
|
||||
public class NewForwardHandler : IClientHandler
|
||||
{
|
||||
ILogger<NewSSHHandler> _logger;
|
||||
public NewSSHHandler(ILogger<NewSSHHandler> logger)
|
||||
ILogger<NewForwardHandler> _logger;
|
||||
public NewForwardHandler(ILogger<NewForwardHandler> 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);
|
||||
connecter_ssh.Connect();
|
||||
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);
|
||||
localConnecter_ssh.Connect();
|
||||
|
||||
new SocketSwap(connecter_ssh.Socket, localConnecter_ssh.Socket, _logger, request_ssh.MsgId).StartSwap();
|
||||
}
|
||||
}
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Server
|
||||
{
|
||||
|
@ -13,9 +14,11 @@ namespace FastTunnel.Core.Handlers.Server
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Handlers
|
||||
{
|
||||
|
@ -12,6 +13,8 @@ namespace FastTunnel.Core.Handlers
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -7,12 +7,13 @@ using FastTunnel.Core.Handlers.Server;
|
|||
using FastTunnel.Core.Listener;
|
||||
using FastTunnel.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Yarp.ReverseProxy.Configuration;
|
||||
using Yarp.Sample;
|
||||
|
||||
|
@ -23,7 +24,6 @@ namespace FastTunnel.Core.Handlers
|
|||
ILogger _logger;
|
||||
|
||||
public bool NeedRecive => true;
|
||||
IConfigHandler _configHandler;
|
||||
|
||||
static object _locker = new object();
|
||||
IProxyConfigProvider proxyConfig;
|
||||
|
@ -32,47 +32,12 @@ namespace FastTunnel.Core.Handlers
|
|||
{
|
||||
this.proxyConfig = proxyConfig;
|
||||
this._logger = logger;
|
||||
|
||||
var custome = FastTunnelGlobal.GetCustomHandler<IConfigHandler>();
|
||||
this._configHandler = custome == null ? new ConfigHandler() : custome;
|
||||
}
|
||||
|
||||
public LogInMassage GetConfig(JObject content)
|
||||
{
|
||||
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)
|
||||
private async Task HandleLoginAsync(FastTunnelServer server, WebSocket client, LogInMassage requet)
|
||||
{
|
||||
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}");
|
||||
sb.Append($"穿透协议 | 映射关系(公网=>内网){Environment.NewLine}");
|
||||
if (requet.Webs != null && requet.Webs.Count() > 0)
|
||||
|
@ -114,11 +79,11 @@ namespace FastTunnel.Core.Handlers
|
|||
{
|
||||
try
|
||||
{
|
||||
if (item.RemotePort.Equals(server.serverOption.CurrentValue.BindPort))
|
||||
{
|
||||
_logger.LogError($"RemotePort can not be same with BindPort: {item.RemotePort}");
|
||||
continue;
|
||||
}
|
||||
//if (item.RemotePort.Equals(server.serverOption.CurrentValue.BindPort))
|
||||
//{
|
||||
// _logger.LogError($"RemotePort can not be same with BindPort: {item.RemotePort}");
|
||||
// continue;
|
||||
//}
|
||||
|
||||
if (item.RemotePort.Equals(server.serverOption.CurrentValue.WebProxyPort))
|
||||
{
|
||||
|
@ -126,20 +91,20 @@ namespace FastTunnel.Core.Handlers
|
|||
continue;
|
||||
}
|
||||
|
||||
SSHInfo<SSHHandlerArg> old;
|
||||
ForwardInfo<ForwardHandlerArg> old;
|
||||
if (server.SSHList.TryGetValue(item.RemotePort, out old))
|
||||
{
|
||||
_logger.LogDebug($"Remove Listener {old.Listener.ListenIp}:{old.Listener.ListenPort}");
|
||||
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);
|
||||
|
||||
ls.Start(new SSHDispatcher(server, client, item));
|
||||
ls.Start(new ForwardDispatcher(server, client, item));
|
||||
|
||||
// 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}");
|
||||
|
||||
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(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;
|
||||
}
|
||||
}
|
||||
|
@ -157,13 +122,20 @@ namespace FastTunnel.Core.Handlers
|
|||
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ using Newtonsoft.Json.Linq;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -38,7 +39,6 @@ namespace FastTunnel.Core.Handlers.Server
|
|||
server.ResponseTasks.TryRemove(SwapMsg.msgId, out _);
|
||||
|
||||
_logger.LogDebug($"SwapMassage:{SwapMsg.msgId}");
|
||||
|
||||
response.SetResult(new NetworkStream(client, true));
|
||||
}
|
||||
else
|
||||
|
@ -59,5 +59,10 @@ namespace FastTunnel.Core.Handlers.Server
|
|||
client.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> HandlerMsg(FastTunnelServer server, WebSocket client, Message<JObject> msg)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
19
FastTunnel.Core/HeaderConst.cs
Normal file
19
FastTunnel.Core/HeaderConst.cs
Normal 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";
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ namespace FastTunnel.Core.Listener
|
|||
_heartHandler = new HeartMessageHandler();
|
||||
_swapMsgHandler = new SwapMessageHandler(_logger);
|
||||
|
||||
server = new Server.Server(2000, 100, false, _logger);
|
||||
server = new Server.Server(10000, 100, false, _logger);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
|
|
|
@ -108,7 +108,7 @@ namespace FastTunnel.Core.Listener
|
|||
try
|
||||
{
|
||||
// 将此客户端交由Dispatcher进行管理
|
||||
_requestDispatcher.Dispatch(accept);
|
||||
_requestDispatcher.DispatchAsync(accept);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Text;
|
|||
|
||||
namespace FastTunnel.Core.Models
|
||||
{
|
||||
public class SSHConfig
|
||||
public class ForwardConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 局域网IP地址
|
|
@ -5,9 +5,9 @@ using System.Text;
|
|||
|
||||
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; }
|
||||
}
|
|
@ -2,15 +2,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
|
||||
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; }
|
||||
}
|
|
@ -6,5 +6,6 @@ namespace FastTunnel.Core.Models
|
|||
{
|
||||
public class HeartMassage : TunnelMassage
|
||||
{
|
||||
public string Time { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,6 @@ namespace FastTunnel.Core.Models
|
|||
/// <summary>
|
||||
/// 端口转发隧道列表
|
||||
/// </summary>
|
||||
public IEnumerable<SSHConfig> SSH { get; set; }
|
||||
public IEnumerable<ForwardConfig> SSH { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@ using System.Text;
|
|||
|
||||
namespace FastTunnel.Core.Models
|
||||
{
|
||||
public class NewSSHRequest : TunnelMassage
|
||||
public class NewForwardMessage : TunnelMassage
|
||||
{
|
||||
public string MsgId { get; set; }
|
||||
|
||||
public SSHConfig SSHConfig { get; set; }
|
||||
public ForwardConfig SSHConfig { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FastTunnel.Core.Models
|
||||
{
|
||||
public enum Protocol
|
||||
{
|
||||
TCP = 0,
|
||||
}
|
||||
}
|
90
FastTunnel.Core/Models/TunnelClient.cs
Normal file
90
FastTunnel.Core/Models/TunnelClient.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
|
||||
namespace FastTunnel.Core.Models
|
||||
{
|
||||
public class WebInfo
|
||||
{
|
||||
public Socket Socket { get; set; }
|
||||
public WebSocket Socket { get; set; }
|
||||
|
||||
public WebConfig WebConfig { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
40
FastTunnel.Core/Protocol/TunnelProtocol.cs
Normal file
40
FastTunnel.Core/Protocol/TunnelProtocol.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging;
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.IO;
|
||||
|
||||
|
@ -31,7 +30,7 @@ namespace FastTunnel.Core.Services
|
|||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
_fastTunnelClient.Start();
|
||||
_fastTunnelClient.StartAsync(cancellationToken);
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
|
@ -46,7 +45,6 @@ namespace FastTunnel.Core.Services
|
|||
try
|
||||
{
|
||||
_logger.LogError("【UnhandledException】" + e.ExceptionObject);
|
||||
_logger.LogError("【UnhandledException】" + JsonConvert.SerializeObject(e.ExceptionObject));
|
||||
var type = e.ExceptionObject.GetType();
|
||||
_logger.LogError("ExceptionObject GetType " + type);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ using FastTunnel.Core.Global;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -40,7 +39,6 @@ namespace FastTunnel.Core.Services
|
|||
try
|
||||
{
|
||||
_logger.LogError("【UnhandledException】" + e.ExceptionObject);
|
||||
_logger.LogError("【UnhandledException】" + JsonConvert.SerializeObject(e.ExceptionObject));
|
||||
var type = e.ExceptionObject.GetType();
|
||||
_logger.LogError("ExceptionObject GetType " + type);
|
||||
}
|
||||
|
|
51
FastTunnel.Core/Sockets/DefultClientSocket.cs
Normal file
51
FastTunnel.Core/Sockets/DefultClientSocket.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
22
FastTunnel.Core/Sockets/IFastTunnelClientSocket.cs
Normal file
22
FastTunnel.Core/Sockets/IFastTunnelClientSocket.cs
Normal 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();
|
||||
}
|
||||
}
|
99
FastTunnel.Core/Sockets/ReadWriteStreamSwap.cs
Normal file
99
FastTunnel.Core/Sockets/ReadWriteStreamSwap.cs
Normal 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}");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using FastTunnel.Core.Utility.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Sockets;
|
||||
|
|
98
FastTunnel.Core/Sockets/StreamSwap.cs
Normal file
98
FastTunnel.Core/Sockets/StreamSwap.cs
Normal 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}");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "3.1.9",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,10 +21,10 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="卸载服务.bat">
|
||||
<None Update="uninstall.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="安装服务.bat">
|
||||
<None Update="install.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
|
|
@ -2,6 +2,8 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Forwarder;
|
||||
using FastTunnel.Core.Forwarder.MiddleWare;
|
||||
using FastTunnel.Core.MiddleWares;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
@ -35,6 +37,8 @@ namespace FastTunnel.Server
|
|||
|
||||
// ------------------------Custom Business------------------------------
|
||||
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.
|
||||
|
@ -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.UseEndpoints(endpoints =>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"urls": "http://*:1270;", // Http¼àÌý¶Ë¿Ú
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
// Trace Debug Information Warning Error
|
||||
|
@ -10,14 +11,11 @@
|
|||
"AllowedHosts": "*",
|
||||
"ServerSettings": {
|
||||
// 监听端口
|
||||
"BindPort": 1271,
|
||||
//"BindPort": 1271,
|
||||
|
||||
// 绑定域名
|
||||
"WebDomain": "test.cc",
|
||||
|
||||
// Http监听端口, 访问自定义域名站点时url为 http://{SubDomain}.{WebDomain}:{WebProxyPort}/
|
||||
"WebProxyPort": 1270,
|
||||
|
||||
// 可选,ngixn反向代理后可省略域名后的端口号进行访问
|
||||
"WebHasNginxProxy": false,
|
||||
|
||||
|
@ -25,6 +23,6 @@
|
|||
"WebAllowAccessIps": [],
|
||||
|
||||
// 可选,是否开启SSH,禁用后不处理SSH类型端口转发.默认false。
|
||||
"SSHEnabled": true
|
||||
"EnableForward": true
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user