Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Подсчет траффик на Delphi (http://forum.oszone.net/showthread.php?t=42614)

fossil 17-12-2004 10:16 280868

Подсчет траффик на Delphi
 
Помогите написать подсчет траффик на Delphi... Я бы хотел чтобы она могла считать и локальный и глобальный траффик. Киньте сорцы или дайте линк плиз...

fossil 20-12-2004 16:21 281810

Мне надо чтобы программа просто перехватывала траффик с подключения. Как это сделать? :(

Netscaper 20-12-2004 16:39 281815

Код:

#include <conio.h>
#include <stdio.h>
#include <winsock2.h>

#define MAX_PACKET_SIZE    0x10000
#define SIO_RCVALL        0x98000001
// Буфер для приёма данных
char Buffer[MAX_PACKET_SIZE]; // 64 Kb

//Структура заголовка IP-пакета

typedef struct IPHeader {
  UCHAR  iph_verlen;  // версия и длина заголовка
  UCHAR  iph_tos;      // тип сервиса
  USHORT  iph_length;  // длина всего пакета
  USHORT  iph_id;      // Идентификация
  USHORT  iph_offset;  // флаги и смещения
  UCHAR  iph_ttl;      // время жизни пакета
  UCHAR  iph_protocol; // протокол
  USHORT  iph_xsum;    // контрольная сумма
  ULONG  iph_src;      // IP-адрес отправителя
  ULONG  iph_dest;    // IP-адрес назначения
} IPHeader;

char src[10];
char dest[10];
char ds[15];
unsigned short lowbyte;
unsigned short hibyte;

void main()
{
  WSADATA    wsadata;  // Инициализация WinSock.
  SOCKET      s;        // Cлущающий сокет.
  char        name[128]; // Имя хоста (компьютера).
  HOSTENT*    phe;      // Информация о хосте.
  SOCKADDR_IN sa;        // Адрес хоста
  IN_ADDR sa1;        //
  unsigned long        flag = 1;  // Флаг PROMISC Вкл/выкл.

  // инициализация
  WSAStartup(MAKEWORD(2,2), &wsadata);
  s = socket( AF_INET, SOCK_RAW, IPPROTO_IP );
  gethostname(name, sizeof(name));
  phe = gethostbyname( name );
  ZeroMemory( &sa, sizeof(sa) );
  sa.sin_family = AF_INET;
  sa.sin_addr.s_addr = ((struct in_addr *)phe->h_addr_list[0])->s_addr;
  bind(s, (SOCKADDR *)&sa, sizeof(SOCKADDR));
 
  // Включение promiscuous mode.
  ioctlsocket(s, SIO_RCVALL, &flag);

  // Бесконечный цикл приёма IP-пакетов.
  while( !_kbhit() )
  {
    int count;
    count = recv( s, Buffer, sizeof(Buffer), 0 );
    // обработка IP-пакета
    if( count >= sizeof(IPHeader) )
    {
      IPHeader* hdr = (IPHeader *)Buffer;
      //Начинаем разбор пакета...

        strcpy(src,"Пакет: ");
        CharToOem(src,dest);
        printf(dest);
        // Преобразуем в понятный вид адрес отправителя.
        printf("From ");
        sa1.s_addr = hdr->iph_src;
        printf(inet_ntoa(sa1));

        // Преобразуем в понятный вид адрес получателя.
        printf(" To ");
        sa1.s_addr = hdr->iph_dest;
        printf(inet_ntoa(sa1));

        // Вычисляем протокол. Полный список этих констант
        // содержится в файле winsock2.h
        printf(" Prot: ");
        if(hdr->iph_protocol == IPPROTO_TCP) printf("TCP ");
        if(hdr->iph_protocol == IPPROTO_UDP) printf("UDP ");

        // Вычисляем размер. Так как в сети принят прямой порядок
        // байтов, а не обратный, то прийдётся поменять байты местами.
        printf("Size: ");
        lowbyte = hdr->iph_length>>8;
        hibyte = hdr->iph_length<<8;
        hibyte = hibyte + lowbyte;
        printf("%s",itoa(hibyte,"",10));

        // Вычисляем время жизни пакета.
        printf(" TTL:%s",itoa(hdr->iph_ttl,"",10));
        printf("\n");

    }
  }

  closesocket( s );
  WSACleanup();
}

Для успешной компиляции, необходимо подключить к проекту файл ws2_32.lib. :insane:

Netscaper 20-12-2004 16:42 281818

(C) Ishodnik.ru... Подумал... Так... Для справки :)

fossil 20-12-2004 17:29 281840

Netscaper
Блин... вроде это на С++ :)
А на этом сайте нету кода на дельфи :(
Я в С++ вообще не соображаю, если кто сможет переписать плз :)

