diff --git a/Netch/Controllers/HTTPController.cs b/Netch/Controllers/HTTPController.cs index c38a2edf..a4c774fc 100644 --- a/Netch/Controllers/HTTPController.cs +++ b/Netch/Controllers/HTTPController.cs @@ -4,8 +4,8 @@ using System.Threading.Tasks; using System.Windows.Forms; using Microsoft.Win32; using Netch.Models; -using Netch.Servers.Socks5; using Netch.Utils; +using WindowsProxy; namespace Netch.Controllers { @@ -36,7 +36,7 @@ namespace Netch.Controllers Global.Job.AddProcess(pPrivoxyController.Instance); } - if (mode.Type == 3) NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", IEProxyExceptions); + //if (mode.Type == 3) NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", IEProxyExceptions); } catch (Exception e) { @@ -91,12 +91,24 @@ namespace Netch.Controllers if (prevEnabled) { if (prevHTTP != "") - NativeMethods.SetGlobal(prevHTTP, prevBypass); + { + using var service = new ProxyService + { + Server = prevHTTP, + Bypass = prevBypass + }; + } if (prevPAC != "") - NativeMethods.SetURL(prevPAC); + { + using var service = new ProxyService + { + AutoConfigUrl = prevPAC + }; + service.Pac(); + } } else - NativeMethods.SetDIRECT(); + new ProxyService().Direct(); }) }; Task.WaitAll(tasks); diff --git a/Netch/Controllers/PrivoxyController.cs b/Netch/Controllers/PrivoxyController.cs index ffe4a3d2..8b2de3b4 100644 --- a/Netch/Controllers/PrivoxyController.cs +++ b/Netch/Controllers/PrivoxyController.cs @@ -2,6 +2,7 @@ using System.Text; using Netch.Models; using Netch.Servers.Socks5; +using Netch.Utils.HttpProxyHandler; namespace Netch.Controllers { @@ -34,11 +35,15 @@ namespace Netch.Controllers File.WriteAllText("data\\privoxy.conf", text.ToString()); + //启动PAC服务器 + PACServerHandle.InitPACServer("127.0.0.1"); + return StartInstanceAuto("..\\data\\privoxy.conf"); } public override void Stop() { + PACServerHandle.Stop(); StopInstance(); } } diff --git a/Netch/Models/Setting.cs b/Netch/Models/Setting.cs index 09751d11..0ba2c1a2 100644 --- a/Netch/Models/Setting.cs +++ b/Netch/Models/Setting.cs @@ -155,6 +155,16 @@ namespace Netch.Models /// public int RequestTimeout = 10000; + /// + /// PAC URL + /// + public string Pac_Url = ""; + + /// + /// PAC端口 + /// + public int Pac_Port = 2803; + /// /// HTTP 本地端口 /// diff --git a/Netch/NativeMethods.cs b/Netch/NativeMethods.cs index 337fdca6..510509f1 100644 --- a/Netch/NativeMethods.cs +++ b/Netch/NativeMethods.cs @@ -28,30 +28,6 @@ namespace Netch [DllImport("NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")] public static extern bool DeleteRoute(string address, int cidr, string gateway, int index, int metric = 0); - /// - /// 设置直连 - /// - /// 是否成功 - [DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)] - public static extern bool SetDIRECT(); - - /// - /// 设置全局 - /// - /// 地址 - /// 绕过 - /// 是否成功 - [DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)] - public static extern bool SetGlobal([MarshalAs(UnmanagedType.LPTStr)] string remote, [MarshalAs(UnmanagedType.LPTStr)] string bypass); - - /// - /// 设置自动代理 - /// - /// URL - /// 是否成功 - [DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)] - public static extern bool SetURL([MarshalAs(UnmanagedType.LPTStr)] string remote); - [DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")] public static extern uint FlushDNSResolverCache(); diff --git a/Netch/Netch.csproj b/Netch/Netch.csproj index 9891bf9f..9bb8860c 100644 --- a/Netch/Netch.csproj +++ b/Netch/Netch.csproj @@ -66,13 +66,14 @@ - + - + + diff --git a/Netch/Utils/HttpProxyHandler/HttpWebServer.cs b/Netch/Utils/HttpProxyHandler/HttpWebServer.cs new file mode 100644 index 00000000..5605faa7 --- /dev/null +++ b/Netch/Utils/HttpProxyHandler/HttpWebServer.cs @@ -0,0 +1,99 @@ +using System; +using System.Net; +using System.Text; +using System.Threading; + +namespace Netch.Utils.HttpProxyHandler +{ + public class HttpWebServer + { + private HttpListener _listener; + private Func _responderMethod; + + public HttpWebServer(string[] prefixes, Func method) + { + try + { + _listener = new HttpListener(); + + if (!HttpListener.IsSupported) + throw new NotSupportedException( + "Needs Windows XP SP2, Server 2003 or later."); + + // URI prefixes are required, for example + // "http://localhost:8080/index/". + if (prefixes == null || prefixes.Length == 0) + throw new ArgumentException("prefixes"); + + // A responder method is required + if (method == null) + throw new ArgumentException("method"); + + foreach (string s in prefixes) + _listener.Prefixes.Add(s); + + _responderMethod = method; + _listener.Start(); + + } + catch (Exception ex) + { + Logging.Error("HttpWebServer():" + ex.Message); + } + } + + public HttpWebServer(Func method, params string[] prefixes) + : this(prefixes, method) { } + + public void Run() + { + ThreadPool.QueueUserWorkItem((o) => + { + Logging.Info("Webserver running..."); + try + { + while (_listener.IsListening) + { + ThreadPool.QueueUserWorkItem((c) => + { + var ctx = c as HttpListenerContext; + try + { + string rstr = _responderMethod(ctx.Request); + byte[] 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 + { + } // suppress any exceptions + finally + { + // always close the stream + ctx.Response.OutputStream.Close(); + } + }, _listener.GetContext()); + } + } + catch (Exception ex) + { + //Logging.Error(ex.Message, ex); + Logging.Error(ex.Message); + } // suppress any exceptions + }); + } + + public void Stop() + { + if (_listener != null) + { + _listener.Stop(); + _listener.Close(); + _listener = null; + } + } + + } +} diff --git a/Netch/Utils/HttpProxyHandler/PACListHandle.cs b/Netch/Utils/HttpProxyHandler/PACListHandle.cs new file mode 100644 index 00000000..f8842e29 --- /dev/null +++ b/Netch/Utils/HttpProxyHandler/PACListHandle.cs @@ -0,0 +1,75 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; + +namespace Netch.Utils.HttpProxyHandler +{ + /// + /// 提供PAC功能支持 + /// + class PACListHandle + { + public event EventHandler UpdateCompleted; + + public class ResultEventArgs : EventArgs + { + public bool Success; + + public ResultEventArgs(bool success) + { + Success = success; + } + } + + private const string GFWLIST_URL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt"; + + private static readonly IEnumerable IgnoredLineBegins = new[] { '!', '[' }; + + /// + /// 更新PAC文件(GFWList) + /// + //public void UpdatePACFromGFWList() + //{ + // WebClient http = new WebClient(); + // http.DownloadStringCompleted += http_DownloadStringCompleted; + // http.DownloadStringAsync(new Uri(GFWLIST_URL)); + //} + + //private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) + //{ + // try + // { + // File.WriteAllText(NUtils.GetTempPath("gfwlist.txt"), e.Result, Encoding.UTF8); + // List lines = ParseResult(e.Result); + // string abpContent = NUtils.UnGzip(Resources.abp_js); + // abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented)); + // File.WriteAllText(NUtils.GetPath("pac.txt"), abpContent, Encoding.UTF8); + // if (UpdateCompleted != null) UpdateCompleted(this, new ResultEventArgs(true)); + // } + // catch (Exception ex) + // { + // Logging.Error("http_DownloadStringCompleted():" + ex.Message); + // } + //} + + //public static List ParseResult(string response) + //{ + // byte[] bytes = Convert.FromBase64String(response); + // string content = Encoding.ASCII.GetString(bytes); + // List valid_lines = new List(); + // using (var sr = new StringReader(content)) + // { + // foreach (var line in sr.NonWhiteSpaceLines()) + // { + // if (line.BeginWithAny(IgnoredLineBegins)) + // continue; + // valid_lines.Add(line); + // } + // } + // return valid_lines; + //} + } +} diff --git a/Netch/Utils/HttpProxyHandler/PACServerHandle.cs b/Netch/Utils/HttpProxyHandler/PACServerHandle.cs new file mode 100644 index 00000000..84aefa7a --- /dev/null +++ b/Netch/Utils/HttpProxyHandler/PACServerHandle.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Net; +using System.Text; +using WindowsProxy; + +namespace Netch.Utils.HttpProxyHandler +{ + /// + /// 提供PAC功能支持 + /// + class PACServerHandle + { + private static Hashtable httpWebServer = new Hashtable(); + private static Hashtable pacList = new Hashtable(); + + public static void InitPACServer(string address) + { + try + { + if (!pacList.ContainsKey(address)) + { + pacList.Add(address, GetPacList(address)); + } + + string prefixes = string.Format("http://{0}:{1}/pac/", address, Global.Settings.Pac_Port); + + HttpWebServer ws = new HttpWebServer(SendResponse, prefixes); + ws.Run(); + + if (!httpWebServer.ContainsKey(address) && ws != null) + { + httpWebServer.Add(address, ws); + } + Global.Settings.Pac_Url = GetPacUrl(); + + using var service = new ProxyService + { + AutoConfigUrl = Global.Settings.Pac_Url + }; + service.Pac(); + + Logging.Info(service.Set(service.Query()) + ""); + Logging.Info($"Webserver InitServer OK: {Global.Settings.Pac_Url}"); + } + catch (Exception ex) + { + Logging.Error("Webserver InitServer " + ex.Message); + } + } + + public static string SendResponse(HttpListenerRequest request) + { + try + { + string[] arrAddress = request.UserHostAddress.Split(':'); + string 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() + { + try + { + if (httpWebServer == null) + { + return; + } + foreach (var key in httpWebServer.Keys) + { + Logging.Info("Webserver Stop " + key.ToString()); + ((HttpWebServer)httpWebServer[key]).Stop(); + } + httpWebServer.Clear(); + } + catch (Exception ex) + { + Logging.Error("Webserver Stop " + ex.Message); + } + } + + private static string GetPacList(string address) + { + try + { + List lstProxy = new List(); + lstProxy.Add(string.Format("PROXY {0}:{1};", address, Global.Settings.HTTPLocalPort)); + + var proxy = string.Join("", lstProxy.ToArray()); + string strPacfile = Path.Combine(Global.NetchDir, $"bin\\pac.txt"); + + var pac = File.ReadAllText(strPacfile, Encoding.UTF8).Replace("__PROXY__", proxy); + return pac; + } + catch + { } + return "No pac content"; + } + + /// + /// 获取PAC地址 + /// + /// + public static string GetPacUrl() + { + string pacUrl = string.Format("http://127.0.0.1:{0}/pac/?t={1}", Global.Settings.Pac_Port, + DateTime.Now.ToString("yyyyMMddHHmmssfff")); + + return pacUrl; + } + } +} diff --git a/binaries b/binaries index 4525fe9c..0b158dbc 160000 --- a/binaries +++ b/binaries @@ -1 +1 @@ -Subproject commit 4525fe9c71c8e0dda2b6e871212115219e5f44cf +Subproject commit 0b158dbc5a5ad8c5f88170c5982d7d9cd1e915af