Железные цепи победы Николай "GorluM" Андреев Хакер, номер #070, стр. 070-122-3 Наверняка ты уже не раз сталкивался с сетевым программированием, и тебе не нужно объяснять, как цеплять к проекту библиотеку для работы с сетевыми функциями и с ws2_32.dll, а также что с помощью функции WSAStartup эта библиотека начинает работать. Буду считать, что ты уже опытный в этом плане чел, и перейду сразу к делу (если же я в тебе жестоко ошибся – изволь взять с диска исходник и основательно его изучить, приду – проверю :)). Все данные об адресах и портах проксей я держу в специальной простенькой структуре: typedef struct _server { DWORD ip; u_short port; } server; Она очень просто инициализируется: port – с помощью функции htons, которая преобразует порт в сетевой вид, ip - с помощью написанной мной функции resolve, которая преобразует строку вроде «www.xakep.ru» или «127.0.0.1» в двойное слово – ip-адрес. Она работает, манипулируя функциями gethostbyname и inet_addr, и ты без проблем все поймешь, единожды взглянув на исходник. В коде инициализация выглядит так: server dest; dest.ip = resolve("irc.dal.net"); dest.port = htons(6667); Именно в структурах server и хранится вся информация о наших проксях. В программе я создал массив таких структур и назвал socks, далее при соединении мы будем работать именно с ним. Итак, для соединения через цепочку я сделал специальную функцию connectbysocks. Ей в параметрах нужно передать указатель на массив проксей, который мы создали и инициализировали, количество проксей в массиве, сокет, с которым мы будем в дальнейшем работать, и структуру server с адресом, куда мы, собственно, через эту цепочку коннектимся. Эта функция – урезанная реализация протокола SOCKS5, о котором мы столько говорили. Урезана она потому, что умеет работать только с одним методом 0x00 и не поддерживает никаких наворотов типа BIND. Работает наш connect следующим образом. Сначала извлекаются данные из первой записи массива проксей и запихиваются в структуру SOCKADDR_IN - это нужно для того, чтобы соединиться с первым в цепочке сервером. Затем, если соединение удалось, программа посылает приветствие в виде строки "\x05\x01\x00" и ждет ответа – двух байт. Анализируя их, она решает, ругнуться ей и прекратить работу (к примеру если требуется авторизация) или послать данные о следующей проксе. Если все прошло успешно и можно посылать адрес, то программа заполняет структуру типа req, основного типа данных на втором этапе соединения. По сути дела эта структура – типичный пример запроса во втором этапе соединения, только в данном случае тип адреса строго задан как заранее резолвленный ip v4. typedef struct _req { BYTE ver; BYTE cmd; BYTE rsv; BYTE type; DWORD addr; u_short port; } req; Если ответ прокси на посланную программой структуру говорит, что все прошло на ура, прога повторяет посылку приветствия и адресов по новой, только используя следующую структуру в массиве socks (как раз поэтому в коде функции цикл). В случае, если проксей в массиве не осталось (условие i == socksnum), программа берет из структуры dest конечный адрес, к которому мы изначально хотели подсоединиться по цепочке соксов. |