Commit 5051fd5e authored by justcoding121's avatar justcoding121

Expose client IP Address #77

parent f6aa5914
......@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Decompression
using (var decompressor = new DeflateStream(stream, CompressionMode.Decompress))
{
var buffer = new byte[Constants.BUFFER_SIZE];
var buffer = new byte[ProxyConstants.BUFFER_SIZE];
using (var output = new MemoryStream())
{
......
......@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Decompression
{
using (var decompressor = new GZipStream(new MemoryStream(compressedArray), CompressionMode.Decompress))
{
var buffer = new byte[Constants.BUFFER_SIZE];
var buffer = new byte[ProxyConstants.BUFFER_SIZE];
using (var output = new MemoryStream())
{
int read;
......
......@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Decompression
var memoryStream = new MemoryStream(compressedArray);
using (var decompressor = new ZlibStream(memoryStream, CompressionMode.Decompress))
{
var buffer = new byte[Constants.BUFFER_SIZE];
var buffer = new byte[ProxyConstants.BUFFER_SIZE];
using (var output = new MemoryStream())
{
......
......@@ -8,6 +8,8 @@ using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Extensions;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Network;
using System.Net;
using System.Net.Sockets;
namespace Titanium.Web.Proxy.EventArguments
{
......@@ -24,26 +26,34 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
internal SessionEventArgs()
{
Client = new ProxyClient();
ProxyClient = new ProxyClient();
WebSession = new HttpWebClient();
}
/// <summary>
/// Holds a reference to server connection
/// </summary>
internal ProxyClient Client { get; set; }
internal ProxyClient ProxyClient { get; set; }
/// <summary>
/// Does this session uses SSL
/// </summary>
public bool IsHttps => WebSession.Request.RequestUri.Scheme == Uri.UriSchemeHttps;
public IPAddress ClientIpAddress => ((IPEndPoint)Client.Client.RemoteEndPoint).Address;
/// <summary>
/// A web session corresponding to a single request/response sequence
/// within a proxy connection
/// </summary>
public HttpWebClient WebSession { get; set; }
/// <summary>
/// Reference to client connection
/// </summary>
internal TcpClient Client { get; set; }
/// <summary>
/// implement any cleanup here
......@@ -76,7 +86,7 @@ namespace Titanium.Web.Proxy.EventArguments
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if (WebSession.Request.IsChunked)
{
await this.Client.ClientStreamReader.CopyBytesToStreamChunked(requestBodyStream).ConfigureAwait(false);
await this.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(requestBodyStream).ConfigureAwait(false);
}
else
{
......@@ -84,7 +94,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (WebSession.Request.ContentLength > 0)
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await this.Client.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength).ConfigureAwait(false);
await this.ProxyClient.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength).ConfigureAwait(false);
}
else if(WebSession.Request.HttpVersion.Major == 1 && WebSession.Request.HttpVersion.Minor == 0)
......
......@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Extensions
return Encoding.GetEncoding("ISO-8859-1");
//extract the encoding by finding the charset
var contentTypes = request.ContentType.Split(Constants.SemiColonSplit);
var contentTypes = request.ContentType.Split(ProxyConstants.SemiColonSplit);
foreach (var contentType in contentTypes)
{
var encodingSplit = contentType.Split('=');
......
......@@ -15,7 +15,7 @@ namespace Titanium.Web.Proxy.Extensions
return Encoding.GetEncoding("ISO-8859-1");
//extract the encoding by finding the charset
var contentTypes = response.ContentType.Split(Constants.SemiColonSplit);
var contentTypes = response.ContentType.Split(ProxyConstants.SemiColonSplit);
foreach (var contentType in contentTypes)
{
var encodingSplit = contentType.Split('=');
......
......@@ -25,12 +25,12 @@ namespace Titanium.Web.Proxy.Extensions
var totalbytesRead = 0;
long bytesToRead;
if (totalBytesToRead < Constants.BUFFER_SIZE)
if (totalBytesToRead < ProxyConstants.BUFFER_SIZE)
{
bytesToRead = totalBytesToRead;
}
else
bytesToRead = Constants.BUFFER_SIZE;
bytesToRead = ProxyConstants.BUFFER_SIZE;
while (totalbytesRead < totalBytesToRead)
......
......@@ -78,12 +78,12 @@ namespace Titanium.Web.Proxy.Helpers
internal async Task<byte[]> ReadBytesAsync(long totalBytesToRead)
{
int bytesToRead = Constants.BUFFER_SIZE;
int bytesToRead = ProxyConstants.BUFFER_SIZE;
if (totalBytesToRead < Constants.BUFFER_SIZE)
if (totalBytesToRead < ProxyConstants.BUFFER_SIZE)
bytesToRead = (int)totalBytesToRead;
var buffer = new byte[Constants.BUFFER_SIZE];
var buffer = new byte[ProxyConstants.BUFFER_SIZE];
var bytesRead = 0;
var totalBytesRead = 0;
......@@ -100,7 +100,7 @@ namespace Titanium.Web.Proxy.Helpers
bytesRead = 0;
var remainingBytes = (totalBytesToRead - totalBytesRead);
bytesToRead = remainingBytes > (long)Constants.BUFFER_SIZE ? Constants.BUFFER_SIZE : (int)remainingBytes;
bytesToRead = remainingBytes > (long)ProxyConstants.BUFFER_SIZE ? ProxyConstants.BUFFER_SIZE : (int)remainingBytes;
}
return outStream.ToArray();
......
......@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.Helpers
try
{
sslStream = new SslStream(tunnelStream);
await sslStream.AuthenticateAsClientAsync(hostName, null, Constants.SupportedProtocols, false);
await sslStream.AuthenticateAsClientAsync(hostName, null, ProxyConstants.SupportedSslProtocols, false);
tunnelStream = sslStream;
}
catch
......
......@@ -64,7 +64,7 @@ namespace Titanium.Web.Proxy.Http
if (ProxyServer.Enable100ContinueBehaviour)
if (this.Request.ExpectContinue)
{
var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(Constants.SpaceSplit, 3);
var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(ProxyConstants.SpaceSplit, 3);
var responseStatusCode = httpResult[1].Trim();
var responseStatusDescription = httpResult[2].Trim();
......@@ -89,7 +89,7 @@ namespace Titanium.Web.Proxy.Http
//return if this is already read
if (this.Response.ResponseStatusCode != null) return;
var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(Constants.SpaceSplit, 3);
var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(ProxyConstants.SpaceSplit, 3);
if (string.IsNullOrEmpty(httpResult[0]))
{
......@@ -131,7 +131,7 @@ namespace Titanium.Web.Proxy.Http
for (int index = 0; index < responseLines.Count; ++index)
{
string[] strArray = responseLines[index].Split(Constants.ColonSplit, 2);
string[] strArray = responseLines[index].Split(ProxyConstants.ColonSplit, 2);
this.Response.ResponseHeaders.Add(new HttpHeader(strArray[0], strArray[1]));
}
}
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Security;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments;
namespace Titanium.Web.Proxy.Network
{
/// <summary>
/// Used to pass in Session object for ServerCertificateValidation Callback
/// </summary>
internal class CustomSslStream : SslStream
{
internal CustomSslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback clientCertificateSelectionCallback)
:base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, clientCertificateSelectionCallback)
{
}
}
}
......@@ -102,14 +102,14 @@ namespace Titanium.Web.Proxy.Network
if (isHttps)
{
CustomSslStream sslStream = null;
SslStream sslStream = null;
if (ProxyServer.UpStreamHttpsProxy != null)
{
client = new TcpClient(ProxyServer.UpStreamHttpsProxy.HostName, ProxyServer.UpStreamHttpsProxy.Port);
stream = (Stream)client.GetStream();
using (var writer = new StreamWriter(stream, Encoding.ASCII, Constants.BUFFER_SIZE, true))
using (var writer = new StreamWriter(stream, Encoding.ASCII, ProxyConstants.BUFFER_SIZE, true))
{
await writer.WriteLineAsync(string.Format("CONNECT {0}:{1} {2}", hostname, port, version)).ConfigureAwait(false);
await writer.WriteLineAsync(string.Format("Host: {0}:{1}", hostname, port)).ConfigureAwait(false);
......@@ -137,9 +137,9 @@ namespace Titanium.Web.Proxy.Network
try
{
sslStream = new CustomSslStream(stream, true, new RemoteCertificateValidationCallback(ProxyServer.ValidateServerCertificate),
sslStream = new SslStream(stream, true, new RemoteCertificateValidationCallback(ProxyServer.ValidateServerCertificate),
new LocalCertificateSelectionCallback(ProxyServer.SelectClientCertificate));
await sslStream.AuthenticateAsClientAsync(hostname, null, Constants.SupportedProtocols, false).ConfigureAwait(false);
await sslStream.AuthenticateAsClientAsync(hostname, null, ProxyConstants.SupportedSslProtocols, false).ConfigureAwait(false);
stream = (Stream)sslStream;
}
catch
......
......@@ -41,7 +41,7 @@ namespace Titanium.Web.Proxy
}
//break up the line into three components (method, remote URL & Http Version)
var httpCmdSplit = httpCmd.Split(Constants.SpaceSplit, 3);
var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3);
var httpVerb = httpCmdSplit[0];
......@@ -86,7 +86,7 @@ namespace Titanium.Web.Proxy
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host, false);
//Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false,
Constants.SupportedProtocols, false).ConfigureAwait(false);
ProxyConstants.SupportedSslProtocols, false).ConfigureAwait(false);
//HTTPS server created - we can now decrypt the client's traffic
clientStream = sslStream;
......@@ -198,12 +198,12 @@ namespace Titanium.Web.Proxy
}
var args = new SessionEventArgs();
args.Client.TcpClient = client;
args.Client = client;
try
{
//break up the line into three components (method, remote URL & Http Version)
var httpCmdSplit = httpCmd.Split(Constants.SpaceSplit, 3);
var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3);
var httpMethod = httpCmdSplit[0];
......@@ -223,7 +223,7 @@ namespace Titanium.Web.Proxy
string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync().ConfigureAwait(false)))
{
var header = tmpLine.Split(Constants.ColonSplit, 2);
var header = tmpLine.Split(ProxyConstants.ColonSplit, 2);
args.WebSession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
}
......@@ -240,9 +240,9 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.Method = httpMethod;
args.WebSession.Request.HttpVersion = version;
args.Client.ClientStream = clientStream;
args.Client.ClientStreamReader = clientStreamReader;
args.Client.ClientStreamWriter = clientStreamWriter;
args.ProxyClient.ClientStream = clientStream;
args.ProxyClient.ClientStreamReader = clientStreamReader;
args.ProxyClient.ClientStreamWriter = clientStreamWriter;
PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession);
......@@ -292,14 +292,14 @@ namespace Titanium.Web.Proxy
if (args.WebSession.Request.Is100Continue)
{
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "100",
"Continue", args.Client.ClientStreamWriter);
await args.Client.ClientStreamWriter.WriteLineAsync();
"Continue", args.ProxyClient.ClientStreamWriter);
await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
}
else if (args.WebSession.Request.ExpectationFailed)
{
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
"Expectation Failed", args.Client.ClientStreamWriter);
await args.Client.ClientStreamWriter.WriteLineAsync();
"Expectation Failed", args.ProxyClient.ClientStreamWriter);
await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
}
if (!args.WebSession.Request.ExpectContinue)
......@@ -415,7 +415,7 @@ namespace Titanium.Web.Proxy
{
try
{
await args.Client.ClientStreamReader.CopyBytesToStream(postStream, args.WebSession.Request.ContentLength).ConfigureAwait(false);
await args.ProxyClient.ClientStreamReader.CopyBytesToStream(postStream, args.WebSession.Request.ContentLength).ConfigureAwait(false);
}
catch
{
......@@ -427,7 +427,7 @@ namespace Titanium.Web.Proxy
{
try
{
await args.Client.ClientStreamReader.CopyBytesToStreamChunked(postStream).ConfigureAwait(false);
await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(postStream).ConfigureAwait(false);
}
catch
{
......@@ -496,7 +496,7 @@ namespace Titanium.Web.Proxy
string[] acceptableIssuers)
{
X509Certificate clientCertificate = null;
var customSslStream = sender as CustomSslStream;
var customSslStream = sender as SslStream;
if (acceptableIssuers != null &&
acceptableIssuers.Length > 0 &&
......
......@@ -45,18 +45,18 @@ namespace Titanium.Web.Proxy
if (args.WebSession.Response.Is100Continue)
{
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "100",
"Continue", args.Client.ClientStreamWriter);
await args.Client.ClientStreamWriter.WriteLineAsync();
"Continue", args.ProxyClient.ClientStreamWriter);
await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
}
else if (args.WebSession.Response.ExpectationFailed)
{
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
"Expectation Failed", args.Client.ClientStreamWriter);
await args.Client.ClientStreamWriter.WriteLineAsync();
"Expectation Failed", args.ProxyClient.ClientStreamWriter);
await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
}
await WriteResponseStatus(args.WebSession.Response.HttpVersion, args.WebSession.Response.ResponseStatusCode,
args.WebSession.Response.ResponseStatusDescription, args.Client.ClientStreamWriter);
args.WebSession.Response.ResponseStatusDescription, args.ProxyClient.ClientStreamWriter);
if (args.WebSession.Response.ResponseBodyRead)
{
......@@ -73,24 +73,24 @@ namespace Titanium.Web.Proxy
args.WebSession.Response.ContentLength = -1;
}
await WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders).ConfigureAwait(false);
await WriteResponseBody(args.Client.ClientStream, args.WebSession.Response.ResponseBody, isChunked).ConfigureAwait(false);
await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, args.WebSession.Response.ResponseHeaders).ConfigureAwait(false);
await WriteResponseBody(args.ProxyClient.ClientStream, args.WebSession.Response.ResponseBody, isChunked).ConfigureAwait(false);
}
else
{
await WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders);
await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, args.WebSession.Response.ResponseHeaders);
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 ||
(args.WebSession.Response.HttpVersion.Major == 1 && args.WebSession.Response.HttpVersion.Minor == 0))
await WriteResponseBody(args.WebSession.ServerConnection.StreamReader, args.Client.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength).ConfigureAwait(false);
await WriteResponseBody(args.WebSession.ServerConnection.StreamReader, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength).ConfigureAwait(false);
}
await args.Client.ClientStream.FlushAsync();
await args.ProxyClient.ClientStream.FlushAsync();
}
catch
{
Dispose(args.Client.TcpClient, args.Client.ClientStream, args.Client.ClientStreamReader, args.Client.ClientStreamWriter, args);
Dispose(args.ProxyClient.TcpClient, args.ProxyClient.ClientStream, args.ProxyClient.ClientStreamReader, args.ProxyClient.ClientStreamWriter, args);
}
finally
{
......@@ -164,12 +164,12 @@ namespace Titanium.Web.Proxy
if (ContentLength == -1)
ContentLength = long.MaxValue;
int bytesToRead = Constants.BUFFER_SIZE;
int bytesToRead = ProxyConstants.BUFFER_SIZE;
if (ContentLength < Constants.BUFFER_SIZE)
if (ContentLength < ProxyConstants.BUFFER_SIZE)
bytesToRead = (int)ContentLength;
var buffer = new byte[Constants.BUFFER_SIZE];
var buffer = new byte[ProxyConstants.BUFFER_SIZE];
var bytesRead = 0;
var totalBytesRead = 0;
......@@ -184,7 +184,7 @@ namespace Titanium.Web.Proxy
bytesRead = 0;
var remainingBytes = (ContentLength - totalBytesRead);
bytesToRead = remainingBytes > (long)Constants.BUFFER_SIZE ? Constants.BUFFER_SIZE : (int)remainingBytes;
bytesToRead = remainingBytes > (long)ProxyConstants.BUFFER_SIZE ? ProxyConstants.BUFFER_SIZE : (int)remainingBytes;
}
}
else
......@@ -206,17 +206,17 @@ namespace Titanium.Web.Proxy
var chunkHeadBytes = Encoding.ASCII.GetBytes(chunkSize.ToString("x2"));
await outStream.WriteAsync(chunkHeadBytes, 0, chunkHeadBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(buffer, 0, chunkSize).ConfigureAwait(false);
await outStream.WriteAsync(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length).ConfigureAwait(false);
await inStreamReader.ReadLineAsync().ConfigureAwait(false);
}
else
{
await inStreamReader.ReadLineAsync().ConfigureAwait(false);
await outStream.WriteAsync(Constants.ChunkEnd, 0, Constants.ChunkEnd.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.ChunkEnd, 0, ProxyConstants.ChunkEnd.Length).ConfigureAwait(false);
break;
}
}
......@@ -227,11 +227,11 @@ namespace Titanium.Web.Proxy
var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2"));
await outStream.WriteAsync(chunkHead, 0, chunkHead.Length).ConfigureAwait(false);
await outStream.WriteAsync(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(data, 0, data.Length).ConfigureAwait(false);
await outStream.WriteAsync(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(Constants.ChunkEnd, 0, Constants.ChunkEnd.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.ChunkEnd, 0, ProxyConstants.ChunkEnd.Length).ConfigureAwait(false);
}
......
using System;
using System.Security.Authentication;
using System.Text;
using System.Text.RegularExpressions;
namespace Titanium.Web.Proxy.Shared
{
/// <summary>
/// Literals shared by Proxy Server
/// </summary>
internal class Constants
{
internal static readonly int BUFFER_SIZE = 8192;
internal class ProxyConstants
{
internal static readonly char[] SpaceSplit = { ' ' };
internal static readonly char[] ColonSplit = { ':' };
internal static readonly char[] SemiColonSplit = { ';' };
......@@ -21,6 +18,8 @@ namespace Titanium.Web.Proxy.Shared
internal static readonly byte[] ChunkEnd =
Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine);
internal static SslProtocols SupportedProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3;
public static SslProtocols SupportedSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3;
public static readonly int BUFFER_SIZE = 8192;
}
}
......@@ -74,7 +74,6 @@
<Compile Include="Http\Request.cs" />
<Compile Include="Http\Response.cs" />
<Compile Include="Models\ExternalProxy.cs" />
<Compile Include="Network\CustomSslStream.cs" />
<Compile Include="Network\TcpConnectionManager.cs" />
<Compile Include="Models\HttpHeader.cs" />
<Compile Include="Http\HttpWebClient.cs" />
......@@ -88,7 +87,7 @@
<Compile Include="Extensions\StreamExtensions.cs" />
<Compile Include="Http\Responses\OkResponse.cs" />
<Compile Include="Http\Responses\RedirectResponse.cs" />
<Compile Include="Shared\Constants.cs" />
<Compile Include="Shared\ProxyConstants.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
......
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