C/C++ Миниатюрный сокс-сервер

Николай "GorluM" Андреев

Xakep, номер #054, стр. 054-088-2


}

Нулевой байт будет означать, что клиентский sock4-запрос окончен, и нашему проксику пора соединиться с адресом назначения dwDesIp. Если соединение прошло успешно, мы создаем канал данных между начальным и конечным пунктом. Если же соединение не удалось, то сервер просто убьет созданный ранее сокет при помощи WinSock-функции closesocket.

Пишем

Для работы sock4-сервера, помимо главного потока, создающегося из EntryPoint виндами (в нем мы слушаем порт), нам потребуется еще один поток. Через него будет производиться коннект и пересылка данных от отправителя к получателю.

Из статьи в ][ 12.02 "Пишем своего трояна" ты уже должен знать, как создавать сокет и слушать порт. На этот раз нам придется немного модифицировать механизм приема новых соединений. Функцию accept, ожидающую подключений на указанный порт и возвращающую сокет, мы должны будем запихнуть в бесконечный цикл. А в самом цикле при новом соединении создадим тред и передадим ему полученный сокет. Выглядит это так:

while (true) {

CreateThread(0,0,secthread,(LPVOID)accept(s, 0, 0), 0, &a);

}

где secthread - имя треда для обработки соединения, s - сокет, слушающий порт. Теперь, если кто-то приконнектится к открытому порту, сервер создаст нить (thread), в которую передаст переменную типа SOCKET для работы с новым соединением.

С главным потоком все ясно, а вот как обстоят дела с побочным, мы сейчас выясним. Для более удобного объявления треда я создал небольшой макрос:

#define _Thread(x) unsigned long __stdcall x (LPVOID pParam)

И теперь, если необходимо создать тред, достаточно написать: _Thread (имя_нити). Но на этом способе облегчения кодинга я не остановился. Пользуясь Visual Studio .NET, я откопал немало очень интересных для си-кодера фишек. Вот одна из них: user keyword, по-русски - пользовательские ключевые слова. Они позволяют выделить в VS определенные слова каким-нибудь цветом (см. скрин).

Я ими активно пользуюсь и тебе советую. Если ты юзаешь свои макросы, то очень удобно сделать их выделяющимися в тексте программы. Для добавления ключевых слов достаточно создать файл usertype.dat в директории, где лежит твоя VS.NET, в Common7\IDE, и записать notepad'ом в него нужные ключевые слова по одному в строке. После этого перезагрузи VS.NET и радуйся красивому сорцу.

Но вернемся к нашим баранам. В созданной нити мы будем обрабатывать входящие соединения и при необходимости создавать новые коннекты с серверами, указанными в запросах. Вот как это происходит. Сначала принимаем один байт, в нем содержится версия требуемого сокс-протокола. Причем получим этот байт, не удаляя его из очереди сообщений. Для этого при вызове winsock-функции recv в четвертом параметре передадим значение MSG_PEEK. Теперь, при следующем чтении из сокета, мы сначала получим этот же байт и только потом все остальное. Это необходимо для отброса лишних байт при проверке версии. Итак, если версия равна четырем, то заполним структуру socks4Request типа SOCKS4_REQUEST из нашего сокета:

recv(s, (char*)&socks4Request, sizeof(socks4Request), 0);

Назад на стр. 054-088-1  Содержание  Вперед на стр. 054-088-3