Socks5 своїми руками
Анонімність в мережі - тема не нова. І ви напевно встановлювали до себе на комп прогу типу A4Proxy, SocksChain
і їм подібні. Особисто я не люблю, коли для роботи з проксі потрібна якась окрема прога. По перше
некрасиво, коли багато вікон на панелі завдань або значків в треї, по-друге проги ці вимагають кряков, а їх
шукати лінь 🙂 Тому я і написав класи для підтримки SOCKS5-серверів, які я тепер можу заюзать
в який-небудь своєї проге. І ось тепер хочу всім розповісти, як це робити.
Сконнектівшісь з сервером, клієнт шле пакет, в якому вказана версія протоколу і підтримувані
методи аутентифікації. Цей пакет має такий вигляд:
BYTE Version;
BYTE nMethods;
BYTE methods [nMethods]
Версія повинна бути 5. Кожен елемент methods визначає не тільки метод аутентифікації, але і спосіб шифрування даних,
якщо воно використовується. З цих методів сервер вибирає один. Можна вказувати будь-яку кількість методів, але, якщо сервер не вимагає аутентифікації, то ніякі методи,
крім 0x00 (не використовувати ні аутентифікацію, ні шифрування) не будуть потрібні. У відповідь сервер шле пакет такого змісту:
BYTE Version
BYTE method,
де method - обраний сервером метод або 0xFF (жоден із запропонованих методів не підтримується). Якщо метод 0x00, то можна відразу посилати команду.
Пакет команди мають такий вигляд:
BYTE Version; // 5
BYTE Cmd; // 1 - CONNECT
BYTE Reserved; // 0
BYTE AType; // 1 - IPv4; 3 - domain name; 4 - IPv6
BYTE addr [];
WORD port; // Байти в мережевому порядку, т. Е. Htons (Port);
Якщо використовується доменне ім'я, то спочатку йде байт довжини, а потім рядок без завершального нуля.
Сервер посилає відповідь:
BYTE Version; // 5
BYTE Rep; // 0 - Ok
BYTE Reserved; // 0
BYTE AType; // 1 - IPv4; 3 - domain name; 4 - IPv6
BYTE addr [];
WORD port;
Оскільки socks инкапсулирует TCP, доцільно зробити клас socks-з'єднання похідним від
класу сокета, але MFCшний CSocket не підходить, тому що у нього все методи
не віртуально. Напишемо свій клас сокета і назвемо його, скажімо, CTSocket
private:
SOCKET sock;
>;
class CSocksSocket. public CTSocket
public:
virtual BOOL CreateSocket ();
virtual BOOL Connect (unsigned long ip, unsigned short port);
virtual BOOL Connect (LPCSTR name, unsigned short port);
virtual int Send (const char * str, int len);
virtual int Recv (char * buf, int max);
virtual BOOL Close ();
virtual unsigned long GetHost ();
CTSocket * pSocket;
unsigned long socks_ip;
unsigned short socks_port;
// Реалізація
BOOL CSocksSocket :: CreateSocket ()
if (! pSocket-> CreateSocket ()) return FALSE;
if (! pSocket-> Connect (socks_ip, socks_port)) return FALSE;
buffer [0] = 5; // Ver
buffer [1] = 1; // 1 method
buffer [2] = 0; // no auth
pSocket-> Send (buffer, 3);
int n = pSocket-> Recv (buffer, 2);
if (n! = 2) return FALSE;
if (buffer [1]! = 0) return FALSE; // method 0 not supported
return TRUE;
>
BOOL CSocksSocket :: Connect (unsigned long ip, unsigned short port)
buffer [0] = 5; // Ver
buffer [1] = 1; // CONNECT
buffer [2] = 0; // Reserved
buffer [3] = 1; // IPv4
* ((Unsigned long *) (buffer + 4)) = ip;
* ((Unsigned short *) (buffer + 8)) = port;
pSocket-> Send (buffer, 10);
int n = pSocket-> Recv (buffer, 10);
if (n! = 10) return FALSE;
if (buffer [1]! = 0) return FALSE; // Can not connect
if (buffer [3]! = 1) return FALSE; // Будемо вимагати, щоб нам сказали IP, а не що-небудь інше.
l_ip = * ((unsigned long *) (buffer + 4));
return TRUE;
>
BOOL CSocksSocket :: Connect (LPCSTR name, unsigned short port)
buffer [0] = 5;
buffer [1] = 1;
buffer [2] = 0;
buffer [3] = 3; // Domain name
int m = strlen (name);
buffer [4] = m; // Length byte
memcpy (buffer + 5, name, m); // Копіюємо рядок без завершального нуля
* ((Unsigned short *) (buffer + 5 + m)) = port;
pSocket-> Send (buffer, m + 7);
int n = pSocket-> Recv (buffer, 10);
if (n! = 10) return FALSE;
if (buffer [1]! = 0) return FALSE;
if (buffer [3]! = 1) return FALSE; // Будемо вимагати, щоб нам сказали IP, а не що-небудь інше.
l_ip = * ((unsigned long *) (buffer + 4));
return TRUE;
>
int CSocksSocket :: Send (const char * str, int len)
return pSocket-> Send (str, len);
>
int CSocksSocket :: Recv (char * buf, int max)
return pScoket-> Recv (buf, max);
>
void CSocksSocket :: Close ()
pSocket-> Close ();
>
unsigned long CSocksSocket :: GetHost ()
return l_ip;
>
// Ну, а тепер тестова прога
void main ()
WSADATA wsadata;
CTSocket tsock;
CSocksSocket ssock (tsock);
if (! ssock.CreateSocket ()) return; // Can not connect to socks
// or auth required
if (! ssock.Connect ( «www.mail.ru», htons (80))) return; // www.mail.ru
// is inaccessible
LPSTR q = «HEAD / HTTP / 1.1 \ xD \ xAHost: www.mail.ru:80\xD\xAUser-Agent: xakep \ xD \ xA \ xD \ xA»;
ssock.Send (q, strlen (q));
char buf [тисячі];
int n = ssock.Recv (buf 1000);
buf [n] = 0;
printf ( "% s", buf);
Покажи цю статтю друзям: