2014-02-10 7 views
0

Для маршрута трассировки можно прочитать в Инди documentationКак traceroute с Indy10 TIdIcmpClient?

«Для применения Traceroute, отправить пинг эхо-запросы с повышенными значениями 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.ru ответы) и я получаю rsEcho взамен.

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

+0

В Indy имеется отдельный компонент TIdTraceRoute. –

+0

Да, я нашел его, но он не работает. Для каждого тайм-аута TTL Indy не возвращается до тех пор, пока не будет достигнут его собственный тайм-аут, а не когда ICMP вернет дейтаграмму тайм-аута (я проверил это с помощью WireShark). Когда Indy, наконец, вернется и вызовет OnReply ... –

+0

... (продолжение) AReplyStatus не инициализирован правильно. Исходный адрес - 0.0.0.0, а не последний IP-адрес трассировки. Я получаю тот же результат, что и выше, с TraceRoute. TraaceRoute также испытывает проблему TIdIcmpClient со случайной ошибкой # 10040 (и это было бы логично, если в TIdIcmpClient есть ошибка). –

ответ

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