add GlobalListener

This commit is contained in:
陈国伟 2021-11-25 11:37:55 +08:00
parent a5d79b40db
commit 402b7c5f2a
9 changed files with 149 additions and 141 deletions

View File

@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
namespace FastGithub.Configuration
{
/// <summary>
/// 监听器
/// </summary>
public static class GlobalListener
{
private static readonly IPGlobalProperties global = IPGlobalProperties.GetIPGlobalProperties();
private static readonly HashSet<int> tcpListenPorts = GetListenPorts(global.GetActiveTcpListeners);
private static readonly HashSet<int> udpListenPorts = GetListenPorts(global.GetActiveUdpListeners);
/// <summary>
/// ssh端口
/// </summary>
public static int SshPort { get; } = GetAvailableTcpPort(22);
/// <summary>
/// git端口
/// </summary>
public static int GitPort { get; } = GetAvailableTcpPort(9418);
/// <summary>
/// http端口
/// </summary>
public static int HttpPort { get; } = OperatingSystem.IsWindows() ? GetAvailableTcpPort(80) : GetAvailableTcpPort(3880);
/// <summary>
/// https端口
/// </summary>
public static int HttpsPort { get; } = OperatingSystem.IsWindows() ? GetAvailableTcpPort(443) : GetAvailableTcpPort(38443);
/// <summary>
/// 获取已监听的端口
/// </summary>
/// <param name="func"></param>
/// <returns></returns>
private static HashSet<int> GetListenPorts(Func<IPEndPoint[]> func)
{
var hashSet = new HashSet<int>();
try
{
foreach (var endpoint in func())
{
hashSet.Add(endpoint.Port);
}
}
catch (Exception)
{
}
return hashSet;
}
/// <summary>
/// 是可以监听TCP
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
public static bool CanListenTcp(int port)
{
return tcpListenPorts.Contains(port) == false;
}
/// <summary>
/// 是可以监听UDP
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
public static bool CanListenUdp(int port)
{
return udpListenPorts.Contains(port) == false;
}
/// <summary>
/// 是可以监听TCP和Udp
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
public static bool CanListen(int port)
{
return CanListenTcp(port) && CanListenUdp(port);
}
/// <summary>
/// 获取可用的随机Tcp端口
/// </summary>
/// <param name="minPort"></param>
/// <returns></returns>
public static int GetAvailableTcpPort(int minPort)
{
return GetAvailablePort(CanListenTcp, minPort);
}
/// <summary>
/// 获取可用的随机Udp端口
/// </summary>
/// <param name="minPort"></param>
/// <returns></returns>
public static int GetAvailableUdpPort(int minPort)
{
return GetAvailablePort(CanListenUdp, minPort);
}
/// <summary>
/// 获取可用的随机端口
/// </summary>
/// <param name="minPort"></param>
/// <returns></returns>
public static int GetAvailablePort(int minPort)
{
return GetAvailablePort(CanListen, minPort);
}
/// <summary>
/// 获取可用端口
/// </summary>
/// <param name="canFunc"></param>
/// <param name="minPort"></param>
/// <returns></returns>
/// <exception cref="FastGithubException"></exception>
private static int GetAvailablePort(Func<int, bool> canFunc, int minPort)
{
for (var port = minPort; port < IPEndPoint.MaxPort; port++)
{
if (canFunc(port) == true)
{
return port;
}
}
throw new FastGithubException("当前无可用的端口");
}
}
}

View File

@ -1,82 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
namespace FastGithub.Configuration
{
/// <summary>
/// 反向代理端口
/// </summary>
public static class ReverseProxyPort
{
/// <summary>
/// ssh端口
/// </summary>
public static int Ssh { get; }
/// <summary>
/// git端口
/// </summary>
public static int Git { get; }
/// <summary>
/// http端口
/// </summary>
public static int Http { get; }
/// <summary>
/// https端口
/// </summary>
public static int Https { get; }
/// <summary>
/// 反向代理端口
/// </summary>
static ReverseProxyPort()
{
var ports = new TcpListenerPortCollection();
Ssh = ports.GetAvailablePort(22);
Git = ports.GetAvailablePort(9418);
Http = OperatingSystem.IsWindows() ? ports.GetAvailablePort(80) : ports.GetAvailablePort(3880);
Https = OperatingSystem.IsWindows() ? ports.GetAvailablePort(443) : ports.GetAvailablePort(38443);
}
/// <summary>
/// 已监听的tcp端口集合
/// </summary>
private class TcpListenerPortCollection
{
private readonly HashSet<int> tcpPorts = new();
/// <summary>
/// 已监听的tcp端口集合
/// </summary>
public TcpListenerPortCollection()
{
var tcpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners();
foreach (var endpoint in tcpListeners)
{
this.tcpPorts.Add(endpoint.Port);
}
}
/// <summary>
/// 获取可用的随机Tcp端口
/// </summary>
/// <param name="minValue"></param>
/// <returns></returns>
public int GetAvailablePort(int minValue)
{
for (var port = minValue; port < IPEndPoint.MaxPort; port++)
{
if (this.tcpPorts.Contains(port) == false)
{
return port;
}
}
throw new FastGithubException("当前无可用的端口");
}
}
}
}

View File

@ -1,13 +1,10 @@
using FastGithub.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using static PInvoke.AdvApi32;
@ -75,7 +72,7 @@ namespace FastGithub.DomainResolve
/// <returns></returns>
private async Task StartCoreAsync(CancellationToken cancellationToken)
{
var port = GetAvailablePort(IPAddress.Loopback.AddressFamily);
var port = GlobalListener.GetAvailablePort(5533);
var localEndPoint = new IPEndPoint(IPAddress.Loopback, port);
await TomlUtil.SetListensAsync(this.tomlFilePath, localEndPoint, cancellationToken);
@ -129,37 +126,6 @@ namespace FastGithub.DomainResolve
}
}
/// <summary>
/// 获取可用的随机端口
/// </summary>
/// <param name="addressFamily"></param>
/// <param name="min">最小值</param>
/// <returns></returns>
private static int GetAvailablePort(AddressFamily addressFamily, int min = 5533)
{
var hashSet = new HashSet<int>();
var tcpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners();
var udpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners();
foreach (var endPoint in tcpListeners.Concat(udpListeners))
{
if (endPoint.AddressFamily == addressFamily)
{
hashSet.Add(endPoint.Port);
}
}
for (var port = min; port < IPEndPoint.MaxPort; port++)
{
if (hashSet.Contains(port) == false)
{
return port;
}
}
throw new FastGithubException("当前无可用的端口");
}
/// <summary>
/// 启动DnscryptProxy进程
/// </summary>

View File

@ -212,13 +212,13 @@ namespace FastGithub.HttpServer
if (targetPort == HTTP_PORT)
{
yield return new IPEndPoint(IPAddress.Loopback, ReverseProxyPort.Http);
yield return new IPEndPoint(IPAddress.Loopback, GlobalListener.HttpPort);
yield break;
}
if (targetPort == HTTPS_PORT)
{
yield return new IPEndPoint(IPAddress.Loopback, ReverseProxyPort.Https);
yield return new IPEndPoint(IPAddress.Loopback, GlobalListener.HttpsPort);
yield break;
}

View File

@ -7,8 +7,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using System.Net.NetworkInformation;
namespace FastGithub
{
@ -37,7 +35,7 @@ namespace FastGithub
var options = kestrel.ApplicationServices.GetRequiredService<IOptions<FastGithubOptions>>().Value;
var httpProxyPort = options.HttpProxyPort;
if (CanListenTcp(httpProxyPort) == false)
if (GlobalListener.CanListenTcp(httpProxyPort) == false)
{
throw new FastGithubException($"tcp端口{httpProxyPort}已经被其它进程占用,请在配置文件更换{nameof(FastGithubOptions.HttpProxyPort)}为其它端口");
}
@ -53,7 +51,7 @@ namespace FastGithub
/// <param name="kestrel"></param>
public static void ListenSshReverseProxy(this KestrelServerOptions kestrel)
{
var sshPort = ReverseProxyPort.Ssh;
var sshPort = GlobalListener.SshPort;
kestrel.ListenLocalhost(sshPort, listen =>
{
listen.UseFlowAnalyze();
@ -69,7 +67,7 @@ namespace FastGithub
/// <param name="kestrel"></param>
public static void ListenGitReverseProxy(this KestrelServerOptions kestrel)
{
var gitPort = ReverseProxyPort.Git;
var gitPort = GlobalListener.GitPort;
kestrel.ListenLocalhost(gitPort, listen =>
{
listen.UseFlowAnalyze();
@ -85,7 +83,7 @@ namespace FastGithub
/// <param name="kestrel"></param>
public static void ListenHttpReverseProxy(this KestrelServerOptions kestrel)
{
var httpPort = ReverseProxyPort.Http;
var httpPort = GlobalListener.HttpPort;
kestrel.ListenLocalhost(httpPort);
if (OperatingSystem.IsWindows())
@ -105,7 +103,7 @@ namespace FastGithub
certService.CreateCaCertIfNotExists();
certService.InstallAndTrustCaCert();
var httpsPort = ReverseProxyPort.Https;
var httpsPort = GlobalListener.HttpsPort;
kestrel.ListenLocalhost(httpsPort, listen =>
{
if (OperatingSystem.IsWindows())
@ -135,16 +133,5 @@ namespace FastGithub
var loggerFactory = kestrel.ApplicationServices.GetRequiredService<ILoggerFactory>();
return loggerFactory.CreateLogger($"{nameof(FastGithub)}.{nameof(HttpServer)}");
}
/// <summary>
/// 是否可以监听指定tcp端口
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
private static bool CanListenTcp(int port)
{
var tcpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners();
return tcpListeners.Any(item => item.Port == port) == false;
}
}
}

View File

@ -15,7 +15,7 @@ namespace FastGithub.PacketIntercept.Tcp
/// </summary>
/// <param name="logger"></param>
public GitInterceptor(ILogger<HttpInterceptor> logger)
: base(9418, ReverseProxyPort.Git, logger)
: base(9418, GlobalListener.GitPort, logger)
{
}
}

View File

@ -15,7 +15,7 @@ namespace FastGithub.PacketIntercept.Tcp
/// </summary>
/// <param name="logger"></param>
public HttpInterceptor(ILogger<HttpInterceptor> logger)
: base(80, ReverseProxyPort.Http, logger)
: base(80, GlobalListener.HttpPort, logger)
{
}
}

View File

@ -15,7 +15,7 @@ namespace FastGithub.PacketIntercept.Tcp
/// </summary>
/// <param name="logger"></param>
public HttpsInterceptor(ILogger<HttpsInterceptor> logger)
: base(443, ReverseProxyPort.Https, logger)
: base(443, GlobalListener.HttpsPort, logger)
{
}
}

View File

@ -15,7 +15,7 @@ namespace FastGithub.PacketIntercept.Tcp
/// </summary>
/// <param name="logger"></param>
public SshInterceptor(ILogger<HttpInterceptor> logger)
: base(22, ReverseProxyPort.Ssh, logger)
: base(22, GlobalListener.SshPort, logger)
{
}
}