0

To do a trace route we can read in the Indy documentation

"For Traceroute application, send ping echo requests with increased TTL values"

The problem is that the TTL property is protected and can't be set. Is this just another bug or do I really have to define a new class to make the TTL property public?

However, I did a new class (including the Ping work around):

class TPing : public TIdIcmpClient {

  public:
    __property TTL;

    __fastcall TPing(TComponent* Owner) : TIdIcmpClient(Owner) {};
    __fastcall Ping(unsigned int Id = 0) {
      AnsiString Proxy = StringOfChar('X',PacketSize);
      TIdIcmpClient::Ping(Proxy,Id);
    }

};

If I set TTL to 5 and call Ping to google.com (I have checked that there is 6 TTL to google.com from my location).

So a TTL of 5 will generate an ICMP timeout message and according to the documentation, the last IP will be returned. But instead I get IP 0.0.0.0. This is the member values of AReplyStatus in the OnReply(TComponent *ASender, const TReplyStatus *AReplyStatus) callback.

FByteReceived    0,
FFromIpAddress   { u"0.0.0.0" },
FToIpAddress     { u"0.0.0.0" },
FMsgType         '\0',
FMsgCode         '\0',
FSequenceId      3490U(0x0DA2),
FMsRoundTripTime 109,
FTimeToLive      '\0',
FReplyStatus     2 /* rsTimeOut */,
FPacketNumber    0,
FHostName        { NULL },
FMsg             { NULL },
FRedirectTo      { NULL }

If I change the TTL to 6 everything works as expected (google.com answers) and I get rsEcho in return.

So to clarify the question:
How can I do a traceroute (Incrementing TTL) to collect all the router IP addresses along the way?

4

1 回答 1

0

我做了一些探索,并设法使用 Win32 API 而不是 Indy 进行跟踪。Win32 API 非常简单,并且有一个仅用于 ICMP Echo 的函数:IcmpSendEcho

您需要使用可选的 RequestOptions 将 TTL 从 1 设置为每次调用都增加,直到您达到跃点限制或成功返回。

Indy 组件似乎没有返回错误,只有成功或超时(ms 不是 TTL)。

我已经将我的代码精简到最低限度(虽然没有经过测试)。

IP_OPTION_INFORMATION Options;

IPAddr           Host;   // Host address to ping
char             SendData[32] = "Echo";
HANDLE           hIcmp;
LPVOID           ReplyBuffer;
DWORD            ReplySize;
PICMP_ECHO_REPLY pEchoReply;
int              TTL = 0;
int              Timeout = 5000; // 5 seconds timeout
bool             done = false;

// Prepare ICMP operation
Host = inet_addr("74.125.232.95"); // Google server
hIcmp = IcmpCreateFile();

if (hIcmp == INVALID_HANDLE_VALUE) {
  return psICMPFailure;
}

// Prepare ISMP reply buffer
ReplySize   = sizeof(ICMP_ECHO_REPLY) + 32;
ReplyBuffer = (VOID*) malloc(ReplySize);

while (!done && TTL++<30) {

  // Prepare options
  Options.Ttl = TTL;
  Options.Tos = 0;
  Options.Flags = IP_FLAG_DF;
  Options.OptionsSize = 0;
  Options.OptionsData = NULL;

  // PING
  IcmpSendEcho(hIcmp,Host,SendData,sizeof(SendData),&Options,ReplyBuffer,ReplySize, Timeout);

  // get result
  pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;

  // Do something like adding the Host IP to a list

  // Check ICMP status
  done = (pEchoReply->Status == 0);
}

// Cleanup
IcmpCloseHandle(hIcmp);
free(ReplyBuffer);
于 2014-02-23T01:59:08.370 回答