Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Все просто, как... ping

243
21 ноября 2005 года
pacific_7
1.9K / / 06.09.2004
Значится так, имеем обычный ping, который используется в виндах. И сорцы от мелкомягких. Сравниваем, получаем следующие баги в пинге собраном по их исходникам:
1. Не работает под пользователем с урезанными правами - выдается ошибка "Сделана попытка доступа к сокету методом запрещенным правами доступа".
2. При попытке пинговать не существующий узел - программа виснет, хотя согласно мелкомягкой документации должна выполняться после истечения некоторого заданного таймаута.Стандартный пинг в этих случаях пишет "Превышен интервал..." Например 150.65.65.65.
Я там уже все что мог пересмотрел, и вариантов 2 - либо в стандартном пинге опять-таки использованы какие-то недокументированные функции, либо я чего-то не досмотрел.
Сорцы пинга в прицепленном файле, если кому интересно и может помочь - буду благодарен.
243
21 ноября 2005 года
pacific_7
1.9K / / 06.09.2004
Так, отвечу сам себе на 2-ой вопрос :)
В стандартном пинге эта проблема решается видимо так, как я сразу и подумал. Там 2 потока и наверняка один контролирует зависания второго. С этим понятно, сделаем. Теперь интересен первый вопрос.
243
21 ноября 2005 года
pacific_7
1.9K / / 06.09.2004
Дальше - больше и интереснее. В ХР ping как-то укладывается в один поток. Как - ума не приложу.
243
23 января 2006 года
pacific_7
1.9K / / 06.09.2004
Давно разгребся, все ни как не соберусь поделиться. Можно сделать и через RAW_SOCKET, как я в начале и сделал, но тогда действительно надо 2 потока и еще тот минус, что функции работы с RAW_SOCKET можно применять только под админом.
Понятно что так делать - не хорошо. Потому нашел более корректный, и как выяснилось, более простой вариант. В виндах есть системная библиотека icmp.dll. Надо работать с ней. Пример ниже:
Код:
#include <windows.h>
#include <Ipexport.h>
#include <stdio.h>
#include <conio.h>

//ДЕСКРИПТОР ДЛЯ ЗАГРУЗКИ СИСТЕМНОЙ БИБЛИОТЕКИ ICMP.DLL
HINSTANCE icmpdll;
//ОПРЕДЕЛЯЕМ ТИП УКАЗАТЕЛЯ НА ФУНКЦИЮ IcmpSendEcho:
typedef DWORD(CALLBACK* IcmpSendEcho)(HANDLE,IPAddr,LPVOID,WORD,
                PIP_OPTION_INFORMATION,LPVOID,DWORD,DWORD);
//ОПРЕДЕЛЯЕМ ТИП УКАЗАТЕЛЯ НА ФУНКЦИЮ IcmpCreateFile
//HANDLE IcmpCreateFile(void);
typedef HANDLE (CALLBACK* IcmpCreateFile)(void);
//BOOL IcmpCloseHandle(HANDLE IcmpHandle);
typedef bool (CALLBACK* IcmpCloseHandle)(HANDLE IcmpHandle);

