一个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是一 ...
随机推荐
- MFC 打开文件对话框 打开单个文件
CFileDialog的语法: CFileDialog(BOOL bOpenFileDialog,LPCTSTR lpszDefExt=NULL,LPCTSTR lpszFileName=NULL,D ...
- 《HBase实战》
对,我正在研读这本书,今天开始,我希望我看完后能有收获和大家分享,这个日志作为开始,勉励自己! 对,我应该静下心,做一些我更喜欢的事情,不能在自我陶醉中迷失! 断断续的看,到今天大概把这本书看完了,没 ...
- React的第一步
首先了解React中所牵扯到的几个重要的概念 什么是React? 是Facebook的开发团队开发出来的一个用于构建用户界面个js库,最近才开源出来公布于世,它的初衷是用于创建“独立的视图组件”,一个 ...
- Python连接Oracle
http://wenku.baidu.com/link?url=2yVoHbJ3XTnZdbyOkN923ncGPqXygJiB6wSRBkqlqimR6H8XxWpBT6GxCTFgmALyqGH0 ...
- iOS数据持久化文件读写之偏好设置
很多iOS应用都支持偏好设置,比如保存用户名.密码.字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能.每个应用都有个NSUserDefaults实例,通过它来存取偏好设置.比如, ...
- Storm编译打包过程中遇到的一些问题及解决方法
作者: 大圆那些事 | 文章可以转载,请以超链接形式标明文章原始出处和作者信息 网址: http://www.cnblogs.com/panfeng412/archive/2013/11/30/som ...
- Codeforces Beta Round #2 A. Winner
A. Winner time limit per test 1 second memory limit per test 64 megabytes input standard input outpu ...
- ACM: 限时训练题解-Runtime Error-二分查找
Runtime Error Bahosain was trying to solve this simple problem, but he got a Runtime Error on one ...
- ACM: The Suspects-并查集-解题报告
The Suspects Time Limit:1000MS Memory Limit:20000KB 64bit IO Format:%lld & %llu Description 严重急性 ...
- ACM:统计难题 解题报告-字典树(Trie树)
统计难题 Time Limit:2000MS Memory Limit:65535KB 64bit IO Format:%I64d & %I64u Submit Status ...