unit CapIp; interface uses Windows, Messages,Classes,winsock,sysutils; const WM_CapIp = WM_USER + 200; STATUS_FAILED =$FFFF; //定义异常出错代码 MAX_PACK_LEN =65535; //接收的最大IP报文 MAX_ADDR_LEN =16; //点分十进制地址的最大长度 MAX_PROTO_TEXT_LEN =16; //子协议名称(如"TCP")最大长度 MAX_PROTO_NUM =12; //子协议数量 MAX_HOSTNAME_LAN =255; //最大主机名长度 CMD_PARAM_HELP =true; IOC_IN =$80000000; IOC_VENDOR =$18000000; IOC_out =$40000000; SIO_RCVALL =IOC_IN or IOC_VENDOR or 1;// or IOC_out; SIO_RCVALL_MCAST =IOC_IN or IOC_VENDOR or 2; SIO_RCVALL_IGMPMCAST =IOC_IN or IOC_VENDOR or 3; SIO_KEEPALIVE_VALS =IOC_IN or IOC_VENDOR or 4; SIO_ABSORB_RTRALERT =IOC_IN or IOC_VENDOR or 5; SIO_UCAST_IF =IOC_IN or IOC_VENDOR or 6; SIO_LIMIT_BROADCASTS =IOC_IN or IOC_VENDOR or 7; SIO_INDEX_BIND =IOC_IN or IOC_VENDOR or 8; SIO_INDEX_MCASTIF =IOC_IN or IOC_VENDOR or 9; SIO_INDEX_ADD_MCAST =IOC_IN or IOC_VENDOR or 10; SIO_INDEX_DEL_MCAST =IOC_IN or IOC_VENDOR or 11; type tcp_keepalive=record onoff:Longword; keepalivetime:Longword; keepaliveinterval:Longword; end; // New WSAIoctl Options //IP头 type _iphdr=record h_lenver :byte; //4位首部长度+4位IP版本号 tos :char; //8位服务类型TOS total_len :char; //16位总长度(字节) ident :word; //16位标识 frag_and_flags :word; //3位标志位 ttl :byte; //8位生存时间 TTL proto :byte; //8位协议 (TCP, UDP 或其他) checksum :word; //16位IP首部校验和 sourceIP :Longword; //32位源IP地址 destIP :Longword; //32位目的IP地址 end; IP_HEADER=_iphdr; type _tcphdr=record //定义TCP首部 TCP_Sport :word; //16位源端口 TCP_Dport :word; //16位目的端口 th_seq :longword; //32位序列号 th_ack :longword; //32位确认号 th_lenres :byte; //4位首部长度/6位保留字 th_flag :char; //6位标志位 th_win :word; //16位窗口大小 th_sum :word; //16位校验和 th_urp :word; //16位紧急数据偏移量 end; TCP_HEADER=_tcphdr; type _udphdr=record //定义UDP首部 uh_sport :word; //16位源端口 uh_dport :word; //16位目的端口 uh_len :word; //16位长度 uh_sum :word; //16位校验和 end; UDP_HEADER=_udphdr; type _icmphdr=record //定义ICMP首部 i_type :byte; //8位类型 i_code :byte; //8位代码 i_cksum :word; //16位校验和 i_id :word; //识别号(一般用进程号作为识别号) // i_seq :word; //报文序列号 timestamp :word; //时间戳 end; ICMP_HEADER=_icmphdr; type _protomap=record //定义子协议映射表 ProtoNum :integer; ProtoText :array[0..MAX_PROTO_TEXT_LEN] of char; end; TPROTOMAP=_protomap; type ESocketException = class(Exception); TWSAStartup = function (wVersionRequired: word; var WSData: TWSAData): Integer; stdcall; TOpenSocket = function (af, Struct, protocol: Integer): TSocket; stdcall; TInet_addr = function (cp: PChar): u_long; stdcall; Thtons = function (hostshort: u_short): u_short; stdcall; TConnect = function (s: TSocket; var name: TSockAddr; namelen: Integer): Integer; stdcall; TWSAIoctl = function (s: TSocket; cmd: DWORD;lpInBuffer: PCHAR; dwInBufferLen:DWORD;lpOutBuffer: PCHAR; dwOutBufferLen: DWORD; lpdwOutBytesReturned: LPDWORD;lpOverLapped: POINTER; lpOverLappedRoutine: POINTER): Integer; stdcall; TCloseSocket = function (s: TSocket): Integer; stdcall; Tsend = function( s:TSOCKET; buf:pchar;Len:integer;flags:integer):Integer;stdcall; Trecv = function( s:TSOCKET; var buf;Len:integer;flags:integer):Integer;stdcall; TWSAAsyncSelect =function (s: TSocket; HWindow: HWND; wMsg: u_int; lEvent: Longint): Integer; stdcall; TWSACleanup =function():integer;stdcall; //TOnCap = procedure(ip,proto,sourceIP,destIP,SourcePort,DestPort: string; // header:pchar;header_size:integer;data:pchar;data_size:integer) of object; //TOnCap = procedure(dateStr,timeStr,protoType,PaKnum,direct,proto,Flag, // remoteIP,DestPort,data_size: string) of object; TOnCap = procedure(Allinfo:string) of object; TOnError = procedure(Error : string) of object; TCapIp = class private Fhand_dll :HModule; // Handle for mpr.dll FWindowHandle : HWND; FOnCap :TOnCap; //捕捉数据的事件 FOnError :TOnError; //发生错误的事件 Fsocket :array of Tsocket; FActiveIP :array of string; //存放可用的IP FWSAStartup : TWSAStartup; FOpenSocket : TOpenSocket; FInet_addr : TInet_addr; Fhtons : Thtons; FConnect : TConnect; FCloseSocket : TCloseSocket; Fsend :Tsend; FWSAIoctl :TWSAIoctl; Frecv :Trecv; FWSACleanup :TWSACleanup; FWSAAsyncSelect :TWSAAsyncSelect; direct,proto,Flag,remoteIP,DestPort,data_size:string; localIp:string; protected procedure WndProc(var MsgRec: TMessage); //IP解包函数 function DecodeIpPack(ip:string;buf:pchar;iBufSize:integer):integer; //TCP解包函数 //function DecodeTcpPack(TcpBuf:pchar;iBufSize:integer):integer; //UDP解包函数 //function DecodeUdpPack(p:pchar;i:integer):integer; //ICMP解包函数 //function DecodeIcmpPack(p:pchar;i:integer):integer; //协议检查 function CheckProtocol(iProtocol:integer):string; procedure CapIp(socket_no:integer); //得当前的IP列表 procedure get_ActiveIP; //设置网卡状态 procedure set_socket_state; //出错处理函数 function CheckSockError(iErrorCode:integer):boolean; public Fpause :boolean;//暂停 Finitsocket :boolean;//是否已初始化 constructor Create(); destructor Destroy; override; function init_socket:boolean;//初始化 procedure StartCap;//开始捕捉 procedure pause; //暂停 procedure StopCap;//结束捕捉 property Handle : HWND read FWindowHandle; published property OnCap : TOnCap read FOnCap write FOnCap; property OnError : TOnError read FOnError write FOnError; end; implementation function XSocketWindowProc(ahWnd : HWND;auMsg : Integer;awParam : WPARAM; alParam : LPARAM): Integer; stdcall; var Obj : TCapIp; MsgRec : TMessage; begin { At window creation ask windows to store a pointer to our object } {GetWindowLong:his function returns the 32 bit value at the specified } {offset into the extra window memory for the specified window. } Obj := TCapIp(GetWindowLong(ahWnd, 0)); { If the pointer is not assigned, just call the default procedure } { DefWindowProc: This function ensures that all incoming Windows messages are processed. } if not Assigned(Obj) then Result := DefWindowProc(ahWnd, auMsg, awParam, alParam) else begin { Delphi use a TMessage type to pass paramter to his own kind of } { windows procedure. So we are doing the same... } MsgRec.Msg := auMsg; MsgRec.wParam := awParam; MsgRec.lParam := alParam; Obj.WndProc(MsgRec); Result := MsgRec.Result; end; end; var XSocketWindowClass: TWndClass = ( style : 0; lpfnWndProc : @XSocketWindowProc; cbClsExtra : 0; cbWndExtra : SizeOf(Pointer); hInstance : 0; hIcon : 0; hCursor : 0; hbrBackground : 0; lpszMenuName : nil; lpszClassName : 'TCapIp'); function XSocketAllocateHWnd(Obj : TObject): HWND; var TempClass : TWndClass; ClassRegistered : Boolean; begin { Check if the window class is already registered } XSocketWindowClass.hInstance := HInstance; ClassRegistered := GetClassInfo(HInstance, XSocketWindowClass.lpszClassName, TempClass); if not ClassRegistered then begin { Not yet registered, do it right now } Result := Windows.RegisterClass(XSocketWindowClass); if Result = 0 then Exit; end; { Now create a new window } Result := CreateWindowEx(WS_EX_TOOLWINDOW, XSocketWindowClass.lpszClassName, '', { Window name } WS_POPUP, { Window Style } 0, 0, { X, Y } 0, 0, { Width, Height } 0, { hWndParent } 0, { hMenu } HInstance, { hInstance } nil); { CreateParam } { if successfull, the ask windows to store the object reference } { into the reserved byte (see RegisterClass) } if (Result <> 0) and Assigned(Obj) then SetWindowLong(Result, 0, Integer(Obj)); end; procedure XSocketDeallocateHWnd(Wnd: HWND); begin DestroyWindow(Wnd); end; procedure TCapIp.get_ActiveIP; type TaPInAddr = Array[0..20] of PInAddr; PaPInAddr = ^TaPInAddr; var phe: PHostEnt; pptr: PaPInAddr; Buffer: Array[0..63] of Char; I: Integer; begin setlength(FActiveIP,20); GetHostName(Buffer, SizeOf(Buffer)); phe := GetHostByName(buffer); if phe = nil then begin setlength(FActiveIP,0); if Assigned(FOnError) then FOnError('没有找到可绑定的IP!'); exit; end; pPtr:= PaPInAddr(phe^.h_addr_list); I:= 0; while (pPtr^[I] <> nil) and (i<20) do begin FActiveIP[I]:=inet_ntoa(pptr^[I]^); Inc(I); end; setlength(FActiveIP,i); localIp:=FActiveIP[i-1]; end; procedure TCapIp.set_socket_state; var i,iErrorCode:integer; sa: tSockAddrIn; dwBufferLen:array[0..10]of DWORD; dwBufferInLen:DWORD; dwBytesReturned:DWORD; begin if high(FActiveIP)=-1 then exit; setlength(Fsocket,high(FActiveIP)+1); for i:=0 to high(FActiveIP) do begin Fsocket[i]:= socket(AF_INET , SOCK_RAW , IPPROTO_IP); sa.sin_family:= AF_INET; sa.sin_port := htons(i); sa.sin_addr.S_addr:=Inet_addr(pchar(FActiveIP[i])); iErrorCode := bind(Fsocket[i],sa, sizeof(sa)); CheckSockError(iErrorCode); dwBufferInLen :=1; dwBytesReturned:=0; //receive all packages ! iErrorCode:=FWSAIoctl(Fsocket[i], SIO_RCVALL,@dwBufferInLen, sizeof(dwBufferInLen), @dwBufferLen, sizeof(dwBufferLen),@dwBytesReturned ,nil ,nil); CheckSockError(iErrorCode); iErrorCode:=WSAAsyncSelect(Fsocket[i],FWindowHandle,WM_CapIp+i,FD_READ or FD_CLOSE); CheckSockError(iErrorCode); end; end; procedure TCapIp.CapIp(socket_no:integer); var iErrorCode:integer; RecvBuf:array[0..MAX_PACK_LEN] of char; begin fillchar(RecvBuf,sizeof(RecvBuf),0); iErrorCode := frecv(Fsocket[socket_no], RecvBuf, sizeof(RecvBuf), 0); CheckSockError(iErrorCode); data_size:=inttostr(iErrorCode); if not Fpause then begin iErrorCode := DecodeIpPack(FActiveIP[socket_no],RecvBuf, iErrorCode); CheckSockError(iErrorCode); end; end; function TCapIp.CheckProtocol(iProtocol:integer):string; begin result:=''; case iProtocol of IPPROTO_IP :result:='IP'; IPPROTO_ICMP :result:='ICMP'; IPPROTO_IGMP :result:='IGMP'; IPPROTO_GGP :result:='GGP'; IPPROTO_TCP :result:='TCP'; IPPROTO_PUP :result:='PUP'; IPPROTO_UDP :result:='UDP'; IPPROTO_IDP :result:='IDP'; IPPROTO_ND :result:='NP'; IPPROTO_RAW :result:='RAW'; IPPROTO_MAX :result:='MAX'; else result:=''; end; end; function TCapIp.DecodeIpPack(ip:string;buf:pchar;iBufSize:integer):integer; var // LSourcePort,LDestPort:word; LDestPort:word; iProtocol, iTTL:integer; szProtocol :array[0..MAX_PROTO_TEXT_LEN] of char; szSourceIP :array[0..MAX_ADDR_LEN] of char; szDestIP :array[0..MAX_ADDR_LEN] of char; pIpheader:IP_HEADER; pTcpHeader:TCP_HEADER; pUdpHeader:UDP_HEADER; pIcmpHeader:ICMP_HEADER; saSource, saDest:TSockAddrIn; iIphLen:integer; // TcpHeaderLen:integer; // TcpData:pchar; AllInfo:string; begin result:=0; CopyMemory(@pIpheader,buf,sizeof(pIpheader)); iProtocol := pIpheader.proto; StrLCopy(szProtocol, pchar(CheckProtocol(iProtocol)),15); saSource.sin_addr.s_addr := pIpheader.sourceIP; strlcopy(szSourceIP, inet_ntoa(saSource.sin_addr), MAX_ADDR_LEN); saDest.sin_addr.s_addr := pIpheader.destIP; strLcopy(szDestIP, inet_ntoa(saDest.sin_addr), MAX_ADDR_LEN); iTTL := pIpheader.ttl; Flag:='0'; iIphLen :=sizeof(pIpheader); case iProtocol of IPPROTO_TCP : begin CopyMemory(@pTcpHeader,buf+iIphLen,sizeof(pTcpHeader)); //LSourcePort := ntohs(pTcpHeader.TCP_Sport); LDestPort := ntohs(pTcpHeader.TCP_Dport); //TcpData:=buf+iIphLen+sizeof(pTcpHeader); //data_size:=iBufSize-iIphLen-sizeof(pTcpHeader); flag:='1'; end; IPPROTO_UDP : begin CopyMemory(@pUdpHeader,buf+iIphLen,sizeof(pUdpHeader)); //LSourcePort := ntohs(pUdpHeader.uh_sport); LDestPort := ntohs(pUdpHeader.uh_dport); //TcpData:=buf+iIphLen+sizeof(pUdpHeader); //data_size:=iBufSize-iIphLen-sizeof(pUdpHeader); end; IPPROTO_ICMP : begin CopyMemory(@pIcmpHeader,buf+iIphLen,sizeof(pIcmpHeader)); //LSourcePort := pIcmpHeader.i_type; LDestPort := pIcmpHeader.i_code; //TcpData:=buf+iIphLen+sizeof(pIcmpHeader); //data_size:=iBufSize-iIphLen-sizeof(pIcmpHeader); end; else begin //LSourcePort :=0; LDestPort := 0; //TcpData:=buf+iIphLen; //data_size:=iBufSize-iIphLen; end; end; if StrLIComp(szDestIP,pchar(localIp),9)=0 then begin direct:='0'; Proto:=string(szProtocol); remoteIP:=string(szSourceIP); DestPort:=inttostr(LDestPort); end else begin direct:='1'; Proto:=string(szProtocol); remoteIP:=string(szDestIP); DestPort:=inttostr(LDestPort); end; ///////////// //protoType:='NET'; AllInfo:='8'+direct+'|'+'1'+'|'+proto+'|'+ remoteIP +'|'+ DestPort;//+'|'+ data_size; if (Assigned(FOnCap)) and (iTTL>0) then //FOnCap(dateStr,timeStr,'NET','1',direct,proto,Flag,remoteIP,DestPort,data_size); FOnCap(AllInfo); ///////////// end; function TCapIp.CheckSockError(iErrorCode:integer):boolean; begin if(iErrorCode=SOCKET_ERROR) then begin if Assigned(FOnError) then FOnError(inttostr(GetLastError)+SysErrorMessage(GetLastError)); result:=true; end else result:=false; end; procedure TCapIp.WndProc(var MsgRec: TMessage); begin with MsgRec do if (Msg >=WM_CapIp) and (Msg <= WM_CapIp+high(FActiveIP)) then CapIp(msg-WM_CapIp) else Result := DefWindowProc(Handle, Msg, wParam, lParam); end; constructor TCapIp.Create(); begin Fpause:=false; Finitsocket:=false; setlength(Fsocket,0); FWindowHandle := XSocketAllocateHWnd(Self); end; destructor TCapIp.Destroy; var i:integer; begin for i:=0 to high(Fsocket) do FCloseSocket(Fsocket[i]); if self.Finitsocket then begin FWSACleanup; if Fhand_dll <> 0 then FreeLibrary(Fhand_dll); end; end; function TCapIp.init_socket:boolean;//初始化 var GInitData:TWSAData; begin result:=true; if Finitsocket then exit; Fhand_dll := LoadLibrary('ws2_32.dll'); if Fhand_dll = 0 then begin raise ESocketException.Create('Unable to register ws2_32.dll'); result:=false; exit; end; @FWSAStartup := GetProcAddress(Fhand_dll, 'WSAStartup'); @FOpenSocket := GetProcAddress(Fhand_dll, 'socket'); @FInet_addr := GetProcAddress(Fhand_dll, 'inet_addr'); @Fhtons := GetProcAddress(Fhand_dll, 'htons'); @FConnect := GetProcAddress(Fhand_dll, 'connect'); @FCloseSocket := GetProcAddress(Fhand_dll, 'closesocket'); @Fsend := GetProcAddress(Fhand_dll, 'send'); @FWSAIoctl := GetProcAddress(Fhand_dll, 'WSAIoctl'); @Frecv := GetProcAddress(Fhand_dll, 'recv'); @FWSACleanup := GetProcAddress(Fhand_dll, 'WSACleanup'); @FWSAAsyncSelect:=GetProcAddress(Fhand_dll, 'WSAAsyncSelect'); if (@FWSAStartup =nil) or(@Fhtons =nil) or (@FConnect =nil) or (@Fsend =nil) or (@FWSACleanup=nil) or (@FOpenSocket =nil) or (@FInet_addr =nil) or (@FCloseSocket =nil) or (@recv=nil)or (@FWSAIoctl=nil) or (@FWSAAsyncSelect=nil) then begin raise ESocketException.Create('加载dll函数错误!'); result:=false; exit; end; if FWSAStartup($201,GInitData)<>0 then begin raise ESocketException.Create('初始化SOCKET2函数失败!'); result:=false; exit; end; Finitsocket:=true; end; procedure TCapIp.StartCap; begin if not Finitsocket then if not init_socket then exit; get_ActiveIP; set_socket_state; end; procedure TCapIp.pause; begin if Finitsocket and (high(Fsocket)>-1) then Fpause:=not Fpause; end; procedure TCapIp.StopCap; var i:integer; begin for i:=0 to high(Fsocket) do FCloseSocket(Fsocket[i]); end; end.