一个ICMP单元
unit ICMPUtils;
interface
{$IFDEF VER80}
{
This source file is *NOT* compatible with Delphi 1 because it uses
Win 32 features.
}
{$ENDIF}
uses
  Windows, SysUtils, Classes, WinSock;
const
  IcmpVersion = ;
  IcmpDLL     = 'icmp.dll';
  {IP status codes returned to transports and user IOCTLs.}
  IP_SUCCESS                  = ;
  IP_STATUS_BASE              = ;
  IP_BUF_TOO_SMALL            = (IP_STATUS_BASE + );
  IP_DEST_NET_UNREACHABLE     = (IP_STATUS_BASE + );
  IP_DEST_HOST_UNREACHABLE    = (IP_STATUS_BASE + );
  IP_DEST_PROT_UNREACHABLE    = (IP_STATUS_BASE + );
  IP_DEST_PORT_UNREACHABLE    = (IP_STATUS_BASE + );
  IP_NO_RESOURCES             = (IP_STATUS_BASE + );
  IP_BAD_OPTION               = (IP_STATUS_BASE + );
  IP_HW_ERROR                 = (IP_STATUS_BASE + );
  IP_PACKET_TOO_BIG           = (IP_STATUS_BASE + );
  IP_REQ_TIMED_OUT            = (IP_STATUS_BASE + );
  IP_BAD_REQ                  = (IP_STATUS_BASE + );
  IP_BAD_ROUTE                = (IP_STATUS_BASE + );
  IP_TTL_EXPIRED_TRANSIT      = (IP_STATUS_BASE + );
  IP_TTL_EXPIRED_REASSEM      = (IP_STATUS_BASE + );
  IP_PARAM_PROBLEM            = (IP_STATUS_BASE + );
  IP_SOURCE_QUENCH            = (IP_STATUS_BASE + );
  IP_OPTION_TOO_BIG           = (IP_STATUS_BASE + );
  IP_BAD_DESTINATION          = (IP_STATUS_BASE + ); 
  {status codes passed up on status indications.}
  IP_ADDR_DELETED             = (IP_STATUS_BASE + );
  IP_SPEC_MTU_CHANGE          = (IP_STATUS_BASE + );
  IP_MTU_CHANGE               = (IP_STATUS_BASE + ); 
  IP_GENERAL_FAILURE          = (IP_STATUS_BASE + ); 
  MAX_IP_STATUS               = IP_GENERAL_FAILURE; 
  IP_PENDING                  = (IP_STATUS_BASE + ); 
  {IP header flags}
  IP_FLAG_DF                  = $; {Don't fragment this packet.}
  {IP Option Types}
  IP_OPT_EOL                  = $; {End of list option}
  IP_OPT_NOP                  = $; {No operation}
  IP_OPT_SECURITY             = $; {Security option.}
  IP_OPT_LSRR                 = $; {Loose source route.}
  IP_OPT_SSRR                 = $; {Strict source route.}
  IP_OPT_RR                   = $; {Record route.}
  IP_OPT_TS                   = $; {Timestamp.}
  IP_OPT_SID                  = $; {Stream ID (obsolete)}
  MAX_OPT_SIZE                = $; 
type
  {IP types}
  TIPAddr   = DWORD; {An IP address.}
  TIPMask   = DWORD; {An IP subnet mask.}
  TIPStatus = DWORD; {Status code returned from IP APIs.}
  PIPOptionInformation = ^TIPOptionInformation;
  TIPOptionInformation = packed record
     TTL:         Byte; {Time To Live (used for traceroute)}
     TOS:         Byte; {Type Of Service (usually 0)}
     Flags:       Byte; {IP header flags (usually 0)}
     OptionsSize: Byte; {Size of options data (usually 0, max 40)}
     OptionsData: PChar; {Options data buffer}
  end; 
  PIcmpEchoReply = ^TIcmpEchoReply;
  TIcmpEchoReply = packed record
     Address:       TIPAddr; {Replying address}
     Status:        DWord; {IP status value}
     RTT:           DWord; {Round Trip Time in milliseconds}
     DataSize:      Word; {Reply data size}
     Reserved:      Word; {Reserved}
     Data:          Pointer; {Pointer to reply data buffer}
     Options:       TIPOptionInformation; {Reply options}
  end; 
{
  IcmpCreateFile:
      Opens a handle on which ICMP Echo Requests can be issued.
  Arguments:
      None.
  Return Value:
      An open file handle or INVALID_HANDLE_VALUE. Extended error information
      is available by calling GetLastError().
}
  TIcmpCreateFile  = function: THandle; stdcall;
{
  IcmpCloseHandle:
      Closes a handle opened by ICMPOpenFile.
  Arguments:
      IcmpHandle  - The handle to close.
  Return Value:
      TRUE if the handle was closed successfully, otherwise FALSE. Extended
      error information is available by calling GetLastError().
}
  TIcmpCloseHandle = function(IcmpHandle: THandle): Boolean; stdcall; 
{
  IcmpSendEcho:
      Sends an ICMP Echo request and returns one or more replies. The
      call returns when the timeout has expired or the reply buffer
      is filled.
  Arguments:
      IcmpHandle         - An open handle returned by ICMPCreateFile.
      DestinationAddress - The destination of the echo request.
      RequestData        - A buffer containing the data to send in the
                           request.
      RequestSize        - The number of bytes in the request data buffer.
      RequestOptions     - Pointer to the IP header options for the request.
                           May be NULL.
      ReplyBuffer        - A buffer to hold any replies to the request.
                           On return, the buffer will contain an array of
                           ICMP_ECHO_REPLY structures followed by options
                           and data. The buffer should be large enough to
                           hold at least one ICMP_ECHO_REPLY structure
                           and 8 bytes of data - this is the size of
                           an ICMP error message.
      ReplySize          - The size in bytes of the reply buffer.
      Timeout            - The time in milliseconds to wait for replies.
  Return Value:
      Returns the number of replies received and stored in ReplyBuffer. If
      the return value is zero, extended error information is available
      via GetLastError().
}
  TIcmpSendEcho    = function(IcmpHandle:          THandle;
                              DestinationAddress:  TIPAddr;
                              RequestData:         Pointer;
                              RequestSize:         Word;
                              RequestOptions:      PIPOptionInformation;
                              ReplyBuffer:         Pointer;
                              ReplySize:           DWord;
                              Timeout:             DWord
                             ): DWord; stdcall; 
  {Event handler type declaration for TICMP.OnDisplay event.}
  TICMPDisplay = procedure(Sender: TObject; Msg : String) of object;
  TICMPReply   = procedure(Sender: TObject; Error : Integer) of object;
  {The object wich encapsulate the ICMP.DLL}
  TICMP = class(TObject)
  private
    hICMPdll :        HModule; {Handle for ICMP.DLL}
    IcmpCreateFile :  TIcmpCreateFile;
    IcmpCloseHandle : TIcmpCloseHandle;
    IcmpSendEcho :    TIcmpSendEcho;
    hICMP :           THandle; {Handle for the ICMP Calls}
    FReply :          TIcmpEchoReply; {ICMP Echo reply buffer}
    FAddress :        String; {Address given}
    FHostName :       String; {Dotted IP of host (output)}
    FHostIP :         String; {Name of host      (Output)}
    FIPAddress :      TIPAddr; {Address of host to contact}
    FSize :           Integer; {Packet size (default to 56)}
    FTimeOut :        Integer; {Timeout (default to 4000mS)}
    FTTL :            Integer; {Time To Live (for send)}
    FOnDisplay :      TICMPDisplay; {Event handler to display}
    FOnEchoRequest :  TNotifyEvent;
    FOnEchoReply :    TICMPReply;
    FLastError :      DWORD; {After sending ICMP packet}
    FAddrResolved :   Boolean;
    procedure ResolveAddr;
  public
    constructor Create; virtual;
    destructor  Destroy; override;
    function    Ping : Integer;
    procedure   SetAddress(Value : String);
    function    GetErrorString : String; 
    property Address       : String         read  FAddress   write SetAddress;
    property Size          : Integer        read  FSize      write FSize;
    property Timeout       : Integer        read  FTimeout   write FTimeout;
    property Reply         : TIcmpEchoReply read  FReply;
    property TTL           : Integer        read  FTTL       write FTTL;
    property ErrorCode     : Cardinal       read  FLastError;
    property ErrorString   : String         read  GetErrorString;
    property HostName      : String         read  FHostName;
    property HostIP        : String         read  FHostIP;
    property OnDisplay     : TICMPDisplay   read  FOnDisplay write FOnDisplay;
    property OnEchoRequest : TNotifyEvent   read  FOnEchoRequest
                                            write FOnEchoRequest;
    property OnEchoReply   : TICMPReply     read  FOnEchoReply
                                            write FOnEchoReply;
  end; 
  TICMPException = class(Exception); 
implementation 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
constructor TICMP.Create;
var
  WSAData: TWSAData;
begin
  hICMP := INVALID_HANDLE_VALUE;
  FSize := ;
  FTTL := ;
  FTimeOut := ;
  {initialise winsock}
  if WSAStartup($, WSAData) <>  then
    raise TICMPException.Create('Error initialising Winsock');
  {register the icmp.dll stuff}
  hICMPdll := LoadLibrary(icmpDLL);
  if hICMPdll =  then
    raise TICMPException.Create('Unable to register ' + icmpDLL);
  @ICMPCreateFile := GetProcAddress(hICMPdll, 'IcmpCreateFile');
  @IcmpCloseHandle := GetProcAddress(hICMPdll, 'IcmpCloseHandle');
  @IcmpSendEcho := GetProcAddress(hICMPdll, 'IcmpSendEcho');
  if (@ICMPCreateFile = nil)
    or (@IcmpCloseHandle = nil)
    or (@IcmpSendEcho = nil) then
    raise TICMPException.Create('Error loading dll functions');
  hICMP := IcmpCreateFile;
  if hICMP = INVALID_HANDLE_VALUE then
    raise TICMPException.Create('Unable to get ping handle');
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
destructor TICMP.Destroy;
begin
  if hICMP <> INVALID_HANDLE_VALUE then
    IcmpCloseHandle(hICMP);
  if hICMPdll <>  then
    FreeLibrary(hICMPdll);
  WSACleanup;
  inherited Destroy;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function MinInteger(X, Y: Integer): Integer;
begin
  if X >= Y then
    Result := Y
  else
    Result := X;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TICMP.ResolveAddr;
var
  Phe: PHostEnt; {HostEntry buffer for name lookup}
begin
  {Convert host address to IP address}
  FIPAddress := inet_addr(PAnsiChar(AnsiString(FAddress)));
  if FIPAddress <> INADDR_NONE then
    {Was a numeric dotted address let it in this format}
    FHostName := FAddress
  else begin
    {Not a numeric dotted address, try to resolve by name}
    Phe := GetHostByName(PAnsiChar(AnsiString(FAddress)));
    if Phe = nil then
    begin
      FLastError := GetLastError;
      if Assigned(FOnDisplay) then
        FOnDisplay(Self, 'Unable to resolve ' + FAddress);
      Exit;
    end;
    FIPAddress := longint(plongint(Phe^.h_addr_list^)^);
    FHostName := Phe^.h_name;
  end;
  FHostIP := StrPas(inet_ntoa(TInAddr(FIPAddress)));
  FAddrResolved := TRUE;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TICMP.SetAddress(Value : String);
begin
  {Only change if needed (could take a long time)}
  if FAddress = Value then
    Exit;
  FAddress := Value;
  FAddrResolved := FALSE;
//  ResolveAddr;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TICMP.GetErrorString : String;
begin
  case FLastError of
    IP_SUCCESS:               Result := 'No error';
    IP_BUF_TOO_SMALL:         Result := 'Buffer too small';
    IP_DEST_NET_UNREACHABLE:  Result := 'Destination network unreachable';
    IP_DEST_HOST_UNREACHABLE: Result := 'Destination host unreachable';
    IP_DEST_PROT_UNREACHABLE: Result := 'Destination protocol unreachable';
    IP_DEST_PORT_UNREACHABLE: Result := 'Destination port unreachable';
    IP_NO_RESOURCES:          Result := 'No resources';
    IP_BAD_OPTION:            Result := 'Bad option';
    IP_HW_ERROR:              Result := 'Hardware error';
    IP_PACKET_TOO_BIG:        Result := 'Packet too big';
    IP_REQ_TIMED_OUT:         Result := 'Request timed out';
    IP_BAD_REQ:               Result := 'Bad request';
    IP_BAD_ROUTE:             Result := 'Bad route';
    IP_TTL_EXPIRED_TRANSIT:   Result := 'TTL expired in transit';
    IP_TTL_EXPIRED_REASSEM:   Result := 'TTL expired in reassembly';
    IP_PARAM_PROBLEM:         Result := 'Parameter problem';
    IP_SOURCE_QUENCH:         Result := 'Source quench';
    IP_OPTION_TOO_BIG:        Result := 'Option too big';
    IP_BAD_DESTINATION:       Result := 'Bad Destination';
    IP_ADDR_DELETED:          Result := 'Address deleted';
    IP_SPEC_MTU_CHANGE:       Result := 'Spec MTU change';
    IP_MTU_CHANGE:            Result := 'MTU change';
    IP_GENERAL_FAILURE:       Result := 'General failure';
    IP_PENDING:               Result := 'Pending';
  else
    Result := 'ICMP error #' + IntToStr(FLastError);
  end;
end; 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TICMP.Ping : Integer;
var
  BufferSize: Integer;
  pReqData, pData: Pointer;
  pIPE: PIcmpEchoReply; {ICMP Echo reply buffer}
  IPOpt: TIPOptionInformation; {IP Options for packet to send}
  Msg: String;
begin
  Result := ;
  FLastError := ;
  if not FAddrResolved then
    ResolveAddr;
  if FIPAddress = INADDR_NONE then
  begin
    FLastError := IP_BAD_DESTINATION;
    if Assigned(FOnDisplay) then
      FOnDisplay(Self, 'Invalid host address');
    Exit;
  end;
  {Allocate space for data buffer space}
  BufferSize := SizeOf(TICMPEchoReply) + FSize;
  GetMem(pReqData, FSize);
  GetMem(pData, FSize);
  GetMem(pIPE, BufferSize);
  try
    {Fill data buffer with some data bytes}
    FillChar(pReqData^, FSize, $);
    Msg := 'Pinging from Delphi code written by F. Piette';
    Move(Msg[], pReqData^, MinInteger(FSize, Length(Msg))); 
    pIPE^.Data := pData;
    FillChar(pIPE^, SizeOf(pIPE^), ); 
    if Assigned(FOnEchoRequest) then
      FOnEchoRequest(Self);
    FillChar(IPOpt, SizeOf(IPOpt), );
    IPOpt.TTL := FTTL;
    Result := IcmpSendEcho(hICMP, FIPAddress, pReqData, FSize,
                               @IPOpt, pIPE, BufferSize, FTimeOut);
    FLastError := GetLastError;
    FReply := pIPE^;
    if Assigned(FOnEchoReply) then
      FOnEchoReply(Self, Result);
  finally
    {Free those buffers}
    FreeMem(pIPE);
    FreeMem(pData);
    FreeMem(pReqData);
  end;
end;
end.
一个ICMP单元的更多相关文章
- 利用 Linux tap/tun 虚拟设备写一个 ICMP echo 程序
		本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 前面两篇文章已 ... 
- PING的原理以及ICMP协议
		主要内容: 1.ping的原理以及工作过程 2.ICMP协议 3.ICMP的应用:ping,traceroute 1.ping的原理以及工作过程 ping的原理 ping 程序是用来探测主机到主机 ... 
- UNIX网络编程——利用ARP和ICMP协议解释ping命令
		一.MTU 以太网和IEEE 802.3对数据帧的长度都有限制,其最大值分别是1500和1492字节,将这个限制称作最大传输单元(MTU,Maximum Transmission Unit) ... 
- 利用ARP和ICMP协议解释ping命令
		一.MTU 以太网和IEEE 802.3对数据帧的长度都有限制,其最大值分别是1500和1492字节,将这个限制称作最大传输单元(MTU,Maximum Transmission Unit).如果IP ... 
- ping 原理与ICMP协议[转]
		原文:http://blog.csdn.net/inject2006/article/details/2139149 ping 的原理 ping 程序是用来探测主机到主机之间是否可通信,如果不 ... 
- Firewalld防火墙与ICMP攻击
		原文地址:http://www.excelib.com/article/293/show 提到ICMP大家应该都很熟悉,可能有人会说:不就是ping吗?但是说到ICMP攻击以及相关防御措施可能就有的人 ... 
- ping 原理与ICMP协议
		ping 的原理 ping 程序是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接.ping 使用的是ICMP协议,它发送icmp回送请求消息给目的主机 ... 
- 一个完整的http请求响应过程
		一. HTTP请求和响应步骤 图片来自:理解Http请求与响应 以上完整表示了HTTP请求和响应的7个步骤,下面从TCP/IP协议模型的角度来理解HTTP请求和响应如何传递的. 二.TCP/IP协 ... 
- ICMP&&PING
		ICMP 1.定位:互联网控制报文协议(Internet Control Message Protocol),是TCP/IP协议族的一个子协议,位于网络层.它被IP用于提供许多不同的服务.ICMP是一 ... 
随机推荐
- CSS font 复合属性的顺序
			CSS 参考手册 实例 在一个声明中设置所有字体属性: p.ex1 { font:italic arial,sans-serif; } p.ex2 { font:italic bold 12px/20 ... 
- JavaScript 全局对象
			全局属性和函数可用于所有内建的 JavaScript 对象. 顶层函数(全局函数) 函数 描述 decodeURI() 解码某个编码的 URI. decodeURIComponent() 解码一个编码 ... 
- DOM基础2
			插入元素 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF- ... 
- Eclipse:  The superclass “javax.servlet.http.HttpServlet” was not found on the Java Build Path
			Link: http://stackoverflow.com/questions/22756153/the-superclass-javax-servlet-http-httpservlet-was- ... 
- BZOJ2448 : 挖油
			$f[i][j]$表示仅考虑$[i,j]$区间的答案,则 $f[i][j]=\min(\max(f[i][k-1],f[k+1][j])+a[k]),i\leq k\leq j$ 维护出$\max$的 ... 
- SPFA 的两个优化
			From NOCOW SPFA算法有两个优化算法 SLF 和 LLL: SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将 ... 
- CNN训练Cifar-10技巧
			关于数据集 Cifar-10是由Hinton的两个大弟子Alex Krizhevsky.Ilya Sutskever收集的一个用于普适物体识别的数据集.Cifar是加拿大政府牵头投资的一个先进科学项目 ... 
- BZOJ 1054 题解
			1054: [HAOI2008]移动玩具 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1888 Solved: 1035[Submit][Stat ... 
- 【BZOJ1270】1270: [BeijingWc2008]雷涛的小猫 DP
			Description Input Output Sample Input Sample Output 8 HINT Source 唉这么蠢的Dp没一下子看出来,Dp真是太弱了啦. #includ ... 
- Bug:播放页面自动跳到首页
			一,经历: 1.第一感觉就是从直播间中收到了通知,然后通知得知了用户未登录,直播间便 pop 退出了. 2.由于这个问题是很难复现的,研究了快一个星期后,才发现是直播间底部的我的历史页面中接收到了直播 ... 
