mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Update PAC Http Server
This commit is contained in:
@@ -3,6 +3,7 @@ using WindowsProxy;
|
|||||||
using Netch.Models;
|
using Netch.Models;
|
||||||
using Netch.Servers.Socks5;
|
using Netch.Servers.Socks5;
|
||||||
using Netch.Servers.Trojan;
|
using Netch.Servers.Trojan;
|
||||||
|
using Netch.Utils;
|
||||||
using Netch.Utils.HttpProxyHandler;
|
using Netch.Utils.HttpProxyHandler;
|
||||||
|
|
||||||
namespace Netch.Controllers
|
namespace Netch.Controllers
|
||||||
@@ -24,16 +25,30 @@ namespace Netch.Controllers
|
|||||||
{
|
{
|
||||||
PrivoxyController.Start(MainController.Server!);
|
PrivoxyController.Start(MainController.Server!);
|
||||||
Global.Job.AddProcess(PrivoxyController.Instance!);
|
Global.Job.AddProcess(PrivoxyController.Instance!);
|
||||||
|
string? pacUrl = null;
|
||||||
|
|
||||||
|
if (MainController.Server is Socks5 or Trojan && mode.BypassChina || (Global.Settings.AlwaysStartPACServer ?? false))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PortHelper.CheckPort(Global.Settings.Pac_Port);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Global.Settings.Pac_Port = PortHelper.GetAvailablePort();
|
||||||
|
}
|
||||||
|
|
||||||
|
pacUrl = PACServerHandle.InitPACServer("127.0.0.1");
|
||||||
|
}
|
||||||
|
|
||||||
if (mode.Type is 3)
|
if (mode.Type is 3)
|
||||||
{
|
{
|
||||||
using var service = new ProxyService();
|
using var service = new ProxyService();
|
||||||
_oldState = service.Query();
|
_oldState = service.Query();
|
||||||
|
|
||||||
if (MainController.Server is Socks5 or Trojan && mode.BypassChina)
|
if (pacUrl != null)
|
||||||
{
|
{
|
||||||
service.AutoConfigUrl = PACServerHandle.InitPACServer("127.0.0.1");
|
service.AutoConfigUrl = pacUrl;
|
||||||
|
|
||||||
service.Pac();
|
service.Pac();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ namespace Netch.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// PAC端口
|
/// PAC端口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Pac_Port { get; set; } = 2803;
|
public ushort Pac_Port { get; set; } = 2803;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 不代理TCP
|
/// 不代理TCP
|
||||||
@@ -293,6 +293,8 @@ namespace Netch.Models
|
|||||||
|
|
||||||
public V2rayConfig V2RayConfig { get; set; } = new();
|
public V2rayConfig V2RayConfig { get; set; } = new();
|
||||||
|
|
||||||
|
public bool? AlwaysStartPACServer { get; set; }
|
||||||
|
|
||||||
public Setting Clone()
|
public Setting Clone()
|
||||||
{
|
{
|
||||||
return (Setting) MemberwiseClone();
|
return (Setting) MemberwiseClone();
|
||||||
|
|||||||
@@ -1,85 +1,67 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Netch.Utils.HttpProxyHandler
|
namespace Netch.Utils.HttpProxyHandler
|
||||||
{
|
{
|
||||||
public class HttpWebServer
|
public class HttpWebServer
|
||||||
{
|
{
|
||||||
private HttpListener? _listener;
|
|
||||||
private readonly Func<HttpListenerRequest, string>? _responderMethod;
|
private readonly Func<HttpListenerRequest, string>? _responderMethod;
|
||||||
|
private HttpListener? _listener;
|
||||||
|
|
||||||
public HttpWebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
|
public HttpWebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
|
||||||
{
|
{
|
||||||
try
|
_listener = new HttpListener();
|
||||||
{
|
|
||||||
_listener = new HttpListener();
|
|
||||||
|
|
||||||
if (!HttpListener.IsSupported)
|
// URI prefixes are required, for example
|
||||||
throw new NotSupportedException("Needs Windows XP SP2, Server 2003 or later.");
|
// "http://localhost:8080/index/".
|
||||||
|
if (prefixes == null || prefixes.Length == 0)
|
||||||
|
throw new ArgumentException("prefixes");
|
||||||
|
|
||||||
// URI prefixes are required, for example
|
// A responder method is required
|
||||||
// "http://localhost:8080/index/".
|
if (method == null)
|
||||||
if (prefixes == null || prefixes.Length == 0)
|
throw new ArgumentException("method");
|
||||||
throw new ArgumentException("prefixes");
|
|
||||||
|
|
||||||
// A responder method is required
|
foreach (var s in prefixes)
|
||||||
if (method == null)
|
_listener.Prefixes.Add(s);
|
||||||
throw new ArgumentException("method");
|
|
||||||
|
|
||||||
foreach (var s in prefixes)
|
_responderMethod = method;
|
||||||
_listener.Prefixes.Add(s);
|
_listener.Start();
|
||||||
|
|
||||||
_responderMethod = method;
|
|
||||||
_listener.Start();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.Error("HttpWebServer():" + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpWebServer(Func<HttpListenerRequest, string> method, params string[] prefixes) : this(prefixes, method)
|
public HttpWebServer(Func<HttpListenerRequest, string> method, params string[] prefixes) : this(prefixes, method)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Run()
|
public void StartWaitingRequest()
|
||||||
{
|
{
|
||||||
ThreadPool.QueueUserWorkItem(o =>
|
Logging.Info("Webserver running...");
|
||||||
|
while (_listener?.IsListening ?? false)
|
||||||
{
|
{
|
||||||
Logging.Info("Webserver running...");
|
HttpListenerContext ctx;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (_listener!.IsListening)
|
ctx = _listener.GetContext();
|
||||||
ThreadPool.QueueUserWorkItem(c =>
|
|
||||||
{
|
|
||||||
var ctx = (HttpListenerContext) c;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var rstr = _responderMethod!(ctx.Request);
|
|
||||||
var buf = Encoding.UTF8.GetBytes(rstr);
|
|
||||||
ctx.Response.StatusCode = 200;
|
|
||||||
ctx.Response.ContentType = "application/x-ns-proxy-autoconfig";
|
|
||||||
ctx.Response.ContentLength64 = buf.Length;
|
|
||||||
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ctx.Response.OutputStream.Close();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_listener.GetContext());
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
Logging.Error(ex.Message);
|
break;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var rstr = _responderMethod!(ctx.Request);
|
||||||
|
var buf = Encoding.UTF8.GetBytes(rstr);
|
||||||
|
ctx.Response.StatusCode = 200;
|
||||||
|
ctx.Response.ContentType = "application/x-ns-proxy-autoconfig";
|
||||||
|
ctx.Response.ContentLength64 = buf.Length;
|
||||||
|
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ctx.Response.OutputStream.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
|
|||||||
@@ -1,102 +1,74 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Netch.Controllers;
|
||||||
|
|
||||||
namespace Netch.Utils.HttpProxyHandler
|
namespace Netch.Utils.HttpProxyHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 提供PAC功能支持
|
/// 提供PAC功能支持
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class PACServerHandle
|
internal static class PACServerHandle
|
||||||
{
|
{
|
||||||
private static readonly Hashtable httpWebServer = new();
|
private static HttpWebServer? _httpWebServer;
|
||||||
private static readonly Hashtable pacList = new();
|
private static string? _pacContent;
|
||||||
|
|
||||||
public static string InitPACServer(string address)
|
public static string InitPACServer(string address)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!pacList.ContainsKey(address))
|
_pacContent = GetPacList(address);
|
||||||
pacList.Add(address, GetPacList(address));
|
|
||||||
|
|
||||||
var prefixes = $"http://{address}:{Global.Settings.Pac_Port}/pac/";
|
var prefixes = $"http://{address}:{Global.Settings.Pac_Port}/pac/";
|
||||||
|
|
||||||
var ws = new HttpWebServer(SendResponse, prefixes);
|
_httpWebServer = new HttpWebServer(SendResponse, prefixes);
|
||||||
ws.Run();
|
Task.Run(() => _httpWebServer.StartWaitingRequest());
|
||||||
|
|
||||||
if (!httpWebServer.ContainsKey(address))
|
|
||||||
httpWebServer.Add(address, ws);
|
|
||||||
|
|
||||||
var pacUrl = GetPacUrl();
|
var pacUrl = GetPacUrl();
|
||||||
Logging.Info($"Webserver InitServer OK: {pacUrl}");
|
Logging.Info($"Webserver InitServer OK: {pacUrl}");
|
||||||
return pacUrl;
|
return pacUrl;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
throw new Exception("Webserver InitServer Error:" + ex.Message);
|
Logging.Error("Webserver InitServer Failed");
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string SendResponse(HttpListenerRequest request)
|
public static string SendResponse(HttpListenerRequest request)
|
||||||
{
|
{
|
||||||
try
|
return _pacContent!;
|
||||||
{
|
|
||||||
var arrAddress = request.UserHostAddress.Split(':');
|
|
||||||
var address = "127.0.0.1";
|
|
||||||
if (arrAddress.Length > 0)
|
|
||||||
address = arrAddress[0];
|
|
||||||
|
|
||||||
return pacList[address].ToString();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.Error("Webserver SendResponse " + ex.Message);
|
|
||||||
return ex.Message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Stop()
|
public static void Stop()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (httpWebServer == null)
|
_httpWebServer?.Stop();
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var key in httpWebServer.Keys)
|
|
||||||
{
|
|
||||||
Logging.Info("Webserver Stop " + key);
|
|
||||||
((HttpWebServer) httpWebServer[key]).Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
httpWebServer.Clear();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
Logging.Error("Webserver Stop " + ex.Message);
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_httpWebServer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetPacList(string address)
|
private static string GetPacList(string address)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var lstProxy = new List<string>();
|
var proxy = $"PROXY {address}:{Global.Settings.HTTPLocalPort};";
|
||||||
lstProxy.Add(string.Format("PROXY {0}:{1};", address, Global.Settings.HTTPLocalPort));
|
var pacfile = Path.Combine(Global.NetchDir, "bin\\pac.txt");
|
||||||
|
|
||||||
var proxy = string.Join("", lstProxy.ToArray());
|
var pac = File.ReadAllText(pacfile, Encoding.UTF8).Replace("__PROXY__", proxy);
|
||||||
var strPacfile = Path.Combine(Global.NetchDir, "bin\\pac.txt");
|
|
||||||
|
|
||||||
var pac = File.ReadAllText(strPacfile, Encoding.UTF8).Replace("__PROXY__", proxy);
|
|
||||||
return pac;
|
return pac;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
throw new MessageException("Pac file not found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return "No pac content";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -105,9 +77,7 @@ namespace Netch.Utils.HttpProxyHandler
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GetPacUrl()
|
public static string GetPacUrl()
|
||||||
{
|
{
|
||||||
var pacUrl = string.Format("http://127.0.0.1:{0}/pac/?t={1}", Global.Settings.Pac_Port, DateTime.Now.ToString("yyyyMMddHHmmssfff"));
|
return $"http://127.0.0.1:{Global.Settings.Pac_Port}/pac/?t={DateTime.Now:yyyyMMddHHmmssfff}";
|
||||||
|
|
||||||
return pacUrl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user