Commit a9d1011b authored by Hakan Arıcı's avatar Hakan Arıcı

IPv6 support is added to finding PID from port mechanism.

parent 12814410
...@@ -15,9 +15,16 @@ using Titanium.Web.Proxy.Tcp; ...@@ -15,9 +15,16 @@ using Titanium.Web.Proxy.Tcp;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal enum IpVersion
{
Ipv4 = 1,
Ipv6 = 2,
}
internal partial class NativeMethods internal partial class NativeMethods
{ {
internal const int AfInet = 2; internal const int AfInet = 2;
internal const int AfInet6 = 23;
internal enum TcpTableType internal enum TcpTableType
{ {
...@@ -75,19 +82,21 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -75,19 +82,21 @@ namespace Titanium.Web.Proxy.Helpers
/// Gets the extended TCP table. /// Gets the extended TCP table.
/// </summary> /// </summary>
/// <returns>Collection of <see cref="TcpRow"/>.</returns> /// <returns>Collection of <see cref="TcpRow"/>.</returns>
internal static TcpTable GetExtendedTcpTable() internal static TcpTable GetExtendedTcpTable(IpVersion ipVersion)
{ {
List<TcpRow> tcpRows = new List<TcpRow>(); List<TcpRow> tcpRows = new List<TcpRow>();
IntPtr tcpTable = IntPtr.Zero; IntPtr tcpTable = IntPtr.Zero;
int tcpTableLength = 0; int tcpTableLength = 0;
var ipVersionValue = ipVersion == IpVersion.Ipv4 ? NativeMethods.AfInet : NativeMethods.AfInet6;
if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, false, NativeMethods.AfInet, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) != 0) if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, false, ipVersionValue, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) != 0)
{ {
try try
{ {
tcpTable = Marshal.AllocHGlobal(tcpTableLength); tcpTable = Marshal.AllocHGlobal(tcpTableLength);
if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, NativeMethods.AfInet, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) == 0) if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, ipVersionValue, (int)NativeMethods.TcpTableType.OwnerPidAll, 0) == 0)
{ {
NativeMethods.TcpTable table = (NativeMethods.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(NativeMethods.TcpTable)); NativeMethods.TcpTable table = (NativeMethods.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(NativeMethods.TcpTable));
......
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
namespace Titanium.Web.Proxy.Models namespace Titanium.Web.Proxy.Models
{ {
/// <summary> /// <summary>
/// An abstract endpoint where the proxy listens /// An abstract endpoint where the proxy listens
/// </summary> /// </summary>
public abstract class ProxyEndPoint public abstract class ProxyEndPoint
{ {
public ProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) public ProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
{ {
this.IpAddress = IpAddress; this.IpAddress = IpAddress;
this.Port = Port; this.Port = Port;
this.EnableSsl = EnableSsl; this.EnableSsl = EnableSsl;
} }
public IPAddress IpAddress { get; internal set; } public IPAddress IpAddress { get; internal set; }
public int Port { get; internal set; } public int Port { get; internal set; }
public bool EnableSsl { get; internal set; } public bool EnableSsl { get; internal set; }
internal TcpListener listener { get; set; } public bool IpV6Enabled => IpAddress == IPAddress.IPv6Any
} || IpAddress == IPAddress.IPv6Loopback
|| IpAddress == IPAddress.IPv6None;
/// <summary>
/// A proxy endpoint that the client is aware of internal TcpListener listener { get; set; }
/// So client application know that it is communicating with a proxy server }
/// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint /// <summary>
{ /// A proxy endpoint that the client is aware of
internal bool IsSystemHttpProxy { get; set; } /// So client application know that it is communicating with a proxy server
internal bool IsSystemHttpsProxy { get; set; } /// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint
public List<string> ExcludedHttpsHostNameRegex { get; set; } {
internal bool IsSystemHttpProxy { get; set; }
public ExplicitProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) internal bool IsSystemHttpsProxy { get; set; }
: base(IpAddress, Port, EnableSsl)
{ public List<string> ExcludedHttpsHostNameRegex { get; set; }
} public ExplicitProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
} : base(IpAddress, Port, EnableSsl)
{
/// <summary>
/// A proxy end point client is not aware of }
/// Usefull when requests are redirected to this proxy end point through port forwarding }
/// </summary>
public class TransparentProxyEndPoint : ProxyEndPoint /// <summary>
{ /// A proxy end point client is not aware of
//Name of the Certificate need to be sent (same as the hostname we want to proxy) /// Usefull when requests are redirected to this proxy end point through port forwarding
//This is valid only when UseServerNameIndication is set to false /// </summary>
public string GenericCertificateName { get; set; } public class TransparentProxyEndPoint : ProxyEndPoint
{
//Name of the Certificate need to be sent (same as the hostname we want to proxy)
// public bool UseServerNameIndication { get; set; } //This is valid only when UseServerNameIndication is set to false
public string GenericCertificateName { get; set; }
public TransparentProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
: base(IpAddress, Port, EnableSsl)
{ // public bool UseServerNameIndication { get; set; }
this.GenericCertificateName = "localhost";
} public TransparentProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
} : base(IpAddress, Port, EnableSsl)
{
} this.GenericCertificateName = "localhost";
}
}
}
...@@ -16,7 +16,6 @@ using Titanium.Web.Proxy.Shared; ...@@ -16,7 +16,6 @@ using Titanium.Web.Proxy.Shared;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using System.Text;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
...@@ -25,16 +24,32 @@ namespace Titanium.Web.Proxy ...@@ -25,16 +24,32 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
partial class ProxyServer partial class ProxyServer
{ {
private int FindProcessIdFromLocalPort(int port, IpVersion ipVersion)
{
var tcpRow = TcpHelper.GetExtendedTcpTable(ipVersion).FirstOrDefault(
row => row.LocalEndPoint.Port == port);
return tcpRow?.ProcessId ?? 0;
}
private int GetProcessIdFromPort(int port, bool ipV6Enabled)
{
var processId = FindProcessIdFromLocalPort(port, IpVersion.Ipv4);
if (processId > 0 && !ipV6Enabled)
{
return processId;
}
return FindProcessIdFromLocalPort(port, IpVersion.Ipv6);
}
//This is called when client is aware of proxy //This is called when client is aware of proxy
//So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy //So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient) private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient)
{ {
var tcpRow = TcpHelper.GetExtendedTcpTable().FirstOrDefault( var processId = GetProcessIdFromPort(((IPEndPoint)tcpClient.Client.RemoteEndPoint).Port, endPoint.IpV6Enabled);
row => row.LocalEndPoint.Port == ((IPEndPoint) tcpClient.Client.RemoteEndPoint).Port);
var processId = tcpRow?.ProcessId ?? 0;
Stream clientStream = tcpClient.GetStream(); Stream clientStream = tcpClient.GetStream();
clientStream.ReadTimeout = ConnectionTimeOutSeconds * 1000; clientStream.ReadTimeout = ConnectionTimeOutSeconds * 1000;
...@@ -175,10 +190,7 @@ namespace Titanium.Web.Proxy ...@@ -175,10 +190,7 @@ namespace Titanium.Web.Proxy
//So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client //So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client
private async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcpClient) private async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcpClient)
{ {
var tcpRow = TcpHelper.GetExtendedTcpTable().FirstOrDefault( var processId = GetProcessIdFromPort(((IPEndPoint)tcpClient.Client.RemoteEndPoint).Port, endPoint.IpV6Enabled);
row => row.LocalEndPoint.Port == ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Port);
var processId = tcpRow?.ProcessId ?? 0;
Stream clientStream = tcpClient.GetStream(); Stream clientStream = tcpClient.GetStream();
...@@ -230,7 +242,6 @@ namespace Titanium.Web.Proxy ...@@ -230,7 +242,6 @@ namespace Titanium.Web.Proxy
endPoint.EnableSsl ? endPoint.GenericCertificateName : null, null); endPoint.EnableSsl ? endPoint.GenericCertificateName : null, null);
} }
private async Task HandleHttpSessionRequestInternal(TcpConnection connection, SessionEventArgs args, ExternalProxy customUpStreamHttpProxy, ExternalProxy customUpStreamHttpsProxy, bool CloseConnection) private async Task HandleHttpSessionRequestInternal(TcpConnection connection, SessionEventArgs args, ExternalProxy customUpStreamHttpProxy, ExternalProxy customUpStreamHttpsProxy, bool CloseConnection)
{ {
try try
...@@ -357,6 +368,7 @@ namespace Titanium.Web.Proxy ...@@ -357,6 +368,7 @@ namespace Titanium.Web.Proxy
connection.Dispose(); connection.Dispose();
} }
} }
/// <summary> /// <summary>
/// This is the core request handler method for a particular connection from client /// This is the core request handler method for a particular connection from client
/// </summary> /// </summary>
...@@ -568,7 +580,6 @@ namespace Titanium.Web.Proxy ...@@ -568,7 +580,6 @@ namespace Titanium.Web.Proxy
webRequest.Request.RequestHeaders = requestHeaders; webRequest.Request.RequestHeaders = requestHeaders;
} }
/// <summary> /// <summary>
/// This is called when the request is PUT/POST to read the body /// This is called when the request is PUT/POST to read the body
/// </summary> /// </summary>
...@@ -590,9 +601,7 @@ namespace Titanium.Web.Proxy ...@@ -590,9 +601,7 @@ namespace Titanium.Web.Proxy
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(BUFFER_SIZE, postStream);
} }
} }
} }
} }
\ No newline at end of file
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