IdTraceRoute.pas 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. unit IdTraceRoute;
  17. interface
  18. {$i IdCompilerDefines.inc}
  19. uses
  20. {$IFDEF DOTNET_2_OR_ABOVE}
  21. IdGlobal,
  22. {$ENDIF}
  23. IdIcmpClient, IdRawBase, IdThread;
  24. type
  25. TIdTraceRoute = class(TIdCustomICMPClient)
  26. protected
  27. FResolveHostNames : Boolean;
  28. procedure DoReply; override;
  29. public
  30. procedure Trace;
  31. published
  32. {$IFDEF DOTNET_2_OR_ABOVE}
  33. property IPVersion default ID_DEFAULT_IP_VERSION;
  34. {$ENDIF}
  35. property PacketSize;
  36. property ReceiveTimeout;
  37. property ResolveHostNames : Boolean read FResolveHostNames write FResolveHostNames;
  38. property OnReply;
  39. end;
  40. implementation
  41. uses
  42. {$IFNDEF DOTNET_2_OR_ABOVE}
  43. IdGlobal,
  44. {$ENDIF}
  45. IdStack;
  46. { TIdTraceRoute }
  47. procedure TIdTraceRoute.DoReply;
  48. begin
  49. if FResolveHostNames and
  50. (PosInStrArray(FReplyStatus.FromIpAddress, ['0.0.0.0', '::0']) = -1) then {do not localize}
  51. begin
  52. //resolve IP to hostname
  53. try
  54. FReplyStatus.HostName := GStack.HostByAddress(FReplyStatus.FromIpAddress, FBinding.IPVersion);
  55. except
  56. {
  57. We do things this way because we are likely have a reverse DNS
  58. failure if you have a computer with IP address and no DNS name at all.
  59. }
  60. FReplyStatus.HostName := FReplyStatus.FromIpAddress;
  61. end;
  62. end;
  63. inherited DoReply;
  64. end;
  65. procedure TIdTraceRoute.Trace;
  66. //In traceroute, there are a maximum of thirty echo request packets. You start
  67. //requests with a TTL of one and keep sending them until you get to thirty or you
  68. //get an echo response (whatever comes sooner).
  69. var
  70. i : Integer;
  71. lSeq : UInt32;
  72. LTTL : Integer;
  73. LIPAddr : String;
  74. begin
  75. // PacketSize := 64;
  76. //We do things this way because we only want to resolve the destination host name
  77. //only one time. Otherwise, there's a performance penalty for earch DNS resolve.
  78. LIPAddr := GStack.ResolveHost(FHost, FBinding.IPVersion);
  79. LSeq := $1;
  80. LTTL := 1;
  81. TTL := LTTL;
  82. for i := 1 to 30 do
  83. begin
  84. ReplyStatus.PacketNumber := i;
  85. InternalPing(LIPAddr, nil, LSeq);
  86. case ReplyStatus.ReplyStatusType of
  87. rsErrorTTLExceeded,
  88. rsTimeout : ;
  89. else
  90. Break;
  91. end;
  92. Inc(LTTL);
  93. TTL := LTTL;
  94. LSeq := LSeq * 2;
  95. end;
  96. end;
  97. end.