添加白名单访问配置

This commit is contained in:
SpringHgui 2020-09-14 15:37:57 +08:00
parent b7705878fa
commit 6908dd2469
12 changed files with 249 additions and 40 deletions

View File

@ -11,7 +11,7 @@ namespace FastTunnel.Core
{
public class AsyncListener<T> : IListener<T>
{
ILogger<object> _logerr;
ILogger _logerr;
public string IP { get; set; }
@ -26,7 +26,7 @@ namespace FastTunnel.Core
// Thread signal.
ManualResetEvent allDone = new ManualResetEvent(false);
public AsyncListener(string ip, int port, ILogger<object> logerr, T data)
public AsyncListener(string ip, int port, ILogger logerr, T data)
{
_logerr = logerr;
_data = data;

View File

@ -10,10 +10,14 @@ namespace FastTunnel.Core.Config
public int BindPort { get; set; }
public int ProxyPort_HTTP { get; set; } = 1270;
public string WebDomain { get; set; }
public string Domain { get; set; }
public int WebProxyPort { get; set; } = 1270;
public bool HasNginxProxy { get; set; } = false;
public string[] WebAllowAccessIps { get; set; }
public bool WebHasNginxProxy { get; set; } = false;
public bool SSHEnabled { get; set; } = true;
}
}

View File

@ -17,19 +17,31 @@ namespace FastTunnel.Core.Config
public DefaultServerConfigBuilder WithWebDomain(string domain)
{
_options.Domain = domain;
_options.WebDomain = domain;
return this;
}
public DefaultServerConfigBuilder WithSSHEnabled(bool enbaled)
{
_options.SSHEnabled = enbaled;
return this;
}
public DefaultServerConfigBuilder WithHasNginxProxy(bool has)
{
_options.HasNginxProxy = has;
_options.WebHasNginxProxy = has;
return this;
}
public DefaultServerConfigBuilder WithWebAllowAccessIps(string[] ips)
{
_options.WebAllowAccessIps = ips;
return this;
}
public DefaultServerConfigBuilder WithHTTPPort(int port)
{
_options.ProxyPort_HTTP = port;
_options.WebProxyPort = port;
return this;
}
@ -41,7 +53,7 @@ namespace FastTunnel.Core.Config
if (_options.BindPort == 0)
throw new ArgumentNullException("You must use WithBindInfo to set port");
if (string.IsNullOrEmpty(_options.Domain))
if (string.IsNullOrEmpty(_options.WebDomain))
throw new ArgumentNullException("You must use WithWebDomain to set domain");
return _options;

View File

@ -10,10 +10,26 @@ namespace FastTunnel.Core.Config
int BindPort { get; set; }
int ProxyPort_HTTP { get; set; }
#region Web相关配置
string Domain { get; set; }
int WebProxyPort { get; set; }
bool HasNginxProxy { get; set; }
string WebDomain { get; set; }
/// <summary>
/// 可选项
/// 当前服务器是否开启了80端口转发至ProxyPort_HTTP的配置
/// </summary>
bool WebHasNginxProxy { get; set; }
/// <summary>
/// 可选项
/// 访问web白名单
/// </summary>
string[] WebAllowAccessIps { get; set; }
#endregion
bool SSHEnabled { get; set; }
}
}

View File

@ -26,7 +26,7 @@ namespace FastTunnel.Core.Core
public Dictionary<string, WebInfo> WebList = new Dictionary<string, WebInfo>();
public Dictionary<int, SSHInfo<SSHHandlerArg>> SSHList = new Dictionary<int, SSHInfo<SSHHandlerArg>>();
public IServerConfig _serverSettings { get; set; }
public IServerConfig _serverSettings { get; private set; }
ILogger<FastTunnelServer> _logger;
@ -34,12 +34,12 @@ namespace FastTunnel.Core.Core
HeartHandler _heartHandler;
SwapMsgHandler _swapMsgHandler;
public FastTunnelServer(ILogger<FastTunnelServer> logger, LoginHandler loginHandler, HeartHandler heartHandler, SwapMsgHandler swapMsgHandler)
public FastTunnelServer(ILogger<FastTunnelServer> logger)
{
_logger = logger;
_loginHandler = loginHandler;
_heartHandler = heartHandler;
_swapMsgHandler = swapMsgHandler;
_loginHandler = new LoginHandler(logger);
_heartHandler = new HeartHandler();
_swapMsgHandler = new SwapMsgHandler(logger);
}
public void Run(IServerConfig settings)
@ -59,16 +59,14 @@ namespace FastTunnel.Core.Core
private void ListenCustomer()
{
var listener = new AsyncListener<object>(_serverSettings.BindAddr, _serverSettings.ProxyPort_HTTP, _logger, null);
var listener = new AsyncListener<object>(_serverSettings.BindAddr, _serverSettings.WebProxyPort, _logger, null);
listener.Listen(ReceiveCustomer);
_logger.LogDebug($"监听HTTP -> {_serverSettings.BindAddr}:{_serverSettings.ProxyPort_HTTP}");
_logger.LogDebug($"监听HTTP -> {_serverSettings.BindAddr}:{_serverSettings.WebProxyPort}");
}
//接收消息
void ReceiveCustomer(Socket client, object _)
{
_logger.LogDebug("Receive HTTP Request");
try
{
@ -98,6 +96,25 @@ namespace FastTunnel.Core.Core
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);
@ -169,6 +186,21 @@ namespace FastTunnel.Core.Core
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}'");

