This commit is contained in:
SpringHgui 2020-04-07 23:56:46 +08:00
parent 7e298f7d17
commit 6663f2804e
15 changed files with 286 additions and 79 deletions

View File

@ -9,8 +9,6 @@
"ClientSettings": {
"Common": {
// ip, BindAddr
//"ServerAddr": "45.132.12.57",
"ServerAddr": "127.0.0.1",
// BindPort
@ -25,12 +23,7 @@
"LocalPort": 80,
// , 访url http://{SubDomain}.{Domain}:{ProxyPort_HTTP}/
"SubDomain": "yz"
},
{
"LocalIp": "127.0.0.1",
"LocalPort": 80,
"SubDomain": "tgjmini"
"SubDomain": "test" // test.test.cc
}
],

View File

@ -27,10 +27,12 @@ namespace FastTunnel.Core.Core
System.Timers.Timer timer_heart;
Func<Connecter> login;
double heartInterval = 5000;
double heartInterval = 10 * 1000; // 10 秒心跳
DateTime lastHeart;
Thread th;
int reTrySpan = 30 * 1000; // 登陆失败后重试间隔
public FastTunnelClient(ILogger<FastTunnelClient> logger)
{
_logger = logger;
@ -42,7 +44,7 @@ namespace FastTunnel.Core.Core
{
timer_heart = new System.Timers.Timer();
timer_heart.AutoReset = true;
timer_heart.Interval = heartInterval; // 5秒心跳
timer_heart.Interval = heartInterval;
timer_heart.Elapsed += HeartElapsed;
timer_timeout = new System.Timers.Timer();
@ -70,7 +72,19 @@ namespace FastTunnel.Core.Core
private void reConnect()
{
Close();
_client = login.Invoke();
try
{
_client = login.Invoke();
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
Thread.Sleep(reTrySpan);
reConnect();
return;
}
LogSuccess(_client.Socket);
}
@ -78,7 +92,7 @@ namespace FastTunnel.Core.Core
{
try
{
_client.Send(new Message<string> { MessageType = MessageType.Heart, Content = null });
_client.Send(new Message<object> { MessageType = MessageType.Heart, Content = null });
}
catch (Exception ex)
{
@ -91,7 +105,19 @@ namespace FastTunnel.Core.Core
_serverConfig = serverConfig;
login = fun;
_client = login.Invoke();
try
{
_client = login.Invoke();
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
Thread.Sleep(reTrySpan);
reConnect();
return;
}
LogSuccess(_client.Socket);
}
@ -204,7 +230,7 @@ namespace FastTunnel.Core.Core
var request = (Msg.Content as JObject).ToObject<NewCustomerRequest>();
var connecter = new Connecter(_serverConfig.ServerAddr, _serverConfig.ServerPort);
connecter.Connect();
connecter.Send(new Message<string> { MessageType = MessageType.C_SwapMsg, Content = request.MsgId });
connecter.Send(new Message<SwapMsgModel> { MessageType = MessageType.C_SwapMsg, Content = new SwapMsgModel(request.MsgId) });
var localConnecter = new Connecter(request.WebConfig.LocalIp, request.WebConfig.LocalPort);
localConnecter.Connect();
@ -215,24 +241,31 @@ namespace FastTunnel.Core.Core
var request_ssh = (Msg.Content as JObject).ToObject<NewSSHRequest>();
var connecter_ssh = new Connecter(_serverConfig.ServerAddr, _serverConfig.ServerPort);
connecter_ssh.Connect();
connecter_ssh.Send(new Message<string> { MessageType = MessageType.C_SwapMsg, Content = request_ssh.MsgId });
connecter_ssh.Send(new Message<SwapMsgModel> { MessageType = MessageType.C_SwapMsg, Content = new SwapMsgModel(request_ssh.MsgId) });
var localConnecter_ssh = new Connecter(request_ssh.SSHConfig.LocalIp, request_ssh.SSHConfig.LocalPort);
localConnecter_ssh.Connect();
new SocketSwap(connecter_ssh.Socket, localConnecter_ssh.Socket).StartSwap();
break;
case MessageType.Info:
var info = Msg.Content.ToJson();
_logger.LogInformation("From Server:" + info);
break;
case MessageType.LogDebug:
var LogDebug = Msg.Content.ToJson();
_logger.LogDebug("From Server:" + LogDebug);
break;
case MessageType.Error:
var err = Msg.Content.ToJson();
_logger.LogError("From Server:" + err);
case MessageType.Log:
var msg = (Msg.Content as JObject).ToObject<LogMsg>();
switch (msg.MsgType)
{
case LogMsgType.Info:
_logger.LogInformation("From Server:" + msg.Msg);
break;
case LogMsgType.Error:
_logger.LogError("From Server:" + msg.Msg);
break;
case LogMsgType.Debug:
_logger.LogDebug("From Server:" + msg.Msg);
break;
default:
break;
}
break;
case MessageType.C_SwapMsg:
case MessageType.C_LogIn:

View File

@ -18,15 +18,16 @@ namespace FastTunnel.Core.Core
{
public class FastTunnelServer
{
Dictionary<string, WebInfo> WebList = new Dictionary<string, WebInfo>();
Dictionary<int, SSHInfo<SSHHandlerArg>> SSHList = new Dictionary<int, SSHInfo<SSHHandlerArg>>();
Dictionary<string, NewRequest> newRequest = new Dictionary<string, NewRequest>();
public Dictionary<string, NewRequest> newRequest = new Dictionary<string, NewRequest>();
public Dictionary<string, WebInfo> WebList = new Dictionary<string, WebInfo>();
public Dictionary<int, SSHInfo<SSHHandlerArg>> SSHList = new Dictionary<int, SSHInfo<SSHHandlerArg>>();
public ServerConfig _serverSettings;
private ServerConfig _serverSettings;
ILogger<FastTunnelServer> _logger;
ILoginHandler _loginHandler;
public FastTunnelServer(ServerConfig settings, ILogger<FastTunnelServer> logger, ILoginHandler loginHandler)
LoginHandler _loginHandler;
public FastTunnelServer(ServerConfig settings, ILogger<FastTunnelServer> logger, LoginHandler loginHandler)
{
_serverSettings = settings;
_logger = logger;
@ -143,7 +144,7 @@ namespace FastTunnel.Core.Core
}
}
private void ReceiveClient(Socket client, object _)
public void ReceiveClient(Socket client, object _)
{
//定义byte数组存放从客户端接收过来的数据
byte[] buffer = new byte[1024 * 1024];
@ -190,13 +191,13 @@ namespace FastTunnel.Core.Core
_logger.LogError($"收到客户端 words{words}");
// throw;
client.Send(new Message<string>() { MessageType = MessageType.Error, Content = ex.Message });
client.Send(new Message<LogMsg>() { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Error, ex.Message) });
}
}
private void HandleWords(string words, Socket client)
{
// 读到两个或多个指令
// 同时读到两个或多个指令
var index = words.IndexOf("}{");
if (index > 0)
{
@ -212,10 +213,35 @@ namespace FastTunnel.Core.Core
}
}
private void handle(string words, Socket client)
private IServerHandler handle(string words, Socket client)
{
Message<JObject> msg = JsonConvert.DeserializeObject<Message<JObject>>(words);
IServerHandler handler = null;
switch (msg.MessageType)
{
case MessageType.C_LogIn:
handler = _loginHandler;
break;
case MessageType.Heart:
break;
case MessageType.C_SwapMsg:
case MessageType.S_NewCustomer:
case MessageType.S_NewSSH:
default:
handler = null;
break;
}
if (handler != null)
{
handler.HandlerMsg(this, client, msg);
return handler;
}
HandleMsg(client, msg);
return null;
}
private void HandleMsg(Socket client, Message<JObject> msg)
@ -223,12 +249,6 @@ namespace FastTunnel.Core.Core
_logger.LogDebug($"收到客户端指令:{msg.MessageType}");
switch (msg.MessageType)
{
case MessageType.C_LogIn:
HandleLogin(client, _loginHandler.GetConfig(msg.Content));
// 递归调用
ReceiveClient(client, null);
break;
case MessageType.Heart:
client.Send(new Message<string>() { MessageType = MessageType.Heart, Content = null });
@ -236,10 +256,10 @@ namespace FastTunnel.Core.Core
ReceiveClient(client, null);
break;
case MessageType.C_SwapMsg:
var msgId = msg.Content.ToObject<string>();
var SwapMsg = msg.Content.ToObject<SwapMsgModel>();
NewRequest request;
if (!string.IsNullOrEmpty(msgId) && newRequest.TryGetValue(msgId, out request))
if (!string.IsNullOrEmpty(SwapMsg.msgId) && newRequest.TryGetValue(SwapMsg.msgId, out request))
{
// Join
Task.Run(() =>
@ -252,8 +272,8 @@ namespace FastTunnel.Core.Core
else
{
// 未找到,关闭连接
_logger.LogError($"未找到请求:{msgId}");
client.Send(new Message<string> { MessageType = MessageType.Error, Content = $"未找到请求:{msgId}" });
_logger.LogError($"未找到请求:{SwapMsg.msgId}");
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Debug, $"未找到请求:{SwapMsg.msgId}") });
}
break;
@ -283,10 +303,10 @@ namespace FastTunnel.Core.Core
WebList.Add(hostName, new WebInfo { Socket = client, WebConfig = item });
}
client.Send(new Message<string> { MessageType = MessageType.Info, Content = $"TunnelForWeb is OK: you can visit {item.LocalIp}:{item.LocalPort} from http://{hostName}:{_serverSettings.ProxyPort_HTTP}" });
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Info, $"TunnelForWeb is OK: you can visit {item.LocalIp}:{item.LocalPort} from http://{hostName}:{_serverSettings.ProxyPort_HTTP}") });
}
client.Send(new Message<string> { MessageType = MessageType.Info, Content = "web隧道已建立完毕" });
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Info, "web隧道已建立完毕") });
}
if (requet.SSH != null && requet.SSH.Count() > 0)
@ -322,18 +342,18 @@ namespace FastTunnel.Core.Core
SSHList.Add(item.RemotePort, new SSHInfo<SSHHandlerArg> { Listener = ls, Socket = client, SSHConfig = item });
_logger.LogDebug($"SSH proxy success: {item.RemotePort} -> {item.LocalIp}:{item.LocalPort}");
client.Send(new Message<string> { MessageType = MessageType.Info, Content = $"TunnelForSSH is OK: [ServerAddr]:{item.RemotePort}->{item.LocalIp}:{item.LocalPort}" });
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Info, $"TunnelForSSH is OK: [ServerAddr]:{item.RemotePort}->{item.LocalIp}:{item.LocalPort}") });
}
catch (Exception ex)
{
_logger.LogError($"SSH proxy error: {item.RemotePort} -> {item.LocalIp}:{item.LocalPort}");
_logger.LogError(ex.Message);
client.Send(new Message<string> { MessageType = MessageType.Error, Content = ex.Message });
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Error, ex.Message) });
continue;
}
}
client.Send(new Message<string> { MessageType = MessageType.Info, Content = "远程桌面隧道已建立完毕" });
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Info, "远程桌面隧道已建立完毕") });
}
}

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
{
public class LoginHandler : ILoginHandler
{
public LogInRequest GetConfig(JObject content)
{
return content.ToObject<LogInRequest>();
}
}
}

View File

@ -6,7 +6,7 @@ using System.Text;
namespace FastTunnel.Core.Handlers
{
public interface ILoginHandler
public interface IConfigHandler
{
LogInRequest GetConfig(JObject content);
}

View File

@ -0,0 +1,15 @@
using FastTunnel.Core.Core;
using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
namespace FastTunnel.Core.Handlers
{
public interface IServerHandler
{
void HandlerMsg(FastTunnelServer server, Socket client, Message<JObject> msg);
}
}

View File

@ -0,0 +1,120 @@
using FastTunnel.Core.Core;
using FastTunnel.Core.Extensions;
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.Text;
namespace FastTunnel.Core.Handlers
{
public class LoginHandler : IServerHandler
{
ILogger<LoginHandler> _logger;
public LoginHandler(ILogger<LoginHandler> logger)
{
_logger = logger;
}
public LogInRequest GetConfig(JObject content)
{
return content.ToObject<LogInRequest>();
}
public void HandlerMsg(FastTunnelServer server, Socket client, Message<JObject> msg)
{
HandleLogin(server, client, GetConfig(msg.Content));
server.ReceiveClient(client, null);
}
public void HandleLogin(FastTunnelServer server, Socket client, LogInRequest requet)
{
if (requet.Webs != null && requet.Webs.Count() > 0)
{
foreach (var item in requet.Webs)
{
var hostName = $"{item.SubDomain}.{server._serverSettings.Domain}".Trim();
if (server.WebList.ContainsKey(hostName))
{
_logger.LogDebug($"renew domain '{hostName}'");
server.WebList.Remove(hostName);
server.WebList.Add(hostName, new WebInfo { Socket = client, WebConfig = item });
}
else
{
_logger.LogDebug($"new domain '{hostName}'");
server.WebList.Add(hostName, new WebInfo { Socket = client, WebConfig = item });
}
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Info, $"TunnelForWeb is OK: you can visit {item.LocalIp}:{item.LocalPort} from http://{hostName}:{server._serverSettings.ProxyPort_HTTP}") });
}
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Info, "web隧道已建立完毕") });
}
if (requet.SSH != null && requet.SSH.Count() > 0)
{
foreach (var item in requet.SSH)
{
try
{
if (item.RemotePort.Equals(server._serverSettings.BindPort))
{
_logger.LogError($"RemotePort can not be same with BindPort: {item.RemotePort}");
continue;
}
if (item.RemotePort.Equals(server._serverSettings.ProxyPort_HTTP))
{
_logger.LogError($"RemotePort can not be same with ProxyPort_HTTP: {item.RemotePort}");
continue;
}
SSHInfo<SSHHandlerArg> old;
if (server.SSHList.TryGetValue(item.RemotePort, out old))
{
_logger.LogDebug($"Remove Listener {old.Listener.IP}:{old.Listener.Port}");
old.Listener.ShutdownAndClose();
server.SSHList.Remove(item.RemotePort);
}
var ls = new Listener<SSHHandlerArg>("0.0.0.0", item.RemotePort, _logger,
(client, local) =>
{
var msgid = Guid.NewGuid().ToString();
local.LocalClient.Send(new Message<NewSSHRequest> { MessageType = MessageType.S_NewSSH, Content = new NewSSHRequest { MsgId = msgid, SSHConfig = local.SSHConfig } });
server.newRequest.Add(msgid, new NewRequest
{
CustomerClient = client,
});
}
, new SSHHandlerArg { LocalClient = client, SSHConfig = item });
ls.Listen();
// listen success
server.SSHList.Add(item.RemotePort, new SSHInfo<SSHHandlerArg> { Listener = ls, Socket = client, SSHConfig = item });
_logger.LogDebug($"SSH proxy success: {item.RemotePort} -> {item.LocalIp}:{item.LocalPort}");
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Info, $"TunnelForSSH is OK: [ServerAddr]:{item.RemotePort}->{item.LocalIp}:{item.LocalPort}") });
}
catch (Exception ex)
{
_logger.LogError($"SSH proxy error: {item.RemotePort} -> {item.LocalIp}:{item.LocalPort}");
_logger.LogError(ex.Message);
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Info, ex.Message) });
continue;
}
}
client.Send(new Message<LogMsg> { MessageType = MessageType.Log, Content = new LogMsg(LogMsgType.Info, "远程桌面隧道已建立完毕") });
}
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FastTunnel.Core.Models
{
public class LogMsg
{
public string Msg { get; set; }
public LogMsgType MsgType { get; set; }
public LogMsg(LogMsgType msgType, string msg)
{
this.Msg = msg;
MsgType = msgType;
}
}
public enum LogMsgType
{
Info,
Error,
Debug
}
}

