ЭХО В СЕТЯХ

Локальной вычислительной сетью из персональных компьютеров сегодня уже никого не удивишь. Более того, прошли те времена, когда компьютеры объединялись в сеть в пределах одной комнаты. Как правило, сеть организации охватывает все административное здание целиком, для сетевых принтеров и серверов выделяются отдельные помещения, появляются и набирают популярность домашние сети. Вместе с неоспоримой выгодой такое увеличение масштаба несет за собой и некоторые неудобства. Ввиду отсутствия прямой видимости сложно определить, работает ли компьютер у коллеги, к которому на винчестер были сброшены документы. А если кто-то выключил сетевой принтер, то созданная очередь заданий на печать может реализовать себя не в самый подходящий момент. И если все описанные проблемы достаточно просто решаются "организационными мероприятиями", то для технического персонала большая вычислительная сеть может стать настоящей головной болью, если не позаботиться о специальных средствах мониторинга ее работоспособности. Выпал из разъема сетевой кабель? Из прорвавшегося водопровода затопило маршрутизатор? "Завис" или перегружен сервер? Получить ответ на любой из поставленных вопросов системный администратор желал бы как можно раньше, дабы избежать справедливого и не очень гнева своих коллег — остальных пользователей системы.

Теперь кажется вполне естественным, что проектировщики стандартов вычислительных сетей предусмотрели в сетевых протоколах штатные
средства, позволяющие выполнять диагностику функционирования системы. При использовании протокола TCP/IP таковым средством является протокол ICMP (Internet Control Message Protocol). Он описан в документе RFC 792 и является частью уровня IP. Сообщения ICMP инкапсулируются в IP- дейтаграммы, так что они могут распространяться по TCP/IP-сетям, в том числе и в Internet.

Протокол ICMP используется для:
. построения и поддержания в актуальном состоянии таблиц маршрутизации;
. определения параметра PMTU (Path Maximum Transmission Unit);
. диагностики сетевых проблем;
. осуществления контроля загруженности маршрутизаторов;
. исследования маршрутов передачи пакетов.

Основной целью этой статьи является рассмотрение лишь одной сферы использования протокола ICMP — в целях определения доступности и
работоспособности сетевого устройства. Хотя в некоторых местах будут затронуты и смежные вопросы определения статистических характеристик сетевой среды.
Любой системный администратор подтвердит, что первым шагом на пути решения возникшей проблемы является проверка доступности сетевого ресурса, будь то сервер, маршрутизатор или сетевой принтер. Для этого в операционной системе (в этой статье речь будет идти преимущественно о Microsoft Windows, хотя многие положения верны и для других систем) припасена команда-утилита Ping. Эта утилита с помощью протокола ICMP отправляет интересующему нас узлу эхо-запросы (Echo Requests) и ожидает получения от него эхо-ответов (Echo Replies). Если перекличка состоялась, то утилита Ping позволяет, кроме установленного факта активности сетевого ресурса, получить некоторую статистическую информацию, как- то: процент успешных запросов и среднее время отклика. В противном случае происходит ожидание в течение некоторого предопределенного временного интервала (тайм-аута).
В простейшем случае команда записывается следующим образом:

ping 192.168.48.10

где 192.168.48.10 — общепринятая запись IP-адреса опрашиваемого ресурса. В этой команде неявно подразумевается, что будет отправлено четыре запроса, максимальное время ожидания ответа на каждый запрос (тайм-аут) составляет 750 миллисекунд. Протокол опроса может выглядеть следующим образом:

Обмен пакетами с 192.168.48.10 по 32 байт:

Ответ от 192.168.48.10: число байт=32 время=14мс TTL=128

Ответ от 192.168.48.10: число байт=32 время=18мс TTL=128

Ответ от 192.168.48.10: число байт=32 время=16мс TTL=128
Ответ от 192.168.48.10: число байт=32 время=20мс TTL=128

