Думаю, ты знаешь что из себя представляет TCP logger и как он жизненно необходим в твоем ремесле 🙂 Поэтому перейду сразу к делу — к написанию программы.

Принцип действия программы следующий — мы как бы вклиниваемся между клиентом
(твоим браузером) и прокси-сервером. Когда все пакеты будут проходить через логгер, то ты будешь подключаться клиентом только к созданному логером серверу,
сам же логгер, если не усложнять программу до неприличия, коннектиться только к одному серваку
и записывает все проходящие данные.

В общем, примерная схема этой цепочки такая — 

Браузер — TCP logger — Прокси

Сразу хочу сказать, что в нижеприведенной проге я больше внимания уделял самой сути программы, а не всяческим декоративным атрибутам вроде окошек и
менюшек 🙂 Программу мы будем писать на Visual C++, который ничем не уступает столь иногда незаслуженно популярному Delphi. Для начала создадим проект — (File — New — Projects — MFC
AppWizard(exe)). Почему мы выбрали именно MFC — объясню позже. В данном случае нам не важны внешние проявления типа разноцветных кнопок, а потребуются некоторые функции библиотеки MFC. Далее выбираем пункт Dialog
Based (не принципиально, но для простоты лучше этот). Далее жмем Finish, и вот мы имеем основу 🙂

Если ты все сделал правильно то начало главного файла должно иметь такой вид:

#include «stdafx.h»

#include «winsock2.h» //для работы с сокетами
// не забудь скопировать этот файл в каталог проекта 

#include «dd.h»
// подключаемые файлы для данного проекта
#include «ddDlg.h»
//названия зависит от его имени. 

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

int s; //глобальные переменные, дескрипторы сокетов.
int s1;
int s2;

UINT Function1( LPVOID pParam)// функция другого потока, см ниже

///////////////////////////////
// CDdApp

BEGIN_MESSAGE_MAP(CDdApp, CWinApp)
//{{AFX_MSG_MAP(CDdApp)
// NOTE — the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()

///////////////////////////////
// CDdApp construction

CDdApp::CDdApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}

///////////////////////////////
// The one and only CDdApp object

CDdApp theApp;

// CDdApp initialization

BOOL CDdApp::InitInstance()
{
/////////здесь должен быт наш код

AfxEnableControlContainer();

Основная процедура — BOOL CDdApp. Наша задача — втиснуть сам код логгера в проект так, чтобы он выполнялся без лишнего геморроя. Самое простое засунуть его перед самой инициализацией формы — т.е. перед выполнением функции
AfxEnableControlContainer(). Теперь можно приступать к написанию кода.

Для начала нужно проинициализировать процесс библиотеки wsock32.dll для работы с сокетами. Что это такое ты думаю знаешь из целого ряда статей с этого сайта, поэтому не буду повторяться в xxx какой-то раз 🙂
(И еще для этого wsock32.dll нужно подключить к проекту в Project
Properties/Link). Инициализация в программе достигается
вызовом функции WSAStartup

WSADATA WsaData; 
int err = WSAStartup (0x0101, &WsaData);
if (err == SOCKET_ERROR) 
{
MessageBox(0,»Error Startup!»,0,0);
//вывод сообщения об ошибке
инициализации

return 1;
}

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

s=socket(AF_INET,SOCK_STREAM,0);

Потом задаем параметры для сокета (сервера), сначала объявив структуру SOCKADDR_IN ser1, а затем заполняем параметры для сервера: 

SOCKADDR_IN ser1; 
ser1.sin_family = AF_INET; 
ser1.sin_port = htons(88);//port
ser1.sin_addr.S_un.S_addr = inet_addr(«127.0.0.1»);

Здесь sin_port=htons(88) — как ты наверно догадался, порт нашего сервера,
inet_addr() — соответственно адрес сервака. Лучше использовать адрес
localhost’a.

Для подключения сокета к среде сети нужно выполнить системный вызов bind, который «привязывает» структуру ser1 к сокету s.

bind( s, (LPSOCKADDR)&ser1, sizeof(ser1));

Cервер создан :).

Теперь будем создавать клиента, который будет подключаться к прокси. Аналогично
создаем сокет:

s1=socket(AF_INET,SOCK_STREAM,0);

Но в структуре будут некоторые отличия:

SOCKADDR_IN cl1; 
cl1.sin_family = AF_INET; 
cl1.sin_port = htons(8000);//port
cl1.sin_addr.S_un.S_addr =INADDR_ANY;//Adress

В данном случае в поле sin_addr стоит INADDR_ANY, чтобы после коннекта привязать сокет к локальному узлу сети.

SOCKADDR_IN sc2; 
sc2.sin_family = AF_INET; 
sc2.sin_port = htons(80);//порт прокси
sc2.sin_addr.S_un.S_addr =inet_addr(«xxx.xxx.xxx.xxx»);
//адрес прокси

В этой структуре мы задаем параметры сервера, к которому будет коннектиться логгер. 
Теперь подключаемся:

int erc;//переменная для кода ошибки подключения
do
{
erc=connect(s1, (struct sockaddr *)&sc2, sizeof(struct sockaddr));
}
while (erc!=0)

Цикл — подключаемся пока не будет коннекта.

