Привет всем. Подскажите пожалуйста как мне выделить HTTP-трафик из TCP-трафика? т.е. мне нужно чтобы моя программа видела по каким сайтам лазиет пользователь, причем любым браузером. В этом примере я определяю только IP-адреса пакетов, но т.к. если зайти на какуюнибудь страничку сайта, пакетов около 150 и больше приходит... как бы мне сделать, чтобы было просто написано, например "forum.vingrad.ru" один раз. Делаю я так:
| Код | uses WinSock;
...
type USHORT = WORD;
TIPHeader = packed record iph_verlen: UCHAR; // версия и длина заголовка iph_tos: UCHAR; // тип сервиса iph_length: USHORT; // длина всего пакета iph_id: USHORT; // Идентификация iph_offset: USHORT; // флаги и смещения iph_ttl: UCHAR; // время жизни пакета iph_protocol: UCHAR; // протокол iph_xsum: USHORT; // контрольная сумма iph_src: ULONG; // IP-адрес отправителя iph_dest: ULONG; // IP-адрес назначения end; PIPHeader = ^TIPHeader;
TTCPHeader = packed record sourcePort: USHORT; // порт отправителя destinationPort: USHORT; // порт назначения sequenceNumber: ULONG; // номер последовательности acknowledgeNumber: ULONG; // номер подтверждения dataoffset: UCHAR; // смещение на область данных flags: UCHAR; // флаги windows: USHORT; // размер окна checksum: USHORT; // контрольная сумма urgentPointer: USHORT; // срочность end; PTCPHeader = ^TTCPHeader;
TSnifferThread = class(TThread) private WSA: TWSAData; hSocket: TSocket; Addr_in: sockaddr_in; Packet: array [0..$10000 - 1] of Byte; LogData: string; procedure ShowPacket; protected function InitSocket: Boolean; virtual; procedure DeInitSocket(const ExitCode: Integer); virtual; procedure Execute; override; procedure ParcePacket(const PacketSize: Word); virtual; public Host: String; end;
TForm1 = class(TForm) Edit1: TEdit; Button1: TButton; Label1: TLabel; XPManifest1: TXPManifest; Memo1: TMemo; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } TotalPacketCount: Integer; FSnifferThread: TSnifferThread; public { Public declarations } end;
const // Размеры используемых структур IPHeaderSize = SizeOf(TIPHeader); TCPHeaderSize = SizeOf(TTCPHeader);
var Form1: TForm1;
implementation
{$R *.dfm}
// узнаем текущий IP function GetLocalIP: string; var WSAData: TWSAData; Host: PHostEnt; Buf: array [0..127] of Char; begin Result := ''; if WSAStartup($101, WSAData) = 0 then begin if GetHostName(@Buf, 128) = 0 then begin Host := GetHostByName(@Buf); if Host <> nil then Result := iNet_ntoa(PInAddr(Host^.h_addr_list^)^); end; WSACleanup; end; end;
{TSnifferThread}
function TSnifferThread.InitSocket: Boolean; var PromiscuousMode: Integer; begin // инициализируем WinSock Result := WSAStartup($202, WSA) = NOERROR; if not Result then begin LogData := 'Ошибка: ' + SysErrorMessage(WSAGetLastError); Synchronize(ShowPacket); Exit; end; // создаем сокет hSocket := socket(AF_INET, SOCK_RAW, IPPROTO_IP); if hSocket = INVALID_SOCKET then begin DeInitSocket(WSAGetLastError); Exit; end; FillChar(Addr_in, SizeOf(sockaddr_in), 0); Addr_in.sin_family:= AF_INET; // указываем за каким интерфейсом будем следить Addr_in.sin_addr.s_addr := inet_addr(PChar(Host)); // связываем сокет с локальным адресом if bind(hSocket, Addr_in, SizeOf(sockaddr_in)) <> 0 then begin DeInitSocket(WSAGetLastError); Exit; end; // Переключаем интерфейс на прием всех пакетов проходящих через интерфейс - promiscuous mode. PromiscuousMode := 1; if ioctlsocket(hSocket, $98000001, PromiscuousMode) <> 0 then begin DeInitSocket(WSAGetLastError); Exit; end; Result := True; end;
procedure TSnifferThread.DeInitSocket(const ExitCode: Integer); begin // Если была ошибка - выводим ее if ExitCode <> 0 then begin LogData := 'Ошибка: ' + SysErrorMessage(ExitCode); Synchronize(ShowPacket); end; // Закрываем сокет if hSocket <> INVALID_SOCKET then closesocket(hSocket); // Деинициализируем WinSock WSACleanup; end;
procedure TSnifferThread.Execute; var PacketSize: Integer; begin // Производим инициализацию if InitSocket then try // Крутим поток до упора while not Terminated do begin // Ждем получения пакета (блокирующий режим) PacketSize := recv(hSocket, Packet, $10000, 0); // Если есть данные - производим их разбор if PacketSize > SizeOf(TIPHeader) then ParcePacket(PacketSize); end; finally // В конце освобождаем занятые ресурсы DeInitSocket(NO_ERROR); end; end;
procedure TSnifferThread.ParcePacket(const PacketSize: Word); var IPHeader: TIPHeader; TCPHeader: TTCPHeader; SrcPort, DestPort: Word; I, Octets, PartOctets: Integer; PacketType, DumpData, ExtendedInfo: String; Addr, A, B: TInAddr; begin Move(Packet[0], IPHeader, IPHeaderSize); SrcPort := 0; DestPort := 0; ExtendedInfo := ''; // определяем тип протокола if IPHeader.iph_protocol = IPPROTO_TCP then begin PacketType := 'TCP'; // Читаем ТСР заголовок Move(Packet[IPHeaderSize], TCPHeader, TCPHeaderSize); // Смотрим порт отправителя и получателя SrcPort := TCPHeader.sourcePort; DestPort := TCPHeader.destinationPort;
// Пишем IP адрес отправителя с портом Addr.S_addr := IPHeader.iph_src; LogData := inet_ntoa(Addr);
// Выводим все что напарсерили в Memo Synchronize(ShowPacket); end; end;
procedure TSnifferThread.ShowPacket; begin Form1.Memo1.Lines.BeginUpdate; Form1.Memo1.Text := Form1.Memo1.Text + FormatDateTime('c', Now) + ' | ' + LogData + sLineBreak; SendMessage(Form1.Memo1.Handle, WM_VSCROLL, SB_BOTTOM, 0); Form1.Memo1.Lines.EndUpdate; end;
{TForm1}
procedure TForm1.FormCreate(Sender: TObject); begin Edit1.Text := GetLocalIP; end;
procedure TForm1.Button1Click(Sender: TObject); begin if FSnifferThread <> nil then begin FSnifferThread.Terminate; FSnifferThread := nil; Button1.Caption := '>>> Start >>>'; end else begin FSnifferThread := TSnifferThread.Create(True); FSnifferThread.Host := Edit1.Text; FSnifferThread.FreeOnTerminate := True; FSnifferThread.Resume; Button1.Caption := '*** Stop ***'; end; end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin if FSnifferThread <> nil then begin FSnifferThread.Terminate; FSnifferThread := nil; end; end;
| |