Думаю, ты знаешь что из себя представляет 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

Windows 10 против шифровальщиков. Как устроена защита в обновленной Windows 10

Этой осенью Windows 10 обновилась до версии 1709 с кодовым названием Fall Creators Update …