Commit e928c25a authored by Jehonathan Thomas's avatar Jehonathan Thomas Committed by GitHub

Merge pull request #215 from justcoding121/develop

Beta merge
parents b62f9f14 e7b254f1
...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
public class Program public class Program
{ {
private static readonly ProxyTestController Controller = new ProxyTestController(); private static readonly ProxyTestController controller = new ProxyTestController();
public static void Main(string[] args) public static void Main(string[] args)
{ {
...@@ -15,13 +15,13 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -15,13 +15,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Start proxy controller //Start proxy controller
Controller.StartProxy(); controller.StartProxy();
Console.WriteLine("Hit any key to exit.."); Console.WriteLine("Hit any key to exit..");
Console.WriteLine(); Console.WriteLine();
Console.Read(); Console.Read();
Controller.Stop(); controller.Stop();
} }
...@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
if (eventType != 2) return false; if (eventType != 2) return false;
try try
{ {
Controller.Stop(); controller.Stop();
} }
catch catch
{ {
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -9,10 +10,10 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -9,10 +10,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
public class ProxyTestController public class ProxyTestController
{ {
private ProxyServer proxyServer; private readonly ProxyServer proxyServer;
//share requestBody outside handlers //share requestBody outside handlers
private Dictionary<Guid, string> requestBodyHistory; private readonly Dictionary<Guid, string> requestBodyHistory = new Dictionary<Guid, string>();
public ProxyTestController() public ProxyTestController()
{ {
...@@ -23,7 +24,8 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -23,7 +24,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Under Mono only BouncyCastle will be supported //Under Mono only BouncyCastle will be supported
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle; //proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;
requestBodyHistory = new Dictionary<Guid, string>(); //optionally set the Root Certificate
//proxyServer.RootCertificate = new X509Certificate2("myCert.pfx", string.Empty, X509KeyStorageFlags.Exportable);
} }
public void StartProxy() public void StartProxy()
......
...@@ -112,7 +112,7 @@ Sample request and response event handlers ...@@ -112,7 +112,7 @@ Sample request and response event handlers
```csharp ```csharp
//To access requestBody from OnResponse handler //To access requestBody from OnResponse handler
private Dictionary<Guid, string> requestBodyHistory; private Dictionary<Guid, string> requestBodyHistory = new Dictionary<Guid, string>();
public async Task OnRequest(object sender, SessionEventArgs e) public async Task OnRequest(object sender, SessionEventArgs e)
{ {
......
...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.UnitTests
[TestClass] [TestClass]
public class CertificateManagerTests public class CertificateManagerTests
{ {
private readonly static string[] hostNames private static readonly string[] hostNames
= new string[] { "facebook.com", "youtube.com", "google.com", = new string[] { "facebook.com", "youtube.com", "google.com",
"bing.com", "yahoo.com"}; "bing.com", "yahoo.com"};
......
...@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy ...@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy
/// <param name="chain"></param> /// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param> /// <param name="sslPolicyErrors"></param>
/// <returns></returns> /// <returns></returns>
internal bool ValidateServerCertificate( private bool ValidateServerCertificate(
object sender, object sender,
X509Certificate certificate, X509Certificate certificate,
X509Chain chain, X509Chain chain,
...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy ...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy
/// <param name="remoteCertificate"></param> /// <param name="remoteCertificate"></param>
/// <param name="acceptableIssuers"></param> /// <param name="acceptableIssuers"></param>
/// <returns></returns> /// <returns></returns>
internal X509Certificate SelectClientCertificate( private X509Certificate SelectClientCertificate(
object sender, object sender,
string targetHost, string targetHost,
X509CertificateCollection localCertificates, X509CertificateCollection localCertificates,
......
...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <summary> /// <summary>
/// Extension methods for Byte Arrays. /// Extension methods for Byte Arrays.
/// </summary> /// </summary>
public static class ByteArrayExtensions internal static class ByteArrayExtensions
{ {
/// <summary> /// <summary>
/// Get the sub array from byte of data /// Get the sub array from byte of data
...@@ -15,7 +15,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -15,7 +15,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="length"></param> /// <param name="length"></param>
/// <returns></returns> /// <returns></returns>
public static T[] SubArray<T>(this T[] data, int index, int length) internal static T[] SubArray<T>(this T[] data, int index, int length)
{ {
var result = new T[length]; var result = new T[length];
Array.Copy(data, index, result, 0, length); Array.Copy(data, index, result, 0, length);
......
...@@ -6,12 +6,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -6,12 +6,12 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// A helper class to set proxy settings for firefox /// A helper class to set proxy settings for firefox
/// </summary> /// </summary>
public class FireFoxProxySettingsManager internal class FireFoxProxySettingsManager
{ {
/// <summary> /// <summary>
/// Add Firefox settings. /// Add Firefox settings.
/// </summary> /// </summary>
public void AddFirefox() internal void AddFirefox()
{ {
try try
{ {
...@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// Remove firefox settings. /// Remove firefox settings.
/// </summary> /// </summary>
public void RemoveFirefox() internal void RemoveFirefox()
{ {
try try
{ {
......
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
...@@ -38,5 +39,42 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -38,5 +39,42 @@ namespace Titanium.Web.Proxy.Helpers
// test if any host IP equals to any local IP or to localhost // test if any host IP equals to any local IP or to localhost
return IPAddress.IsLoopback(address) || localIPs.Contains(address); return IPAddress.IsLoopback(address) || localIPs.Contains(address);
} }
internal static bool IsLocalIpAddress(string hostName)
{
bool isLocalhost = false;
IPHostEntry localhost = Dns.GetHostEntry("127.0.0.1");
if (hostName == localhost.HostName)
{
IPHostEntry hostEntry = Dns.GetHostEntry(hostName);
isLocalhost = hostEntry.AddressList.Any(IPAddress.IsLoopback);
}
if (!isLocalhost)
{
localhost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = null;
if (IPAddress.TryParse(hostName, out ipAddress))
isLocalhost = localhost.AddressList.Any(x => x.Equals(ipAddress));
if (!isLocalhost)
{
try
{
var hostEntry = Dns.GetHostEntry(hostName);
isLocalhost = localhost.AddressList.Any(x => hostEntry.AddressList.Any(x.Equals));
}
catch (SocketException)
{
}
}
}
return isLocalhost;
}
} }
} }
...@@ -53,8 +53,8 @@ namespace Titanium.Web.Proxy.Models ...@@ -53,8 +53,8 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint public class ExplicitProxyEndPoint : ProxyEndPoint
{ {
private List<string> _excludedHttpsHostNameRegex; private List<string> excludedHttpsHostNameRegex;
private List<string> _includedHttpsHostNameRegex; private List<string> includedHttpsHostNameRegex;
internal bool IsSystemHttpProxy { get; set; } internal bool IsSystemHttpProxy { get; set; }
...@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public List<string> ExcludedHttpsHostNameRegex public List<string> ExcludedHttpsHostNameRegex
{ {
get { return _excludedHttpsHostNameRegex; } get { return excludedHttpsHostNameRegex; }
set set
{ {
if (IncludedHttpsHostNameRegex != null) if (IncludedHttpsHostNameRegex != null)
...@@ -73,7 +73,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -73,7 +73,7 @@ namespace Titanium.Web.Proxy.Models
throw new ArgumentException("Cannot set excluded when included is set"); throw new ArgumentException("Cannot set excluded when included is set");
} }
_excludedHttpsHostNameRegex = value; excludedHttpsHostNameRegex = value;
} }
} }
...@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public List<string> IncludedHttpsHostNameRegex public List<string> IncludedHttpsHostNameRegex
{ {
get { return _includedHttpsHostNameRegex; } get { return includedHttpsHostNameRegex; }
set set
{ {
if (ExcludedHttpsHostNameRegex != null) if (ExcludedHttpsHostNameRegex != null)
...@@ -90,7 +90,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -90,7 +90,7 @@ namespace Titanium.Web.Proxy.Models
throw new ArgumentException("Cannot set included when excluded is set"); throw new ArgumentException("Cannot set included when excluded is set");
} }
_includedHttpsHostNameRegex = value; includedHttpsHostNameRegex = value;
} }
} }
......
...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public class ExternalProxy public class ExternalProxy
{ {
private static readonly Lazy<NetworkCredential> DefaultCredentials = new Lazy<NetworkCredential>(() => CredentialCache.DefaultNetworkCredentials); private static readonly Lazy<NetworkCredential> defaultCredentials = new Lazy<NetworkCredential>(() => CredentialCache.DefaultNetworkCredentials);
private string userName; private string userName;
private string password; private string password;
...@@ -18,16 +18,21 @@ namespace Titanium.Web.Proxy.Models ...@@ -18,16 +18,21 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public bool UseDefaultCredentials { get; set; } public bool UseDefaultCredentials { get; set; }
/// <summary>
/// Bypass this proxy for connections to localhost?
/// </summary>
public bool BypassForLocalhost { get; set; }
/// <summary> /// <summary>
/// Username. /// Username.
/// </summary> /// </summary>
public string UserName { public string UserName {
get { return UseDefaultCredentials ? DefaultCredentials.Value.UserName : userName; } get { return UseDefaultCredentials ? defaultCredentials.Value.UserName : userName; }
set set
{ {
userName = value; userName = value;
if (DefaultCredentials.Value.UserName != userName) if (defaultCredentials.Value.UserName != userName)
{ {
UseDefaultCredentials = false; UseDefaultCredentials = false;
} }
...@@ -39,12 +44,12 @@ namespace Titanium.Web.Proxy.Models ...@@ -39,12 +44,12 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public string Password public string Password
{ {
get { return UseDefaultCredentials ? DefaultCredentials.Value.Password : password; } get { return UseDefaultCredentials ? defaultCredentials.Value.Password : password; }
set set
{ {
password = value; password = value;
if (DefaultCredentials.Value.Password != password) if (defaultCredentials.Value.Password != password)
{ {
UseDefaultCredentials = false; UseDefaultCredentials = false;
} }
......
...@@ -21,10 +21,10 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -21,10 +21,10 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <summary> /// <summary>
/// Implements certificate generation operations. /// Implements certificate generation operations.
/// </summary> /// </summary>
public class BCCertificateMaker : ICertificateMaker internal class BCCertificateMaker : ICertificateMaker
{ {
private const int CertificateValidDays = 1825; private const int certificateValidDays = 1825;
private const int CertificateGraceDays = 366; private const int certificateGraceDays = 366;
/// <summary> /// <summary>
/// Makes the certificate. /// Makes the certificate.
...@@ -187,7 +187,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -187,7 +187,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
return certificate; return certificate;
} }
return MakeCertificateInternal(isRoot, subject, $"CN={subject}", DateTime.UtcNow.AddDays(-CertificateGraceDays), DateTime.UtcNow.AddDays(CertificateValidDays), isRoot ? null : signingCert); return MakeCertificateInternal(isRoot, subject, $"CN={subject}", DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays), isRoot ? null : signingCert);
} }
} }
......
...@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// Certificate Maker - uses MakeCert /// Certificate Maker - uses MakeCert
/// Calls COM objects using reflection /// Calls COM objects using reflection
/// </summary> /// </summary>
public class WinCertificateMaker : ICertificateMaker internal class WinCertificateMaker : ICertificateMaker
{ {
private readonly Type typeX500DN; private readonly Type typeX500DN;
...@@ -42,12 +42,12 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -42,12 +42,12 @@ namespace Titanium.Web.Proxy.Network.Certificate
private readonly string sProviderName = "Microsoft Enhanced Cryptographic Provider v1.0"; private readonly string sProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
private object _SharedPrivateKey; private object sharedPrivateKey;
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
public WinCertificateMaker() internal WinCertificateMaker()
{ {
typeX500DN = Type.GetTypeFromProgID("X509Enrollment.CX500DistinguishedName", true); typeX500DN = Type.GetTypeFromProgID("X509Enrollment.CX500DistinguishedName", true);
typeX509PrivateKey = Type.GetTypeFromProgID("X509Enrollment.CX509PrivateKey", true); typeX509PrivateKey = Type.GetTypeFromProgID("X509Enrollment.CX509PrivateKey", true);
...@@ -105,7 +105,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -105,7 +105,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (!isRoot) if (!isRoot)
{ {
sharedPrivateKey = _SharedPrivateKey; sharedPrivateKey = this.sharedPrivateKey;
} }
if (sharedPrivateKey == null) if (sharedPrivateKey == null)
...@@ -130,52 +130,52 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -130,52 +130,52 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (!isRoot) if (!isRoot)
{ {
_SharedPrivateKey = sharedPrivateKey; this.sharedPrivateKey = sharedPrivateKey;
} }
} }
typeValue = new object[1]; typeValue = new object[1];
var OID = Activator.CreateInstance(typeOID); var oid = Activator.CreateInstance(typeOID);
typeValue[0] = "1.3.6.1.5.5.7.3.1"; typeValue[0] = "1.3.6.1.5.5.7.3.1";
typeOID.InvokeMember("InitializeFromValue", BindingFlags.InvokeMethod, null, OID, typeValue); typeOID.InvokeMember("InitializeFromValue", BindingFlags.InvokeMethod, null, oid, typeValue);
var OIDS = Activator.CreateInstance(typeOIDS); var oids = Activator.CreateInstance(typeOIDS);
typeValue[0] = OID; typeValue[0] = oid;
typeOIDS.InvokeMember("Add", BindingFlags.InvokeMethod, null, OIDS, typeValue); typeOIDS.InvokeMember("Add", BindingFlags.InvokeMethod, null, oids, typeValue);
var EKUExt = Activator.CreateInstance(typeEKUExt); var ekuExt = Activator.CreateInstance(typeEKUExt);
typeValue[0] = OIDS; typeValue[0] = oids;
typeEKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, EKUExt, typeValue); typeEKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, ekuExt, typeValue);
var RequestCert = Activator.CreateInstance(typeRequestCert); var requestCert = Activator.CreateInstance(typeRequestCert);
typeValue = new[] { 1, sharedPrivateKey, string.Empty }; typeValue = new[] { 1, sharedPrivateKey, string.Empty };
typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, RequestCert, typeValue); typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, requestCert, typeValue);
typeValue = new[] { x500CertDN }; typeValue = new[] { x500CertDN };
typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeValue[0] = x500RootCertDN; typeValue[0] = x500RootCertDN;
typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeValue[0] = validFrom; typeValue[0] = validFrom;
typeRequestCert.InvokeMember("NotBefore", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("NotBefore", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeValue[0] = validTo; typeValue[0] = validTo;
typeRequestCert.InvokeMember("NotAfter", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("NotAfter", BindingFlags.PutDispProperty, null, requestCert, typeValue);
var KUExt = Activator.CreateInstance(typeKUExt); var kuExt = Activator.CreateInstance(typeKUExt);
typeValue[0] = 176; typeValue[0] = 176;
typeKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, KUExt, typeValue); typeKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, kuExt, typeValue);
var certificate = typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, RequestCert, null); var certificate = typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, requestCert, null);
typeValue = new object[1]; typeValue = new object[1];
if (!isRoot) if (!isRoot)
{ {
typeValue[0] = KUExt; typeValue[0] = kuExt;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
} }
typeValue[0] = EKUExt; typeValue[0] = ekuExt;
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
if (!isRoot) if (!isRoot)
...@@ -203,12 +203,12 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -203,12 +203,12 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (!isRoot) if (!isRoot)
{ {
var SignerCertificate = Activator.CreateInstance(typeSignerCertificate); var signerCertificate = Activator.CreateInstance(typeSignerCertificate);
typeValue = new object[] { 0, 0, 12, signingCertificate.Thumbprint }; typeValue = new object[] { 0, 0, 12, signingCertificate.Thumbprint };
typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, SignerCertificate, typeValue); typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, signerCertificate, typeValue);
typeValue = new[] { SignerCertificate }; typeValue = new[] { signerCertificate };
typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, requestCert, typeValue);
} }
else else
{ {
...@@ -220,24 +220,24 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -220,24 +220,24 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
} }
OID = Activator.CreateInstance(typeOID); oid = Activator.CreateInstance(typeOID);
typeValue = new object[] { 1, 0, 0, hashAlg }; typeValue = new object[] { 1, 0, 0, hashAlg };
typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, OID, typeValue); typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, oid, typeValue);
typeValue = new[] { OID }; typeValue = new[] { oid };
typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, RequestCert, typeValue); typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, RequestCert, null); typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, requestCert, null);
var X509Enrollment = Activator.CreateInstance(typeX509Enrollment); var x509Enrollment = Activator.CreateInstance(typeX509Enrollment);
typeValue[0] = RequestCert; typeValue[0] = requestCert;
typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue); typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
if (isRoot) if (isRoot)
{ {
typeValue[0] = fullSubject; typeValue[0] = fullSubject;
typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null, X509Enrollment, typeValue); typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null, x509Enrollment, typeValue);
} }
...@@ -245,15 +245,15 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -245,15 +245,15 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeValue[0] = 0; typeValue[0] = 0;
var createCertRequest = typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue); var createCertRequest = typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
typeValue = new[] { 2, createCertRequest, 0, string.Empty }; typeValue = new[] { 2, createCertRequest, 0, string.Empty };
typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue); typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
typeValue = new object[] { null, 0, 1 }; typeValue = new object[] { null, 0, 1 };
try try
{ {
var empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, X509Enrollment, typeValue); var empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable); return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable);
} }
catch (Exception) catch (Exception)
......
...@@ -31,6 +31,10 @@ namespace Titanium.Web.Proxy.Network ...@@ -31,6 +31,10 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
internal class CertificateManager : IDisposable internal class CertificateManager : IDisposable
{ {
private const string defaultRootCertificateIssuer = "Titanium";
private const string defaultRootRootCertificateName = "Titanium Root Certificate Authority";
private readonly ICertificateMaker certEngine; private readonly ICertificateMaker certEngine;
private bool clearCertificates { get; set; } private bool clearCertificates { get; set; }
...@@ -66,8 +70,8 @@ namespace Titanium.Web.Proxy.Network ...@@ -66,8 +70,8 @@ namespace Titanium.Web.Proxy.Network
certEngine = new WinCertificateMaker(); certEngine = new WinCertificateMaker();
} }
Issuer = issuer; Issuer = issuer ?? defaultRootCertificateIssuer;
RootCertificateName = rootCertificateName; RootCertificateName = rootCertificateName ?? defaultRootRootCertificateName;
certificateCache = new ConcurrentDictionary<string, CachedCertificate>(); certificateCache = new ConcurrentDictionary<string, CachedCertificate>();
} }
...@@ -88,7 +92,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -88,7 +92,7 @@ namespace Titanium.Web.Proxy.Network
return fileName; return fileName;
} }
internal X509Certificate2 GetRootCertificate() internal X509Certificate2 LoadRootCertificate()
{ {
var fileName = GetRootCertificatePath(); var fileName = GetRootCertificatePath();
if (!File.Exists(fileName)) return null; if (!File.Exists(fileName)) return null;
...@@ -108,11 +112,16 @@ namespace Titanium.Web.Proxy.Network ...@@ -108,11 +112,16 @@ namespace Titanium.Web.Proxy.Network
/// <returns>true if succeeded, else false</returns> /// <returns>true if succeeded, else false</returns>
internal bool CreateTrustedRootCertificate() internal bool CreateTrustedRootCertificate()
{ {
RootCertificate = GetRootCertificate(); if (RootCertificate == null)
{
RootCertificate = LoadRootCertificate();
}
if (RootCertificate != null) if (RootCertificate != null)
{ {
return true; return true;
} }
try try
{ {
RootCertificate = CreateCertificate(RootCertificateName, true); RootCertificate = CreateCertificate(RootCertificateName, true);
...@@ -121,6 +130,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -121,6 +130,7 @@ namespace Titanium.Web.Proxy.Network
{ {
exceptionFunc(e); exceptionFunc(e);
} }
if (RootCertificate != null) if (RootCertificate != null)
{ {
try try
...@@ -133,9 +143,23 @@ namespace Titanium.Web.Proxy.Network ...@@ -133,9 +143,23 @@ namespace Titanium.Web.Proxy.Network
exceptionFunc(e); exceptionFunc(e);
} }
} }
return RootCertificate != null; return RootCertificate != null;
} }
/// <summary>
/// Trusts the root certificate.
/// </summary>
/// <param name="exceptionFunc"></param>
internal void TrustRootCertificate(Action<Exception> exceptionFunc)
{
//current user
TrustRootCertificate(StoreLocation.CurrentUser, exceptionFunc);
//current system
TrustRootCertificate(StoreLocation.LocalMachine, exceptionFunc);
}
/// <summary> /// <summary>
/// Create an SSL certificate /// Create an SSL certificate
/// </summary> /// </summary>
...@@ -144,7 +168,6 @@ namespace Titanium.Web.Proxy.Network ...@@ -144,7 +168,6 @@ namespace Titanium.Web.Proxy.Network
/// <returns></returns> /// <returns></returns>
internal virtual X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate) internal virtual X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate)
{ {
if (certificateCache.ContainsKey(certificateName)) if (certificateCache.ContainsKey(certificateName))
{ {
var cached = certificateCache[certificateName]; var cached = certificateCache[certificateName];
...@@ -152,7 +175,6 @@ namespace Titanium.Web.Proxy.Network ...@@ -152,7 +175,6 @@ namespace Titanium.Web.Proxy.Network
return cached.Certificate; return cached.Certificate;
} }
X509Certificate2 certificate = null; X509Certificate2 certificate = null;
lock (string.Intern(certificateName)) lock (string.Intern(certificateName))
{ {
...@@ -160,6 +182,11 @@ namespace Titanium.Web.Proxy.Network ...@@ -160,6 +182,11 @@ namespace Titanium.Web.Proxy.Network
{ {
try try
{ {
if (!isRootCertificate && RootCertificate == null)
{
CreateTrustedRootCertificate();
}
certificate = certEngine.MakeCertificate(certificateName, isRootCertificate, RootCertificate); certificate = certEngine.MakeCertificate(certificateName, isRootCertificate, RootCertificate);
} }
catch (Exception e) catch (Exception e)
...@@ -168,7 +195,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -168,7 +195,7 @@ namespace Titanium.Web.Proxy.Network
} }
if (certificate != null && !certificateCache.ContainsKey(certificateName)) if (certificate != null && !certificateCache.ContainsKey(certificateName))
{ {
certificateCache.Add(certificateName, new CachedCertificate() { Certificate = certificate }); certificateCache.Add(certificateName, new CachedCertificate { Certificate = certificate });
} }
} }
else else
...@@ -182,10 +209,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -182,10 +209,7 @@ namespace Titanium.Web.Proxy.Network
} }
} }
return certificate; return certificate;
} }
/// <summary> /// <summary>
......
...@@ -7,7 +7,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -7,7 +7,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary> /// <summary>
/// This class wraps Tcp connection to client /// This class wraps Tcp connection to client
/// </summary> /// </summary>
public class ProxyClient internal class ProxyClient
{ {
/// <summary> /// <summary>
/// TcpClient used to communicate with client /// TcpClient used to communicate with client
......
...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// An object that holds TcpConnection to a particular server and port /// An object that holds TcpConnection to a particular server and port
/// </summary> /// </summary>
public class TcpConnection : IDisposable internal class TcpConnection : IDisposable
{ {
internal ExternalProxy UpStreamHttpProxy { get; set; } internal ExternalProxy UpStreamHttpProxy { get; set; }
......
...@@ -41,20 +41,24 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -41,20 +41,24 @@ namespace Titanium.Web.Proxy.Network.Tcp
bool isHttps, SslProtocols supportedSslProtocols, bool isHttps, SslProtocols supportedSslProtocols,
RemoteCertificateValidationCallback remoteCertificateValidationCallback, LocalCertificateSelectionCallback localCertificateSelectionCallback, RemoteCertificateValidationCallback remoteCertificateValidationCallback, LocalCertificateSelectionCallback localCertificateSelectionCallback,
ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy, ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy,
Stream clientStream, EndPoint upStreamEndPoint) Stream clientStream, IPEndPoint upStreamEndPoint)
{ {
TcpClient client; TcpClient client;
Stream stream; Stream stream;
bool isLocalhost = (externalHttpsProxy == null && externalHttpProxy == null) ? false : NetworkHelper.IsLocalIpAddress(remoteHostName);
bool useHttpsProxy = externalHttpsProxy != null && externalHttpsProxy.HostName != remoteHostName && (externalHttpsProxy.BypassForLocalhost && !isLocalhost);
bool useHttpProxy = externalHttpProxy != null && externalHttpProxy.HostName != remoteHostName && (externalHttpProxy.BypassForLocalhost && !isLocalhost);
if (isHttps) if (isHttps)
{ {
SslStream sslStream = null; SslStream sslStream = null;
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections //If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if (externalHttpsProxy != null && externalHttpsProxy.HostName != remoteHostName) if (useHttpsProxy)
{ {
client = new TcpClient(); client = new TcpClient(upStreamEndPoint);
client.Client.Bind(upStreamEndPoint);
await client.ConnectAsync(externalHttpsProxy.HostName, externalHttpsProxy.Port); await client.ConnectAsync(externalHttpsProxy.HostName, externalHttpsProxy.Port);
stream = client.GetStream(); stream = client.GetStream();
...@@ -89,8 +93,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -89,8 +93,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
else else
{ {
client = new TcpClient(); client = new TcpClient(upStreamEndPoint);
client.Client.Bind(upStreamEndPoint);
await client.ConnectAsync(remoteHostName, remotePort); await client.ConnectAsync(remoteHostName, remotePort);
stream = client.GetStream(); stream = client.GetStream();
} }
...@@ -113,17 +116,15 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -113,17 +116,15 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
else else
{ {
if (externalHttpProxy != null && externalHttpProxy.HostName != remoteHostName) if (useHttpProxy)
{ {
client = new TcpClient(); client = new TcpClient(upStreamEndPoint);
client.Client.Bind(upStreamEndPoint);
await client.ConnectAsync(externalHttpProxy.HostName, externalHttpProxy.Port); await client.ConnectAsync(externalHttpProxy.HostName, externalHttpProxy.Port);
stream = client.GetStream(); stream = client.GetStream();
} }
else else
{ {
client = new TcpClient(); client = new TcpClient(upStreamEndPoint);
client.Client.Bind(upStreamEndPoint);
await client.ConnectAsync(remoteHostName, remotePort); await client.ConnectAsync(remoteHostName, remotePort);
stream = client.GetStream(); stream = client.GetStream();
} }
......
...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// Initializes a new instance of the <see cref="TcpRow"/> class. /// Initializes a new instance of the <see cref="TcpRow"/> class.
/// </summary> /// </summary>
/// <param name="tcpRow">TcpRow struct.</param> /// <param name="tcpRow">TcpRow struct.</param>
public TcpRow(NativeMethods.TcpRow tcpRow) internal TcpRow(NativeMethods.TcpRow tcpRow)
{ {
ProcessId = tcpRow.owningPid; ProcessId = tcpRow.owningPid;
...@@ -29,16 +29,16 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -29,16 +29,16 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// Gets the local end point. /// Gets the local end point.
/// </summary> /// </summary>
public IPEndPoint LocalEndPoint { get; } internal IPEndPoint LocalEndPoint { get; }
/// <summary> /// <summary>
/// Gets the remote end point. /// Gets the remote end point.
/// </summary> /// </summary>
public IPEndPoint RemoteEndPoint { get; } internal IPEndPoint RemoteEndPoint { get; }
/// <summary> /// <summary>
/// Gets the process identifier. /// Gets the process identifier.
/// </summary> /// </summary>
public int ProcessId { get; } internal int ProcessId { get; }
} }
} }
\ No newline at end of file
...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// Initializes a new instance of the <see cref="TcpTable"/> class. /// Initializes a new instance of the <see cref="TcpTable"/> class.
/// </summary> /// </summary>
/// <param name="tcpRows">TcpRow collection to initialize with.</param> /// <param name="tcpRows">TcpRow collection to initialize with.</param>
public TcpTable(IEnumerable<TcpRow> tcpRows) internal TcpTable(IEnumerable<TcpRow> tcpRows)
{ {
this.tcpRows = tcpRows; this.tcpRows = tcpRows;
} }
...@@ -25,7 +25,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -25,7 +25,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// Gets the TCP rows. /// Gets the TCP rows.
/// </summary> /// </summary>
public IEnumerable<TcpRow> TcpRows => tcpRows; internal IEnumerable<TcpRow> TcpRows => tcpRows;
/// <summary> /// <summary>
/// Returns an enumerator that iterates through the collection. /// Returns an enumerator that iterates through the collection.
......
...@@ -19,11 +19,10 @@ namespace Titanium.Web.Proxy ...@@ -19,11 +19,10 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
public partial class ProxyServer : IDisposable public partial class ProxyServer : IDisposable
{ {
/// <summary> /// <summary>
/// Is the root certificate used by this proxy is valid? /// Is the root certificate used by this proxy is valid?
/// </summary> /// </summary>
private bool certValidated { get; set; } private bool? certValidated { get; set; }
/// <summary> /// <summary>
/// Is the proxy currently running /// Is the proxy currently running
...@@ -33,7 +32,7 @@ namespace Titanium.Web.Proxy ...@@ -33,7 +32,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Manages certificates used by this proxy /// Manages certificates used by this proxy
/// </summary> /// </summary>
private CertificateManager certificateCacheManager { get; set; } private CertificateManager certificateManager { get; set; }
/// <summary> /// <summary>
/// An default exception log func /// An default exception log func
...@@ -45,6 +44,8 @@ namespace Titanium.Web.Proxy ...@@ -45,6 +44,8 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
private Action<Exception> exceptionFunc; private Action<Exception> exceptionFunc;
private bool trustRootCertificate;
/// <summary> /// <summary>
/// A object that creates tcp connection to server /// A object that creates tcp connection to server
/// </summary> /// </summary>
...@@ -66,27 +67,65 @@ namespace Titanium.Web.Proxy ...@@ -66,27 +67,65 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Buffer size used throughout this proxy /// Buffer size used throughout this proxy
/// </summary> /// </summary>
public int BUFFER_SIZE { get; set; } = 8192; public int BufferSize { get; set; } = 8192;
/// <summary>
/// The root certificate
/// </summary>
public X509Certificate2 RootCertificate
{
get { return certificateManager.RootCertificate; }
set { certificateManager.RootCertificate = value; }
}
/// <summary> /// <summary>
/// Name of the root certificate issuer /// Name of the root certificate issuer
/// (This is valid only when RootCertificate property is not set)
/// </summary> /// </summary>
public string RootCertificateIssuerName { get; set; } public string RootCertificateIssuerName
{
get { return certificateManager.Issuer; }
set
{
CreateCertificateManager(certificateManager.RootCertificateName, value);
certValidated = null;
}
}
/// <summary> /// <summary>
/// Name of the root certificate /// Name of the root certificate
/// (This is valid only when RootCertificate property is not set)
/// If no certificate is provided then a default Root Certificate will be created and used /// If no certificate is provided then a default Root Certificate will be created and used
/// The provided root certificate has to be in the proxy exe directory with the private key /// The provided root certificate will be stored in proxy exe directory with the private key
/// The root certificate file should be named as "rootCert.pfx" /// Root certificate file will be named as "rootCert.pfx"
/// </summary> /// </summary>
public string RootCertificateName { get; set; } public string RootCertificateName
{
get { return certificateManager.RootCertificateName; }
set
{
CreateCertificateManager(value, certificateManager.Issuer);
certValidated = null;
}
}
/// <summary> /// <summary>
/// Trust the RootCertificate used by this proxy server /// Trust the RootCertificate used by this proxy server
/// Note that this do not make the client trust the certificate! /// Note that this do not make the client trust the certificate!
/// This would import the root certificate to the certificate store of machine that runs this proxy server /// This would import the root certificate to the certificate store of machine that runs this proxy server
/// </summary> /// </summary>
public bool TrustRootCertificate { get; set; } public bool TrustRootCertificate
{
get { return trustRootCertificate; }
set
{
trustRootCertificate = value;
if (value)
{
EnsureRootCertificate();
}
}
}
/// <summary> /// <summary>
/// Select Certificate Engine /// Select Certificate Engine
...@@ -211,7 +250,9 @@ namespace Titanium.Web.Proxy ...@@ -211,7 +250,9 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ProxyServer() : this(null, null) { } public ProxyServer() : this(null, null)
{
}
/// <summary> /// <summary>
/// Constructor. /// Constructor.
...@@ -220,9 +261,6 @@ namespace Titanium.Web.Proxy ...@@ -220,9 +261,6 @@ namespace Titanium.Web.Proxy
/// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param> /// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param>
public ProxyServer(string rootCertificateName, string rootCertificateIssuerName) public ProxyServer(string rootCertificateName, string rootCertificateIssuerName)
{ {
RootCertificateName = rootCertificateName;
RootCertificateIssuerName = rootCertificateIssuerName;
//default values //default values
ConnectionTimeOutSeconds = 120; ConnectionTimeOutSeconds = 120;
CertificateCacheTimeOutMinutes = 60; CertificateCacheTimeOutMinutes = 60;
...@@ -233,8 +271,8 @@ namespace Titanium.Web.Proxy ...@@ -233,8 +271,8 @@ namespace Titanium.Web.Proxy
#if !DEBUG #if !DEBUG
new FireFoxProxySettingsManager(); new FireFoxProxySettingsManager();
#endif #endif
RootCertificateName = RootCertificateName ?? "Titanium Root Certificate Authority";
RootCertificateIssuerName = RootCertificateIssuerName ?? "Titanium"; CreateCertificateManager(rootCertificateName, rootCertificateIssuerName);
} }
/// <summary> /// <summary>
...@@ -328,8 +366,10 @@ namespace Titanium.Web.Proxy ...@@ -328,8 +366,10 @@ namespace Titanium.Web.Proxy
.ToList() .ToList()
.ForEach(x => x.IsSystemHttpsProxy = false); .ForEach(x => x.IsSystemHttpsProxy = false);
EnsureRootCertificate();
//If certificate was trusted by the machine //If certificate was trusted by the machine
if (certValidated) if (certValidated == true)
{ {
systemProxySettingsManager.SetHttpsProxy( systemProxySettingsManager.SetHttpsProxy(
Equals(endPoint.IpAddress, IPAddress.Any) | Equals(endPoint.IpAddress, IPAddress.Any) |
...@@ -397,23 +437,6 @@ namespace Titanium.Web.Proxy ...@@ -397,23 +437,6 @@ namespace Titanium.Web.Proxy
throw new Exception("Proxy is already running."); throw new Exception("Proxy is already running.");
} }
certificateCacheManager = new CertificateManager(CertificateEngine,
RootCertificateIssuerName,
RootCertificateName, ExceptionFunc);
certValidated = certificateCacheManager.CreateTrustedRootCertificate();
if (TrustRootCertificate)
{
//current user
certificateCacheManager
.TrustRootCertificate(StoreLocation.CurrentUser, ExceptionFunc);
//current system
certificateCacheManager
.TrustRootCertificate(StoreLocation.LocalMachine, ExceptionFunc);
}
if (ForwardToUpstreamGateway && GetCustomUpStreamHttpProxyFunc == null if (ForwardToUpstreamGateway && GetCustomUpStreamHttpProxyFunc == null
&& GetCustomUpStreamHttpsProxyFunc == null) && GetCustomUpStreamHttpsProxyFunc == null)
{ {
...@@ -426,32 +449,11 @@ namespace Titanium.Web.Proxy ...@@ -426,32 +449,11 @@ namespace Titanium.Web.Proxy
Listen(endPoint); Listen(endPoint);
} }
certificateCacheManager.ClearIdleCertificates(CertificateCacheTimeOutMinutes); certificateManager.ClearIdleCertificates(CertificateCacheTimeOutMinutes);
proxyRunning = true; proxyRunning = true;
} }
/// <summary>
/// Gets the system up stream proxy.
/// </summary>
/// <param name="sessionEventArgs">The <see cref="SessionEventArgs"/> instance containing the event data.</param>
/// <returns><see cref="ExternalProxy"/> instance containing valid proxy configuration from PAC/WAPD scripts if any exists.</returns>
private Task<ExternalProxy> GetSystemUpStreamProxy(SessionEventArgs sessionEventArgs)
{
// Use built-in WebProxy class to handle PAC/WAPD scripts.
var systemProxyResolver = new WebProxy();
var systemProxyUri = systemProxyResolver.GetProxy(sessionEventArgs.WebSession.Request.RequestUri);
// TODO: Apply authorization
var systemProxy = new ExternalProxy
{
HostName = systemProxyUri.Host,
Port = systemProxyUri.Port
};
return Task.FromResult(systemProxy);
}
/// <summary> /// <summary>
/// Stop this proxy server /// Stop this proxy server
...@@ -480,11 +482,24 @@ namespace Titanium.Web.Proxy ...@@ -480,11 +482,24 @@ namespace Titanium.Web.Proxy
ProxyEndPoints.Clear(); ProxyEndPoints.Clear();
certificateCacheManager?.StopClearIdleCertificates(); certificateManager?.StopClearIdleCertificates();
proxyRunning = false; proxyRunning = false;
} }
/// <summary>
/// Dispose Proxy.
/// </summary>
public void Dispose()
{
if (proxyRunning)
{
Stop();
}
certificateManager?.Dispose();
}
/// <summary> /// <summary>
/// Listen on the given end point on local machine /// Listen on the given end point on local machine
/// </summary> /// </summary>
...@@ -499,16 +514,7 @@ namespace Titanium.Web.Proxy ...@@ -499,16 +514,7 @@ namespace Titanium.Web.Proxy
endPoint.Listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint); endPoint.Listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint);
} }
/// <summary>
/// Quit listening on the given end point
/// </summary>
/// <param name="endPoint"></param>
private void QuitListen(ProxyEndPoint endPoint)
{
endPoint.Listener.Stop();
endPoint.Listener.Server.Close();
endPoint.Listener.Server.Dispose();
}
/// <summary> /// <summary>
/// Verifiy if its safe to set this end point as System proxy /// Verifiy if its safe to set this end point as System proxy
...@@ -528,6 +534,48 @@ namespace Titanium.Web.Proxy ...@@ -528,6 +534,48 @@ namespace Titanium.Web.Proxy
} }
} }
/// <summary>
/// Gets the system up stream proxy.
/// </summary>
/// <param name="sessionEventArgs">The <see cref="SessionEventArgs"/> instance containing the event data.</param>
/// <returns><see cref="ExternalProxy"/> instance containing valid proxy configuration from PAC/WAPD scripts if any exists.</returns>
private Task<ExternalProxy> GetSystemUpStreamProxy(SessionEventArgs sessionEventArgs)
{
// Use built-in WebProxy class to handle PAC/WAPD scripts.
var systemProxyResolver = new WebProxy();
var systemProxyUri = systemProxyResolver.GetProxy(sessionEventArgs.WebSession.Request.RequestUri);
// TODO: Apply authorization
var systemProxy = new ExternalProxy
{
HostName = systemProxyUri.Host,
Port = systemProxyUri.Port
};
return Task.FromResult(systemProxy);
}
private void CreateCertificateManager(string rootCertificateName, string rootCertificateIssuerName)
{
certificateManager = new CertificateManager(CertificateEngine,
rootCertificateIssuerName, rootCertificateName, ExceptionFunc);
}
private void EnsureRootCertificate()
{
if (!certValidated.HasValue)
{
certValidated = certificateManager.CreateTrustedRootCertificate();
if (TrustRootCertificate)
{
certificateManager.TrustRootCertificate(ExceptionFunc);
}
}
}
/// <summary> /// <summary>
/// When a connection is received from client act /// When a connection is received from client act
/// </summary> /// </summary>
...@@ -599,16 +647,14 @@ namespace Titanium.Web.Proxy ...@@ -599,16 +647,14 @@ namespace Titanium.Web.Proxy
} }
/// <summary> /// <summary>
/// Dispose Proxy. /// Quit listening on the given end point
/// </summary> /// </summary>
public void Dispose() /// <param name="endPoint"></param>
{ private void QuitListen(ProxyEndPoint endPoint)
if (proxyRunning)
{ {
Stop(); endPoint.Listener.Stop();
} endPoint.Listener.Server.Close();
endPoint.Listener.Server.Dispose();
certificateCacheManager?.Dispose();
} }
/// <summary> /// <summary>
......
...@@ -115,7 +115,7 @@ namespace Titanium.Web.Proxy ...@@ -115,7 +115,7 @@ namespace Titanium.Web.Proxy
sslStream = new SslStream(clientStream, true); sslStream = new SslStream(clientStream, true);
var certificate = endPoint.GenericCertificate ?? certificateCacheManager.CreateCertificate(httpRemoteUri.Host, false); var certificate = endPoint.GenericCertificate ?? certificateManager.CreateCertificate(httpRemoteUri.Host, false);
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, await sslStream.AuthenticateAsServerAsync(certificate, false,
...@@ -147,7 +147,7 @@ namespace Titanium.Web.Proxy ...@@ -147,7 +147,7 @@ namespace Titanium.Web.Proxy
//write back successfull CONNECT response //write back successfull CONNECT response
await WriteConnectResponse(clientStreamWriter, version); await WriteConnectResponse(clientStreamWriter, version);
await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port, await TcpHelper.SendRaw(BufferSize, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port,
null, version, null, null, version, null,
false, SupportedSslProtocols, false, SupportedSslProtocols,
ValidateServerCertificate, ValidateServerCertificate,
...@@ -185,7 +185,7 @@ namespace Titanium.Web.Proxy ...@@ -185,7 +185,7 @@ namespace Titanium.Web.Proxy
var sslStream = new SslStream(clientStream, true); var sslStream = new SslStream(clientStream, true);
//implement in future once SNI supported by SSL stream, for now use the same certificate //implement in future once SNI supported by SSL stream, for now use the same certificate
var certificate = certificateCacheManager.CreateCertificate(endPoint.GenericCertificateName, false); var certificate = certificateManager.CreateCertificate(endPoint.GenericCertificateName, false);
try try
{ {
...@@ -245,7 +245,7 @@ namespace Titanium.Web.Proxy ...@@ -245,7 +245,7 @@ namespace Titanium.Web.Proxy
args.CustomUpStreamHttpProxyUsed = customUpStreamHttpProxy; args.CustomUpStreamHttpProxyUsed = customUpStreamHttpProxy;
args.CustomUpStreamHttpsProxyUsed = customUpStreamHttpsProxy; args.CustomUpStreamHttpsProxyUsed = customUpStreamHttpsProxy;
connection = await tcpConnectionFactory.CreateClient(BUFFER_SIZE, ConnectionTimeOutSeconds, connection = await tcpConnectionFactory.CreateClient(BufferSize, ConnectionTimeOutSeconds,
args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.WebSession.Request.HttpVersion, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.WebSession.Request.HttpVersion,
args.IsHttps, SupportedSslProtocols, args.IsHttps, SupportedSslProtocols,
ValidateServerCertificate, ValidateServerCertificate,
...@@ -378,7 +378,7 @@ namespace Titanium.Web.Proxy ...@@ -378,7 +378,7 @@ namespace Titanium.Web.Proxy
} }
var args = var args =
new SessionEventArgs(BUFFER_SIZE, HandleHttpSessionResponse) new SessionEventArgs(BufferSize, HandleHttpSessionResponse)
{ {
ProxyClient = {TcpClient = client}, ProxyClient = {TcpClient = client},
WebSession = {ConnectHeaders = connectHeaders} WebSession = {ConnectHeaders = connectHeaders}
...@@ -487,7 +487,7 @@ namespace Titanium.Web.Proxy ...@@ -487,7 +487,7 @@ namespace Titanium.Web.Proxy
//if upgrading to websocket then relay the requet without reading the contents //if upgrading to websocket then relay the requet without reading the contents
if (args.WebSession.Request.UpgradeToWebSocket) if (args.WebSession.Request.UpgradeToWebSocket)
{ {
await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port, await TcpHelper.SendRaw(BufferSize, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port,
httpCmd, httpVersion, args.WebSession.Request.RequestHeaders, args.IsHttps, httpCmd, httpVersion, args.WebSession.Request.RequestHeaders, args.IsHttps,
SupportedSslProtocols, ValidateServerCertificate, SupportedSslProtocols, ValidateServerCertificate,
SelectClientCertificate, SelectClientCertificate,
...@@ -581,14 +581,14 @@ namespace Titanium.Web.Proxy ...@@ -581,14 +581,14 @@ namespace Titanium.Web.Proxy
//send the request body bytes to server //send the request body bytes to server
if (args.WebSession.Request.ContentLength > 0) if (args.WebSession.Request.ContentLength > 0)
{ {
await args.ProxyClient.ClientStreamReader.CopyBytesToStream(BUFFER_SIZE, postStream, args.WebSession.Request.ContentLength); await args.ProxyClient.ClientStreamReader.CopyBytesToStream(BufferSize, postStream, args.WebSession.Request.ContentLength);
} }
//Need to revist, find any potential bugs //Need to revist, find any potential bugs
//send the request body bytes to server in chunks //send the request body bytes to server in chunks
else if (args.WebSession.Request.IsChunked) else if (args.WebSession.Request.IsChunked)
{ {
await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(BUFFER_SIZE, postStream); await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(BufferSize, postStream);
} }
} }
} }
......
...@@ -22,7 +22,7 @@ namespace Titanium.Web.Proxy ...@@ -22,7 +22,7 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
/// <param name="args"></param> /// <param name="args"></param>
/// <returns></returns> /// <returns></returns>
public async Task HandleHttpSessionResponse(SessionEventArgs args) private async Task HandleHttpSessionResponse(SessionEventArgs args)
{ {
//read response & headers from server //read response & headers from server
await args.WebSession.ReceiveResponse(); await args.WebSession.ReceiveResponse();
...@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy ...@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy
|| !args.WebSession.Response.ResponseKeepAlive) || !args.WebSession.Response.ResponseKeepAlive)
{ {
await args.WebSession.ServerConnection.StreamReader await args.WebSession.ServerConnection.StreamReader
.WriteResponseBody(BUFFER_SIZE, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, .WriteResponseBody(BufferSize, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked,
args.WebSession.Response.ContentLength); args.WebSession.Response.ContentLength);
} }
//write response if connection:keep-alive header exist and when version is http/1.0 //write response if connection:keep-alive header exist and when version is http/1.0
...@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy ...@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy
else if (args.WebSession.Response.ResponseKeepAlive && args.WebSession.Response.HttpVersion.Minor == 0) else if (args.WebSession.Response.ResponseKeepAlive && args.WebSession.Response.HttpVersion.Minor == 0)
{ {
await args.WebSession.ServerConnection.StreamReader await args.WebSession.ServerConnection.StreamReader
.WriteResponseBody(BUFFER_SIZE, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, .WriteResponseBody(BufferSize, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked,
args.WebSession.Response.ContentLength); args.WebSession.Response.ContentLength);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment