Socks5 proxy server на C#

Категория: Dotnet
Опубликовано 21.12.2013 04:15

Экспериментировал с проксями и написал простенький socks5 прокси сервер на шарпе. Выкладываю на случай, если еще кому-то понадобится.

Да, и не обращайте внимание на название неймспейса, он вводит в заблуждение.

using System;
using System.Net.Sockets;


namespace HttpProxy
{
    abstract class BasicSocketWorker
    {
        protected Socket WorkSocket;
        private bool _socketIsWorking = true;

        protected BasicSocketWorker(Socket workSocket)
        {
            WorkSocket = workSocket;
        }

        protected BasicSocketWorker()
        {
        }



        public event EventHandler<DataAlreadyEventArgs> DataAlready;
        private void OnDataAlready(byte[] buffer, int length)
        {
            DataAlreadyEventArgs dataAlreadyEventAgrs = new DataAlreadyEventArgs { SocketBuffer = buffer, Length = length };
            if (DataAlready != null)
                DataAlready(this, dataAlreadyEventAgrs);
        }

        public event EventHandler TransmissionError;
        private void OnTransmissionError()
        {
            if (TransmissionError != null)
                TransmissionError(this, EventArgs.Empty);
        }

        public void StartWorking()
        {
            byte[] buffer = new byte[8197];
            try
            {
                WorkSocket.BeginReceive(buffer, 5, 8192, SocketFlags.None, Received, buffer);
            }
            catch (ObjectDisposedException)
            {
                ShutdownSocket();
                OnTransmissionError();
            }
        }

        public void SubscribeToEvents(BasicSocketWorker basicSocketWorker)
        {
            DataAlready += basicSocketWorker.OnDataAlreadyAction;
            TransmissionError += basicSocketWorker.OnTransmissionErrorAction;
        }



        private void Received(IAsyncResult ar)
        {
            if (!_socketIsWorking)
                return;
            byte[] incomingBuffer = (byte[]) ar.AsyncState;
            int received = WorkSocket.EndReceive(ar);
            if (received == 0)
            {
                ShutdownSocket();
                OnTransmissionError();
                return;
            }
            try
            {
                OnDataAlready(incomingBuffer, received);
                byte[] buffer = new byte[8197];
                WorkSocket.BeginReceive(buffer, 5, 8192, SocketFlags.None, Received, buffer);
            }
            catch (SocketException)
            {
                ShutdownSocket();
                OnTransmissionError();
            }
            catch (ObjectDisposedException)
            {
                ShutdownSocket();
                OnTransmissionError();
            }
        }

        private void Sent(IAsyncResult ar)
        {
            if (!_socketIsWorking)
                return;
            WorkSocket.EndSend(ar);
        }

        private void OnDataAlreadyAction(object sender, DataAlreadyEventArgs eventArgs)
        {
            WorkSocket.BeginSend(eventArgs.SocketBuffer, 5, eventArgs.Length, SocketFlags.None, Sent, eventArgs.SocketBuffer);
        }

        private void OnTransmissionErrorAction(object sender, EventArgs eventArgs)
        {
            ShutdownSocket();
        }

        private void ShutdownSocket()
        {
            if (!_socketIsWorking)
                return;
            _socketIsWorking = false;
            WorkSocket.Shutdown(SocketShutdown.Both);
            WorkSocket.Close();
        }
    }
}
using System.Net.Sockets;


namespace HttpProxy
{
    class Receiver : BasicSocketWorker
    {
        public Receiver(Socket workSocket)
            : base(workSocket)
        {
        }
    }
}
using System;
using System.Net;
using System.Net.Sockets;


namespace HttpProxy
{
    class Sender : BasicSocketWorker
    {
        public bool Connect(string host, int port)
        {
            IPEndPoint endPoint;
            try
            {
                endPoint = GetEndPoint(host, port);
            }
            catch (Exception)
            {
                return false;
            }

            WorkSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                WorkSocket.Connect(endPoint);
            }
            catch (SocketException)
            {
                return false;
            }
            return true;
        }



        private IPEndPoint GetEndPoint(string host, int port)
        {
            IPAddress address;
            if (IPAddress.TryParse(host, out address))
                return new IPEndPoint(address, port);
            IPAddress[] addresses = Dns.GetHostEntry(host).AddressList;
            if (addresses.Length < 1)
                throw new Exception();
            return new IPEndPoint(addresses[0], port);
        }
    }
}
using System;


namespace HttpProxy
{
    class DataAlreadyEventArgs : EventArgs
    {
        public byte[] SocketBuffer { get; set; }
        public int Length { get; set; }
    }
}
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;


namespace HttpProxy
{
    class Program
    {
        static void Main()
        {
            Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            listener.Bind(new IPEndPoint(IPAddress.Any, 1080));
            listener.Listen(1000);
            listener.BeginAccept(ListenerAccept, listener);
            Console.ReadKey();
        }

        private static void ListenerAccept(IAsyncResult ar)
        {
            //получение данных
            Socket listener = (Socket)ar.AsyncState;
            listener.BeginAccept(ListenerAccept, listener);
            Socket local = listener.EndAccept(ar);
            byte[] buffer = new byte[260];

            //авторизация прокси
            local.Receive(buffer, 0, buffer.Length, SocketFlags.None);
            if (buffer[0] != 5)
            {
                local.Shutdown(SocketShutdown.Both);
                local.Close();
                return;
            }
            buffer[1] = 0;
            local.Send(buffer, 0, 2, SocketFlags.None);

            //проверка данных соединения
            int received;
            try
            {
                received = local.Receive(buffer, 0, buffer.Length, SocketFlags.None);
            }
            catch (SocketException)
            {
                local.Shutdown(SocketShutdown.Both);
                local.Close();
                return;
            }
            if (buffer[1] != 1)
            {
                local.Shutdown(SocketShutdown.Both);
                local.Close();
                return;
            }
            if (buffer[3] != 1 && buffer[3] != 3)
            {
                local.Shutdown(SocketShutdown.Both);
                local.Close();
                return;
            }

            //инстанцирование воркеров
            Receiver receiver = new Receiver(local);
            Sender sender = new Sender();
            receiver.SubscribeToEvents(sender);
            sender.SubscribeToEvents(receiver);

            //коннект к удаленному хосту
            string host = Encoding.ASCII.GetString(buffer, 5, buffer[4]);
            int port = buffer[buffer[4] + 5] * 256 + buffer[buffer[4] + 6];
            if (!sender.Connect(host, port))
            {
                buffer[1] = 4;
                local.Send(buffer, 0, received, SocketFlags.None);
                local.Shutdown(SocketShutdown.Both);
                local.Close();
                return;
            }

            //сообщение об успехе и запуск на прием
            buffer[1] = 0;
            local.Send(buffer, 0, received, SocketFlags.None);
            receiver.StartWorking();
            sender.StartWorking();
        }
    }
}

Для тех, кто хочет досконально разобраться в работе данного вида прокси, нужно предварительно прочитать википедию, раздел о пятой версии.

UPD: обновил код, данная версия работает гораздо быстрее предыдущих.

Комментарии   

0 # Vitalii 16.09.2015 00:58
Не по теме - но не нашёл как зарегистрироват ься на Вашем сайте. Я так думаю, что зарегистрирован ным пользователям приходит рассылка с Вашего сайта?
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 16.09.2015 19:05
А я на сайте просто выложил несколько своих статей, на большее он не планировался. Поэтому и регистрацию отключил, вроде как тут она ни к чему.
Ответить | Ответить с цитатой | Цитировать