Итак, я пишу программу, которая позволит другому компьютеру использовать его как прокси, но не в традиционном смысле.
Компьютер, который будет использовать другой компьютер в качестве прокси, является слушателем, а клиент (который будет действовать как прокси) подключится к нему, затем данные будут передаваться, как и в обычном прокси. Теперь я сделал работающую реализацию SOCKS (традиционный прокси-сервер), но я не знаю, как подключить его по сети. Реализация должна поддерживать несколько подключений одновременно. Локальная реализация делает это легко, но, когда я соединяю его по сети, возможно, я перепутаю данные. google.com) по сети (фактический сокет находится на другом компьютере, и мне нужно одновременно обрабатывать несколько исходящих сообщений и контролировать их через один и тот же сокет клиент-сервер). У меня есть реализация SOCKS, которая работает. Он принимает соединения, затем создает удаленный сокет и перенаправляет любой трафик c между ними. Мне нужно: заменить этот удаленный сокет другим на другом компьютере. Мне нужно соединить их и каким-то образом идентифицировать каждый приходящий пакет для пересылки в нужный сокет.
Код прокси-сервера:
class Socks4Proxy
{
public Socks4Proxy(int port, int bufferSize)
{
this._port = port;
this.bufferSize = bufferSize;
SetupServerSocket();
}
private readonly int _port;
private readonly int bufferSize = 1024;
private Socket _serverSocket;
private bool _running;
private Thread _acceptThread;
private List<ConnectionInfo> _connections =
new List<ConnectionInfo>();
//TODO: Use them to make the logs more detailed.
public event LocalConnectEventHandler LocalConnect;
public event LocalDisconnectEventHandler LocalDisconnect;
public event LocalSentEventHandler LocalSent;
public event LocalReceiveEventHandler LocalReceive;
public event RemoteConnectEventHandler RemoteConnect;
public event RemoteDisconnectEventHandler RemoteDisconnect;
public event RemoteSendEventHandler RemoteSend;
public event RemoteReceivedEventHandler RemoteReceive;
private void SetupServerSocket()
{
IPEndPoint myEndpoint = new IPEndPoint(IPAddress.Any,
_port);
// Create the socket, bind it, and start listening
_serverSocket = new Socket(myEndpoint.Address.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(myEndpoint);
_serverSocket.Listen((int)SocketOptionName.MaxConnections);
_running = true;
_acceptThread = new Thread(AcceptConnections);
_acceptThread.IsBackground = true;
_acceptThread.Start();
}
private void AcceptConnections()
{
while (_running)
{
// Accept a connection
ConnectionInfo connection = new ConnectionInfo();
Socket socket = _serverSocket.Accept();
if (_running == false)
{
break;
}
connection.LocalSocket = socket;
connection.RemoteSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Create the thread for the receives.
connection.LocalThread = new Thread(ProcessLocalConnection);
connection.LocalThread.IsBackground = true;
connection.LocalThread.Start(connection);
LocalConnect?.Invoke(this, (IPEndPoint)socket.RemoteEndPoint);
// Store the socket
lock (_connections) _connections.Add(connection);
}
}
private void ProcessLocalConnection(object state)
{
ConnectionInfo connection = (ConnectionInfo)state;
int bytesRead = 0;
byte[] buffer = new byte[bufferSize];
try
{
// we are setting up the socks!
bytesRead = connection.LocalSocket.Receive(buffer);
Console.WriteLine("Received {0}", bytesRead);
for (int i = 0; i < bytesRead; i++)
Console.Write("{0:X2} ", buffer[i]);
Console.Write("\n");
if (bytesRead > 0)
{
if (buffer[0] == 0x04 && buffer[1] == 0x01)
{
int remotePort = buffer[2] << 8 | buffer[3];
byte[] ipAddressBuffer = new byte[4];
Buffer.BlockCopy(buffer, 4, ipAddressBuffer, 0, 4);
IPEndPoint remoteEndPoint = new IPEndPoint(new IPAddress(ipAddressBuffer), remotePort);
connection.RemoteSocket.Connect(remoteEndPoint);
if (connection.RemoteSocket.Connected)
{
Console.WriteLine("Connected to remote!");
RemoteConnect?.Invoke(this, remoteEndPoint);
byte[] socksResponse = new byte[] {
0x00, 0x5a,
buffer[2], buffer[3], // port
buffer[4], buffer[5], buffer[6], buffer[7] // IP
};
connection.LocalSocket.Send(socksResponse);
// Create the thread for the receives.
connection.RemoteThread = new Thread(ProcessRemoteConnection);
connection.RemoteThread.IsBackground = true;
connection.RemoteThread.Start(connection);
}
else
{
Console.WriteLine("Connection failed.");
byte[] socksResponse = new byte[] {
0x04,
0x5b,
buffer[2], buffer[3], // port
buffer[4], buffer[5], buffer[6], buffer[7] // IP
};
connection.LocalSocket.Send(socksResponse);
return;
}
}
}
else if (bytesRead == 0) return;
// start receiving actual data
while (true)
{
bytesRead = connection.LocalSocket.Receive(buffer);
if (bytesRead == 0)
{
Console.WriteLine("Local connection closed!");
break;
}
else
{
connection.RemoteSocket.Send(buffer, bytesRead, SocketFlags.None);
}
}
}
catch (Exception exc)
{
Console.WriteLine("Exception: " + exc);
}
finally
{
connection.LocalSocket.Close();
connection.RemoteSocket.Close();
lock (_connections) _connections.Remove(connection);
}
}
private void ProcessRemoteConnection(object state)
{
ConnectionInfo connection = (ConnectionInfo)state;
int bytesRead = 0;
byte[] buffer = new byte[bufferSize];
try
{
// start receiving actual data
while (true)
{
bytesRead = connection.RemoteSocket.Receive(buffer);
if (bytesRead == 0)
{
Console.WriteLine("Remote connection closed!");
break;
}
else
{
connection.LocalSocket.Send(buffer, bytesRead, SocketFlags.None);
}
}
}
catch (SocketException exc)
{
Console.WriteLine("Socket exception: " + exc.SocketErrorCode);
}
catch (Exception exc)
{
Console.WriteLine("Exception: " + exc);
}
finally
{
Console.WriteLine("ProcessRemoteConnection Cleaning up...");
connection.LocalSocket.Close();
connection.RemoteSocket.Close();
lock (_connections)
_connections.Remove(connection);
}
}
}
public class ConnectionInfo
{
public Socket LocalSocket { get; set; }
public Thread LocalThread { get; set; }
public Socket RemoteSocket { get; set; }
public Thread RemoteThread { get; set; }
}
public delegate void LocalConnectEventHandler(object sender, System.Net.IPEndPoint iep);
public delegate void LocalDisconnectEventHandler(object sender);
public delegate void LocalSentEventHandler(object sender);
public delegate void LocalReceiveEventHandler(object sender);
public delegate void RemoteConnectEventHandler(object sender, System.Net.IPEndPoint iep);
public delegate void RemoteDisconnectEventHandler(object sender);
public delegate void RemoteSendEventHandler(object sender);
public delegate void RemoteReceivedEventHandler(object sender);
public interface IProxyCore
{
event LocalConnectEventHandler LocalConnect;
event LocalDisconnectEventHandler LocalDisconnect;
event LocalSentEventHandler LocalSent;
event LocalReceiveEventHandler LocalReceive;
event RemoteConnectEventHandler RemoteConnect;
event RemoteDisconnectEventHandler RemoteDisconnect;
event RemoteSendEventHandler RemoteSend;
event RemoteReceivedEventHandler RemoteReceive;
void Start();
void Shutdown();
}
Это код, предоставляемый системой плагинов клиент-серверные приложения [требуются строки, поэтому я буду использовать base64]: [PS. Я мог бы также go другим способом, и вместо этих странных функций я мог бы сделать отдельный, нормальный, сокет со слушателем. Я думаю, что это невозможно с функциями по умолчанию, предоставляемыми системой плагинов приложения]
class SERVER
{
public int Sock;
/// <summary>
/// This function is used to send data to the client.
/// </summary>
/// <param name="data">The data to send.</param>
/// <param name="twoWay">If this condition is true, then the client is supposed to send a response to this data.</param>
public void Send(string data, bool twoWay)
{
System.Reflection.Assembly.GetEntryAssembly().GetType("PluginSystem.Functions").GetMethod("Send").Invoke(null, new object[] { Sock, data, twoWay });
}
/// <summary>
/// This function receives data from the client. Do not try to call this function! Treat is as an event!
/// </summary>
/// <param name="obj">This object represents the data received. It is a string, so casting the type is required.</param>
public void Receive(object obj)
{
string input = (string)obj;
}
}
class CLIENT
{
/// <summary>
/// Very confusing name, this function actually receives data, and returns a response. This function is called if the send command from the cnc is marked as two-way.
/// </summary>
/// <param name="input">Data received from controller.</param>
public string Send(string input)
{
return string.Empty;
}
/// <summary>
/// This function receives data, and does not send anything back. Do not try to call this function! Treat is as an event!
/// </summary>
/// <param name="input">Received data.</param>
public void Receive(object obj)
{
string input = (string)obj;
}
}
Как правильно определить каждый пакет для моста?