Теперь, когда мы подключились к прокси, нужно создать сервер, чтобы к нему мог подключиться клиент, в роли которого выступает твой браузер.
Вся фишка в том, что если бы клиент коннектился бы сразу к прокси, то он каждый раз бы создавал новое соединение, на что уходило бы лишнее время. У нас же коннект логгера с прокси-сервером постоянный и не зависит от состоянии клиента юзера, поэтому соединение логгера с проксей устанавливается раз и навсегда :))

Соединение же клиента с логгером нужно устанавливать каждый раз заново, когда браузер посылает запрос на какой-либо адрес. 

//Слушаем порт все время, фиг с ним, с выходом 🙂
while (1)
{
listen(s,1);
//»cлушаем» сервер, ждем коннекта.

SOCKADDR_IN ser2; 
int serlen=sizeof(ser2);

s2= accept(s,(struct sockaddr*)&ser2, &serlen);

Когда есть запрос, то подключаем клиента к серваку вызовом
accept. В структуре ser2 — параметры установившегося соединения.
s2 — сокет сервера, через который он обменивается данными с клиентом.

После установления связи приступаем к самой важной части — чтением данных из сокета клиента и пересылкой их в сокет прокси, с записью данных в файл конечно!

int nn,rr;
int yy;
char Buf[100000];
//буфер, в которой читаются
(и из которого пишутся) данные

FILE *f;
char c;

while ((nn=recv(s2,Buf,sizeof(Buf),0))!=-1) 
//пока нету ошибки читаем данные функцией recv (Код ошибки «-1»)
{

if (nn>0)
//в переменной nn — кол-во прочитанных байт. 
//Если что-то прочитали — то запишем.

{
f=fopen(«c:\\clt.txt»,»aw+»);
//каждый раз открываем файл и пишем в его конец.
for (yy=0;yy
//пишем в файл прочитанные nn байт данных из буфера,
{
c=Buf[yy];
fprintf(f,»%c»,c);
}

// конечно этот кусок кода, пишущий данные в файл,
//можно усовершенствовать. Я рассматриваю самый простой
//способ, уходящий корнями еще в старый добрый C :)))

fclose(f);
//думаю догадался — закрываем файл.

rr=send(s1,Buf,nn,0); 
//посылаем данные прокси. 
//nn — кол-во пересылаемых байт. 0 -флаг.
//rr — кол-во отосланных байт, -1 — когда ошибка

}
}

}

Если бы был нормальный выход, то в конце нужно было бы 
закрыть сокеты:

shutdown(s,0);
closesocket(s);
shutdown(s1,0);
closesocket(s1);
shutdown(s2,0);
closesocket(s2);

В общем, одну часть программы мы сделали — выполнили передачу данных от клиента к прокси. Но самое интересное — впереди 🙂 Думаю ты знаешь, что передача данных должна идти в две стороны — от клиента к прокси и от прокси к клиенту. Самое прикольное, что они должны идти параллельно. Вот для этого мы и юзаем MFC :). Нам нужно, чтобы параллельно с вышеописанным процессом передачи данных от клиента к прокси шел и
обратный процесс. Для этого мы запустим его параллельно с уже идущим. Такую возможность дает функция
AfxBeginThread — «начать поток». Поэтому вставим эту функцию сразу после подключения логгера к прокси:

AfxBeginThread(*Function1,NULL);
//*Functuion1 — указатель на нужную функцию.

Опишем ее — для этого перед основной функцией TheApp:
 
UINT Function1( LPVOID pParam);

А в самом конце программы собственно должна находиться сама функция —

UINT Function1( LPVOID pParam)
{

// эта функция аналогична уже описанной, читающей передающий данные
//от клиента к прокси.

char Buf1[100000];
int nn1;
int rr1;
int yy1;

FILE *f1;
char c1;

while (1)
//опять-таки читаем все время, так как коннект у логгера с прокси постоянный,
//а сервер шлет пакеты только при запросе клиента. 

{
nn1=recv(s1,Buf1,sizeof(Buf1),0);

rr1=send(s2,Buf1,nn1,0); 
if (nn1>0)
{

f1=fopen(«c:\\serv.txt»,»aw+»);
for(yy1=0;yy1 {
c1=Buf1[yy1];
fprintf(f1,»%c»,c1);
}
fclose(f1);
}

}

return 0;
//код завершения
}

И не забудь — переменные дескрипоторов сокетов
s, s1 и s2 должны быть глобальные, так как доступ к ним необходим
из обеих функций.  Поэтому объяви их вне функций, можешь сразу после includ’ов.

Как юзать? Элементарно — в браузер вбивается IPшник и порт логгера, как обычный прокси.

После всего вышеперечисленного программу можно считать законченной.
Она конечно далека от совершенства, в ней не предусмотрены мелочи типа выхода
(а Ctrl-Alt-Del тебе на что 🙂 ), да и кроме ведения лога можно добавить ей новые функции, но это уже тема для новой отдельной статьи.

Оставить мнение

Check Also

Google будет блокировать попытки логина через встроенные браузерные фреймворки для защиты от MitM-атак

Инженеры Google намерены запретить вход в учетную запись с помощью Chromium Embedded Frame…