Многопоточный ICMP сканер (pingscan)

Поддерживаемая платформа: Windows.
Однажды мне потребовался простой ICMP сканер сегментов, имеющий адекватную скорость сканирования, простой интерфейс и возможность работы в Windows от имени непривелигерованного пользователя. Различные утилиты, найденные в сети, обычно, обладали как минимум одним из перечисленных недостатков: низкая скорости сканирования сегмента; необходимость запуска с правами администратора; сложный интерфейс. В связи с этим (а так же с целью удовлетворения праздного любопытства - "как это работает?"), была написана простенькая, но достаточно эффективная программа pingscan, обладающая возможностью сканирования сегментов задаваемых сетевой маской в CIDR нотации и возможностью тестирования сети при помощи ICMP флуда для отдельно взятого хоста.

Описание режимов работы программы

pingscan работает в 2х режимах использующих два разных подхода для создания потока ICMP сообщений:

  1. Режим сканирования диапазона адресов. В этом случае производится динамическая загрузка функций для работы с ICMP протоколом из icmp.dll (системная DLL Windows) - методика применяется при сканировании диапазона адресов заданых сетевой маской. Высокая скорость сканирования достигается за счёт создания пула потоков (до 64х одновременно) в каждом из которых производся опрос отдельного хоста.
  2. Режим флуда. В этом случае используется низкоуровневая сборка пакетов ICMP сообщений и отправка/получение их при помощи RAW сокетов. Отправка и получение ICMP сообщений производятся в разных потоках. Работа в этом режиме возможна только с правами администратора системы.

Параметры и ключи программы

Формат командной строки для запуска программы:

> pingscan <IP-address>[/netmask] [-n] [-s packet-size] [-c packets-count] [-w time-wait]
							

IP-address - любой IP адрес входящий в сканируемую подсеть.
netmask - длина маски сканируемой подсети. Если не указано - используется значение 24 бита. Список ключей принимаемых программой:

-n - отключает преобразование IP адресов хостов в доменные имена. По умолчанию - включено.
-s - задаёт размер отправляемых пакетов. По умолчанию - 32 байта.
-c - число пакетов отправляемых к каждому хосту. По умолчанию - 2.
-w - таймаут ожидания ICMP-эхо ответа в миллисекундах. Должно быть >= 500,
      по умолчанию - 1000.
-f - режим флуда. Применяется только для одного хоста. Не для подсети! 
      Длина маски должна быть равной 32м битам. Для бесконечного 
      флуда задайте значение ключа '-c' равным 0.

Примеры использования программы

Режим сканирования.
Сканирование с параметрами по умолчанию, в качестве цели использован один из адресов хоста mail.ru:

X:\>pingscan 194.67.57.226
Pingscan version 0.9.1 (01.10.2008) started.
Found 194.67.57.3     video4-2.mail.ru          time=4 ms TTL=55 size=32 bytes
Found 194.67.57.21    video2.mail.ru            time=4 ms TTL=55 size=32 bytes
Found 194.67.57.6     f96.mail.ru               time=4 ms TTL=55 size=32 bytes
Found 194.67.57.9     f99.mail.ru               time=4 ms TTL=55 size=32 bytes
Found 194.67.57.4     ns4.mail.ru               time=4 ms TTL=55 size=32 bytes
Found 194.67.57.12    video4.mail.ru            time=4 ms TTL=55 size=32 bytes
Found 194.67.57.10    f102.mail.ru              time=4 ms TTL=55 size=32 bytes
Found 194.67.57.18    video1-2.mail.ru          time=4 ms TTL=55 size=32 bytes
Found 194.67.57.17    video2-2.mail.ru          time=4 ms TTL=55 size=32 bytes
Found 194.67.57.11    af1.mail.ru               time=4 ms TTL=55 size=32 bytes
Found 194.67.57.2     f108.mail.ru              time=4 ms TTL=55 size=32 bytes
***часть вывода программы пропущена***
Found 194.67.57.215   time=3 ms TTL=250 size=32 bytes
Found 194.67.57.204   time=2 ms TTL=55 size=32 bytes
Found 194.67.57.226   time=2 ms TTL=119 size=32 bytes
Found 194.67.57.223   time=3 ms TTL=119 size=32 bytes
Found 194.67.57.240   time=2 ms TTL=118 size=32 bytes
Found 194.67.57.250   time=2 ms TTL=119 size=32 bytes
Found 194.67.57.251   time=3 ms TTL=118 size=32 bytes
Found 194.67.57.253   time=2 ms TTL=118 size=32 bytes
Found 194.67.57.101   time=2 ms TTL=118 size=32 bytes
Found 194.67.57.100   time=3 ms TTL=118 size=32 bytes
Found 194.67.57.96    time=4 ms TTL=54 size=32 bytes
Total hosts scanned: 256 in 6.14 seconds.
Pingscan finished - 249 hosts found.

При использовании значений параметров заданных по умолчанию, программа получает адрес подсети из переданного ей IP адреса хоста используя значение маски равное 24м битам (в данном случае - 194.67.57.0/24), таким образом сканируется 256 IP адресов включая получаемый адрес сети и широковещательный адрес - ведь фактическая длина маски удалённой подсети не известна и по этим адресам так же могут находиться хосты. Как видно из вывода программы - для начальныых хостов подсети (по значению IP адреса) имеются записи в обратной зоне DNS. Для последних хостов этих записей нет, потому информация о них выводится без доменных имён. Замечу что на обратное разрешение имён тратится значительное время, особенно в случае отсутствия записи для хоста в обратной зоне, потому суммарное время сканирования данной подсети равно примерно 6ти секундам. При использовании ключа '-n' обратное преобразование имён отключается и время сканирования указаной подсети сокращается примерно до 2х секунд.
Возможно вам бросился в глаза не упорядоченный по IP адресу вывод информации о полученных от хостов ответах. Например сперва выведена информация о хосте 194.67.57.3, потом о 194.67.57.21 а за ним - 194.67.57.6 и т.д. Это объясняется тем что программа не производит внутреннего упорядочивания полученных данных и выводит информацию об ответах хостов в режиме реального времени.
Теперь пример сканирования с указанием того же адреса и дополнительными параметрами:

