/** * Grasscutter Tools * Copyright (C) 2023 jie65535 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * **/ using System; using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Win32; using Eavesdrop; using System.Net; namespace GrasscutterTools.Utils { internal static class ProxyHelper { private const string TAG = "Proxy"; #region - Windows API - [DllImport("wininet.dll")] private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); private const int INTERNET_OPTION_SETTINGS_CHANGED = 39; private const int INTERNET_OPTION_REFRESH = 37; #endregion #region - System Proxy - private const string RegKeyInternetSettings = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; private const string RegProxyEnable = "ProxyEnable"; private const string RegProxyServer = "ProxyServer"; private const string RegProxyOverride = "ProxyOverride"; private const string PassBy = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*"; private static void FlushOs() { InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0); InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); } private static bool _isSetSystemProxy; private static void SetSystemProxy(int proxyPort) { using (var reg = Registry.CurrentUser.OpenSubKey(RegKeyInternetSettings, true)) { reg.SetValue(RegProxyServer, $"http=127.0.0.1:{proxyPort};https=127.0.0.1:{proxyPort}"); reg.SetValue(RegProxyOverride, PassBy); reg.SetValue(RegProxyEnable, 1); } _isSetSystemProxy = true; FlushOs(); } private static void CloseSystemProxy() { if (!_isSetSystemProxy) return; _isSetSystemProxy = false; using (var reg = Registry.CurrentUser.OpenSubKey(RegKeyInternetSettings, true)) reg.SetValue(RegProxyEnable, 0); FlushOs(); } #endregion #region - GS Proxy Server - private const string ProxyOverrides = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*;*ttvnw*;*edge*;*microsoft*;*bing*;*google*;*discordapp*;*gstatic.com;*imgur.com;*github.com;*googleapis.com;*facebook.com;*cloudfront.net;*gvt1.com;*jquery.com;*akamai.net;*ultra-rv.com;*youtube*;*ytimg*;*ggpht*"; private static void StartGsProxyServer(int port) { if (Eavesdropper.IsRunning) return; Eavesdropper.Overrides.Clear(); Eavesdropper.Overrides.AddRange(ProxyOverrides.Split(';')); Eavesdropper.RequestInterceptedAsync += EavesdropperOnRequestInterceptedAsync; Eavesdropper.Initiate(port); } private static string[] urls = { "hoyoverse.com", "mihoyo.com", "yuanshen.com", }; private static Task EavesdropperOnRequestInterceptedAsync(object sender, RequestInterceptedEventArgs e) { var url = e.Request.RequestUri.OriginalString; foreach (var mhy in urls) { var i = url.IndexOf(mhy, StringComparison.CurrentCultureIgnoreCase); if (i == -1) continue; var p = url.IndexOf('/', i + mhy.Length); var target = p >= 0 ? _gcDispatch + url.Substring(p) : _gcDispatch; e.Request = RedirectRequest(e.Request as HttpWebRequest, new Uri(target)); Logger.I(TAG, $"Redirect to {e.Request.RequestUri}"); break; } return Task.CompletedTask; } private static HttpWebRequest RedirectRequest(HttpWebRequest request, Uri newUri) { var newRequest = WebRequest.CreateHttp(newUri); newRequest.ProtocolVersion = request.ProtocolVersion; newRequest.CookieContainer = request.CookieContainer; newRequest.AllowAutoRedirect = request.AllowAutoRedirect; newRequest.KeepAlive = request.KeepAlive; newRequest.Method = request.Method; newRequest.Proxy = request.Proxy; foreach (var name in request.Headers.AllKeys) { switch (name.ToLower()) { case "host" : newRequest.Host = request.Host; break; case "accept" : newRequest.Accept = request.Accept; break; case "referer" : newRequest.Referer = request.Referer; break; case "user-agent" : newRequest.UserAgent = request.UserAgent; break; case "content-type" : newRequest.ContentType = request.ContentType; break; case "content-length" : newRequest.ContentLength = request.ContentLength; break; case "if-modified-since": newRequest.IfModifiedSince = request.IfModifiedSince; break; case "date" : newRequest.Date = request.Date; break; default: newRequest.Headers[name] = request.Headers[name]; break; } } //newRequest.Headers = request.Headers; return newRequest; } private static void StopGsProxyServer() { Eavesdropper.Terminate(); } #endregion private const int ProxyServerPort = 8146; private static string _gcDispatch; public static void StartProxy(string gcDispatch) { _gcDispatch = gcDispatch.TrimEnd('/'); Logger.I(TAG, "Start Proxy, redirect to " + _gcDispatch); StartGsProxyServer(ProxyServerPort); //SetSystemProxy(ProxyServerPort); } public static void StopProxy() { Logger.I(TAG, "Start Proxy"); //CloseSystemProxy(); StopGsProxyServer(); } public static bool CheckAndCreateCertifier() { Eavesdropper.Certifier = new Certifier("jie65535", "GrasscutterTools Root Certificate Authority"); return Eavesdropper.Certifier.CreateTrustedRootCertificate(); } public static bool IsRunning => Eavesdropper.IsRunning; } }