int main(void)
{
    WSADATA wsaData;

    if (WSAStartup(0x0101,&wsaData) != 0)
    {
        fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
        return -1;
    }
// Check WinSock version
   if (0x0101 != wsaData.wVersion)
   {
       fprintf(stderr,"\nWinSock version 1.1 not supported\n");
       WSACleanup();
       return -1;
   }   
    //ЗАГРУЖАЕМ БИБЛИОТЕКУ
    icmpdll=LoadLibrary("icmp.dll");
    if(!icmpdll)
    {
        printf("LoadLibrary failed!\n");
        return -1;
    }
   
    //ОБЪЯВЛЯЕМ ССЫЛКИ НА ФУНКЦИИ ИЗ БИБЛИОТЕКИ ICMP.DLL
    IcmpSendEcho icmp_echo;
    IcmpCreateFile icmp_create_file;
    IcmpCloseHandle close_icmp_file;

    //ПРОИЗВОДИМ ИМПОРТ ФУНКЦИЙ
    icmp_echo=(IcmpSendEcho)GetProcAddress(icmpdll,"IcmpSendEcho");
    if(!(DWORD)icmp_echo)
    {
        printf("Faild get address IcmpSendEcho!\n");
        return -1;
    }
    icmp_create_file=(IcmpCreateFile)GetProcAddress(icmpdll,"IcmpCreateFile");
    if(!(DWORD)icmp_create_file)
    {
        printf("Faild get address IcmpCreateFile!\n");
        return -1;
    }
    close_icmp_file=(IcmpCloseHandle)GetProcAddress(icmpdll,"IcmpCloseHandle");
    if(!(DWORD)close_icmp_file)
    {
        printf("Faild get address IcmpCloseHandle!\n");
        return -1;
    }
    //ПУСКАЕМ ПИНГ
    char *SendData = "Data Buffer";
    HANDLE hIcmpFile;

    hIcmpFile=icmp_create_file();
    if(hIcmpFile==INVALID_HANDLE_VALUE)
    {
        printf("Failed icmp_create_file!\n");
        return -1;
    }//else printf("Success icmp_create_file...\n");

    //ICMP_ECHO_REPLY icmpEcho;
    in_addr iaDest;
    IP_OPTION_INFORMATION ipInfo;
    ipInfo.Ttl= 128;
    ipInfo.Tos = 0;
    ipInfo.Flags= 0;
    ipInfo.OptionsSize= 0;
    ipInfo.OptionsData= NULL;
    u_int packet_size=1024;
    char *send_buffer=(char*)malloc(packet_size);
    memset(send_buffer,'A',packet_size);
    if(packet_size<8)packet_size=8;
    LPVOID repl_buf=(VOID*) malloc(sizeof(ICMP_ECHO_REPLY) + packet_size);
    for(int i=0;i<10;i++)
    {
        DWORD dwRet = icmp_echo(
                        hIcmpFile,               // Handle from IcmpCreateFile()
                        inet_addr("10.65.5.1"),             // Destination IP address
                        send_buffer,                   // Pointer to buffer to send
                        packet_size,// Size of buffer in bytes
                        &ipInfo,                // Request options
                        repl_buf,              // Reply buffer
                        packet_size+sizeof(ICMP_ECHO_REPLY),
                        3000);                  // Time to wait in milliseconds
    // Print the results
//      if(!dwRet)return -1;
        PICMP_ECHO_REPLY icmpEcho = (PICMP_ECHO_REPLY)repl_buf;
        iaDest.s_addr = icmpEcho->Address;
        printf("Reply from %s Time=%ldms TTL=%d size=%u bytes; status: ",
                                    inet_ntoa(iaDest),
                                    icmpEcho->RoundTripTime,
                                    icmpEcho->Options.Ttl,icmpEcho->DataSize);
        switch(icmpEcho->Status)
        {
        case IP_SUCCESS: printf("IP_SUCCESS\n");break;
            //ТУТ ЕЩЕ КУЧАЙ case'ов, ЗА ПОЯСНЕНИЯМИ СМ. ipexport.h
        default: printf("Uncknown status!\n");break;
        }
        Sleep(500);
        //getch();
    }
    free(repl_buf);
    //ОСВОБОЖДАЕМ БИБЛИОТЕКУ
    if(!FreeLibrary(icmpdll))
    {
        printf("FreeLibrary failed!\n");
        return -1;
    }
    if(!CloseHandle(hIcmpFile))
    {
        printf("Failed close_icmp_file!\n");
        return -1;
    }
    WSACleanup();
    printf("Press any key to exit program...\n");
    getch();
    return 0;
}
398
24 января 2006 года
Alexandoros
630 / / 21.10.2005
Хорошо копаеш :).
243
25 января 2006 года
pacific_7
1.9K / / 06.09.2004
Цитата:
Originally posted by Alexandoros
Хорошо копаеш :).


Кстати, я был прав. Про недокументированные функции. Те функции что я заюзал применяются в traceroute. А в пинге используются отнюдь не они. Там ХЗ что юзается.

398
25 января 2006 года
Alexandoros
630 / / 21.10.2005
Цитата:
Originally posted by pacific_7
Кстати, я был прав. Про недокументированные функции. Те функции что я заюзал применяются в traceroute. А в пинге используются отнюдь не они. Там ХЗ что юзается.


Я вон отдизассемблил ping от в2к3 - там идут вызовы WSAIoctl, getaddrinfo, IcmpSendEcho2 и т.д. Документировано таки.

243
25 января 2006 года
pacific_7
1.9K / / 06.09.2004
Цитата:
Originally posted by Alexandoros
IcmpSendEcho2 и т.д. Документировано таки.


Согласен, щас не дома, потому сам глянуть не могу. Но! Во первых, IcmpSendEcho2!=IcmpSendEcho, а применять надо судя по ТЗ вроде как именно вторую. Но даже это ладно - если там только эти функции, то не хвататет как минимум IcmpCreateFile. Если смотреть msdn, то там вообще бред какой-то непонятный пишут :). Во первых в примере для IcmpSendEcho2 первые 3 параметра установлены в NULL. Ладно, допустим что это дефолтное значение. Только не очень понятно что и как там работает в общем. Проверять как она работает я даже не стал.
Смотрим функцию IcmpSendEcho - там дан откровенно не рабочий пример: неправильно указан размер буфера отправки. В примере он расчитывается из длинны данных и длинны icmp-ответа (sizeof(SendData) + sizeof(ICMP_ECHO_REPLY)) - при чем в запросе размер ответа, не очень понятно сразу, но фича в том, что оно вообще не работает, если не убрать sizeof(ICMP_ECHO_REPLY)!!! Возвращает ошибку о недостаточности размера приемного буфера который расчитывается так же. При чем нехватает как раз строго на длинну ICMP_ECHO_REPLY из чего можно сделать не сложный вывод :)
Ну и последнее. В самом конце доки на IcmpSendEcho написано: "Client Requires Windows Vista or Windows XP." И не меньше. Хотя в 2000-ной оно тоже есть и юзается самими же мелкософтами в tracert. И у меня в 2000-ной все на ура работает. Вывод: мелкософты сами заколбасились в своей документации по уши и не задокументировали толком ни первую, ни вторую функции.

ЗЫ Често говоря я не понимаю почему в tracert применяются одни функции, а в ping - другие. Хотя задачи выполняют одинаковые. Очередная замута MS.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог