将代理内核换为 Titanium.Web.Proxy ,解决了高内存,高cpu 占用的问题
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ColorConsole;
|
||||
using Fiddler;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace BarrageGrab.Proxy
|
||||
{
|
||||
/// <summary>
|
||||
/// FiddlerCore 代理程序
|
||||
/// </summary>
|
||||
[Obsolete("由于框架存在内存泄漏,已弃用,请使用TitaniumProxy)", false)]
|
||||
internal class FiddlerProxy : SystemProxy
|
||||
{
|
||||
bool disposed = false;
|
||||
ConsoleWriter console = new ConsoleWriter();
|
||||
|
||||
public FiddlerProxy()
|
||||
{
|
||||
InitFiddler();
|
||||
}
|
||||
|
||||
//初始化Fiddler
|
||||
private void InitFiddler()
|
||||
{
|
||||
//这个名字随便
|
||||
FiddlerApplication.SetAppDisplayName("FiddlerCore");
|
||||
FiddlerApplication.OnWebSocketMessage += FiddlerApplication_OnWebSocketMessage;
|
||||
//FiddlerApplication.OnReadResponseBuffer += OnReadResponseBuffer;
|
||||
//设置pac规则,匹配douyin且排除douyincdn的host走代理,其余的直连
|
||||
FiddlerApplication.Prefs.SetStringPref("fiddler.proxy.pacfile.text", $"if (/douyin(?!cdn)/.test(host)) {{return 'PROXY 127.0.0.1:{base.ProxyPort}' }} return 'DIRECT'");
|
||||
|
||||
|
||||
X509Certificate2 oRootCert;
|
||||
if (null == CertMaker.GetRootCertificate())
|
||||
{
|
||||
CertMaker.createRootCert();
|
||||
oRootCert = CertMaker.GetRootCertificate();
|
||||
X509Store certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
|
||||
certStore.Open(OpenFlags.ReadWrite);
|
||||
try
|
||||
{
|
||||
certStore.Add(oRootCert);
|
||||
}
|
||||
finally
|
||||
{
|
||||
certStore.Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
oRootCert = CertMaker.GetRootCertificate();
|
||||
}
|
||||
//信任证书
|
||||
CertMaker.trustRootCert();
|
||||
|
||||
FiddlerApplication.oDefaultClientCertificate = oRootCert;
|
||||
//忽略服务器证书错误
|
||||
CONFIG.IgnoreServerCertErrors = true;
|
||||
CONFIG.bEnableIPv6 = false;
|
||||
//CONFIG.bCaptureCONNECT = true;
|
||||
//CONFIG.bUseEventLogForExceptions = false;
|
||||
//CONFIG.bAutoProxyLogon = false;
|
||||
//CONFIG.bMITM_HTTPS = false;
|
||||
////CONFIG.SetNoDecryptList("*");
|
||||
}
|
||||
|
||||
|
||||
private void FiddlerApplication_OnWebSocketMessage(object sender, WebSocketMessageEventArgs e)
|
||||
{
|
||||
var msg = e.oWSM;
|
||||
|
||||
FieldInfo field = msg.GetType().GetField("_wsOwner", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
WebSocket obj = (WebSocket)field.GetValue(msg);
|
||||
field = obj.GetType().GetField("oCP", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
var sessionField = obj.GetType().GetField("_mySession", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
ClientPipe ocp = (ClientPipe)field.GetValue(obj);
|
||||
Session session = (Session)sessionField.GetValue(obj);
|
||||
|
||||
this.SendWebSocketData(new WsMessageEventArgs()
|
||||
{
|
||||
Payload = msg.PayloadData,
|
||||
ProcessID = ocp.LocalProcessID,
|
||||
ProcessName = ocp.LocalProcessName,
|
||||
HostName = session.hostname,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
FiddlerApplication.Startup(Appsetting.Instanse.ProxyPort, FiddlerCoreStartupFlags.Default);
|
||||
console.WriteLine("Fiddler代理已启动", ConsoleColor.Green);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (disposed) return;
|
||||
FiddlerApplication.Shutdown();
|
||||
CloseSystemProxy();
|
||||
console.WriteLine("Fiddler代理已关闭");
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using Fiddler;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BarrageGrab.Proxy
|
||||
{
|
||||
internal interface ISystemProxy : IDisposable
|
||||
{
|
||||
event EventHandler<WsMessageEventArgs> OnWebSocketData;
|
||||
|
||||
/// <summary>
|
||||
/// 开始监听
|
||||
/// </summary>
|
||||
void Start();
|
||||
}
|
||||
|
||||
public class WsMessageEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息体
|
||||
/// </summary>
|
||||
public byte[] Payload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 进程ID
|
||||
/// </summary>
|
||||
public int ProcessID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 进程名
|
||||
/// </summary>
|
||||
public string ProcessName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 域名
|
||||
/// </summary>
|
||||
public string HostName { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BarrageGrab.Proxy
|
||||
{
|
||||
internal abstract class SystemProxy : ISystemProxy
|
||||
{
|
||||
//弹幕服务域名
|
||||
protected string[] barrageWsHostNames = new string[]
|
||||
{
|
||||
"webcast3-ws-web-hl.douyin.com",
|
||||
"webcast3-ws-web-lf.douyin.com",
|
||||
"frontier-im.douyin.com"
|
||||
};
|
||||
|
||||
|
||||
//https://live.douyin.com/webcast/gift/list/
|
||||
|
||||
/// <summary>
|
||||
/// 接收到websocket消息事件
|
||||
/// </summary>
|
||||
public event EventHandler<WsMessageEventArgs> OnWebSocketData;
|
||||
|
||||
/// <summary>
|
||||
/// 代理端口
|
||||
/// </summary>
|
||||
public int ProxyPort { get => Appsetting.Instanse.ProxyPort; }
|
||||
|
||||
public abstract void Dispose();
|
||||
|
||||
public abstract void Start();
|
||||
|
||||
protected void SendWebSocketData(WsMessageEventArgs args)
|
||||
{
|
||||
OnWebSocketData?.Invoke(this, args);
|
||||
}
|
||||
|
||||
protected string GetProcessName(int processID)
|
||||
{
|
||||
var process = Process.GetProcessById(processID);
|
||||
if (process != null)
|
||||
{
|
||||
return process.ProcessName;
|
||||
}
|
||||
return $"<{processID}>";
|
||||
}
|
||||
|
||||
// 生成自签名证书
|
||||
protected X509Certificate2 EnsureCertificate(string subjectName)
|
||||
{
|
||||
// 添加证书到证书存储
|
||||
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
|
||||
store.Open(OpenFlags.ReadWrite);
|
||||
//判断证书是否已经存在
|
||||
var certificates = store.Certificates.Find(X509FindType.FindBySubjectName, subjectName, false);
|
||||
if (certificates.Count > 0)
|
||||
{
|
||||
return certificates[0];
|
||||
}
|
||||
|
||||
// 创建证书请求
|
||||
var request = new CertificateRequest($"CN={subjectName}", RSA.Create(2048), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
|
||||
// 添加扩展属性
|
||||
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
|
||||
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));
|
||||
request.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
|
||||
|
||||
// 用自己的私钥签名并生成证书
|
||||
var certificate = request.CreateSelfSigned(DateTimeOffset.Now.AddDays(-1), DateTimeOffset.Now.AddDays(365));
|
||||
store.Add(certificate);
|
||||
store.Close();
|
||||
|
||||
return certificate;
|
||||
}
|
||||
|
||||
//注册系统代理
|
||||
protected void RegisterSystemProxy()
|
||||
{
|
||||
RegistryKey registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
|
||||
registry.SetValue("ProxyEnable", 1);
|
||||
registry.SetValue("ProxyServer", $"http=localhost:{ProxyPort};https=localhost:{ProxyPort}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭系统代理
|
||||
/// </summary>
|
||||
protected void CloseSystemProxy()
|
||||
{
|
||||
RegistryKey registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
|
||||
registry.SetValue("ProxyEnable", 0);
|
||||
registry.SetValue("ProxyServer", $"http=localhost:{ProxyPort};https=localhost:{ProxyPort}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32;
|
||||
using Titanium.Web.Proxy;
|
||||
using Titanium.Web.Proxy.EventArguments;
|
||||
using Titanium.Web.Proxy.Http;
|
||||
using Titanium.Web.Proxy.Models;
|
||||
using Titanium.Web.Proxy.StreamExtended.Network;
|
||||
|
||||
namespace BarrageGrab.Proxy
|
||||
{
|
||||
internal class TitaniumProxy : SystemProxy
|
||||
{
|
||||
ProxyServer proxyServer = null;
|
||||
ExplicitProxyEndPoint explicitEndPoint = null;
|
||||
|
||||
public TitaniumProxy()
|
||||
{
|
||||
//注册系统代理
|
||||
//RegisterSystemProxy();
|
||||
proxyServer = new ProxyServer();
|
||||
|
||||
//var cert = EnsureCertificate("localhost");
|
||||
|
||||
proxyServer.ReuseSocket = false;
|
||||
proxyServer.EnableConnectionPool = true;
|
||||
proxyServer.ForwardToUpstreamGateway = true;
|
||||
proxyServer.CertificateManager.SaveFakeCertificates = true;
|
||||
|
||||
proxyServer.ServerCertificateValidationCallback += ProxyServer_ServerCertificateValidationCallback; ;
|
||||
proxyServer.BeforeResponse += ProxyServer_BeforeResponse;
|
||||
|
||||
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any,ProxyPort, true);
|
||||
explicitEndPoint.BeforeTunnelConnectRequest += ExplicitEndPoint_BeforeTunnelConnectRequest;
|
||||
proxyServer.AddEndPoint(explicitEndPoint);
|
||||
}
|
||||
|
||||
|
||||
private Task ProxyServer_ServerCertificateValidationCallback(object sender, CertificateValidationEventArgs e)
|
||||
{
|
||||
// set IsValid to true/false based on Certificate Errors
|
||||
if (e.SslPolicyErrors == SslPolicyErrors.None)
|
||||
{
|
||||
e.IsValid = true;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
|
||||
{
|
||||
string hostname = e.HttpClient.Request.RequestUri.Host;
|
||||
if (!barrageWsHostNames.Contains(hostname)) return;
|
||||
|
||||
if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Websocket)
|
||||
{
|
||||
e.DataReceived += WebSocket_DataReceived;
|
||||
}
|
||||
}
|
||||
|
||||
//List<string> hostlist = new List<string>();
|
||||
|
||||
private async Task ExplicitEndPoint_BeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
|
||||
{
|
||||
string hostname = e.HttpClient.Request.RequestUri.Host;
|
||||
if (!barrageWsHostNames.Contains(hostname))
|
||||
{
|
||||
e.DecryptSsl = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async void WebSocket_DataReceived(object sender, DataEventArgs e)
|
||||
{
|
||||
var args = (SessionEventArgs)sender;
|
||||
|
||||
string hostname = args.HttpClient.Request.RequestUri.Host;
|
||||
|
||||
var processid = args.HttpClient.ProcessId.Value;
|
||||
|
||||
var frames = args.WebSocketDecoderReceive.Decode(e.Buffer, e.Offset, e.Count).ToList();
|
||||
//Console.WriteLine(frames.Count);
|
||||
|
||||
foreach (var frame in frames)
|
||||
{
|
||||
//Console.WriteLine(frame.GetText());
|
||||
base.SendWebSocketData(new WsMessageEventArgs()
|
||||
{
|
||||
ProcessID = processid,
|
||||
HostName = hostname,
|
||||
Payload = frame.Data.ToArray(),
|
||||
ProcessName = base.GetProcessName(processid)
|
||||
});
|
||||
}
|
||||
//Console.WriteLine("获取到弹幕信息:" + hostname);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源,关闭系统代理
|
||||
/// </summary>
|
||||
override public void Dispose()
|
||||
{
|
||||
proxyServer.Stop();
|
||||
proxyServer.Dispose();
|
||||
CloseSystemProxy();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动监听
|
||||
/// </summary>
|
||||
override public void Start()
|
||||
{
|
||||
proxyServer.Start();
|
||||
proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
|
||||
proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user