Unverified Commit abe87ce7 authored by justcoding121's avatar justcoding121 Committed by GitHub

Merge pull request #406 from justcoding121/develop

Beta 3.0.393+
parents 736b66b7 f90e356a
...@@ -78,7 +78,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -78,7 +78,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//proxyServer.EnableWinAuth = true; //proxyServer.EnableWinAuth = true;
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000)
{ {
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown //You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
......
...@@ -17,6 +17,11 @@ namespace Titanium.Web.Proxy.Models ...@@ -17,6 +17,11 @@ namespace Titanium.Web.Proxy.Models
internal bool IsSystemHttpsProxy { get; set; } internal bool IsSystemHttpsProxy { get; set; }
/// <summary>
/// Enable SSL?
/// </summary>
public bool DecryptSsl { get; }
/// <summary> /// <summary>
/// Generic certificate to use for SSL decryption. /// Generic certificate to use for SSL decryption.
/// </summary> /// </summary>
...@@ -40,9 +45,10 @@ namespace Titanium.Web.Proxy.Models ...@@ -40,9 +45,10 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
/// <param name="ipAddress"></param> /// <param name="ipAddress"></param>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="enableSsl"></param> /// <param name="decryptSsl"></param>
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl) public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port)
{ {
this.DecryptSsl = decryptSsl;
} }
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc) internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
......
...@@ -17,11 +17,10 @@ namespace Titanium.Web.Proxy.Models ...@@ -17,11 +17,10 @@ namespace Titanium.Web.Proxy.Models
/// <param name="ipAddress"></param> /// <param name="ipAddress"></param>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="enableSsl"></param> /// <param name="enableSsl"></param>
protected ProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) protected ProxyEndPoint(IPAddress ipAddress, int port)
{ {
IpAddress = ipAddress; IpAddress = ipAddress;
Port = port; Port = port;
EnableSsl = enableSsl;
} }
/// <summary> /// <summary>
...@@ -39,10 +38,6 @@ namespace Titanium.Web.Proxy.Models ...@@ -39,10 +38,6 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public int Port { get; internal set; } public int Port { get; internal set; }
/// <summary>
/// Enable SSL?
/// </summary>
public bool EnableSsl { get; }
/// <summary> /// <summary>
/// Is IPv6 enabled? /// Is IPv6 enabled?
......
...@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Models
/// <param name="ipAddress"></param> /// <param name="ipAddress"></param>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="enableSsl"></param> /// <param name="enableSsl"></param>
public TransparentProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl) public TransparentProxyEndPoint(IPAddress ipAddress, int port) : base(ipAddress, port)
{ {
GenericCertificateName = "localhost"; GenericCertificateName = "localhost";
} }
......
...@@ -319,10 +319,6 @@ namespace Titanium.Web.Proxy ...@@ -319,10 +319,6 @@ namespace Titanium.Web.Proxy
if (isHttps) if (isHttps)
{ {
if (!endPoint.EnableSsl)
{
throw new Exception("Endpoint do not support Https connections");
}
CertificateManager.EnsureRootCertificate(); CertificateManager.EnsureRootCertificate();
......
...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy ...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy
await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc); await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc);
//filter out excluded host names //filter out excluded host names
bool excluded = connectArgs.Excluded; bool excluded = !endPoint.DecryptSsl || connectArgs.Excluded;
if (await CheckAuthorization(connectArgs) == false) if (await CheckAuthorization(connectArgs) == false)
{ {
...@@ -92,17 +92,15 @@ namespace Titanium.Web.Proxy ...@@ -92,17 +92,15 @@ namespace Titanium.Web.Proxy
//write back successfull CONNECT response //write back successfull CONNECT response
var response = ConnectResponse.CreateSuccessfullConnectResponse(version); var response = ConnectResponse.CreateSuccessfullConnectResponse(version);
// Set ContentLength explicitly to properly handle HTTP 1.0
response.ContentLength = 0;
response.Headers.FixProxyHeaders(); response.Headers.FixProxyHeaders();
connectArgs.WebSession.Response = response; connectArgs.WebSession.Response = response;
await clientStreamWriter.WriteResponseAsync(response); await clientStreamWriter.WriteResponseAsync(response);
ClientHelloInfo clientHelloInfo = null; var clientHelloInfo = await SslTools.PeekClientHello(clientStream);
if (endPoint.EnableSsl)
{
clientHelloInfo = await SslTools.PeekClientHello(clientStream);
}
bool isClientHello = clientHelloInfo != null; bool isClientHello = clientHelloInfo != null;
if (isClientHello) if (isClientHello)
{ {
...@@ -232,48 +230,46 @@ namespace Titanium.Web.Proxy ...@@ -232,48 +230,46 @@ namespace Titanium.Web.Proxy
try try
{ {
if (endPoint.EnableSsl) var clientHelloInfo = await SslTools.PeekClientHello(clientStream);
{
var clientHelloInfo = await SslTools.PeekClientHello(clientStream);
if (clientHelloInfo != null) var isHttps = clientHelloInfo != null;
{ string httpsHostName = null;
SslStream sslStream = null;
string sniHostName = null;
try if (isHttps)
{ {
sslStream = new SslStream(clientStream); SslStream sslStream = null;
try
{
sslStream = new SslStream(clientStream);
sniHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName; httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;
string certName = HttpHelper.GetWildCardDomainName(sniHostName); string certName = HttpHelper.GetWildCardDomainName(httpsHostName);
var certificate = await CertificateManager.CreateCertificateAsync(certName); var certificate = await CertificateManager.CreateCertificateAsync(certName);
//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, SslProtocols.Tls, false); await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
//HTTPS server created - we can now decrypt the client's traffic //HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize); clientStream = new CustomBufferedStream(sslStream, BufferSize);
clientStreamReader.Dispose(); clientStreamReader.Dispose();
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize); clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
} }
catch (Exception e) catch (Exception e)
{ {
ExceptionFunc(new Exception($"Could'nt authenticate client '{sniHostName}' with fake certificate.", e)); ExceptionFunc(new Exception($"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e));
sslStream?.Dispose(); sslStream?.Dispose();
return; return;
}
} }
//HTTPS server created - we can now decrypt the client's traffic
} }
//HTTPS server created - we can now decrypt the client's traffic
//Now create the request //Now create the request
await HandleHttpSessionRequest(tcpClient, clientStream, clientStreamReader, clientStreamWriter, await HandleHttpSessionRequest(tcpClient, clientStream, clientStreamReader, clientStreamWriter,
endPoint.EnableSsl ? endPoint.GenericCertificateName : null, endPoint, null, true); isHttps ? httpsHostName : null, endPoint, null, true);
} }
finally finally
{ {
...@@ -621,7 +617,7 @@ namespace Titanium.Web.Proxy ...@@ -621,7 +617,7 @@ namespace Titanium.Web.Proxy
/// <param name="requestHeaders"></param> /// <param name="requestHeaders"></param>
private void PrepareRequestHeaders(HeaderCollection requestHeaders) private void PrepareRequestHeaders(HeaderCollection requestHeaders)
{ {
if(requestHeaders.HeaderExists(KnownHeaders.AcceptEncoding)) if (requestHeaders.HeaderExists(KnownHeaders.AcceptEncoding))
{ {
requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding, "gzip,deflate"); requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding, "gzip,deflate");
} }
......
...@@ -14,21 +14,21 @@ namespace Titanium.Web.Proxy ...@@ -14,21 +14,21 @@ namespace Titanium.Web.Proxy
public partial class ProxyServer public partial class ProxyServer
{ {
//possible header names //possible header names
private static readonly List<string> authHeaderNames = new List<string> private static readonly HashSet<string> authHeaderNames = new HashSet<string>
{ {
"WWW-Authenticate", "WWW-Authenticate".ToLower(),
//IIS 6.0 messed up names below //IIS 6.0 messed up names below
"WWWAuthenticate", "WWWAuthenticate".ToLower(),
"NTLMAuthorization", "NTLMAuthorization".ToLower(),
"NegotiateAuthorization", "NegotiateAuthorization".ToLower(),
"KerberosAuthorization" "KerberosAuthorization".ToLower()
}; };
private static readonly List<string> authSchemes = new List<string> private static readonly HashSet<string> authSchemes = new HashSet<string>
{ {
"NTLM", "NTLM".ToLower(),
"Negotiate", "Negotiate".ToLower(),
"Kerberos" "Kerberos".ToLower()
}; };
/// <summary> /// <summary>
...@@ -49,7 +49,7 @@ namespace Titanium.Web.Proxy ...@@ -49,7 +49,7 @@ namespace Titanium.Web.Proxy
//check in non-unique headers first //check in non-unique headers first
var header = response.Headers.NonUniqueHeaders.FirstOrDefault( var header = response.Headers.NonUniqueHeaders.FirstOrDefault(
x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase))); x => authHeaderNames.Contains(x.Key.ToLower()));
if (!header.Equals(new KeyValuePair<string, List<HttpHeader>>())) if (!header.Equals(new KeyValuePair<string, List<HttpHeader>>()))
{ {
...@@ -65,8 +65,10 @@ namespace Titanium.Web.Proxy ...@@ -65,8 +65,10 @@ namespace Titanium.Web.Proxy
//check in unique headers //check in unique headers
if (authHeader == null) if (authHeader == null)
{ {
headerName = null;
//check in non-unique headers first //check in non-unique headers first
var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase))); var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Contains(x.Key.ToLower()));
if (!uHeader.Equals(new KeyValuePair<string, HttpHeader>())) if (!uHeader.Equals(new KeyValuePair<string, HttpHeader>()))
{ {
...@@ -84,7 +86,7 @@ namespace Titanium.Web.Proxy ...@@ -84,7 +86,7 @@ namespace Titanium.Web.Proxy
if (authHeader != null) if (authHeader != null)
{ {
string scheme = authSchemes.FirstOrDefault(x => authHeader.Value.Equals(x, StringComparison.OrdinalIgnoreCase)); string scheme = authSchemes.Contains(authHeader.Value.ToLower()) ? authHeader.Value.ToLower() : null;
var expectedAuthState = scheme == null ? State.WinAuthState.INITIAL_TOKEN : State.WinAuthState.UNAUTHORIZED; var expectedAuthState = scheme == null ? State.WinAuthState.INITIAL_TOKEN : State.WinAuthState.UNAUTHORIZED;
...@@ -109,7 +111,7 @@ namespace Titanium.Web.Proxy ...@@ -109,7 +111,7 @@ namespace Titanium.Web.Proxy
//replace existing authorization header if any //replace existing authorization header if any
request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth); request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth);
//don't need to send body for Authorization request //don't need to send body for Authorization request
if (request.HasBody) if (request.HasBody)
{ {
...@@ -131,7 +133,7 @@ namespace Titanium.Web.Proxy ...@@ -131,7 +133,7 @@ namespace Titanium.Web.Proxy
request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth); request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth);
//send body for final auth request //send body for final auth request
if (request.HasBody) if (request.OriginalHasBody)
{ {
request.ContentLength = request.Body.Length; request.ContentLength = request.Body.Length;
} }
......
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