Netscaper 20-12-2004 18:09 281854

Я перепишу на Delphi как только время появится... Завтра, скорее.

fossil 20-12-2004 19:27 281870

Netscaper
Ок спасибо огромное. Ты настоящий друг :)

Netscaper 21-12-2004 01:09 281964

Держи. Конечно, в Delphi такое лучше не делать - мозги свернешь...
Рабочая консольная версия. Всё же рекомендуется поизучать socket'ы.
У меня вроде работает... Оказывается в сетке два компа broadcast шлют, может, игровые серверы?
Код:

program Sniffer;

// Translated by Netscaper :)

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows, WinSock;

const
  // Максимальный размер пакета
  MaxPacketSize = 65536;
  // Принимаем все пакеты
  SIO_RCVALL = $98000001;

type
  // Список адресов машины
  PInAddrList = ^TInAddrList;
  TInAddrList = Array[0..255] of PInAddr;
  // Заголовок Ip4
  PIPHeader = ^TIPHeader;
  TIPHeader = record
    verlen, tos : Byte;
    length, id, offset : Word;
    ttl, protocol : Byte;
    xsum : Word;
    src, dest : Cardinal;
  end;

// Получаем IP-адрес (ненавижу PChar и inet_ntoa)
function get_ip4(ip4 : Cardinal): string;
begin
  Result := IntToStr(Lo(LoWord(ip4))) + '.' +
            IntToStr(Hi(LoWord(ip4))) + '.' +
            IntToStr(Lo(HiWord(ip4))) + '.' +
            IntToStr(Hi(HiWord(ip4)));
end;

var
  // практически всё то же, что и на C++
  hdr : PIPHeader;
  buffer : Array[0..MaxPacketSize - 1] of byte;
  wsa : WSADATA;
  s, size : Integer;
  hostname : Array[0..127] of char;
  phe : Phostent;
  sa : sockaddr_in;
  flag : Integer;
  Len : Word;
  outstr : String;
  inaddrlist : PInAddrlist;

begin
  flag := 1;
  // Иницилизируем
  WSAStartup(2, wsa);
  s := socket(AF_INET, SOCK_RAW, IPPROTO_IP);
  // Получаем название нашего хоста
  gethostname(@hostname, 128);
  // Получаем информацию о хосте
  phe := gethostbyname(@hostname);
  FillChar(sa, sizeof(sa), 0);
  inaddrlist := PInAddrList(phe.h_addr_list);
  // Привязываемся к нашему сокету :)
  sa.sin_family := AF_INET;
  sa.sin_addr.S_addr := inaddrlist^[0].S_addr;
  if (bind(s, sa, sizeof(sa)) = SOCKET_ERROR) then
  begin
    // Ошибка
    flag := WSAGetLastError;
    writeln('bind fails.result=',flag);
    readln;
    halt;
  end;
  // Выбираем режим "прослушки"
  ioctlsocket(s, SIO_RCVALL, flag);
  while(true) do
  begin
    // Ждем пакет :)
    size := recv(s, Buffer, sizeof(Buffer), 0);
    if (size = SOCKET_ERROR) then
    begin
      // Бывают же глюки :)
      flag := WSAGetLastError; break;
    end;
    // Если пакет имеет размер с заголовок или больше, то это - хорошо :)
    if (size >= sizeof(TIPHeader)) then
    begin
      // Печатаем
      hdr := PIPHeader(@Buffer);
      outstr := 'Packet from ' + get_ip4(hdr.src) +
      ' to ' + get_ip4(hdr.dest) + ', protocol ';

      if hdr.protocol = IPPROTO_TCP then outstr := outstr + 'TCP';
      if hdr.protocol = IPPROTO_UDP then outstr := outstr + 'UDP';

      outstr := outstr + ', size ';
      Len := hdr.length shl 8 + hdr.length shr 8;
      outstr := outstr + IntToStr(Len) + ', TTL ' + IntToStr(hdr.ttl);
      writeln(outstr);
    end;
  end;
  // Теоретически, у нас бесконечный цикл, но после использования лучше
  // закрыть сокет и освободить WS2_32.DLL
  writeln('flag=',flag);
  readln;
  closesocket(s);
  WSACleanup;

