Как обрабатывать идентификационные пакеты и данные для написания приложения обратного прокси [как имитировать локальный сокет через сеть?] - PullRequest
0 голосов
/ 05 августа 2020

Итак, я пишу программу, которая позволит другому компьютеру использовать его как прокси, но не в традиционном смысле.

Компьютер, который будет использовать другой компьютер в качестве прокси, является слушателем, а клиент (который будет действовать как прокси) подключится к нему, затем данные будут передаваться, как и в обычном прокси. Теперь я сделал работающую реализацию 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;
        }

    }

Как правильно определить каждый пакет для моста?

...