Думаю, ты знаешь что из себя представляет 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 тебе на что 🙂 ), да и кроме ведения лога можно добавить ей новые функции, но это уже тема для новой отдельной статьи.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии