1. unit ICMPUtils;
  2.  
  3. interface
  4.  
  5. {$IFDEF VER80}
  6. {
  7. This source file is *NOT* compatible with Delphi 1 because it uses
  8. Win 32 features.
  9. }
  10. {$ENDIF}
  11.  
  12. uses
  13. Windows, SysUtils, Classes, WinSock;
  14.  
  15. const
  16. IcmpVersion = ;
  17. IcmpDLL = 'icmp.dll';
  18.  
  19. {IP status codes returned to transports and user IOCTLs.}
  20. IP_SUCCESS = ;
  21. IP_STATUS_BASE = ;
  22. IP_BUF_TOO_SMALL = (IP_STATUS_BASE + );
  23. IP_DEST_NET_UNREACHABLE = (IP_STATUS_BASE + );
  24. IP_DEST_HOST_UNREACHABLE = (IP_STATUS_BASE + );
  25. IP_DEST_PROT_UNREACHABLE = (IP_STATUS_BASE + );
  26. IP_DEST_PORT_UNREACHABLE = (IP_STATUS_BASE + );
  27. IP_NO_RESOURCES = (IP_STATUS_BASE + );
  28. IP_BAD_OPTION = (IP_STATUS_BASE + );
  29. IP_HW_ERROR = (IP_STATUS_BASE + );
  30. IP_PACKET_TOO_BIG = (IP_STATUS_BASE + );
  31. IP_REQ_TIMED_OUT = (IP_STATUS_BASE + );
  32. IP_BAD_REQ = (IP_STATUS_BASE + );
  33. IP_BAD_ROUTE = (IP_STATUS_BASE + );
  34. IP_TTL_EXPIRED_TRANSIT = (IP_STATUS_BASE + );
  35. IP_TTL_EXPIRED_REASSEM = (IP_STATUS_BASE + );
  36. IP_PARAM_PROBLEM = (IP_STATUS_BASE + );
  37. IP_SOURCE_QUENCH = (IP_STATUS_BASE + );
  38. IP_OPTION_TOO_BIG = (IP_STATUS_BASE + );
  39. IP_BAD_DESTINATION = (IP_STATUS_BASE + );
  40.  
  41. {status codes passed up on status indications.}
  42. IP_ADDR_DELETED = (IP_STATUS_BASE + );
  43. IP_SPEC_MTU_CHANGE = (IP_STATUS_BASE + );
  44. IP_MTU_CHANGE = (IP_STATUS_BASE + );
  45.  
  46. IP_GENERAL_FAILURE = (IP_STATUS_BASE + );
  47.  
  48. MAX_IP_STATUS = IP_GENERAL_FAILURE;
  49.  
  50. IP_PENDING = (IP_STATUS_BASE + );
  51.  
  52. {IP header flags}
  53. IP_FLAG_DF = $; {Don't fragment this packet.}
  54.  
  55. {IP Option Types}
  56. IP_OPT_EOL = $; {End of list option}
  57. IP_OPT_NOP = $; {No operation}
  58. IP_OPT_SECURITY = $; {Security option.}
  59. IP_OPT_LSRR = $; {Loose source route.}
  60. IP_OPT_SSRR = $; {Strict source route.}
  61. IP_OPT_RR = $; {Record route.}
  62. IP_OPT_TS = $; {Timestamp.}
  63. IP_OPT_SID = $; {Stream ID (obsolete)}
  64. MAX_OPT_SIZE = $;
  65.  
  66. type
  67. {IP types}
  68. TIPAddr = DWORD; {An IP address.}
  69. TIPMask = DWORD; {An IP subnet mask.}
  70. TIPStatus = DWORD; {Status code returned from IP APIs.}
  71.  
  72. PIPOptionInformation = ^TIPOptionInformation;
  73. TIPOptionInformation = packed record
  74. TTL: Byte; {Time To Live (used for traceroute)}
  75. TOS: Byte; {Type Of Service (usually 0)}
  76. Flags: Byte; {IP header flags (usually 0)}
  77. OptionsSize: Byte; {Size of options data (usually 0, max 40)}
  78. OptionsData: PChar; {Options data buffer}
  79. end;
  80.  
  81. PIcmpEchoReply = ^TIcmpEchoReply;
  82. TIcmpEchoReply = packed record
  83. Address: TIPAddr; {Replying address}
  84. Status: DWord; {IP status value}
  85. RTT: DWord; {Round Trip Time in milliseconds}
  86. DataSize: Word; {Reply data size}
  87. Reserved: Word; {Reserved}
  88. Data: Pointer; {Pointer to reply data buffer}
  89. Options: TIPOptionInformation; {Reply options}
  90. end;
  91.  
  92. {
  93. IcmpCreateFile:
  94. Opens a handle on which ICMP Echo Requests can be issued.
  95. Arguments:
  96. None.
  97. Return Value:
  98. An open file handle or INVALID_HANDLE_VALUE. Extended error information
  99. is available by calling GetLastError().
  100. }
  101. TIcmpCreateFile = function: THandle; stdcall;
  102.  
  103. {
  104. IcmpCloseHandle:
  105. Closes a handle opened by ICMPOpenFile.
  106. Arguments:
  107. IcmpHandle - The handle to close.
  108. Return Value:
  109. TRUE if the handle was closed successfully, otherwise FALSE. Extended
  110. error information is available by calling GetLastError().
  111. }
  112. TIcmpCloseHandle = function(IcmpHandle: THandle): Boolean; stdcall;
  113.  
  114. {
  115. IcmpSendEcho:
  116. Sends an ICMP Echo request and returns one or more replies. The
  117. call returns when the timeout has expired or the reply buffer
  118. is filled.
  119. Arguments:
  120. IcmpHandle - An open handle returned by ICMPCreateFile.
  121. DestinationAddress - The destination of the echo request.
  122. RequestData - A buffer containing the data to send in the
  123. request.
  124. RequestSize - The number of bytes in the request data buffer.
  125. RequestOptions - Pointer to the IP header options for the request.
  126. May be NULL.
  127. ReplyBuffer - A buffer to hold any replies to the request.
  128. On return, the buffer will contain an array of
  129. ICMP_ECHO_REPLY structures followed by options
  130. and data. The buffer should be large enough to
  131. hold at least one ICMP_ECHO_REPLY structure
  132. and 8 bytes of data - this is the size of
  133. an ICMP error message.
  134. ReplySize - The size in bytes of the reply buffer.
  135. Timeout - The time in milliseconds to wait for replies.
  136. Return Value:
  137. Returns the number of replies received and stored in ReplyBuffer. If
  138. the return value is zero, extended error information is available
  139. via GetLastError().
  140. }
  141. TIcmpSendEcho = function(IcmpHandle: THandle;
  142. DestinationAddress: TIPAddr;
  143. RequestData: Pointer;
  144. RequestSize: Word;
  145. RequestOptions: PIPOptionInformation;
  146. ReplyBuffer: Pointer;
  147. ReplySize: DWord;
  148. Timeout: DWord
  149. ): DWord; stdcall;
  150.  
  151. {Event handler type declaration for TICMP.OnDisplay event.}
  152. TICMPDisplay = procedure(Sender: TObject; Msg : String) of object;
  153. TICMPReply = procedure(Sender: TObject; Error : Integer) of object;
  154.  
  155. {The object wich encapsulate the ICMP.DLL}
  156. TICMP = class(TObject)
  157. private
  158. hICMPdll : HModule; {Handle for ICMP.DLL}
  159. IcmpCreateFile : TIcmpCreateFile;
  160. IcmpCloseHandle : TIcmpCloseHandle;
  161. IcmpSendEcho : TIcmpSendEcho;
  162. hICMP : THandle; {Handle for the ICMP Calls}
  163. FReply : TIcmpEchoReply; {ICMP Echo reply buffer}
  164. FAddress : String; {Address given}
  165. FHostName : String; {Dotted IP of host (output)}
  166. FHostIP : String; {Name of host (Output)}
  167. FIPAddress : TIPAddr; {Address of host to contact}
  168. FSize : Integer; {Packet size (default to 56)}
  169. FTimeOut : Integer; {Timeout (default to 4000mS)}
  170. FTTL : Integer; {Time To Live (for send)}
  171. FOnDisplay : TICMPDisplay; {Event handler to display}
  172. FOnEchoRequest : TNotifyEvent;
  173. FOnEchoReply : TICMPReply;
  174. FLastError : DWORD; {After sending ICMP packet}
  175. FAddrResolved : Boolean;
  176. procedure ResolveAddr;
  177. public
  178. constructor Create; virtual;
  179. destructor Destroy; override;
  180. function Ping : Integer;
  181. procedure SetAddress(Value : String);
  182. function GetErrorString : String;
  183.  
  184. property Address : String read FAddress write SetAddress;
  185. property Size : Integer read FSize write FSize;
  186. property Timeout : Integer read FTimeout write FTimeout;
  187. property Reply : TIcmpEchoReply read FReply;
  188. property TTL : Integer read FTTL write FTTL;
  189. property ErrorCode : Cardinal read FLastError;
  190. property ErrorString : String read GetErrorString;
  191. property HostName : String read FHostName;
  192. property HostIP : String read FHostIP;
  193. property OnDisplay : TICMPDisplay read FOnDisplay write FOnDisplay;
  194. property OnEchoRequest : TNotifyEvent read FOnEchoRequest
  195. write FOnEchoRequest;
  196. property OnEchoReply : TICMPReply read FOnEchoReply
  197. write FOnEchoReply;
  198. end;
  199.  
  200. TICMPException = class(Exception);
  201.  
  202. implementation
  203.  
  204. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  205. constructor TICMP.Create;
  206. var
  207. WSAData: TWSAData;
  208. begin
  209. hICMP := INVALID_HANDLE_VALUE;
  210. FSize := ;
  211. FTTL := ;
  212. FTimeOut := ;
  213.  
  214. {initialise winsock}
  215. if WSAStartup($, WSAData) <> then
  216. raise TICMPException.Create('Error initialising Winsock');
  217.  
  218. {register the icmp.dll stuff}
  219. hICMPdll := LoadLibrary(icmpDLL);
  220. if hICMPdll = then
  221. raise TICMPException.Create('Unable to register ' + icmpDLL);
  222.  
  223. @ICMPCreateFile := GetProcAddress(hICMPdll, 'IcmpCreateFile');
  224. @IcmpCloseHandle := GetProcAddress(hICMPdll, 'IcmpCloseHandle');
  225. @IcmpSendEcho := GetProcAddress(hICMPdll, 'IcmpSendEcho');
  226.  
  227. if (@ICMPCreateFile = nil)
  228. or (@IcmpCloseHandle = nil)
  229. or (@IcmpSendEcho = nil) then
  230. raise TICMPException.Create('Error loading dll functions');
  231.  
  232. hICMP := IcmpCreateFile;
  233. if hICMP = INVALID_HANDLE_VALUE then
  234. raise TICMPException.Create('Unable to get ping handle');
  235. end;
  236.  
  237. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  238. destructor TICMP.Destroy;
  239. begin
  240. if hICMP <> INVALID_HANDLE_VALUE then
  241. IcmpCloseHandle(hICMP);
  242. if hICMPdll <> then
  243. FreeLibrary(hICMPdll);
  244. WSACleanup;
  245. inherited Destroy;
  246. end;
  247.  
  248. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  249. function MinInteger(X, Y: Integer): Integer;
  250. begin
  251. if X >= Y then
  252. Result := Y
  253. else
  254. Result := X;
  255. end;
  256.  
  257. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  258. procedure TICMP.ResolveAddr;
  259. var
  260. Phe: PHostEnt; {HostEntry buffer for name lookup}
  261. begin
  262. {Convert host address to IP address}
  263. FIPAddress := inet_addr(PAnsiChar(AnsiString(FAddress)));
  264. if FIPAddress <> INADDR_NONE then
  265. {Was a numeric dotted address let it in this format}
  266. FHostName := FAddress
  267. else begin
  268. {Not a numeric dotted address, try to resolve by name}
  269. Phe := GetHostByName(PAnsiChar(AnsiString(FAddress)));
  270. if Phe = nil then
  271. begin
  272. FLastError := GetLastError;
  273. if Assigned(FOnDisplay) then
  274. FOnDisplay(Self, 'Unable to resolve ' + FAddress);
  275. Exit;
  276. end;
  277.  
  278. FIPAddress := longint(plongint(Phe^.h_addr_list^)^);
  279. FHostName := Phe^.h_name;
  280. end;
  281.  
  282. FHostIP := StrPas(inet_ntoa(TInAddr(FIPAddress)));
  283. FAddrResolved := TRUE;
  284. end;
  285.  
  286. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  287. procedure TICMP.SetAddress(Value : String);
  288. begin
  289. {Only change if needed (could take a long time)}
  290. if FAddress = Value then
  291. Exit;
  292. FAddress := Value;
  293. FAddrResolved := FALSE;
  294. // ResolveAddr;
  295. end;
  296.  
  297. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  298. function TICMP.GetErrorString : String;
  299. begin
  300. case FLastError of
  301. IP_SUCCESS: Result := 'No error';
  302. IP_BUF_TOO_SMALL: Result := 'Buffer too small';
  303. IP_DEST_NET_UNREACHABLE: Result := 'Destination network unreachable';
  304. IP_DEST_HOST_UNREACHABLE: Result := 'Destination host unreachable';
  305. IP_DEST_PROT_UNREACHABLE: Result := 'Destination protocol unreachable';
  306. IP_DEST_PORT_UNREACHABLE: Result := 'Destination port unreachable';
  307. IP_NO_RESOURCES: Result := 'No resources';
  308. IP_BAD_OPTION: Result := 'Bad option';
  309. IP_HW_ERROR: Result := 'Hardware error';
  310. IP_PACKET_TOO_BIG: Result := 'Packet too big';
  311. IP_REQ_TIMED_OUT: Result := 'Request timed out';
  312. IP_BAD_REQ: Result := 'Bad request';
  313. IP_BAD_ROUTE: Result := 'Bad route';
  314. IP_TTL_EXPIRED_TRANSIT: Result := 'TTL expired in transit';
  315. IP_TTL_EXPIRED_REASSEM: Result := 'TTL expired in reassembly';
  316. IP_PARAM_PROBLEM: Result := 'Parameter problem';
  317. IP_SOURCE_QUENCH: Result := 'Source quench';
  318. IP_OPTION_TOO_BIG: Result := 'Option too big';
  319. IP_BAD_DESTINATION: Result := 'Bad Destination';
  320. IP_ADDR_DELETED: Result := 'Address deleted';
  321. IP_SPEC_MTU_CHANGE: Result := 'Spec MTU change';
  322. IP_MTU_CHANGE: Result := 'MTU change';
  323. IP_GENERAL_FAILURE: Result := 'General failure';
  324. IP_PENDING: Result := 'Pending';
  325. else
  326. Result := 'ICMP error #' + IntToStr(FLastError);
  327. end;
  328. end;
  329.  
  330. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  331. function TICMP.Ping : Integer;
  332. var
  333. BufferSize: Integer;
  334. pReqData, pData: Pointer;
  335. pIPE: PIcmpEchoReply; {ICMP Echo reply buffer}
  336. IPOpt: TIPOptionInformation; {IP Options for packet to send}
  337. Msg: String;
  338. begin
  339. Result := ;
  340. FLastError := ;
  341.  
  342. if not FAddrResolved then
  343. ResolveAddr;
  344.  
  345. if FIPAddress = INADDR_NONE then
  346. begin
  347. FLastError := IP_BAD_DESTINATION;
  348. if Assigned(FOnDisplay) then
  349. FOnDisplay(Self, 'Invalid host address');
  350. Exit;
  351. end;
  352.  
  353. {Allocate space for data buffer space}
  354. BufferSize := SizeOf(TICMPEchoReply) + FSize;
  355. GetMem(pReqData, FSize);
  356. GetMem(pData, FSize);
  357. GetMem(pIPE, BufferSize);
  358.  
  359. try
  360. {Fill data buffer with some data bytes}
  361. FillChar(pReqData^, FSize, $);
  362. Msg := 'Pinging from Delphi code written by F. Piette';
  363. Move(Msg[], pReqData^, MinInteger(FSize, Length(Msg)));
  364.  
  365. pIPE^.Data := pData;
  366. FillChar(pIPE^, SizeOf(pIPE^), );
  367.  
  368. if Assigned(FOnEchoRequest) then
  369. FOnEchoRequest(Self);
  370.  
  371. FillChar(IPOpt, SizeOf(IPOpt), );
  372. IPOpt.TTL := FTTL;
  373. Result := IcmpSendEcho(hICMP, FIPAddress, pReqData, FSize,
  374. @IPOpt, pIPE, BufferSize, FTimeOut);
  375. FLastError := GetLastError;
  376. FReply := pIPE^;
  377.  
  378. if Assigned(FOnEchoReply) then
  379. FOnEchoReply(Self, Result);
  380. finally
  381. {Free those buffers}
  382. FreeMem(pIPE);
  383. FreeMem(pData);
  384. FreeMem(pReqData);
  385. end;
  386. end;
  387.  
  388. end.

一个ICMP单元的更多相关文章

  1. 利用 Linux tap/tun 虚拟设备写一个 ICMP echo 程序

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 前面两篇文章已 ...

  2. PING的原理以及ICMP协议

    主要内容: 1.ping的原理以及工作过程 2.ICMP协议 3.ICMP的应用:ping,traceroute 1.ping的原理以及工作过程  ping的原理  ping 程序是用来探测主机到主机 ...

  3. UNIX网络编程——利用ARP和ICMP协议解释ping命令

    一.MTU 以太网和IEEE 802.3对数据帧的长度都有限制,其最大值分别是1500和1492字节,将这个限制称作最大传输单元(MTU,Maximum Transmission Unit)      ...

  4. 利用ARP和ICMP协议解释ping命令

    一.MTU 以太网和IEEE 802.3对数据帧的长度都有限制,其最大值分别是1500和1492字节,将这个限制称作最大传输单元(MTU,Maximum Transmission Unit).如果IP ...

  5. ping 原理与ICMP协议[转]

    原文:http://blog.csdn.net/inject2006/article/details/2139149 ping 的原理     ping 程序是用来探测主机到主机之间是否可通信,如果不 ...

  6. Firewalld防火墙与ICMP攻击

    原文地址:http://www.excelib.com/article/293/show 提到ICMP大家应该都很熟悉,可能有人会说:不就是ping吗?但是说到ICMP攻击以及相关防御措施可能就有的人 ...

  7. ping 原理与ICMP协议

    ping 的原理     ping 程序是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接.ping 使用的是ICMP协议,它发送icmp回送请求消息给目的主机 ...

  8. 一个完整的http请求响应过程

    一. HTTP请求和响应步骤   图片来自:理解Http请求与响应 以上完整表示了HTTP请求和响应的7个步骤,下面从TCP/IP协议模型的角度来理解HTTP请求和响应如何传递的. 二.TCP/IP协 ...

  9. ICMP&&PING

    ICMP 1.定位:互联网控制报文协议(Internet Control Message Protocol),是TCP/IP协议族的一个子协议,位于网络层.它被IP用于提供许多不同的服务.ICMP是一 ...

随机推荐

  1. iOS socket TCP UDP

    TCP: 服务器: #import <Foundation/Foundation.h> #include <sys/socket.h> #include <netinet ...

  2. ie不支持getElementsByName的解决办法

    在chrome下getElementsByName运行正常,可在IETester7~11下都不支持  w3c规范中getElementsByName是按着name属性进行检索的,而MS的IE却是按着i ...

  3. Mac OS Storm+Kafka+Zookeeper配置

    先补充一个前两天mac配置的文档. 首先确定由jdk scala环境 JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/Cu ...

  4. POJ 1681 (开关问题+高斯消元法)

    题目链接: http://poj.org/problem?id=1681 题目大意:一堆格子,或白或黄.每次可以把一个改变一个格子颜色,其上下左右四个格子颜色也改变.问最后使格子全部变黄,最少需要改变 ...

  5. NOIp 2013 #3 转圈游戏 Label:模拟

    题目描述 n 个小伙伴(编号从 0 到 n-1)围坐一圈玩游戏.按照顺时针方向给 n 个位置编号,从0 到 n-1.最初,第 0 号小伙伴在第 0 号位置,第 1 号小伙伴在第 1 号位置,……,依此 ...

  6. 【BZOJ】2456: mode

    http://www.lydsy.com/JudgeOnline/problem.php?id=2456 题意:给一个$n<=500000$的数列,求出现次数超过$\lfloor \frac{n ...

  7. Linq to Entities下存储过程的使用方法

    1.首先在数据库中创建好存储过程. 2.在实体模型中添加存储过程的映射.此时根据映射过来的查询结果有两种途径:第一种可以选择添加选择的存储过程的函数到实体模型中.这样的话,查询的结果将会是xxx_re ...

  8. BZOJ4176: Lucas的数论

    Description 去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了. 在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其 ...

  9. Maven3路程(一)用Maven创建第一个web项目(1)

    一.创建项目 1.Eclipse中用Maven创建项目 上图中Next 2.继续Next 3.选maven-archetype-webapp后,next 4.填写相应的信息,Packaged是默认创建 ...

  10. javascript模块化应用

    这是一篇关于js模块化历程的长长的流水账,记录js模块化思想的诞生与变迁,展望ES6模块化标准的未来.经历过这段历史的人或许会感到沧桑,没经历过的人也应该知道这段历史. 无模块时代 在ajax还未提出 ...