end.


fossil 21-12-2004 07:50 281992

Netscaper Нда уж... тут ты прав (про мозги) :)
Сейчас попробую.. спасибо.

fossil 21-12-2004 10:13 282003

Если кто-нибудь найдет другую реализацию, пожалуйста выкладывайте сюда :)

Netscaper 21-12-2004 12:23 282036

В чём проблема? Нельзя сосчитать исходящий/входящий трафик? Сделай фильтр по нужным хостам.

fossil 21-12-2004 13:44 282053

Netscaper
Да нет, все ок... впринципе можно сделать все :)
Перепишу только ее под форму и тогда вообще ок будет..
Просто может быть у кого-нибудь есть еще варианты :)
У меня вот еще вопрос... размер пакета указывается ведь в байтах?

Netscaper 21-12-2004 13:56 282058

Разумеется, всё в байтах. Лучше запихни обработку в отдельный Thread, а то у тебя же тогда накроется основной поток, т.к. recv ожидает пакеты, т.е. во время ожидания будет «накрывать» основной поток.

fossil 21-12-2004 14:12 282062

Netscaper
Что-то у меня не получается под форму засунуть :((((((((((

Netscaper 21-12-2004 14:30 282072

В плане?

Netscaper 21-12-2004 14:47 282077

Вот, то же самое, только на Delphi c окошками.
[Вложение удалено]

fossil 21-12-2004 16:17 282103

Netscaper
Ок спасибо, сейчас посмотрю
Аааааа :) все донал...

fossil 21-12-2004 16:24 282105

Слушай... дак тут пакеты то не только которые идут ко мне... тут вообще какие-то левые пакеты?!
Или это все пакеты идут ко мне?
Хм... а как мне ловить не сетевой траффик, а инетовский? :)
Сори если надоел... я программер самоучка ;)

Netscaper 21-12-2004 16:29 282107

Естественно, мне тоже. Оставляй те, которые идут от тебя или к тебе. Инетовский очень просто - трафик на шлюз или прокси (конкрентный компьютер в сети).

fossil 21-12-2004 16:33 282108

Netscaper
Ок. Ясно. Пойду пробовать, если что напишу :)
Кст. А как отфильтровать на себя или от себя?

Netscaper 21-12-2004 16:50 282109

Сделал фильтр. Укажи в полях "dest" и "src" IP-адреса твоей машины и шлюза в интернет. Посмотри, как работает (т.е. зайди на какой-нибудь сайт). Останутся входящие и исходящие твои.
[Вложение удалено]

fossil 21-12-2004 17:09 282113

Хммм.. А dest и src за что отвечают? dest это локальный адрес машины, а src адрес шлюза в инет? Интересно... а если вообще как-нибудть левый тип юзает мою прогу :D ... ему что сорцы тепепрь менят..
А никак нельзя просто перехватить значения с соединения (будь этот инет или лвс)? Просто те которые указаны там "Отправлено" и "Получено". Мне впринципе кроме этих параметров ничего и не надо...
Нифига мы с тобой уже вторую страницу открыли ;)
Кстати, как ты подгружаешь файлы?

Netscaper 21-12-2004 17:22 282118

Понимаешь, программа ловит все, которые валятся к тебе, даже если они напрямую твоему хосту не предназначены. Иными словами, тебе приходят пакеты у которых в заголовке указано, хост-получатель и хост-отправитель (dest и src). Например, ты работаешь в сети со шлюзом (твой-192.168.0.1, шлюз-192.168.0.2). Когда ты делаешь запрос на какой-то сайт, ты отправляешь сообщения (dest-192.168.0.2,src-192.168.0.1) шлюзу, когда получаешь ответ (страницы HTML, файлы и т.п), ты получаешь сообщения от шлюза (dest-192.168.0.1,src-192.168.0.2). Таким образом, тебе надо оставлять сообщения, у которых dest твой и шлюза и src твой и шлюза (трафик в обоих направлениях). Если ты хочешь посчитать только входящий трафик, то тебе надо оставлять сообщения, где dest - твой компьютер, а src - шлюз.
Цитата:

Нифига мы с тобой уже вторую страницу открыли
... У меня уже третья (по десять).
Цитата:

Кстати, как ты подгружаешь файлы?
... В «расширенном» режиме внизу появляется...

fossil 21-12-2004 17:35 282123

Netscaper
ясно.
А нельзя никак отловить от соединения? Я имею ввиду что когда к инету цепляешься, в трее появляются телеки :) вот в них написаны сколько отправлено и получено, оттуда нельзя выдернуть никак?

Netscaper 21-12-2004 17:42 282126

Можно. Слушай, скачай себе какой-нибудь TMeter и посмотри как он работает, а то, я подозреваю, что ты не очень разбираешься в сетях :lamer:

fossil 21-12-2004 17:57 282131

Netscaper Хехе.. в сетях то разбираюсь... не разбираюсь в программирование :) А ты думаешь есть компоненты для подсчета траффика? Тогда чего я геморрой ловлю?!

Netscaper 21-12-2004 18:01 282132

Нет, TMeter - это программа которая позволяет считать трафик. Кстати, насчёт компонентов идея неплохая, посмотри на Torry.Net, может, найдешь что-нибудь.

fossil 21-12-2004 18:02 282133

Netscaper
Ок.. ща гляну

fossil 21-12-2004 18:09 282135

Что-то вроде нету :(
А ты знаешь как реализовать перехват с соединения? :)

Netscaper 21-12-2004 18:37 282142

Последний вариант. Я не знаю какой компьютер у тебя в сети выполняет роль шлюза или прокси, так что разбирайся сам, как тебе его определять для подсчёта интернет-трафика. Указываешь машину в сети для которой следует считать трафик, прога тебе все посчитает.

fossil 21-12-2004 18:39 282143

Netscaper
Спасибо.

Netscaper 21-12-2004 18:58 282150

Пожалуйста :oszone:

fossil 21-12-2004 20:03 282164

Вобщем если кто знает как в соединении отлавливать траффик пишите сюда. Или может у кого есть компонент..

DeaDMan77 09-01-2005 16:55 286980

Народ, а можно с помощью этой проги еще порт посмотреть? Если можно, то что нужно добавить?

fossil 10-01-2005 14:15 287248

DeaDMan77
Навреное можно, раз определяется его протокол, значит и сам номер можно :)
Netscaper
Помогай, без тебя не справимся :)

Netscaper 10-01-2005 23:23 287377

По заявкам... Добавил в код сниффера заголовки TCP и UDP, которые содержат номера портов. Программа не претендует на эффективность и оптимальность, но суть, на мой взгляд, отражает. Краткое пояснение. Заголовки TCP и UDP вкладываются внутрь сообщение протокола TCP/IP. Иначе, сначала идет заголовок IP (структура IPHeader) в котором указывается, какой протокол будет использоваться TCP или UDP, в зависимости от этого далее идет либо заголовок TCP (TTCPHeader) или UDP (TUDPHeader). Исходный код прилагается, надеюсь, что страждущие всё же разберутся...

DeaDMan77 11-01-2005 02:11 287425

Вери велл сенькаю :)

