public class LocalProxyServer
{
bool decryptSsl = true;
ConcurrentDictionary<int, IExternalProxy> upStreamHttpProxies = new ConcurrentDictionary<int, IExternalProxy>();
public ProxyServer proxyServer = new ProxyServer();
private ExplicitProxyEndPoint tcpProxy;
public LocalProxyServer()
{
proxyServer.EnableHttp2 = true;
proxyServer.TcpTimeWaitSeconds = 20;
proxyServer.ConnectionTimeOutSeconds = 25;
proxyServer.ReuseSocket = true;
proxyServer.EnableConnectionPool = false;
proxyServer.ForwardToUpstreamGateway = false;
proxyServer.CertificateManager.SaveFakeCertificates = true;
proxyServer.ServerCertificateValidationCallback += OnServerCertificateValidation;
proxyServer.BeforeRequest += OnBeforeRequest;
}
async Task<IExternalProxy> onGetCustomUpStreamProxyFunc(SessionEventArgsBase ev)
{
IExternalProxy x;
upStreamHttpProxies.TryGetValue(ev.ProxyEndPoint.Port, out x);
//await Task.CompletedTask;
await Task.Delay(0);
return x;
}
private async Task<IExternalProxy> onCustomUpStreamProxyFailureFunc(SessionEventArgsBase ev)
{
IExternalProxy x;
upStreamHttpProxies.TryGetValue(ev.ProxyEndPoint.Port, out x);
//await Task.CompletedTask;
await Task.Delay(0);
return x;
}
void Start()
{
if (!proxyServer.ProxyRunning) proxyServer.Start();
}
public void Start(int localPort, string remoteHost, int remotePort, string user = "", string pwd = "")
{
if (!string.IsNullOrWhiteSpace(remoteHost))
{
AddEndPoint(localPort, remoteHost, remotePort, user, pwd);
}
else
{
AddEndPoint(localPort);
}
Start();
}
public void Start(int localPort, string proxyServer)
{
if (!string.IsNullOrWhiteSpace(proxyServer))
{
AddEndPoint(localPort, proxyServer);
}
else
{
AddEndPoint(localPort);
}
Start();
}
public void AddEndPoint(int localPort, string proxyServer)
{
if (!string.IsNullOrWhiteSpace(proxyServer) && proxyServer.IndexOf(":") != -1)
{
var args = proxyServer.Split(":".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
var host = args[0];
var port = Convert.ToInt32(args[1]);
var user = string.Empty;
var pwd = string.Empty;
if (args.Length >= 4)
{
user = args[2];
pwd = args[3];
}
AddEndPoint(localPort, host, port, user, pwd);
}
else
{
//Console.WriteLine("proxy server format error: " + proxyServer+ "\r\nfotmat: ip:port or ip:port:user:pwd");
}
}
public void AddEndPoint(int localPort, string remoteHost, int remotePort, string user = "", string pwd = "")
{
//if (!string.IsNullOrWhiteSpace(remoteHost))
if (!string.IsNullOrWhiteSpace(remoteHost) && !upStreamHttpProxies.ContainsKey(localPort))
{
AddEndPoint(localPort);
//UpStreamHttpProxies.TryAdd(localPort, new ExternalProxy
//{
// HostName = remoteHost,
// Port = remotePort,
// Password = user,
// UserName = pwd,
// BypassLocalhost = true,
// UseDefaultCredentials = false,
//});
var upStreamProxy = new ExternalProxy(remoteHost, remotePort, user, pwd) { ProxyType = ExternalProxyType.Http };
upStreamHttpProxies.TryAdd(localPort, upStreamProxy);
}
}
public void AddEndPoint(int localPort)
{
tcpProxy = new ExplicitProxyEndPoint(IPAddress.Any, localPort, decryptSsl);
tcpProxy.BeforeTunnelConnectRequest += onBeforeTunnelConnectRequest;
proxyServer.AddEndPoint(tcpProxy);
// Console.WriteLine(string.Format("LocalProxyServer Listening on '{0}' endpoint at Ip {1} and port: {2} ", tcpProxy.GetType().Name, tcpProxy.IpAddress, tcpProxy.Port)) ;
}
public void Stop()
{
try
{
tcpProxy.BeforeTunnelConnectRequest -= onBeforeTunnelConnectRequest;
proxyServer.BeforeRequest -= OnBeforeRequest;
proxyServer.ServerCertificateValidationCallback -= OnServerCertificateValidation;
proxyServer.Stop();
// proxyServer.CertificateManager.RemoveTrustedRootCertificate(true);
proxyServer.Dispose();
}
catch
{
Console.WriteLine("DM");
}
}
public Dictionary<int, string> GetUpStreamProxies()
{
var dic = new Dictionary<int, string>();
foreach (var localPort in upStreamHttpProxies.Keys)
{
IExternalProxy px;
upStreamHttpProxies.TryGetValue(localPort, out px);
if (px != null)
{
dic.Add(localPort, string.Format("{0}:{1}", px.HostName, px.Port));
}
}
return dic;
}
async Task OnServerCertificateValidation(object sender, CertificateValidationEventArgs ev)
{
// If our destination server has only the domain name in the certificate, we might check it
// or simply don't care (FOR DEVELOPMENT ONLY).
ev.IsValid = true;
//if (ev.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
// ev.IsValid = true;
await Task.FromResult(0);
}
async Task onBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{
var clientLocalPort = e.ClientLocalEndPoint.Port;
IExternalProxy x;
upStreamHttpProxies.TryGetValue(clientLocalPort, out x);
if (x != null)
{
e.CustomUpStreamProxy = x;
}
await Task.FromResult(0);
}
async Task OnBeforeRequest(object sender, SessionEventArgs ev)
{
//ev.CustomUpStreamProxy = GetCustomUpStreamProxy(ev);
var request = ev.HttpClient.Request;
var cep = ev.ClientRemoteEndPoint;
IExternalProxy x;
upStreamHttpProxies.TryGetValue(ev.ProxyEndPoint.Port, out x);
if (x != null)
{
ev.CustomUpStreamProxy = x;
}
else
{
}
await Task.FromResult(0);
}
async Task OnResponse(object sender, SessionEventArgs ev)
{
await Task.FromResult(0);
}
}