Статистика Ping для 192.168.48.10:
Пакетов: послано = 4, получено = 4, потеряно = 0 (0% потерь),
Приблизительное время передачи и приема:
наименьшее = 14мс, наибольшее = 20мс, среднее = 17мс

В случаях, когда нужно выполнить более детальный анализ соединения между двумя IP-устройствами, можно воспользоваться дополнительными возможностями команды Ping. Если требуется проанализировать качество соединения за более продолжительный промежуток времени, нужно в командной строке, кроме адреса сетевого узла, указать параметр -n с количеством отправляемых пакетов либо параметр -t. В последнем случае опрос узла будет осуществляться до тех пор, пока не будет нажата комбинация клавиш [Ctrl]+[C]. Чтобы ознакомиться с промежуточной статистикой, можно нажать [Ctrl]+[Break]. Маршрут к опрашиваемому сетевому ресурсу может лежать через некоторое (в случае Internet иногда довольно большое) количество промежуточных узлов — серверов и маршрутизаторов. Эхо-запрос, отправляемый командой Ping, несет в себе счетчик, который увеличивается на единицу при прохождении каждого промежуточного узла. Максимальное значение этого счетчика носит название "Time to live" (TTL) — "время жизни". По достижении счетчиком значения TTL эхо-запрос считается "заблудившимся" и уничтожается. Указать значение TTL можно с помощью параметра -i командной строки утилиты Ping.

Обмен информацией между сетевыми устройствами по протоколу TCP/IP осуществляется не непрерывными потоками, а последовательными пакетами данных. Размер пакета не стандартизирован и может отличаться для различных пар узлов. В определении его максимального размера может помочь команда Ping. Если внимательно прочитать приведенный выше протокол опроса, то можно заметить указание на размер пакетов, которыми осуществляется обмен. По умолчанию он равен 32 байтам, но это значение можно изменить с помощью ключа -l. Если запрашиваемый размер пакета больше того, который согласован между сетевыми устройствами, при его передаче будет осуществляться фрагментация, то есть он будет разбит на несколько пакетов меньшего размера. Но в команде Ping фрагментацию можно запретить, указав в командной строке параметр -f. В этом случае при попытке передать пакет большего размера, чем максимально установленный, будет получено следующее сообщение: "Требуется фрагментация пакета, но установлен запрещающий флаг". Эту возможность команды Ping можно использовать для определения методом подбора максимального размера пакета данных, который может быть передан по протоколу TCP/IP между указанными устройствами. Для того, чтобы реализовать на практике вышеописанные действия, не нужно прилагать каких-либо дополнительных усилий, кроме ввода команд в командной строке операционной системы. Однако вполне можно представить себе ситуацию, когда процесс опроса сетевого ресурса и анализ ответа нужно автоматизировать, дабы компьютер занимался тем, чем ему положено заниматься — выполнял нетворческую работу диспетчера и сообщал администратору лишь о возникающих отклонениях от нормального состояния системы. Видятся два существенно различных способа реализации схемы такого мониторинга. Первый основан на заложенных в операционную систему возможностях осуществления информационного обмена между выполняющимися процессами. Дело в том, что утилита Ping выдает информацию на стандартное устройство вывода, коим в обычной ситуации является экран монитора. Однако ничто не мешает нам перенаправить вывод в какой-нибудь файл. Тогда остается сконструировать простой командный bat-файл следующего вида:

ping -n 10 192.168.1.1 > C:\LOG\ping.log
:loop
wait 300
ping -n 10 192.168.1.1 > > C:\LOG\ping.log
goto loop

