CapIp.pas

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.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值