А можно еще вопрос? :) Можноли ненужные пакеты блокировать и как насчет других протоколов, типа ICMP?

Netscaper 11-01-2005 08:08 287462

Можно, наверняка. Хотя я и не пытался... Поищи в Google, сложно разве? Надеюсь, смысл моей программы понят, а описания всяких протоколов можно найти тут, ICMP в частности.

fossil 11-01-2005 08:54 287471

Netscaper
Благодарю Вас :)

fossil 11-01-2005 09:07 287474

Только мне не понятно зачем ты два раза прописал hdr.protocol?
Код:

case hdr.protocol of
        IPPROTO_TCP:
        begin
          tcphdr := PTCPHeader(@Buffer[20]);
          outstr := outstr + ':' + IntToStr(InvertWord(tcphdr.srcport));
        end;
        IPPROTO_UDP:
        begin
          udphdr := PUDPHeader(@Buffer[20]);
          outstr := outstr + ':' + IntToStr(InvertWord(udphdr.srcport));
        end;
      end;


Netscaper 11-01-2005 15:19 287565

Я же ясно сказал, что
Цитата:

Программа не претендует на эффективность и оптимальность, но суть, на мой взгляд, отражает
Первый раз - печатается порт отправителя, второй раз - порт получателя. Во второй раз можно было присвоения не писать, но... Блин, спать хотелось... Я и Ctrl-C + Ctrl-V cделал и не мучился...
Кстати, о птичках... Зацени проект http://delphi.about.com/od/fullcodep.../aa112903a.htm