который с интервалом в 5 минут будет десятикратно опрашивать узел 192.168.1.1 и записывать результат опроса в текстовый файл Ping.log. Поясним работу этого bat-сценария. Первая строка создает журнальный файл ping.log и записывает в него первую порцию информации (чему способствует символ перенаправления вывода "> "). Третья строка выполняет задержку выполнения bat-сценария с помощью утилиты wait, которая, к сожалению, не входит в стандартную поставку DOS или Windows, на 300 секунд. Эту строку можно опустить, однако тогда запросы будут выполняться непрерывно, что, с одной стороны, увеличит загрузку вычислительной сети, а с другой — отнимет процессорное время у сервера, на котором выполняется командный файл. Четвертая строка выполняет запрос к узлу аналогично первой команде, но, в отличие от нее, не создает новый log-файл, а дописывает информацию в уже существующий (это достигнуто посредством использования символа перенаправления вывода "> > "). Пятая строка организует потенциально бесконечный цикл опроса сетевого ресурса, который, однако, может быть прерван стандартным сочетанием клавиш [Ctrl]+[C]. В результате можно получить журнал опроса сетевого узла для анализа вручную или с помощью специально разработанной программы. У этого способа, однако, есть существенный недостаток. Он может быть использован только для "разбора полетов", но мало полезен в ситуации, когда анализ или реакция на изменяющуюся ситуацию должны осуществляться незамедлительно, в реальном времени. Если немного поразмыслить, можно предложить некоторую модификацию предложенного командного файла. Предположим, что в наличии имеется программа, способная извлекать полезную информацию из текстового файла, который формируется указанным выше способом из выходного потока утилиты Ping. Такую программу, затратив некоторые усилия, можно реализовать практически на любом распространенном языке программирования. Допустим, что программа откомпилирована в файл PingAnalyse.exe и для своей работы требует указания в командной строке имени log-файла утилиты Ping. Тогда можно написать командный bat-файл:

:loop
ping -n 10 192.168.1.1 > C:\LOG\ping.log
PingAnalyse.exe C:\LOG\ping.log
wait 300
goto loop

который позволит внести элемент автоматизации в процесс мониторинга состояния сетевого узла. Эту схему можно сделать немного лучше, если вспомнить, что операционная система позволяет непосредственно связывать поток вывода одного процесса с потоком ввода другого (практика показывает, что при этом все равно создается временный файл, однако это не отменяет права этого способа на существование). Если удастся доработать программу PingAnalyse.exe таким образом, чтобы она принимала информацию не из файла, а со стандартного ввода (это представляется в ряде случаев даже проще), то bat-файл можно изменить:

:loop
ping -n 10 192.168.1.1 | PingAnalyse.exe
wait 300
goto loop

Во второй строке символ "|" как раз и указывает требование увязать выходной поток команды Ping с входным потоком программы PingAnalyse.exe. При всей своей простоте, красоте и изяществе предложенный способ реализации мониторинга с использованием командного файла имеет ряд существенных недостатков. Он начисто лишен пользовательского интерфейса (если не считать таковым комбинацию клавиш [Ctrl]+[C]) — для внесения каких-либо изменений потребуется как минимум исправление bat-файла, а то и изменение с последующей перекомпиляцией программы PingAnalyse. Устранить указанные недостатки можно лишь путем разработки собственной утилиты, что и является вторым способом реализации схемы мониторинга.

Как же отправить эхо-запрос из собственной программы? Вполне естественно предположить, что такая взрослая операционная система, как Windows, имеет в составе своих API-функций что-нибудь подходящее. Однако на практике все оказывается не так просто и радужно. Беглый обзор документации по Win32 API не помог в решении поставленного вопроса. Более серьезные поиски позволили узреть в недрах Windows динамическую библиотеку ICMP.DLL, функции которой, по словам ее авторов, позволяют реализовать Ping-функциональность в собственных приложениях. Однако предлагается не рассматривать как саму библиотеку, так и экспортируемые ею функции в качестве части Win32 API, потому что в дальнейшем планируется исключить их из новых версий Windows. В качестве альтернативы рекомендуется обратиться к механизмам Winsock 2.0 RAW SOCKETS, однако это нельзя считать равноценной заменой, потому что RAW SOCKETS являются субъектом политики безопасности Windows NT/2000 и могут использоваться только пользователями с администраторскими полномочиями, в отличие от функций библиотеки ICMP.DLL. Но как бы то ни было, на сегодняшний день в распоряжении программистов есть динамическая библиотека, позволяющая достаточно простым способом реализовать опрос сетевого узла из любого Windows-приложения. Поэтому продолжим рассмотрение правил использования функций, предоставляемых ICMP.DLL.

