Unverified Commit 08167b4d authored by Jehonathan Thomas's avatar Jehonathan Thomas Committed by GitHub

Merge pull request #496 from justcoding121/master

Dns resolve from code
parents c3fc1d35 fb33defa
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
"**/*.Basic.csproj/": true, "**/*.Basic.csproj/": true,
"**/*.Docs.csproj/": true, "**/*.Docs.csproj/": true,
"**/*.Proxy.csproj/": true, "**/*.Proxy.csproj/": true,
"**/*.Proxy.csproj" : true "**/*.Mono.csproj" : true
}, },
"search.exclude": { "search.exclude": {
"**/.build": true, "**/.build": true,
...@@ -32,6 +32,6 @@ ...@@ -32,6 +32,6 @@
"**/*.Basic.csproj/": true, "**/*.Basic.csproj/": true,
"**/*.Docs.csproj/": true, "**/*.Docs.csproj/": true,
"**/*.Proxy.csproj/": true, "**/*.Proxy.csproj/": true,
"**/*.Proxy.csproj" : true "**/*.Mono.csproj" : true
} }
} }
\ No newline at end of file
{ {
"fileOptions": { "fileOptions": {
"excludeSearchPatterns": [ "excludeSearchPatterns": [
"**/*.sln",
"**/*.Docs.csproj", "**/*.Docs.csproj",
"**/tests/", "**/tests/",
"**/Titanium.Web.Proxy.Examples.Wpf/", "**/Titanium.Web.Proxy.Examples.Wpf/",
......
...@@ -22,6 +22,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -22,6 +22,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary> /// </summary>
internal class TcpConnectionFactory : IDisposable internal class TcpConnectionFactory : IDisposable
{ {
//Tcp server connection pool cache //Tcp server connection pool cache
private readonly ConcurrentDictionary<string, ConcurrentQueue<TcpServerConnection>> cache private readonly ConcurrentDictionary<string, ConcurrentQueue<TcpServerConnection>> cache
= new ConcurrentDictionary<string, ConcurrentQueue<TcpServerConnection>>(); = new ConcurrentDictionary<string, ConcurrentQueue<TcpServerConnection>>();
...@@ -74,10 +75,10 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -74,10 +75,10 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// Gets the connection cache key. /// Gets the connection cache key.
/// </summary> /// </summary>
/// <param name="args">The session event arguments.</param> /// <param name="session">The session event arguments.</param>
/// <param name="applicationProtocol"></param> /// <param name="applicationProtocol"></param>
/// <returns></returns> /// <returns></returns>
internal async Task<string> GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase args, internal async Task<string> GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase session,
SslApplicationProtocol applicationProtocol) SslApplicationProtocol applicationProtocol)
{ {
List<SslApplicationProtocol> applicationProtocols = null; List<SslApplicationProtocol> applicationProtocols = null;
...@@ -88,19 +89,19 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -88,19 +89,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
ExternalProxy customUpStreamProxy = null; ExternalProxy customUpStreamProxy = null;
bool isHttps = args.IsHttps; bool isHttps = session.IsHttps;
if (server.GetCustomUpStreamProxyFunc != null) if (server.GetCustomUpStreamProxyFunc != null)
{ {
customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args); customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(session);
} }
args.CustomUpStreamProxyUsed = customUpStreamProxy; session.CustomUpStreamProxyUsed = customUpStreamProxy;
return GetConnectionCacheKey( return GetConnectionCacheKey(
args.WebSession.Request.RequestUri.Host, session.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port, session.WebSession.Request.RequestUri.Port,
isHttps, applicationProtocols, isHttps, applicationProtocols,
server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint, server, session.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy)); customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy));
} }
...@@ -108,12 +109,12 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -108,12 +109,12 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// Create a server connection. /// Create a server connection.
/// </summary> /// </summary>
/// <param name="args">The session event arguments.</param> /// <param name="session">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param> /// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocol"></param> /// <param name="applicationProtocol"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param> /// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns> /// <returns></returns>
internal Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect, internal Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect,
SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken) SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken)
{ {
List<SslApplicationProtocol> applicationProtocols = null; List<SslApplicationProtocol> applicationProtocols = null;
...@@ -122,36 +123,36 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -122,36 +123,36 @@ namespace Titanium.Web.Proxy.Network.Tcp
applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol }; applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol };
} }
return GetServerConnection(server, args, isConnect, applicationProtocols, noCache, cancellationToken); return GetServerConnection(server, session, isConnect, applicationProtocols, noCache, cancellationToken);
} }
/// <summary> /// <summary>
/// Create a server connection. /// Create a server connection.
/// </summary> /// </summary>
/// <param name="args">The session event arguments.</param> /// <param name="session">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param> /// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocols"></param> /// <param name="applicationProtocols"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param> /// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns> /// <returns></returns>
internal async Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect, internal async Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect,
List<SslApplicationProtocol> applicationProtocols, bool noCache, CancellationToken cancellationToken) List<SslApplicationProtocol> applicationProtocols, bool noCache, CancellationToken cancellationToken)
{ {
ExternalProxy customUpStreamProxy = null; ExternalProxy customUpStreamProxy = null;
bool isHttps = args.IsHttps; bool isHttps = session.IsHttps;
if (server.GetCustomUpStreamProxyFunc != null) if (server.GetCustomUpStreamProxyFunc != null)
{ {
customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args); customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(session);
} }
args.CustomUpStreamProxyUsed = customUpStreamProxy; session.CustomUpStreamProxyUsed = customUpStreamProxy;
return await GetServerConnection( return await GetServerConnection(
args.WebSession.Request.RequestUri.Host, session.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port, session.WebSession.Request.RequestUri.Port,
args.WebSession.Request.HttpVersion, session.WebSession.Request.HttpVersion,
isHttps, applicationProtocols, isConnect, isHttps, applicationProtocols, isConnect,
server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint, server, session, session.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy), customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy),
noCache, cancellationToken); noCache, cancellationToken);
} }
...@@ -172,7 +173,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -172,7 +173,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <returns></returns> /// <returns></returns>
internal async Task<TcpServerConnection> GetServerConnection(string remoteHostName, int remotePort, internal async Task<TcpServerConnection> GetServerConnection(string remoteHostName, int remotePort,
Version httpVersion, bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isConnect, Version httpVersion, bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isConnect,
ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, ProxyServer proxyServer, SessionEventArgsBase session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
bool noCache, CancellationToken cancellationToken) bool noCache, CancellationToken cancellationToken)
{ {
var cacheKey = GetConnectionCacheKey(remoteHostName, remotePort, var cacheKey = GetConnectionCacheKey(remoteHostName, remotePort,
...@@ -203,7 +204,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -203,7 +204,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
var connection = await createServerConnection(remoteHostName, remotePort, httpVersion, isHttps, var connection = await createServerConnection(remoteHostName, remotePort, httpVersion, isHttps,
applicationProtocols, isConnect, proxyServer, upStreamEndPoint, externalProxy, cancellationToken); applicationProtocols, isConnect, proxyServer, session, upStreamEndPoint, externalProxy, cancellationToken);
connection.CacheKey = cacheKey; connection.CacheKey = cacheKey;
...@@ -220,13 +221,14 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -220,13 +221,14 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="applicationProtocols">The list of HTTPS application level protocol to negotiate if needed.</param> /// <param name="applicationProtocols">The list of HTTPS application level protocol to negotiate if needed.</param>
/// <param name="isConnect">Is this a CONNECT request.</param> /// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="proxyServer">The current ProxyServer instance.</param> /// <param name="proxyServer">The current ProxyServer instance.</param>
/// <param name="session">The http session.</param>
/// <param name="upStreamEndPoint">The local upstream endpoint to make request via.</param> /// <param name="upStreamEndPoint">The local upstream endpoint to make request via.</param>
/// <param name="externalProxy">The external proxy to make request via.</param> /// <param name="externalProxy">The external proxy to make request via.</param>
/// <param name="cancellationToken">The cancellation token for this async task.</param> /// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns> /// <returns></returns>
private async Task<TcpServerConnection> createServerConnection(string remoteHostName, int remotePort, private async Task<TcpServerConnection> createServerConnection(string remoteHostName, int remotePort,
Version httpVersion, bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isConnect, Version httpVersion, bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isConnect,
ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, ProxyServer proxyServer, SessionEventArgsBase session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
//deny connection to proxy end points to avoid infinite connection loop. //deny connection to proxy end points to avoid infinite connection loop.
...@@ -282,16 +284,37 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -282,16 +284,37 @@ namespace Titanium.Web.Proxy.Network.Tcp
tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
} }
// If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections var hostname = useUpstreamProxy ? externalProxy.HostName : remoteHostName;
if (useUpstreamProxy) var port = useUpstreamProxy ? externalProxy.Port : remotePort;
var ipHostEntry = await Dns.GetHostEntryAsync(hostname);
if (ipHostEntry == null || ipHostEntry.AddressList.Length == 0)
{ {
await tcpClient.ConnectAsync(externalProxy.HostName, externalProxy.Port); throw new Exception($"Could not resolve the hostname {hostname}");
} }
else
session.TimeLine["Dns Resolved"] = DateTime.Now;
var ipAddresses = ipHostEntry.AddressList;
for (int i = 0; i < ipAddresses.Length; i++)
{ {
await tcpClient.ConnectAsync(remoteHostName, remotePort); try
{
await tcpClient.ConnectAsync(ipAddresses[i], port);
break;
}
catch (Exception e)
{
if (i == ipAddresses.Length - 1)
{
throw new Exception($"Could not establish connection to {hostname}", e);
}
}
} }
session.TimeLine["Connection Established"] = DateTime.Now;
await proxyServer.InvokeConnectionCreateEvent(tcpClient, false); await proxyServer.InvokeConnectionCreateEvent(tcpClient, false);
stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferPool, proxyServer.BufferSize); stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferPool, proxyServer.BufferSize);
...@@ -347,6 +370,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -347,6 +370,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
#if NETCOREAPP2_1 #if NETCOREAPP2_1
negotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol; negotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif #endif
session.TimeLine["HTTPS Established"] = DateTime.Now;
} }
} }
catch (Exception) catch (Exception)
......
...@@ -94,8 +94,6 @@ namespace Titanium.Web.Proxy ...@@ -94,8 +94,6 @@ namespace Titanium.Web.Proxy
bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false,
bool trustRootCertificateAsAdmin = false) bool trustRootCertificateAsAdmin = false)
{ {
// default values
ConnectionTimeOutSeconds = 60;
if (BufferPool == null) if (BufferPool == null)
{ {
...@@ -186,7 +184,7 @@ namespace Titanium.Web.Proxy ...@@ -186,7 +184,7 @@ namespace Titanium.Web.Proxy
/// This will also determine the pool eviction time when connection pool is enabled. /// This will also determine the pool eviction time when connection pool is enabled.
/// Default value is 60 seconds. /// Default value is 60 seconds.
/// </summary> /// </summary>
public int ConnectionTimeOutSeconds { get; set; } public int ConnectionTimeOutSeconds { get; set; } = 60;
/// <summary> /// <summary>
/// Maximum number of concurrent connections per remote host in cache. /// Maximum number of concurrent connections per remote host in cache.
......
...@@ -207,7 +207,7 @@ namespace Titanium.Web.Proxy ...@@ -207,7 +207,7 @@ namespace Titanium.Web.Proxy
//for connection pool, retry fails until cache is exhausted. //for connection pool, retry fails until cache is exhausted.
var result = await retryPolicy<ServerConnectionException>().ExecuteAsync(async (serverConnection) => var result = await retryPolicy<ServerConnectionException>().ExecuteAsync(async (serverConnection) =>
{ {
args.TimeLine["Server Connection Created"] = DateTime.Now; args.TimeLine["Connection Ready"] = DateTime.Now;
// if upgrading to websocket then relay the request without reading the contents // if upgrading to websocket then relay the request without reading the contents
if (request.UpgradeToWebSocket) if (request.UpgradeToWebSocket)
...@@ -369,6 +369,8 @@ namespace Titanium.Web.Proxy ...@@ -369,6 +369,8 @@ namespace Titanium.Web.Proxy
} }
} }
args.TimeLine["Request Sent"] = DateTime.Now;
// If not expectation failed response was returned by server then parse response // If not expectation failed response was returned by server then parse response
if (!request.ExpectationFailed) if (!request.ExpectationFailed)
{ {
......
...@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy ...@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy
//it could cause floating server connections when client exits //it could cause floating server connections when client exits
prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port, prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
httpVersion: null, isHttps: true, applicationProtocols: null, isConnect: false, httpVersion: null, isHttps: true, applicationProtocols: null, isConnect: false,
proxyServer: this, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy, proxyServer: this, session: null, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy,
noCache: false, cancellationToken: CancellationToken.None); noCache: false, cancellationToken: CancellationToken.None);
} }
...@@ -102,7 +102,7 @@ namespace Titanium.Web.Proxy ...@@ -102,7 +102,7 @@ namespace Titanium.Web.Proxy
{ {
var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port, var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
httpVersion: null, isHttps: false, applicationProtocols: null, httpVersion: null, isHttps: false, applicationProtocols: null,
isConnect: true, proxyServer: this, upStreamEndPoint: UpStreamEndPoint, isConnect: true, proxyServer: this, session:null, upStreamEndPoint: UpStreamEndPoint,
externalProxy: UpStreamHttpsProxy, noCache: true, cancellationToken: cancellationToken); externalProxy: UpStreamHttpsProxy, noCache: true, cancellationToken: cancellationToken);
try try
......
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