View File

@ -1,5 +1,6 @@
using FastTunnel.Core.Core;
using FastTunnel.Core.Extensions;
using FastTunnel.Core.Handlers.Server;
using FastTunnel.Core.Models;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
@ -13,15 +14,15 @@ namespace FastTunnel.Core.Handlers
{
public class LoginHandler : IServerHandler
{
ILogger<LoginHandler> _logger;
ILogger _logger;
public bool NeedRecive => true;
IConfigHandler _configHandler;
public LoginHandler(ILogger<LoginHandler> logger, IConfigHandler configHandler)
public LoginHandler(ILogger logger)
{
_logger = logger;
_configHandler = configHandler;
_configHandler = new ConfigHandler();
}
public LogInMassage GetConfig(JObject content)
@ -44,7 +45,7 @@ namespace FastTunnel.Core.Handlers
hasTunnel = true;
foreach (var item in requet.Webs)
{
var hostName = $"{item.SubDomain}.{server._serverSettings.Domain}".Trim();
var hostName = $"{item.SubDomain}.{server._serverSettings.WebDomain}".Trim();
if (server.WebList.ContainsKey(hostName))
{
_logger.LogDebug($"renew domain '{hostName}'");
@ -58,7 +59,7 @@ namespace FastTunnel.Core.Handlers
server.WebList.Add(hostName, new WebInfo { Socket = client, WebConfig = item });
}
sb.Append($"{Environment.NewLine} http://{hostName}{(server._serverSettings.HasNginxProxy ? string.Empty : ":" + server._serverSettings.ProxyPort_HTTP)} => {item.LocalIp}:{item.LocalPort}");
sb.Append($"{Environment.NewLine} http://{hostName}{(server._serverSettings.WebHasNginxProxy ? string.Empty : ":" + server._serverSettings.WebProxyPort)} => {item.LocalIp}:{item.LocalPort}");
}
}
@ -77,7 +78,7 @@ namespace FastTunnel.Core.Handlers
continue;
}
if (item.RemotePort.Equals(server._serverSettings.ProxyPort_HTTP))
if (item.RemotePort.Equals(server._serverSettings.WebProxyPort))
{
_logger.LogError($"RemotePort can not be same with ProxyPort_HTTP: {item.RemotePort}");
continue;
@ -110,7 +111,7 @@ namespace FastTunnel.Core.Handlers
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}");
sb.Append($"{Environment.NewLine} {server._serverSettings.Domain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
sb.Append($"{Environment.NewLine} {server._serverSettings.WebDomain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
}
catch (Exception ex)
{

View File

@ -15,9 +15,9 @@ namespace FastTunnel.Core.Handlers.Server
{
public bool NeedRecive => false;
ILogger<LoginHandler> _logger;
ILogger _logger;
public SwapMsgHandler(ILogger<LoginHandler> logger)
public SwapMsgHandler(ILogger logger)
{
_logger = logger;
}

View File

@ -127,6 +127,35 @@ namespace FastTunnel.Core {
}
}
/// <summary>
/// 查找类似 &lt;!DOCTYPE html&gt;
///&lt;html lang=&quot;en&quot;&gt;
///
///&lt;head&gt;
/// &lt;meta charset=&quot;utf-8&quot; /&gt;
/// &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
/// &lt;title&gt;FastTunnel&lt;/title&gt;
/// &lt;link href=&quot;https://cdn.bootcss.com/twitter-bootstrap/4.4.1/css/bootstrap.min.css&quot; rel=&quot;stylesheet&quot;&gt;
/// &lt;style&gt;
/// .err-info {
/// margin-top: 120px;
/// }
///
/// /* Provide sufficient contrast against white background */
/// a {
/// color: #0366d6;
/// }
///
/// .btn-primary {
/// color: #fff;
/// background-color [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary>
internal static string Page_NotAccessIps {
get {
return ResourceManager.GetString("Page_NotAccessIps", resourceCulture);
}
}
/// <summary>
/// 查找类似 &lt;!DOCTYPE html&gt;
///&lt;html lang=&quot;en&quot;&gt;

View File

@ -353,6 +353,122 @@
&lt;/html&gt;</value>
<comment>内网服务未开启</comment>
</data>
<data name="Page_NotAccessIps" xml:space="preserve">
<value>&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
&lt;meta charset="utf-8" /&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
&lt;title&gt;FastTunnel&lt;/title&gt;
&lt;link href="https://cdn.bootcss.com/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"&gt;
&lt;style&gt;
.err-info {
margin-top: 120px;
}
/* Provide sufficient contrast against white background */
a {
color: #0366d6;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active,
.nav-pills .show&gt;.nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px;
/* Vertically center the text there */
}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div class="container err-info"&gt;
&lt;main role="main" class="pb-3"&gt;
&lt;div class="text-center"&gt;
&lt;h1 class="display-4"&gt;您无权访问此站点&lt;/h1&gt;
&lt;p&gt;登录遇到问题? 去github提交&lt;a target="_blank" href="https://github.com/SpringHgui/FastTunnel/issues"&gt;issue&lt;/a&gt;给软件作者.
&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote style="padding-top: 4em;"&gt;
&lt;p class="lead"&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- &lt;ol&gt;
&lt;li class="lead"&gt;&lt;/li&gt;
&lt;li class="lead"&gt;&lt;/li&gt;
&lt;li class="lead"&gt;&lt;/li&gt;
&lt;/ol&gt;--&gt;
&lt;blockquote style="padding-top: 4em;"&gt;
&lt;p class="lead"&gt;提醒:当前软件处于开发阶段,客户端版本可能会更新频繁,如遇到客户端异常,请登录&lt;a target="_blank" href="https://suidao.io"&gt;suidao.io&lt;/a&gt;下载最新的客户端重试。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/main&gt;
&lt;/div&gt;
&lt;footer class="border-top footer text-muted"&gt;
&lt;div class="container"&gt;
&lt;a href="https://github.com/SpringHgui/FastTunnel" target="_blank"&gt;© Power By FastTunnel&lt;/a&gt;
&lt;/div&gt;
&lt;/footer&gt;
&lt;/body&gt;
&lt;/html&gt;</value>
</data>
<data name="Page_NoTunnel" xml:space="preserve">
<value>&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;

View File

@ -34,10 +34,6 @@ namespace FastTunnel.Server
// DI
services.AddTransient<FastTunnelServer>();
services.AddTransient<LoginHandler>();
services.AddTransient<HeartHandler>();
services.AddTransient<SwapMsgHandler>();
services.AddTransient<IConfigHandler, ConfigHandler>();
});
}
}

View File

@ -34,10 +34,11 @@ namespace FastTunnel.Server.Service
_fastTunnelServer.Run(
new DefaultServerConfigBuilder()
.WithWebAllowAccessIps(setting.WebAllowAccessIps)
.WithBindInfo(setting.BindAddr, setting.BindPort)
.WithHasNginxProxy(setting.HasNginxProxy)
.WithWebDomain(setting.Domain)
.WithHTTPPort(setting.ProxyPort_HTTP).Build());
.WithHasNginxProxy(setting.WebHasNginxProxy)
.WithWebDomain(setting.WebDomain).WithSSHEnabled(false)
.WithHTTPPort(setting.WebProxyPort).Build());
}
catch (Exception ex)
{

View File

@ -10,10 +10,12 @@
"BindAddr": "0.0.0.0", //
"BindPort": 1271, //
"Domain": "test.cc", // web穿
"WebDomain": "test.cc", // web穿
// , 访url http://{SubDomain}.{Domain}:{ProxyPort_HTTP}/
"ProxyPort_HTTP": 1270, // web穿
"HasNginxProxy": false // ngixn访
"WebProxyPort": 1270, // web穿
"WebHasNginxProxy": false, // ngixn访
"WebAllowAccessIps": [ "192.168.0.99" ],
"SSHEnabled": false,
}
}