> pingscan 194.67.57.226/30 -n -c 3 -w 2000 -s 5000
Pingscan version 0.9.1 (01.10.2008) started.
Found 194.67.57.224   time=7 ms TTL=55 size=5000 bytes
Found 194.67.57.225   time=8 ms TTL=55 size=5000 bytes
Total hosts scanned: 4 in 5.625 seconds.
Pingscan finished - 2 hosts found.

В данном примере указана длина сетевой маски равной 30ти битам (CIDR нотация), отключено обратное преобразование доменных имён, задано отправлять до 3х пакетов к каждому хосту в случае его не ответа, задан таймаут ответа в 2 секунды и установлен размер пакета равный 5000 байт. Как можно заметить - результат выполнения программы изменился. Например увеличилось время получения ответа, а хосты с адресами 194.67.57.226, 194.67.57.227 и вовсе не ответили на запросы. Если задать размер пакета равным например 1000 байт, то эти хосты ответят. Судя по всему фаерволл блокирует ответы на фрагментированные ICMP запросы.
Примечание: программа не принимает в качестве параметра имя хоста, т.к. доменное имя может разрешаться сразу в несколько IP адресов. Порядок выдачи этих адресов DNS сервером является случайным. Таким образом при сканировании сегмента заданного доменным именем получается сканирование случайного сегмента. Что как мне кажется - лишено смысла.

Режим ICMP флуда.
Внимание! Использование ICMP флуда требует разумного подхода! В противном случае не исключена блокировка вас со стороны администратора сети, провайдера и т.д. Крайне не рекомендуется запускать флуд в интернет.
Как уже указывалось выше - запустить флуд можно только с правами администратора системы. Тестирование одного из хостов локальной сети:

X:\>pingscan 192.168.2.102/32 -f -c 1000 -s 1000
Loss: . (1 packets)
Total hosts scanned: 1 in 2.203 seconds.
Flood mode statistic: 1000 packets transmitted, 999 received, 0.10% packets loss.
Pingscan finished.

Как мне кажется - вывод программы достаточно очевиден что бы его дополнительно пояснять. Можно обратить внимание на передаваемые параметры: маска обязательно должна быть указана равной 32м битам. В случае использования бесконечного флуда (до прерывания по Ctrl+C) значение ключа '-c' нужно задать равным нулю:

X:\>pingscan 192.168.2.102/32 -f -c 1000 -s 1000 -c 0
Loss:  (19 packets)
Program terminated at 3.078 seconds.
Flood statistic: 14557 packets transmitted, 14538 received, 0.13% packets loss.
^C

Символы "^C" в последней строке вывода обозначают что программа завершена по клавиатурному прерыванию через Ctrl+C.

Используемые системные функции

Ниже приведён список системных функций используемых в программе.

Функции для работы с ICMP протоколом (производится динамическая загрузка DLL):
  • IcmpCreateFile - открывает хэндл для выполнения ICMP запросов.
  • IcmpSendEcho - выполняет отправку ICMP-echo и завершается либо при получении ответа, либо по заданному таймауту.
  • IcmpCloseHandle - закрывает хэндл созданный при помощи IcmpCreateFile
Функции создания и завершения потоков:
  • _beginthreadex() - создаёт дочерний поток выполнения. Используется как в режиме сканирования, так и в режиме флуда для создания дочернего потока-приёмника ICMP сообщений.
  • _endthreadex() - завершение дочернего потока. Вызывается внутри завершающегося потока.
  • TerminateThread() - принудительное завершение порождённого потока. Обычно (и в данном случае) выполняется из породившего потока. Используется в режиме флуда для завершения потока-приёмника
Функции для синхронизации потоков:
  • WaitForMultipleObjects() - производит блокировку вызвавшего потока до перехода указанного числа объектов в сигнальное состояние. Используется в режиме сканирования.
  • WaitForSingleObject() - производит блокировку вызвавшего потока до перехода указанного (одного) объекта в сигнальное состояние. Используется в режиме флуда для ожидания завершения потока - передатчика ICMP сообщений.
  • InitializeCriticalSection, EnterCriticalSection Function, LeaveCriticalSection и DeleteCriticalSection - функции для работы с критическими секциями. Используются в обоих режимах работы программы.

Ознакомиться с подробностями принципов работы программы вы можете скачав архив исходных кодов, либо в HTML формате:

  • pingscan.c, pingscan.h - функция main(), основные типы и константы.
  • func.c, func.h - функции для работы с icmp.dll, исполняемая функция дочерних потоков (one_ping()), а так же вспомогательные фунции.
  • raw_ping.c, raw_ping.h - функции использующие RAW сокеты для отправки и получения ICMP сообщений. Используются в режиме флуда.

Сборка производилась в "Eclipse Platform Version: 3.3.2" + компилятор gcc, но т.к. в программе используется практически чистый WinAPI + стандартный Си - сборка не должна составить проблем с использованием любой другой IDE и компилятора.

Все возникшие пожелания и предложения можно (или даже нужно) сообщить в гостевую или на и статья будет скорректированна, если это будет уместно.


Вернуться в "Проекты"