Как отследить маршрут с Indy10 TIdIcmpClient?

Чтобы сделать трассировку маршрута мы можем прочитать в документации Indy

"Для приложения Traceroute отправляйте эхо-запросы ping с увеличенными значениями TTL"

Проблема в том, что свойство TTL защищено и не может быть установлено. Это просто еще одна ошибка или мне действительно нужно определить новый класс, чтобы сделать свойство TTL общедоступным?

Тем не менее, я сделал новый класс (включая обход Ping):

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);
    }

};

Если я установлю TTL на 5 и вызову Ping на google.com (я проверил, что на моем сайте есть 6 TTL для google.com).

Таким образом, значение TTL, равное 5, сгенерирует сообщение об истечении времени ICMP, и в соответствии с документацией будет возвращен последний IP-адрес. Но вместо этого я получаю IP 0.0.0.0, Это значения членов AReplyStatus в OnReply(TComponent *ASender, const TReplyStatus *AReplyStatus) Перезвоните.

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 }

Если я изменю TTL на 6, все будет работать как положено (ответы google.com), и я получу взамен rsEcho.

Итак, чтобы уточнить вопрос:
Как я могу сделать traceroute (увеличение TTL), чтобы собрать все IP-адреса маршрутизатора по пути?

1 ответ

Решение

Я немного покопался и сумел провести трассировку с помощью Win32 API вместо Indy. Win32 API довольно прост и имеет функцию только для ICMP Echo: IcmpSendEcho.

Вам необходимо использовать необязательные параметры RequestOptions, чтобы установить TTL от 1 и увеличивать для каждого вызова, пока вы не достигнете своего предела прыжка или не добьетесь успеха.

Компонент Indy, похоже, просто не возвращает ошибок, только в случае успеха или тайм-аута (мс не 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);
Другие вопросы по тегам