DeaDMan77 11-01-2005 17:53 287608

Че-то ничего по этой ссылке не кажет :(

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

Netscaper 11-01-2005 20:06 287639

Это я для fossil - http://delphi.about.com/od/fullcode...l/aa112903a.htm
Разберись :tongue:

fossil 11-01-2005 21:42 287668

Netscaper
Да я уже просек... у них порты то могут быть разные, я первый раз не сообразил :)
Ща зацению проект, отпишусь...

fossil 11-01-2005 21:49 287671

Netscaper
Слушай... а вот эти левые пакеты которые летают, это бродкосные? Т.е. фактически они нафиг не нужны... так мусор летающий по сети.
DeaDMan77 Интересно как ты собираешься блокировать? :) Если найдешь что-нить интересное создай тему...

Netscaper
Это что пага с компонентами и статьями? :)

Netscaper 11-01-2005 23:54 287702

fossil
Вовсе не обязательно... Broadcast, это, скорее те, у которых destination ip - 255.255.255.255 или, например, 192.168.0.127/24. Может попасться пакет, который к твоему компу вообще отношения не имеет, но, в основном, broadcast.

Про прогу.Эта программка считает траффик с помощью Microsoft IP Helper. Библиотечка такая есть, которая позволяет получать и/или изменять текущие сетевые настройки (сетевые интерфейсы, их IP-адреса, маршрутизацией и т.д. С помощью неё можно отслеживать текущие TCP соединения (UDP прослушки) и их состояние, но, насколько я знаю, нельзя получить объем входящих/исходящих данных. Однако, с помощью неё можно создавать фильтры. Обидно то, что в Platform SDK сказано, что эти функции поддерживаются только серверными системами Windows 2000, 2003. Но я не поленился заглянуть в библиотечку (у меня 2000 Proffesional). Оказалось, что там эти функции есть. Я ещё в сомнениях, но они должны работать...
Скачать конкретно её так - http://delphi.about.com/library/week.../src112903.zip

fossil 12-01-2005 12:14 287831

Netscaper
Я так и понял...
Сейчас скачаю эту библиотеку, посмотрим чего там :) Жаль что не выдирает траф

fossil 12-01-2005 12:38 287841

Netscaper
Хм.... прикольная штучка, правда она у меня какие-то ошибки выдавала на
Код:

self.FAverageOutPerSec := OutTotal div ActiveCountOut
вот я их и закомментировал :)
Вроде запустилась и работат, только траффик немного не совпадает с тем который в соединении (примерно на 100 Кб).
Пойду еще в ней поковыряюсь...

fossil 12-01-2005 13:01 287850

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

Народ если у кого есть еще какие-нить проги или компоненты или статьи, выкладывайте их сюда :)

n1ppl3 30-05-2008 14:02 814484

Разумеется, всё в байтах. Лучше запихни обработку в отдельный Thread, а то у тебя же тогда накроется основной поток, т.к. recv ожидает пакеты, т.е. во время ожидания будет «накрывать» основной поток.

блин а я и смотрю у меня этот сниффер лагает пипец как. а как же сделать два раздельных потока? знает кто?


Время: 01:50.

Время: 01:50.
© OSzone.net 2001-