View File

@ -23,10 +23,6 @@ namespace FastTunnel.Core.Models
S_NewSSH,
// twoway
Info,
LogDebug,
Error,
Log,
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FastTunnel.Core.Models
{
public class SwapMsgModel
{
public string msgId { get; set; }
public SwapMsgModel(string msgId)
{
this.msgId = msgId;
}
}
}

View File

@ -16,6 +16,7 @@ using NLog;
using FastTunnel.Core.Config;
using FastTunnel.Core.Host;
using FastTunnel.Core.Core;
using FastTunnel.Core.Handlers;
namespace FastTunnel.Server
{
@ -65,6 +66,7 @@ namespace FastTunnel.Server
private static void Config(ServiceCollection service)
{
service.AddTransient<FastTunnelServer>()
.AddSingleton<LoginHandler>()
.AddSingleton<ServerConfig>(implementationFactory);
}

View File

@ -11,7 +11,7 @@
"BindPort": 1271,
//
"Domain": "ft.suidao.io",
"Domain": "test.cc",
// , 访url http://{SubDomain}.{Domain}:{ProxyPort_HTTP}/
"ProxyPort_HTTP": 1270

View File

@ -99,8 +99,6 @@ namespace SuiDao.Client
return _client;
}, new SuiDaoServer { ServerAddr = server.ip, ServerPort = server.bind_port });
}
else
{

View File

@ -1,14 +1,16 @@
using FastTunnel.Core.Exceptions;
using FastTunnel.Core.Core;
using FastTunnel.Core.Exceptions;
using FastTunnel.Core.Handlers;
using FastTunnel.Core.Models;
using Newtonsoft.Json.Linq;
using SuiDao.Client;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
namespace SuiDao.Server
{
public class SuiDaoLoginHandler : ILoginHandler
public class SuiDaoLoginHandler : IConfigHandler
{
public LogInRequest GetConfig(JObject content)
{

View File

@ -58,7 +58,7 @@ namespace SuiDao.Server
{
service.AddTransient<FastTunnelServer>()
.AddSingleton<ServerConfig>(implementationFactory)
.AddTransient<ILoginHandler, SuiDaoLoginHandler>();
.AddTransient<IConfigHandler, SuiDaoLoginHandler>();
}
private static void Run(IServiceProvider servicesProvider)