В первую очередь следует обратить внимание на то, что перед обращением к функциям ICMP следует инициализировать Winsock 1.1 путем вызова WSAStartup (0x0101, &wsaData), где wsaData — переменная типа WSADATA — служит для приема информации о деталях реализации Windows Sockets DLL. Вторым шагом должно стать получение манипулятора для выполнения ICMP-запросов. Возвращается манипулятор функцией IcmpCreateFile (). После выполнения описанных подготовительных действий можно приступать к отправке эхо-запросов. Для этих целей служит функция IcmpSendEcho (hIcmp, IpAddr, pDataToSend, nDataToSend, IpHeaderOpt, pRcvBuf, nRcvBuf, nTime). Она отправляет ICMP эхо-запрос по указанному IP-адресу и возвращает любые ответы, полученные в пределах заданного тайм-аута nTime и до исчерпания пространства буфера pRcvBuf. Эта функция синхронна (то есть приостанавливает выполнение процесса до завершения своей работы), и во избежание блокировки процесс должен перед ее вызовом породить соответствующую нить. Первым параметром функции IcmpSendEcho служит манипулятор, полученный на втором шаге инициализации. Вторым — IP-адрес опрашиваемого узла. Третьим и четвертым параметрами являются указатель на отправляемые в эхо-запросе данные и размер этих данных соответственно. Пятый параметр является указателем на структуру, содержащую дополнительные опции запроса (в том числе из уже знакомых по этой статье TTL — время жизни пакета). Шестой и седьмой параметры описывают соответственно указатель на буфер для эхо-ответов и размер этого буфера. Тайм-аут, как уже было сказано, указывается восьмым параметром. Возвращаемое функцией IcmpSendEcho значение представляет собой количество полученных эхо-ответов. По завершении работы функции IcmpSendEcho буфер, на который указывает pRcvBuf, будет заполнен массивом структур типа ICMP_ECHO_REPLY, за которым последуют опции и данные ответов. Буфер должен быть достаточно большим, чтобы разместить хотя бы одну структуру ICMP_ECHO_REPLY плюс Max (nDataToSend, 8) байт, так как сообщение об ошибке ICMP занимает 8 байт. Структура ICMP_ECHO_REPLY описывается следующим образом:

typedef struct {
DWORD Address; // адрес ответившего узла
unsigned long Status; // статус ответа
unsigned long RoundTripTime; // время прохождения запроса
unsigned short DataSize; // размер данных ответа
unsigned short Reserved; // зарезервировано
void *Data; // указатель на данные ответа
IP_OPTION_INFORMATION Options; // опции ответа
} ICMP_ECHO_REPLY;

Как видно, наибольший интерес для наших целей представляет поле RoundTripTime, с помощью которого можно определить время, прошедшее с момента отправки эхо-запроса до получения эхо-ответа (RTT), и вести некоторую статистику. Для корректного завершения работы с ICMP-функциями нужно в обратном порядке выполнить действия, соответствующие шагам инициализации. Первым делом с помощью вызова функции IcmpCloseHandle (hIcmp) освобождается ICMP-манипулятор. Затем нужно освободить Windows Sockets, вызвав WSACleanup ().

Пришло время подвести итоги. В статье был обобщен опыт использования возможностей протокола ICMP в приложениях мониторинга IP-сетей как посредством стандартной утилиты Ping (с элементами автоматизации, легко реализуемыми в среде ОС Windows), так и средствами API-подобных функций библиотеки ICMP.DLL. Попутно были отмечены основные понятия, часто встречающиеся в контексте анализа статистических параметров сетевого трафика. Автор надеется, что читатели найдут применение материалам статьи в своей повседневной работе. Успешного пингования!

Игорь Орещенков, 2005


Компьютерная газета. Статья была опубликована в номере 10 за 2005 год в рубрике hard :: технологии

©1997-2024 Компьютерная газета