Rambler's Top100

Архитектура захвата пакетов для Windows WinPCAP: бальзам на душу хакера или панацея для программиста?

(Часть 3)

Алексей Волков, Вячеслав Семенов

Библиотека PACKET.DLL

Библиотека packet.dll представляет собой динамически загружаемую библиотеку, с помощью которой приложение пользователя взаимодействует с драйвером захвата пакетов. Функции библиотеки предназначены для упрощения процесса взаимодействия с драйвером и обеспечивают выполнение таких операций, как получение дескрипторов сетевых адаптеров, прием и передачу пакетов по сети, установку буферов и фильтров драйвера и т.д. Существует две версии библиотеки – для Windows 95/98/ME и Windows NT/2000, полностью совместимыx друг с другом.

Таким образом, используя packet.dll, можно работать на всех версиях Windows без внесения каких-либо изменений в исходный код программ. Эта возможность позволила создать единую версию Libpcap для всех версий Windows.

Структуры данных

В библиотеке packet.dll описаны и используются следующие структуры данных:

1.     Структура PACKET описывает принимаемый или передаваемый пакет. Состоит из следующих полей:

·        OVERLAPPED OverLappedструктура, описанная в DDK Windows, используется для поддержки синхронных вызовов драйвера

·        PVOID Bufferуказатель на буфер, содержащий пакет;

·        UINT Lengthразмер буфера;

·        PVOID Next – указатель на следующий пакет;

·        UINT ulBytesReceivedразмер части буфера, содержащей «верные» данные;

·        BOOLEAN bIoCompleteпоказывает, содержит ли буфер «верные» данные после асинхронного вызова.

2.     Структура ADAPTER содержит описание сетевого адаптера:

·        HANDLE hFileуказатель на дескриптор драйвера адаптера;

·        TCHAR SymbolicLinkстрока, содержащая имя сетевого адаптера, открытого в данный момент.

3.     Структура PACKET_OID_DATA используется для взаимодействия с сетевым адаптером при помощи OID-запросов и установки операций:

·        ULONG Oidчисловой идентификатор, определяющий тип запроса/установки операции, выполняемой адаптером при помощи функции PacketRequest (см. далее);

·        ULONG Lengthдлина поля Data;

·        UCHAR Dataданные, передаваемые адаптеру или принимаемые от него.

4.     Структура bpf_insn содержит одиночную машинную инструкцию интерпретатора BPF, и используется для передачи программы фильтра драйверу:

·        USHORT codeсодержит тип инструкции и режимы адресации;

·        UCHAR jt, UCHAR jfсодержат смещение к следующей инструкции при необходимости условного перехода по результатам выполнения текущей инструкции «истина» (jt) или «ложь» (jf);

·        int kзарезервировано.

5.     Структура bpf_program является указателем на программу BPF-фильтра и используется функцией PacketSetBPF для установки фильтра в драйвере:

·        UINT bf_lenразмер программы-фильтра;

·        struct bpf_insn *bpf_insnsуказатель на первую инструкцию программы.

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

·        struct timeval:

tv_secдата захвата в стандартном формате UNIX (число секунд, начиная с 1/1/1970);

tv_usecмикросекунды захвата;

·        UINT bh_caplenдлина снимка (захваченной порции данных);

·        UINT bh_datalenреальная длина захваченного пакета;

·        USHORT bh_hdrlenразмер структуры bpf_hdr.

7.     Структура bpf_stat используется для получения статистической информации о текущей сессии:

·        UINT bs_recvчисло пакетов, принятых адаптером с момента начала сессии;

·        UINT bs_dropчисло потерянных пакетов с момента начала сессии.

8.     Структура NetType используется функцией PacketGetNetType для получения информации о типе текущего адаптера:

·        UINT LinkTypeтип текущего сетевого адаптера;

·        UINT LinkSpeedскорость адаптера в битах в секунду.

Первые две структуры используются только драйвером, тогда как остальные  были заданы в библиотеке Libpcap. Эта группа структур используется для выполнения таких операций, как установка фильтра или интерпретация данных, поступающих от драйвера. На самом деле для взаимодействия с приложениями драйвер использует синтаксис, схожий с синтаксисом BPF, поэтому формат этих структур одинаков.

Функции библиотеки packet.dll

Библиотека packet.dll предоставляет набор функций, которые позволяют принять или отправить пакет произвольной структуры, запросить или установить параметры сетевого адаптера, получить дескрипторы динамически размещаемых структур типа PACKET, установить или снять BPF-фильтр, изменить размер буфера драйвера и получить статистическую информацию о текущей сессии.

Имеются следующие функции:

·        ULONG PacketGetAdapterNames (PTSTR pStr, PULONG BufferSize)предназначена для получения информации об адаптерах, установленных в системе. Функция опрашивает регистр ОС, производит OID-вызовы драйвера пакетов и записывает имена установленных сетевых адаптеров и их описание в заданный пользователем буфер pStr. BufferSizeразмер этого буфера. Формат данных, записываемых в буфер, отличен для версий Windows 95/98 и WindowsNT/2000, из-за разницы в кодировках строк у этих ОС (Windows 95/98 использует кодировку ASCII, Windows NT/2000 – UNICODE).

·        LPADAPTER PacketOpenAdapter (LPSTR AdapterName)предназначена для инициализации адаптера. Функции передается имя адаптера в качестве аргумента AdapterName (получено с помощью PacketGetAdapterNames), результатом функции является указатель на структуру ADAPTER открытого адаптера.

·        VOID PacketCloseAdapter (LPADAPTER lpAdapter) – высвобождает структуру ADAPTER, связанную с указателем lpAdapter, и закрывает адаптер, связанный с ней.

·        LPPACKET PacketAllocatePacket (void)определяет положение структуры PACKET, инициализированной функцией PacketInitPacket, и возвращает указатель на нее.

·        VOID PacketInitPacket (LPPACKET lpPacket, PVOID Buffer, UINT Length)инициализирует структуру PACKET и имеет следующие аргументы:

o       lpPacketуказатель на инициализируемую структуру;

o       Bufferуказатель на буфер, задаваемый пользователем и содержащий данные пакета;

o       Lengthдлина буфера – максимальный размер данных, которые могут быть переданы драйвером приложению за один сеанс чтения.

·        VOID PacketFreePacket (LPPACKET lpPacket)высвобождает структуру PCAKET, связанную с указателем lpPacket.

·        VOID PacketReceivePacket (lpAdapter AdapterObject, LPPACKET lpPacket, BOOLEAN Sync)выполняет захват группы пакетов, и имеет следующие аргументы:

o       AdapterObjectуказатель на структуру ADAPTER, определяющую адаптер, который будет задействован в текущей сессии;

o       lpPacket – указатель на структуру PACKET, используемую для записи принятых пакетов;

o       Sync – флаг, определяющий режим выполнения операции. Если выбран синхронный режим (True), функция блокирует программу до завершения операции. Если выбран асинхронный режим (False), блокировки не происходит. В последнем случае необходимо использовать функцию PacketWaitPaket для корректного выполнения операции.

Число принятых пакетов зависит от количества пакетов, сохраненных в буфере драйвера, размера этих пакетов и размера буфера, связанного со структурой lpPacket. Ниже показан формат передачи данных приложению драйвером.

 

Пакеты сохраняются в буфере структуры lpPacket. Каждый пакет имеет трейлер, состоящий из структуры bpf_hdr и содержащий информацию о длине пакета и времени его приема. Поле Padding используется для выравнивания данных в буфере. Поля bf_datalen и bf_hdrlen структуры bpf_hdr используются для извлечения пакетов из буфера. Заметим, что Pcap извлекает каждый пакет до того, как передать его приложению.

·        BOOLEAN PacketWaitPacket (LPADAPTER AdapterObject, LPPACKET lpPacket)используется для корректного завершения операции ввода/вывода драйвера захвата пакетов. Она является блокирующей в том случае, если драйвер выполняет операцию ввода/вывода. Функция возвращает значение True, если операция завершена успешно, в противном случае – False. Используя функцию GETLASTERROR, можно получить код возникшей ошибки.

·        BOOLEAN PacketSendPacket (LPADAPTER AdapterObject, LPPACKET lpPacket, BOOLEAN Sync)позволяет передать сформированный пользователем пакет ПРОИЗВОЛЬНОЙ СТРУКТУРЫ в сеть через адаптер, заданный переменной AdapterObject. При этом пользователь программным образом создает заголовок пакета, заполняет его данными и отправляет его в сеть «как есть». Формировать структуру bpf_hdr перед заголовком отправляемого пакета не нужно. Также нет необходимости рассчитывать CRC пакета, поскольку она будет автоматически рассчитана сетевым интерфейсом и помещена в конце блока данных. Функция имеет те же аргументы, что и PacketReceivePacket.

Возможности данной функции дополняет функция PacketSetNumWrites, которая устанавливает число повторов передачи одного пакета при вызове функции PacketSendPacket.

·        BOOLEAN PacketResetAdapter (LPADAPTER AdapterObject) - сбрасывает адаптер, указанный в качестве аргумента.

·        BOOLEAN PacketSetHwFilter (LPADAPTER AdapterObject, ULONG Filter)устанавливает аппаратный (hardware) фильтр входящих пакетов. Константы, с помощью которых задается фильтр, объявлены в файле ntddndis.h. В качестве аргументов функции задается адаптер, на который устанавливается фильтр, и идентификатор фильтра. Функция возвращает значение True, если операция выполнена успешно. Ниже перечислены наиболее часто используемые фильтры:

o       NDIS_PACKET_TYPE_PROMISCUOUS: каждый входящий пакет принимается адаптером;

o       NDIS_PACKET_TYPE_DIRECTED: принимаются пакеты, предназначенные для данной рабочей станции;

o       NDIS_PACKET_TYPE_BROADCAST: принимаются только широковещательные запросы;

o       NDIS_PACKET_TYPE_MULTICAST: принимаются пакеты, предназначенные группе, которой принадлежит рабочая станция;

o       NDIS_PACKET_TYPE_ALL_MULTICAST: принимаются пакеты любой группы.

·        BOOLEAN PacketRequest (LPADAPTER AdapterObject, BOOLEAN Set, PACKET_OID_DATA OidData)предназначена для выполнения запроса/установки параметров адаптера AdapterObject. Эта функция используется для получения значений различных параметров сетевого адаптера (размер внутреннего буфера, скорость соединения, значение счетчика пакетов и др.) или их изменения. Второй аргумент определяет тип операции (Set=1 – установка параметра, Set=0 – запрос на получение значения параметра). Третий аргумент – указатель на структуру PACKET_OID_DATA, определяющую параметр адаптера. Функция возвращает True, если операция была выполнена без ошибок.

·        BOOLEAN PacketSetBuff (LPADAPTER AdapterObject, int dim) - устанавливает новый размер буфера драйвера, связанного с адаптером AdapterObject. dim – новый размер буфера. Функция возвращает True, если операция была выполнена успешно, False – если для выполнения операции недостаточно памяти. При установке нового размера буфера все данные, находящиеся в нем, стираются.

·        BOOLEAN PacketSetBpf (LPADAPTER AdapterObject, struct bpf_program *fp)связывает новый BPF-фильтр с адаптером AdapterObject. Фильтр, указанный *fp, представляет собой набор инструкций, которые будут выполняться после приема каждого входящего пакета. Функция возвращает значение True, если фильтр установлен успешно, False – если программа-фильтр не принята драйвером.

Фильтр может быть создан автоматически путем вызова функции pcap_compile библиотеки libpcap. При этом происходит преобразование текстового фильтра (синтаксис фильтра описан в предыдущей статье) в программу BPF. Если использование функций libpcap нецелесообразно, имеется возможность получения исходного кода путем запуска программы WinDump с указанием текстового фильтра и ключей -d, -dd или -ddd. Полученный псевдокод можно использовать в функции PacketSetBpf.

·        BOOLEAN PacketGetStats (LPADAPTER AdapterObject, struct bpf_stst *s) – с помощью этой функции программист может получить значение двух внутренних переменных драйвера:

o       число пакетов, принятых адаптером AdapterObject, с момента его открытия при помощи функции PacketOpenAdapter;

o       число пакетов, принятых адаптером, но проигнорированных ядром. Пакет игнорируется в том случае, если приложение пользователя не готово принять его и буфер, связанный с адаптером, заполнен.

В структуру bpf_stat драйвер записывает два значения:

·        большое значение переменной bs_receive означает, что трафик сети весьма высок. Если приложению нет необходимости принимать все входящие пакеты, рекомендуется установить избирательный фильтр BPF для уменьшения числа обрабатываемых приложением пакетов.

·        если значение переменной bs_drop выше нуля, приложение пользователя не успевает обрабатывать входящие пакеты и теряет их. В этом случае рекомендуется увеличить размер буфера при помощи функции PaсketSetBuff, увеличить размер буфера в структуре PACKET либо оптимизировать алгоритм приложения.

·        BOOLEAN PacketGetNetType (LPADAPTER AdapterObject, NetType *type) – записывает тип адаптера AdapterObject в структуру NetType. Переменной LinkType структуры может быть присвоено одно из следующих значений:

o       NdisMedium802_3: Ethernet (802.3)

o       NdisMedium802_5: Token Ring (802.5)

o       NdisMediumFddi: FDDI

o       NdisMediumWan: WAN

o       NdisMediumLocalTalk: LocalTalk

o       NdisMediumDix: DIX

o       NdisMediumAtm: ATM

o       NdisMediumArcnetRaw: ARCNET (raw)

o       NdisMediumArcnet878_2: ARCNET (878.2)

o       NdisMediumWirelessWan: Различные NdisWireless Ххх.

Переменная LinkSpeed содержит скорость передачи данных по сети в битах в секунду. Функция возвращает значение True, если операция выполнена успешно.

·        BOOLEAN PacketSetReadTimeout (LPADAPTER AdapterObject, int timeout) – устанавливает время ожидания (аргумент timeout) входящего пакета, по истечении которого все пакеты, сохраненные в буфере, будут переданы приложению.

·        BOOLEAN PacketSetMode (LPADAPTER AdapterObject, int mode) - переводит адаптер AdapterObject в режим работы mode, имеющий два возможных значения:

o       MODE_CAPT – стандартный режим захвата, устанавливается по умолчанию после вызова функции PacketOpenAdapter;

o       MODE_STAT – режим статистики. В этом режиме драйвер не перехватывает пакеты, а производит лишь подсчет принятых пакетов и принятых байт. Эти значения могут быть запрошены приложением путем вызова функции PacketReceivePacket. Приложение имеет возможность получать данную информацию периодически по истечении времени ожидания, которое по умолчанию составляет 1 секунду, но может быть изменено на другое значение с дискретностью 1 мС при помощи функции PacketSetReadTimeout.

Для того, чтобы работать в режиме статистики, приложению необходимо выполнить следующие операции:

o       открыть адаптер

o       установить режим статистики функцией PacketSetMode

o       установить фильтр, определяющий тип подсчитываемых пакетов, функцией PacketSetBpf

o       установить необходимое время ожидания при помощи PacketSetReadTimeout

o       принять результаты при помощи PacketReceivePacket.

При этом функция PacketReceivePacket возвращает число принятых пакетов и число принятых байт, удовлетворяющих требованиям установленного фильтра, за последний временной интервал. Эти значения являются 64-битными целыми числами, и снабжены заголовком, определяемым структурой bpf_hdr:

struct timeval bh_tstamp

UINT bh_caplen=16

UINT bh_datalen=16

USHORT bh_hdrlen=18

LARGE_INTEGER PacketsAccepted

LARGE_INTEGER BytesAccepted

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

·        BOOLEAN PacketSetNumWrites (LPADAPTER AdapterObject, int nwrites)определяет число повторов одиночной операции передачи данных (аргумент nwrites). По умолчанию nwrites=1, однако при помощи этой функции значение можно изменить. Так, если установлено 5 повторов, то вместо одного пакета, отправляемого при помощи вызова PacketReceivePacket, будет отправлено 5 копий этого пакета.

Создание приложения с использованием библиотеки packet.dll

Метод создания приложения рассмотрим на примере программы Traffic Generator. Эта простая программа показывает, как создать пакет произвольной структуры и отправить его в сеть при помощи драйвера захвата пакетов. Напоминаем, что программа может быть откомпилирована под Win32 в среде Microsoft Visual C++ 6.0 (не забудьте предварительно установить библиотеку libpcap и выполнить настройку переменных среды для обеспечения возможности компиляции программ, использующих эту библиотеку). Для работы программы под Win32 необходимо установить драйвера WinPCap.

Traffic Generator представляет собой имитатор сетевого трафика. В качестве исходных данных при запуске программы необходимо указать три параметра: имя используемого интерфейса, число отправляемых пакетов и их размер. Генерируемые пакеты в качестве источника имеют MAC-адрес 1:1:1:1:1:1, и адрес 2:2:2:2:2:2 в качестве приемника.

Исходный код программы Traffic Generator приведен ниже.

#include <windows.h>

#include <stdio.h>

#include <conio.h>

#include <time.h>

 

#include "..\..\Include\packet32.h" //подключаем заголовочный файл библиотеки packet.dll

 

// задаем переменные

#define SIMULTANEOU_READS 10

#define MAX_ETHERNET_FRAME_SIZE 1514

#define Max_Num_Adapter 10 //максимальное число адаптеров

 

// Prototypes

 

void PrintPackets(LPPACKET lpPacket); // печать пакетов

 

char AdapterList[Max_Num_Adapter][1024];// список адаптеров – по 1024 байт на адаптер

 

 

 

int main(int argc, char **argv)

{

      

       char packetbuff[5000];// буфер для данных пакета

      

       // указатель на структуру ADAPTER

      

       LPADAPTER  lpAdapter = 0;

      

       // указатель на структуру PACKET

      

       LPPACKET   lpPacket;

      

       int        i,npacks,Snaplen;

       DWORD      dwErrorCode;

      

       DWORD dwVersion;

       DWORD dwWindowsMajorVersion;

      

       // строки формата unicode (winnt)

       WCHAR        AdapterName[512]; // строка, содержащая список сетевых адаптеров

       WCHAR        *temp,*temp1;

      

       // строки формата ascii (win95)

       char         AdapterNamea[512]; // строка, содержащая список сетевых адаптеров  char          *tempa,*temp1a;

      

       int                 AdapterNum=0,Open;// номер адаптера

       ULONG        AdapterLength; // длина

      

       float  cpu_time;

      

       printf("Генератор сетевого трафика v 0.9999\nCopyright 1999 Loris Degioanni (loris@netgroup-serv.polito.it)");

       printf("\nОтправляет группу пакетов в сеть.");

      

       if (argc == 1){

             printf("\n\n Параметры: tg [-i адаптер] -n число_пакетов -s размер");

             printf("\n размер в пределах от 60 до 1514\n\n");

             return -1;

       }

      

      

       AdapterNamea[0]=0; // инициализация переменной

      

       // получение параметров командной строки

       for(i=1;i<argc;i+=2){

            

             switch (argv[i] [1])

             {

                   

             case 'i':

                    sscanf(argv[i+1],"%s",AdapterNamea);

                    break;

                   

             case 'n':

                    sscanf(argv[i+1],"%d",&npacks);

                    break;

                   

             case 's':

                    sscanf(argv[i+1],"%d",&Snaplen);

                    break;

                   

             }

            

       }

      

      

      

       if(AdapterNamea[0]==0){

             // если имени адаптера при запуске не указано

             // получаем имена адаптеров, установленных в системе

             AdapterLength=1024;

            

             printf("Установленные адаптеры:\n");

             i=0;// номер первого адаптера

            

       // формат данных, возвращаемых PacketGetAdapterNames различен в Win95 и в WinNT.

       // из-за разных кодировок

// поэтому необходимо проверить версию ОС, на которой работает программа

             dwVersion=GetVersion();

             dwWindowsMajorVersion =  (DWORD)(LOBYTE(LOWORD(dwVersion)));

             if (!(dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4))

             {  // Windows NT

                    //получаем список имен адаптеров, записанных в строку AdapterName

                    PacketGetAdapterNames(AdapterName,&AdapterLength);

                    temp=AdapterName;// работать будем не с AdapterName, а

                    temp1=AdapterName;// с temp и c temp1

             while ((*temp!='\0')||(*(temp-1)!='\0'))// конец списка – два нуля

// ASCII

             // имя записывается в соотв. строку массива AdapterNames

                    {

                           if (*temp=='\0')// один ноль ASCII разделяет имена адаптеров

                           {

                           // копируем имя адаптера в массив из temp1, длина имени

                           // рассчитывается при помощи temp

                                  memcpy(AdapterList[i],temp1,(temp-temp1)*2);

                                  temp1=temp+1;

                                  i++;

                           }

                          

                           temp++;

                    }

                   

                    AdapterNum=i;// число установленных адаптеров

                    for (i=0;i<AdapterNum;i++)

                           wprintf(L"\n%d- %s\n",i+1,AdapterList[i]);// печатаем список

                    printf("\n");

                   

             }

            

             else   //windows 95

             // обработка осуществляется аналогично, за исключением того, что

             // длина имени рассчитывается для кодировки ascii

             {

                    PacketGetAdapterNames(AdapterNamea,&AdapterLength);

                    tempa=AdapterNamea;

                    temp1a=AdapterNamea;

                   

                    while ((*tempa!='\0')||(*(tempa-1)!='\0'))

                    {

                           if (*tempa=='\0')

                           {

                                  memcpy(AdapterList[i],temp1a,tempa-temp1a);

                                  temp1a=tempa+1;

                                  i++;

                           }

                           tempa++;

                    }

                   

                    AdapterNum=i;

                    for (i=0;i<AdapterNum;i++)

                           printf("\n%d- %s\n",i+1,AdapterList[i]);

                    printf("\n");

                   

             }

            

             do

             {

                    printf("Выберите номер открываемого адаптера : ");scanf("%d",&Open);

                    if (Open>AdapterNum) printf("\nНомер должен быть меньше %d",AdapterNum);

             } while (Open>AdapterNum);

            

            

            

            

             lpAdapter =   PacketOpenAdapter(AdapterList[Open-1]);// открываем адаптер

             // -1, поскольку номера печатались от 1, а первый адаптер в системе

//имеет номер 0

             // если указатель не был получен, или поле hFile содержит значение

// INVALID_HANDLE_VALUE, открыть адаптер не удалось.

// Код ошибки можно прочитать при помощи GetLastError

             if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))

             {

                    dwErrorCode=GetLastError();

                    printf("Unable to open the driver, Error Code : %lx\n",dwErrorCode);

                   

                    return(-1);

             }     

            

       }

       // если было указано имя адаптера, то обработка ошибки аналогична

       else{

            

             lpAdapter =  PacketOpenAdapter(AdapterNamea);

            

             if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))

             {

                    dwErrorCode=GetLastError();

                    printf("Unable to open the driver, Error Code : %lx\n",dwErrorCode);

                   

                    return(-1);

             }

            

       }

      

       // устанавливаем сетевой адаптер в режим приема всех пакетов

       PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS);

 

       // ошибка, если не был получен указатель на структуру PACKET

       if((lpPacket = PacketAllocatePacket())==NULL){

             printf("\nОшибка: невозможно обнаружить структуру LPPACKET.");

             return (-1);

       }

 

// так побайтно создается пакет произвольной структуры.

// пакет отправляется в сеть в таком виде, в каком он записан в буфере,

// поэтому программисту нужно самому создавать заголовки и т.д.

 

       packetbuff[0]=1;

       packetbuff[1]=1;

       packetbuff[2]=1;

       packetbuff[3]=1;

       packetbuff[4]=1;

       packetbuff[5]=1;

      

       packetbuff[6]=2;

       packetbuff[7]=2;

       packetbuff[8]=2;

       packetbuff[9]=2;

       packetbuff[10]=2;

       packetbuff[11]=2;

      

       for(i=12;i<1514;i++){

             packetbuff[i]=i%256;

       }

 

// пакет сформирован

 

 

       PacketInitPacket(lpPacket,packetbuff,Snaplen);

       // инициализация структуры PACKET в соответствии с данными

       // Snaplen – размер пакета

      

       // устанавливаем количество пакетов

       PacketSetNumWrites(lpAdapter,npacks);

      

       printf("\n\nСгенерировано %d пакетов...",npacks);

      

       cpu_time = clock (); // начало времени передачи

      

       // отправляем пакеты в синхронном режиме

       PacketSendPacket(lpAdapter,lpPacket,TRUE);

      

       cpu_time = (clock() - cpu_time)/CLK_TCK; //вычисляем время, затраченное на передачу

      

       printf ("\n\nВремя передачи: %5.3f\n", cpu_time);

       printf ("\nСгенерировано пакетов = %d", npacks);

       printf ("\nСгенерировано байт = %d", (Snaplen+24)*npacks);

       printf ("\nСгенерировано бит = %d", (Snaplen+24)*npacks*8);

       printf ("\nСкорость передачи пакетов/сек. = %d", (int)((double)npacks/cpu_time));

       printf ("\nСкорость передачи байт/сек. = %d", (int)((double)((Snaplen+24)*npacks)/cpu_time));

       printf ("\nСкорость передачи бит/сек. = %d", (int)((double)((Snaplen+24)*npacks*8)/cpu_time));

       printf ("\n");

      

       PacketFreePacket(lpPacket);// высвобождаем структуру

      

       // закрываем адаптер и выходим из программы

      

       PacketCloseAdapter(lpAdapter);

       return (0);

Заключение

В заключении приведем несколько советов по созданию высокопроизводительных приложений:

1.     Размер буфера драйвера и буфера структуры PACKET является очень важным параметром, определяющим быстродействие приложения. Если буфер драйвера создается библиотекой packet.dll, то его размер равен 0 (libpcap создает буфер размером 1 мегабайт), что означает очень низкую производительность. Рекомендуемый размер буфера драйвера – 512 кБ, буфера структуры PACKET – 256 кБ и выше.

2.     Установите фильтр на входящие пакеты и отсеивайте пакеты, не нужные приложению. Если в данных пакетов нет необходимости, создайте фильтр, оставляющий только заголовки (первые 68 байт) пакетов.

3.     При проведении статистического анализа трафика в реальном времени используйте статистический режим.

Этой статьей мы закончили обзор средств архитектуры WinPCap, но мы надеемся, что Ваши практические изыскания на этом не закончатся. Как говорится, творите, выдумывайте, пробуйте! Напоминаем, что дистрибутив WinPCap вы можете скачать с сайта http://www.cherepovets-city.ru/insecure или с сайта разработчика http://netgroup-serv.polito.it/winpcap. Вся документация по WinPCAP, правда, на английском языке, доступна по этому же адресу. Ваши вопросы отправляйте по адресу alex@cherepovets-city.ru.

Rambler's Top100 ???????@Mail.ru