mirror of
https://github.com/FastTunnel/FastTunnel.git
synced 2025-02-08 02:39:29 +08:00
提取接口,进行重构
This commit is contained in:
parent
7c4f5aa3f7
commit
60aea3e9f4
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
@ -17,14 +18,11 @@ namespace FastTunnel.Core
|
|||
|
||||
public int Port { get; set; }
|
||||
|
||||
Action<Socket> receiveClient;
|
||||
int m_numConnectedSockets;
|
||||
|
||||
IListenerDispatcher _requestDispatcher;
|
||||
Socket listenSocket;
|
||||
|
||||
bool Shutdown { get; set; }
|
||||
|
||||
// Thread signal.
|
||||
ManualResetEvent allDone = new ManualResetEvent(false);
|
||||
|
||||
public AsyncListener(string ip, int port, ILogger logerr)
|
||||
{
|
||||
_logerr = logerr;
|
||||
|
@ -38,9 +36,9 @@ namespace FastTunnel.Core
|
|||
listenSocket.Bind(localEndPoint);
|
||||
}
|
||||
|
||||
public void Listen(Action<Socket> receiveClient)
|
||||
public void Listen(IListenerDispatcher requestDispatcher)
|
||||
{
|
||||
this.receiveClient = receiveClient;
|
||||
_requestDispatcher = requestDispatcher;
|
||||
|
||||
listenSocket.Listen(100);
|
||||
|
||||
|
@ -68,8 +66,6 @@ namespace FastTunnel.Core
|
|||
}
|
||||
}
|
||||
|
||||
int m_numConnectedSockets;
|
||||
|
||||
private void ProcessAccept(SocketAsyncEventArgs e)
|
||||
{
|
||||
Interlocked.Increment(ref m_numConnectedSockets);
|
||||
|
@ -81,7 +77,7 @@ namespace FastTunnel.Core
|
|||
// Accept the next connection request
|
||||
StartAccept(e);
|
||||
|
||||
receiveClient.Invoke(accept);
|
||||
_requestDispatcher.Dispatch(accept);
|
||||
}
|
||||
|
||||
private void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
|
||||
|
@ -91,7 +87,6 @@ namespace FastTunnel.Core
|
|||
|
||||
public void ShutdownAndClose()
|
||||
{
|
||||
Shutdown = true;
|
||||
try
|
||||
{
|
||||
listenSocket.Shutdown(SocketShutdown.Both);
|
||||
|
|
|
@ -1,343 +1,47 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Exceptions;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using FastTunnel.Core.Handlers;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using FastTunnel.Core.Helper;
|
||||
using System.IO;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace FastTunnel.Core.Core
|
||||
{
|
||||
public class FastTunnelServer
|
||||
{
|
||||
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 ConcurrentDictionary<string, NewRequest> newRequest = new ConcurrentDictionary<string, NewRequest>();
|
||||
public ConcurrentDictionary<string, WebInfo> WebList = new ConcurrentDictionary<string, WebInfo>();
|
||||
public ConcurrentDictionary<int, SSHInfo<SSHHandlerArg>> SSHList = new ConcurrentDictionary<int, SSHInfo<SSHHandlerArg>>();
|
||||
|
||||
public IServerConfig _serverSettings { get; private set; }
|
||||
public readonly IServerConfig ServerSettings;
|
||||
readonly ILogger _logger;
|
||||
|
||||
ILogger<FastTunnelServer> _logger;
|
||||
|
||||
LoginHandler _loginHandler;
|
||||
HeartHandler _heartHandler;
|
||||
SwapMsgHandler _swapMsgHandler;
|
||||
|
||||
public FastTunnelServer(ILogger<FastTunnelServer> logger)
|
||||
public FastTunnelServer(ILogger logger, IServerConfig settings)
|
||||
{
|
||||
_logger = logger;
|
||||
_loginHandler = new LoginHandler(logger);
|
||||
_heartHandler = new HeartHandler();
|
||||
_swapMsgHandler = new SwapMsgHandler(logger);
|
||||
ServerSettings = settings;
|
||||
}
|
||||
|
||||
public void Run(IServerConfig settings)
|
||||
public void Run()
|
||||
{
|
||||
_serverSettings = settings;
|
||||
_logger.LogDebug("FastTunnel Server Start");
|
||||
ListenFastTunnelClient();
|
||||
ListenCustomer();
|
||||
ListenClient();
|
||||
ListenHttp();
|
||||
}
|
||||
|
||||
private void ListenFastTunnelClient()
|
||||
private void ListenClient()
|
||||
{
|
||||
IListener listener = new AsyncListener(_serverSettings.BindAddr, _serverSettings.BindPort, _logger);
|
||||
listener.Listen(ReceiveClient);
|
||||
_logger.LogDebug($"监听客户端 -> {_serverSettings.BindAddr}:{_serverSettings.BindPort}");
|
||||
IListener client_listener = new AsyncListener(ServerSettings.BindAddr, ServerSettings.BindPort, _logger);
|
||||
client_listener.Listen(new ClientDispatcher(this, _logger, ServerSettings));
|
||||
_logger.LogDebug($"监听客户端 -> {ServerSettings.BindAddr}:{ServerSettings.BindPort}");
|
||||
}
|
||||
|
||||
private void ListenCustomer()
|
||||
private void ListenHttp()
|
||||
{
|
||||
var listener = new AsyncListener(_serverSettings.BindAddr, _serverSettings.WebProxyPort, _logger);
|
||||
listener.Listen(ReceiveCustomer);
|
||||
IListener http_listener = new AsyncListener(ServerSettings.BindAddr, ServerSettings.WebProxyPort, _logger);
|
||||
http_listener.Listen(new HttpDispatcher(this, _logger, ServerSettings));
|
||||
|
||||
_logger.LogDebug($"监听HTTP -> {_serverSettings.BindAddr}:{_serverSettings.WebProxyPort}");
|
||||
}
|
||||
|
||||
void ReceiveCustomer(Socket client)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
//定义byte数组存放从客户端接收过来的数据
|
||||
byte[] buffer = new byte[1024];
|
||||
|
||||
int count;
|
||||
try
|
||||
{
|
||||
count = client.Receive(buffer);
|
||||
if (count == 0)
|
||||
{
|
||||
client.Close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
if (client.Connected)
|
||||
client.Close();
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
throw;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var endpoint = client.RemoteEndPoint as System.Net.IPEndPoint;
|
||||
_logger.LogInformation($"Receive HTTP Request {endpoint.Address}:{endpoint.Port}");
|
||||
|
||||
if (_serverSettings.WebAllowAccessIps != null)
|
||||
{
|
||||
if (!_serverSettings.WebAllowAccessIps.Contains(endpoint.Address.ToString()))
|
||||
{
|
||||
HandlerHostNotAccess(client);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
}
|
||||
|
||||
//将字节转换成字符串
|
||||
string words = Encoding.UTF8.GetString(buffer, 0, count);
|
||||
|
||||
// 正则获取Host
|
||||
String Host = string.Empty;
|
||||
var pattern = @"[hH]ost:.+";
|
||||
var collection = Regex.Matches(words, pattern);
|
||||
if (collection.Count == 0)
|
||||
{
|
||||
_logger.LogError($"Host异常:{words}");
|
||||
|
||||
// 返回错误页
|
||||
HandlerHostRequired(client);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Host = collection[0].Value;
|
||||
}
|
||||
|
||||
_logger.LogDebug(Host.Replace("\r", ""));
|
||||
var domain = Host.Split(":")[1].Trim();
|
||||
|
||||
// 判断是否为ip
|
||||
if (IsIpDomian(domain))
|
||||
{
|
||||
// 返回错误页
|
||||
HandlerHostRequired(client);
|
||||
return;
|
||||
}
|
||||
|
||||
WebInfo web;
|
||||
if (!WebList.TryGetValue(domain, out web))
|
||||
{
|
||||
HandlerClientNotOnLine(client, domain, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!web.Socket.Connected)
|
||||
{
|
||||
WebList.Remove(domain);
|
||||
HandlerClientNotOnLine(client, domain, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
var msgid = Guid.NewGuid().ToString();
|
||||
|
||||
byte[] bytes = new byte[count];
|
||||
Array.Copy(buffer, bytes, count);
|
||||
|
||||
newRequest.Add(msgid, new NewRequest
|
||||
{
|
||||
CustomerClient = client,
|
||||
Buffer = bytes
|
||||
});
|
||||
|
||||
_logger.LogDebug($"OK");
|
||||
web.Socket.Send(new Message<NewCustomerMassage> { MessageType = MessageType.S_NewCustomer, Content = new NewCustomerMassage { MsgId = msgid, WebConfig = web.WebConfig } });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("处理Http失败:" + ex);
|
||||
client.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsIpDomian(string domain)
|
||||
{
|
||||
return Regex.IsMatch(domain, @"^\d.\d.\d.\d.\d$");
|
||||
}
|
||||
|
||||
private void HandlerHostNotAccess(Socket client)
|
||||
{
|
||||
_logger.LogDebug($"### NotAccessIps:'{client.RemoteEndPoint}'");
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
|
||||
byte[] responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NotAccessIps);
|
||||
|
||||
client.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
client.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
client.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
client.Send(responseBody);
|
||||
client.Close();
|
||||
}
|
||||
|
||||
private void HandlerHostRequired(Socket client)
|
||||
{
|
||||
_logger.LogDebug($"### HostRequired:'{client.RemoteEndPoint}'");
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
|
||||
byte[] responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_HostRequired);
|
||||
|
||||
client.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
client.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
client.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
client.Send(responseBody);
|
||||
client.Close();
|
||||
}
|
||||
|
||||
private void HandlerClientNotOnLine(Socket client, string domain, byte[] buffer)
|
||||
{
|
||||
_logger.LogDebug($"### TunnelNotFound:'{domain}'");
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
|
||||
byte[] responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NoTunnel);
|
||||
|
||||
client.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
client.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
client.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
client.Send(responseBody);
|
||||
client.Close();
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[1024 * 1024];
|
||||
string temp = string.Empty;
|
||||
|
||||
public void ReceiveClient(Socket client)
|
||||
{
|
||||
//定义byte数组存放从客户端接收过来的数据
|
||||
int length;
|
||||
|
||||
try
|
||||
{
|
||||
length = client.Receive(buffer);
|
||||
if (length == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
catch
|
||||
{
|
||||
client.Close();
|
||||
}
|
||||
|
||||
// 递归结束
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"接收客户端异常 -> 退出登录 {ex.Message}");
|
||||
|
||||
if (client.Connected)
|
||||
{
|
||||
client.Close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 将字节转换成字符串
|
||||
string words = Encoding.UTF8.GetString(buffer, 0, length);
|
||||
words += temp;
|
||||
temp = string.Empty;
|
||||
|
||||
_logger.LogDebug($"revice from client: {words}");
|
||||
|
||||
try
|
||||
{
|
||||
int index = 0;
|
||||
bool needRecive = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var firstIndex = words.IndexOf("\n");
|
||||
if (firstIndex < 0)
|
||||
{
|
||||
temp += words;
|
||||
ReceiveClient(client);
|
||||
break;
|
||||
}
|
||||
|
||||
var sub_words = words.Substring(index, firstIndex + 1);
|
||||
var res = handle(sub_words, client);
|
||||
|
||||
if (res.NeedRecive)
|
||||
needRecive = true;
|
||||
|
||||
words = words.Replace(sub_words, string.Empty);
|
||||
if (string.IsNullOrEmpty(words))
|
||||
break;
|
||||
}
|
||||
|
||||
if (needRecive)
|
||||
{
|
||||
ReceiveClient(client);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
_logger.LogError($"handle fail msg:{words}");
|
||||
|
||||
// throw;
|
||||
client.Send(new Message<LogMassage>() { MessageType = MessageType.Log, Content = new LogMassage(LogMsgType.Error, ex.Message) });
|
||||
}
|
||||
}
|
||||
|
||||
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: // 心跳
|
||||
handler = _heartHandler;
|
||||
break;
|
||||
case MessageType.C_SwapMsg: // 交换数据
|
||||
handler = _swapMsgHandler;
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"未知的通讯指令 {msg.MessageType}");
|
||||
}
|
||||
|
||||
handler.HandlerMsg(this, client, msg);
|
||||
return handler;
|
||||
_logger.LogDebug($"监听HTTP -> {ServerSettings.BindAddr}:{ServerSettings.WebProxyPort}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
144
FastTunnel.Core/Handlers/Server/ClientDispatcher.cs
Normal file
144
FastTunnel.Core/Handlers/Server/ClientDispatcher.cs
Normal file
|
@ -0,0 +1,144 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Core;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Server
|
||||
{
|
||||
public class ClientDispatcher : IListenerDispatcher
|
||||
{
|
||||
readonly ILogger _logger;
|
||||
readonly IServerConfig _serverSettings;
|
||||
readonly FastTunnelServer _fastTunnelServer;
|
||||
|
||||
readonly LoginMessageHandler _loginHandler;
|
||||
readonly HeartMessageHandler _heartHandler;
|
||||
readonly SwapMessageHandler _swapMsgHandler;
|
||||
|
||||
public ClientDispatcher(FastTunnelServer fastTunnelServer, ILogger logger, IServerConfig serverSettings)
|
||||
{
|
||||
_logger = logger;
|
||||
_serverSettings = serverSettings;
|
||||
_fastTunnelServer = fastTunnelServer;
|
||||
|
||||
_loginHandler = new LoginMessageHandler(logger);
|
||||
_heartHandler = new HeartMessageHandler();
|
||||
_swapMsgHandler = new SwapMessageHandler(logger);
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[1024 * 1024];
|
||||
string temp = string.Empty;
|
||||
|
||||
public void Dispatch(Socket client)
|
||||
{
|
||||
//定义byte数组存放从客户端接收过来的数据
|
||||
int length;
|
||||
|
||||
try
|
||||
{
|
||||
length = client.Receive(buffer);
|
||||
if (length == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
catch
|
||||
{
|
||||
client.Close();
|
||||
}
|
||||
|
||||
// 递归结束
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"接收客户端异常 -> 退出登录 {ex.Message}");
|
||||
|
||||
if (client.Connected)
|
||||
{
|
||||
client.Close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 将字节转换成字符串
|
||||
string words = Encoding.UTF8.GetString(buffer, 0, length);
|
||||
words += temp;
|
||||
temp = string.Empty;
|
||||
|
||||
_logger.LogDebug($"revice from client: {words}");
|
||||
|
||||
try
|
||||
{
|
||||
int index = 0;
|
||||
bool needRecive = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var firstIndex = words.IndexOf("\n");
|
||||
if (firstIndex < 0)
|
||||
{
|
||||
temp += words;
|
||||
Dispatch(client);
|
||||
break;
|
||||
}
|
||||
|
||||
var sub_words = words.Substring(index, firstIndex + 1);
|
||||
var res = handle(sub_words, client);
|
||||
|
||||
if (res.NeedRecive)
|
||||
needRecive = true;
|
||||
|
||||
words = words.Replace(sub_words, string.Empty);
|
||||
if (string.IsNullOrEmpty(words))
|
||||
break;
|
||||
}
|
||||
|
||||
if (needRecive)
|
||||
{
|
||||
Dispatch(client);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
_logger.LogError($"handle fail msg:{words}");
|
||||
|
||||
// throw;
|
||||
client.Send(new Message<LogMassage>() { MessageType = MessageType.Log, Content = new LogMassage(LogMsgType.Error, ex.Message) });
|
||||
}
|
||||
}
|
||||
|
||||
private IClientMessageHandler handle(string words, Socket client)
|
||||
{
|
||||
Message<JObject> msg = JsonConvert.DeserializeObject<Message<JObject>>(words);
|
||||
|
||||
IClientMessageHandler handler = null;
|
||||
switch (msg.MessageType)
|
||||
{
|
||||
case MessageType.C_LogIn: // 登录
|
||||
handler = _loginHandler;
|
||||
break;
|
||||
case MessageType.Heart: // 心跳
|
||||
handler = _heartHandler;
|
||||
break;
|
||||
case MessageType.C_SwapMsg: // 交换数据
|
||||
handler = _swapMsgHandler;
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"未知的通讯指令 {msg.MessageType}");
|
||||
}
|
||||
|
||||
handler.HandlerMsg(this._fastTunnelServer, client, msg);
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ using System.Text;
|
|||
|
||||
namespace FastTunnel.Core.Handlers.Server
|
||||
{
|
||||
public class HeartHandler : IServerHandler
|
||||
public class HeartMessageHandler : IClientMessageHandler
|
||||
{
|
||||
public bool NeedRecive => true;
|
||||
|
194
FastTunnel.Core/Handlers/Server/HttpDispatcher.cs
Normal file
194
FastTunnel.Core/Handlers/Server/HttpDispatcher.cs
Normal file
|
@ -0,0 +1,194 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Core;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Server
|
||||
{
|
||||
public class HttpDispatcher : IListenerDispatcher
|
||||
{
|
||||
readonly ILogger _logger;
|
||||
readonly IServerConfig _serverSettings;
|
||||
readonly FastTunnelServer _fastTunnelServer;
|
||||
|
||||
public HttpDispatcher(FastTunnelServer fastTunnelServer, ILogger logger, IServerConfig serverSettings)
|
||||
{
|
||||
_logger = logger;
|
||||
_serverSettings = serverSettings;
|
||||
_fastTunnelServer = fastTunnelServer;
|
||||
}
|
||||
|
||||
public void Dispatch(Socket httpClient)
|
||||
{
|
||||
try
|
||||
{
|
||||
//定义byte数组存放从客户端接收过来的数据
|
||||
byte[] buffer = new byte[1024];
|
||||
|
||||
int count;
|
||||
try
|
||||
{
|
||||
count = httpClient.Receive(buffer);
|
||||
if (count == 0)
|
||||
{
|
||||
httpClient.Close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
if (httpClient.Connected)
|
||||
httpClient.Close();
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
throw;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var endpoint = httpClient.RemoteEndPoint as System.Net.IPEndPoint;
|
||||
_logger.LogInformation($"Receive HTTP Request {endpoint.Address}:{endpoint.Port}");
|
||||
|
||||
if (_serverSettings.WebAllowAccessIps != null)
|
||||
{
|
||||
if (!_serverSettings.WebAllowAccessIps.Contains(endpoint.Address.ToString()))
|
||||
{
|
||||
HandlerHostNotAccess(httpClient);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
}
|
||||
|
||||
//将字节转换成字符串
|
||||
string words = Encoding.UTF8.GetString(buffer, 0, count);
|
||||
|
||||
// 正则获取Host
|
||||
String Host = string.Empty;
|
||||
var pattern = @"[hH]ost:.+";
|
||||
var collection = Regex.Matches(words, pattern);
|
||||
if (collection.Count == 0)
|
||||
{
|
||||
_logger.LogError($"Host异常:{words}");
|
||||
|
||||
// 返回错误页
|
||||
HandlerHostRequired(httpClient);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Host = collection[0].Value;
|
||||
}
|
||||
|
||||
_logger.LogDebug(Host.Replace("\r", ""));
|
||||
var domain = Host.Split(":")[1].Trim();
|
||||
|
||||
// 判断是否为ip
|
||||
if (IsIpDomian(domain))
|
||||
{
|
||||
// 返回错误页
|
||||
HandlerHostRequired(httpClient);
|
||||
return;
|
||||
}
|
||||
|
||||
WebInfo web;
|
||||
if (!_fastTunnelServer.WebList.TryGetValue(domain, out web))
|
||||
{
|
||||
HandlerClientNotOnLine(httpClient, domain, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!web.Socket.Connected)
|
||||
{
|
||||
_fastTunnelServer.WebList.TryRemove(domain, out WebInfo invalidWeb);
|
||||
HandlerClientNotOnLine(httpClient, domain, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
var msgid = Guid.NewGuid().ToString();
|
||||
|
||||
byte[] bytes = new byte[count];
|
||||
Array.Copy(buffer, bytes, count);
|
||||
|
||||
_fastTunnelServer.newRequest.TryAdd(msgid, new NewRequest
|
||||
{
|
||||
CustomerClient = httpClient,
|
||||
Buffer = bytes
|
||||
});
|
||||
|
||||
_logger.LogDebug($"OK");
|
||||
web.Socket.Send(new Message<NewCustomerMassage> { MessageType = MessageType.S_NewCustomer, Content = new NewCustomerMassage { MsgId = msgid, WebConfig = web.WebConfig } });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("处理Http失败:" + ex);
|
||||
httpClient.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool IsIpDomian(string domain)
|
||||
{
|
||||
return Regex.IsMatch(domain, @"^\d.\d.\d.\d.\d$");
|
||||
}
|
||||
|
||||
private void HandlerHostNotAccess(Socket client)
|
||||
{
|
||||
_logger.LogDebug($"### NotAccessIps:'{client.RemoteEndPoint}'");
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
|
||||
byte[] responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NotAccessIps);
|
||||
|
||||
client.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
client.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
client.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
client.Send(responseBody);
|
||||
client.Close();
|
||||
}
|
||||
|
||||
private void HandlerHostRequired(Socket client)
|
||||
{
|
||||
_logger.LogDebug($"### HostRequired:'{client.RemoteEndPoint}'");
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
|
||||
byte[] responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_HostRequired);
|
||||
|
||||
client.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
client.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
client.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
client.Send(responseBody);
|
||||
client.Close();
|
||||
}
|
||||
|
||||
private void HandlerClientNotOnLine(Socket client, string domain, byte[] buffer)
|
||||
{
|
||||
_logger.LogDebug($"### TunnelNotFound:'{domain}'");
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
|
||||
byte[] responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NoTunnel);
|
||||
|
||||
client.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
client.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
client.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
client.Send(responseBody);
|
||||
client.Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ using System.Text;
|
|||
|
||||
namespace FastTunnel.Core.Handlers
|
||||
{
|
||||
public interface IServerHandler
|
||||
public interface IClientMessageHandler
|
||||
{
|
||||
Boolean NeedRecive { get; }
|
||||
|
12
FastTunnel.Core/Handlers/Server/IListenerDispatcher.cs
Normal file
12
FastTunnel.Core/Handlers/Server/IListenerDispatcher.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Server
|
||||
{
|
||||
public interface IListenerDispatcher
|
||||
{
|
||||
void Dispatch(Socket httpClient);
|
||||
}
|
||||
}
|
|
@ -12,14 +12,14 @@ using System.Text;
|
|||
|
||||
namespace FastTunnel.Core.Handlers
|
||||
{
|
||||
public class LoginHandler : IServerHandler
|
||||
public class LoginMessageHandler : IClientMessageHandler
|
||||
{
|
||||
ILogger _logger;
|
||||
|
||||
public bool NeedRecive => true;
|
||||
IConfigHandler _configHandler;
|
||||
|
||||
public LoginHandler(ILogger logger)
|
||||
public LoginMessageHandler(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_configHandler = new ConfigHandler();
|
||||
|
@ -45,21 +45,21 @@ namespace FastTunnel.Core.Handlers
|
|||
hasTunnel = true;
|
||||
foreach (var item in requet.Webs)
|
||||
{
|
||||
var hostName = $"{item.SubDomain}.{server._serverSettings.WebDomain}".Trim();
|
||||
var hostName = $"{item.SubDomain}.{server.ServerSettings.WebDomain}".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 });
|
||||
server.WebList.TryRemove(hostName, out WebInfo web);
|
||||
server.WebList.TryAdd(hostName, new WebInfo { Socket = client, WebConfig = item });
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug($"new domain '{hostName}'");
|
||||
server.WebList.Add(hostName, new WebInfo { Socket = client, WebConfig = item });
|
||||
server.WebList.TryAdd(hostName, new WebInfo { Socket = client, WebConfig = item });
|
||||
}
|
||||
|
||||
sb.Append($"{Environment.NewLine} http://{hostName}{(server._serverSettings.WebHasNginxProxy ? string.Empty : ":" + server._serverSettings.WebProxyPort)} => {item.LocalIp}:{item.LocalPort}");
|
||||
sb.Append($"{Environment.NewLine} http://{hostName}{(server.ServerSettings.WebHasNginxProxy ? string.Empty : ":" + server.ServerSettings.WebProxyPort)} => {item.LocalIp}:{item.LocalPort}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,13 +72,13 @@ namespace FastTunnel.Core.Handlers
|
|||
{
|
||||
try
|
||||
{
|
||||
if (item.RemotePort.Equals(server._serverSettings.BindPort))
|
||||
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.WebProxyPort))
|
||||
if (item.RemotePort.Equals(server.ServerSettings.WebProxyPort))
|
||||
{
|
||||
_logger.LogError($"RemotePort can not be same with ProxyPort_HTTP: {item.RemotePort}");
|
||||
continue;
|
||||
|
@ -89,26 +89,18 @@ namespace FastTunnel.Core.Handlers
|
|||
{
|
||||
_logger.LogDebug($"Remove Listener {old.Listener.IP}:{old.Listener.Port}");
|
||||
old.Listener.ShutdownAndClose();
|
||||
server.SSHList.Remove(item.RemotePort);
|
||||
server.SSHList.TryRemove(item.RemotePort, out SSHInfo<SSHHandlerArg> _);
|
||||
}
|
||||
|
||||
var ls = new AsyncListener("0.0.0.0", item.RemotePort, _logger);
|
||||
|
||||
ls.Listen((_socket) =>
|
||||
{
|
||||
var msgid = Guid.NewGuid().ToString();
|
||||
client.Send(new Message<NewSSHRequest> { MessageType = MessageType.S_NewSSH, Content = new NewSSHRequest { MsgId = msgid, SSHConfig = item } });
|
||||
server.newRequest.Add(msgid, new NewRequest
|
||||
{
|
||||
CustomerClient = _socket,
|
||||
});
|
||||
});
|
||||
ls.Listen(new SSHDispatcher(server, client, item));
|
||||
|
||||
// listen success
|
||||
server.SSHList.Add(item.RemotePort, new SSHInfo<SSHHandlerArg> { Listener = ls, Socket = client, SSHConfig = item });
|
||||
server.SSHList.TryAdd(item.RemotePort, new SSHInfo<SSHHandlerArg> { Listener = ls, Socket = client, SSHConfig = item });
|
||||
_logger.LogDebug($"SSH proxy success: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
|
||||
|
||||
sb.Append($"{Environment.NewLine} {server._serverSettings.WebDomain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
|
||||
sb.Append($"{Environment.NewLine} {server.ServerSettings.WebDomain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
34
FastTunnel.Core/Handlers/Server/SSHDispatcher.cs
Normal file
34
FastTunnel.Core/Handlers/Server/SSHDispatcher.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using FastTunnel.Core.Core;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Server
|
||||
{
|
||||
public class SSHDispatcher : IListenerDispatcher
|
||||
{
|
||||
private FastTunnelServer _server;
|
||||
private Socket _client;
|
||||
private SSHConfig _config;
|
||||
|
||||
public SSHDispatcher(FastTunnelServer server, Socket client, SSHConfig config)
|
||||
{
|
||||
_server = server;
|
||||
_client = client;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public void Dispatch(Socket _socket)
|
||||
{
|
||||
var msgid = Guid.NewGuid().ToString();
|
||||
_client.Send(new Message<NewSSHRequest> { MessageType = MessageType.S_NewSSH, Content = new NewSSHRequest { MsgId = msgid, SSHConfig = _config } });
|
||||
_server.newRequest.TryAdd(msgid, new NewRequest
|
||||
{
|
||||
CustomerClient = _socket,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,13 +11,13 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FastTunnel.Core.Handlers.Server
|
||||
{
|
||||
public class SwapMsgHandler : IServerHandler
|
||||
public class SwapMessageHandler : IClientMessageHandler
|
||||
{
|
||||
public bool NeedRecive => false;
|
||||
|
||||
ILogger _logger;
|
||||
|
||||
public SwapMsgHandler(ILogger logger)
|
||||
public SwapMessageHandler(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
@ -11,7 +12,7 @@ namespace FastTunnel.Core
|
|||
|
||||
int Port { get; }
|
||||
|
||||
void Listen(Action<Socket> receiveClient);
|
||||
void Listen(IListenerDispatcher requestDispatcher);
|
||||
|
||||
void ShutdownAndClose();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using Microsoft.Extensions.Hosting;
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using FastTunnel.Server.Service;
|
||||
using FastTunnel.Core.Logger;
|
||||
using FastTunnel.Core.Config;
|
||||
|
||||
namespace FastTunnel.Server
|
||||
{
|
||||
|
@ -34,6 +35,7 @@ namespace FastTunnel.Server
|
|||
|
||||
// DI
|
||||
services.AddTransient<FastTunnelServer>();
|
||||
//services.AddSingleton<IServerConfig>();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,12 @@ namespace FastTunnel.Server.Service
|
|||
public class ServiceFastTunnelServer : IHostedService
|
||||
{
|
||||
ILogger<ServiceFastTunnelServer> _logger;
|
||||
IConfiguration _configuration;
|
||||
FastTunnelServer _fastTunnelServer;
|
||||
|
||||
public ServiceFastTunnelServer(ILogger<ServiceFastTunnelServer> logger, IConfiguration configuration, FastTunnelServer fastTunnelServer)
|
||||
public ServiceFastTunnelServer(ILogger<ServiceFastTunnelServer> logger, IConfiguration configuration)
|
||||
{
|
||||
_logger = logger;
|
||||
_configuration = configuration;
|
||||
_fastTunnelServer = fastTunnelServer;
|
||||
_fastTunnelServer = new FastTunnelServer(_logger, configuration.Get<Appsettings>().ServerSettings);
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
|
@ -30,15 +28,7 @@ namespace FastTunnel.Server.Service
|
|||
|
||||
try
|
||||
{
|
||||
var setting = _configuration.Get<Appsettings>().ServerSettings;
|
||||
|
||||
_fastTunnelServer.Run(
|
||||
new DefaultServerConfigBuilder()
|
||||
.WithWebAllowAccessIps(setting.WebAllowAccessIps)
|
||||
.WithBindInfo(setting.BindAddr, setting.BindPort)
|
||||
.WithHasNginxProxy(setting.WebHasNginxProxy)
|
||||
.WithWebDomain(setting.WebDomain).WithSSHEnabled(false)
|
||||
.WithHTTPPort(setting.WebProxyPort).Build());
|
||||
_fastTunnelServer.Run();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user