Данная статья является продолжением предыдущей, вводной статьи, в которой речь шла о мотивации и истории создания терминала/сниффера IO Ninja, и было немного рассказано про встроенные возможности нашего продукта. Продолжим рассказ о том, что доступно «из коробки», но с более практическим уклоном.
IO Ninja изначально задумывалась как утилита типа «всё-в-одном», и в комплект поставки входит большое количество встроеных плагинов для работы со всеразличными транспортами в разных режимах. Однако вместо сухого перечисления списка плагинов и их возможностей я решил продемонстрировать маленькую выборку задач из жизни, с которыми в нашей компании сталкивались на практике, и с которыми общеизвестные терминалы и мониторы справляются хуже, чем IO Ninja (а чаще не справляются вообще).
Пользователи Unix-подобных систем хорошо знакомы с возможностью перенаправления выхода одной программы на вход другой. Связывание сессий (Session Linking) в IO Ninja предоставляет похожий функционал. Различие заключается в том, что вместо однонаправленного каскада данных, как в случае Unix pipes, связываение двух сессий «закорачивает» выход одной на вход другой и наоборот (при этом в лог записываются все передаваемые данные). Тем самым появляется возможность использовать IO Ninja в качестве универсального посредника для перенаправления и/или прослушивания.
Допустим, к компьютеру через последовательный интерфейс (serial) подключено устройство. Открываем IO Ninja и запускаем сессию Serial. Открываем и конфигурируем последовательный порт (возможно, посылаем несколько тестовых команд устройству, дабы убедиться, что оно живо-здорово).
Далее запускаем сессию TCP Listener, выбираем интерфейс и TCP порт, на котором будем слушать. Связываем наши две сессии Serial и TCP Listener через диалог настроек и – вуаля! Теперь к нашему последовательному устройству можно подсоединяться по TCP с любого другого компьютера!
Типовым методом автообнаружения устройств в сети является широковещательная UDP рассылка некоего эхо-запроса и последующий сбор ответных пакетов – так, в частности, работает автообнаружение у всех встраиваемых модулей, производимых нашей компанией. IO Ninja может быть использована в качестве широковещательного UDP терминала для общения в режиме «one-to-many».
Открываем UDP Socket, прописываем в качестве адреса 255.255.255.255 (или же subnet-broadcast типа 192.168.1.255), и рассылаем эхо-запрос. В результате мы видим список всех устройств в локальном сегменте. Далее, если это необходимо, мы можем продолжать общение с каким-то конкретным устройством.
Кстати, обратите внимание на кнопочку с компасом. При работе с UDP (и в особенности на стороне сервера) часто требуется запоминать адрес, с которого пришёл пакет, и отвечать именно туда – соединения-то нет! В принципе, ничто не мешает копировать адрес из лога и вставлять его в поле ввода “Remote address”. Но зачем делать руками то, что можно переложить на машину? Жмём компас, и получаем требуемую автоматизацию – UDP-сессия будет автоматически перенастраивать Remote address.
Иногда во время отладки требуется сохранить кусок принятых данных в файл. Это может быть, например, блок, который надо отправить в неизменном виде в этой или какой-то другой сессии, может быть, это переданный удалённым узлом файл, может быть ещё что-то третье.
Стандартные терминалы часто буксуют на этой достаточно простой задаче, и связано это со следующими моментами:
IO Ninja выгодно отличается наличием лога в виде «шестнадцатеричной простыни» со склеиванием входящих пакетов – это позволяет выполнить именно то, что нам надо.
Выделяем нужный блок данных (поглядывая, если надо, на статус-бар – там отображается смещение и длина выделенного блока), сохраняем в файл, и потом используем. Например, пересылаем его по другой сессии:
Выше мы видели, как с помощью TCP Listener можно организовать перенаправление, чтобы можно было подсоединяться к последовательному устройству по TCP. Однако изначальным назначением плагина TCP Listener является не это, а работа в качестве server-side TCP терминала (в частности, для отладки клиентской стороны TCP соединения).
Создаём новую сессию TCP Listener, выбираем интерфейс и порт, и запускаем наш сервер. После приёма входящего соединения от клиента с терминалом можно работать как обычно.
Отметим, что в TCP Listener также имеется возможность выбора: принимать или нет новые входящие соединения, если соединение уже имеется в наличии. Данная опция может быть крайне полезной в ситуациях, когда клиент устанавливает множество вторичных соединений на один и тот же адрес (как, например, многие web-браузеры)
IO Ninja включает в себя плагин Network Sniffer – основанный на PCap сетевой сниффер для прослушивания сетевых соединений. Однако, в ряде случаев значительно удобнее использовать другой встроенный плагин, а именно TCP Proxy.
TCP Proxy – это комбинация TCP Connection и TCP Listener, которая позволяет организовать посредника для TCP соединений. Удобство данного подхода заключается в том, что он сразу даёт чистый лог потоков данных в реальном времени (вместо лога в виде пакетов, из которых потоки данных надо ещё потом восстановить). Помимо этого, данная модель работает и там, где прослушивание с помощью сниффера может быть затруднительно (с определёнными моделями сетевых свичей, Wi-Fi карточек и т.д.)
Создаём сессию TCP Proxy, конфигурируем серверную и клиентскую стороны и запускаем наш прокси-сервер. Любое подсоединение к данному серверу породит вторичное подсоединение с клиентской стороны нашего прокси, при этом все данные принятые на клиентской стороне, будет переданы на серверную и наоборот. В этом смысле TCP Proxy напоминает связывание сессий, но специально заточенное под TCP и вследствие этого более удобное.
IO Ninja может быть использована в качестве инструмента для отладки достаточно распространённого подхода к IPC (Inter-Process Communication) в Windows – named pipes. В частности, так общаются некоторые наши Windows-драйвера с сопутствующими сервисами и приложениями.
Для эмуляции серверной стороны вашего приложения (той, где вызывается ConnectNamedPipe), запустите Named Pipe Listener. Данный плагин позволяет принимать входящие named pipe-соединения, которые будут исходить от вашего клиентского приложения/сервиса.
После установления соединения вы можете общаться с клиентом, анализируя лог полученных запросов и отсылая ему ответные пакеты (созданные, например, в строителе пакетов).
Для эмуляции клиентской стороны (той, где вызывается CreateFile) используется плагин Generic File.
Помимо отладки named pipes (или FIFOs в *nix), данный плагин также может быть использован для чтения и записи в драйверы нестандартных устройств.
Кратко коснёмся вопроса прослушивания named pipes. Предположим, имеется приложение или драйвер, использующие pipes для IPC. Если вы можете каким-то образом настраивать адрес named pipe на клиентской стороне, то появляется возможность прослушивания pipe-соединений с помощью посредника (аналогично TCP Proxy).
Со временем в будущих версиях IO Ninja будет также добавлено полноценное прослушивание named pipes без организации man-in-the-middle (в качестве первого приближения, скорее всего, через user-mode API hooking, а впоследствии – через file system filter).
Необходимость в отправке «битых» или иным образом специально сформированных Ethernet фреймов встречается не столь часто и может казаться относящейся, скорее, к разряду экзотики. Тем не менее данный функционал востребован в ряде вполне себе реальных сценариев. Например, в нашей практике это было необходимо во время отладки реализации TCP/IP стека у производимых нашей компанией встраиваемых модулей; другой реалистичной областью приложения могут быть задачи, стоящие перед специалистами по сетевой безопасности, разработчиками firewall-ов и т.д.
Открываем сессию Network Sniffer, выбираем интерфейс и фильтр захвата, запускаем захват. В строителе пакетов подготавливаем необходимый фрейм – например, можно воспользоваться встроенной библиотекой шаблонов пакетов TCP/IP, или же просто скопировать какой-то из захваченных фреймов в шестнадцатеричный редактор и подправить нужные поля.
Нажимаем Send, и любовно составленный нами фрейм отправляется выполнять боевое задание!
Данный список сценариев использования IO Ninja далеко не полон, но, в принципе, достаточен для демонстрации общей картинки. Помимо этого, он абсолютно честен – все описанные выше функции родились из практических нужд, возникавших при разработке наших продуктов.
В следующей части статьи мы перейдём к с самому интересному – к программируемости IO Ninja и открываемых этим новых возможностях.
IO Ninja изначально задумывалась как утилита типа «всё-в-одном», и в комплект поставки входит большое количество встроеных плагинов для работы со всеразличными транспортами в разных режимах. Однако вместо сухого перечисления списка плагинов и их возможностей я решил продемонстрировать маленькую выборку задач из жизни, с которыми в нашей компании сталкивались на практике, и с которыми общеизвестные терминалы и мониторы справляются хуже, чем IO Ninja (а чаще не справляются вообще).
Перенаправление TCP в Serial
Пользователи Unix-подобных систем хорошо знакомы с возможностью перенаправления выхода одной программы на вход другой. Связывание сессий (Session Linking) в IO Ninja предоставляет похожий функционал. Различие заключается в том, что вместо однонаправленного каскада данных, как в случае Unix pipes, связываение двух сессий «закорачивает» выход одной на вход другой и наоборот (при этом в лог записываются все передаваемые данные). Тем самым появляется возможность использовать IO Ninja в качестве универсального посредника для перенаправления и/или прослушивания.
Допустим, к компьютеру через последовательный интерфейс (serial) подключено устройство. Открываем IO Ninja и запускаем сессию Serial. Открываем и конфигурируем последовательный порт (возможно, посылаем несколько тестовых команд устройству, дабы убедиться, что оно живо-здорово).
Далее запускаем сессию TCP Listener, выбираем интерфейс и TCP порт, на котором будем слушать. Связываем наши две сессии Serial и TCP Listener через диалог настроек и – вуаля! Теперь к нашему последовательному устройству можно подсоединяться по TCP с любого другого компьютера!
Поиск устройств в локальном сегменте с помощью UDP broadcast
Типовым методом автообнаружения устройств в сети является широковещательная UDP рассылка некоего эхо-запроса и последующий сбор ответных пакетов – так, в частности, работает автообнаружение у всех встраиваемых модулей, производимых нашей компанией. IO Ninja может быть использована в качестве широковещательного UDP терминала для общения в режиме «one-to-many».
Открываем UDP Socket, прописываем в качестве адреса 255.255.255.255 (или же subnet-broadcast типа 192.168.1.255), и рассылаем эхо-запрос. В результате мы видим список всех устройств в локальном сегменте. Далее, если это необходимо, мы можем продолжать общение с каким-то конкретным устройством.
Кстати, обратите внимание на кнопочку с компасом. При работе с UDP (и в особенности на стороне сервера) часто требуется запоминать адрес, с которого пришёл пакет, и отвечать именно туда – соединения-то нет! В принципе, ничто не мешает копировать адрес из лога и вставлять его в поле ввода “Remote address”. Но зачем делать руками то, что можно переложить на машину? Жмём компас, и получаем требуемую автоматизацию – UDP-сессия будет автоматически перенастраивать Remote address.
Сохранение части входного потока в файл
Иногда во время отладки требуется сохранить кусок принятых данных в файл. Это может быть, например, блок, который надо отправить в неизменном виде в этой или какой-то другой сессии, может быть, это переданный удалённым узлом файл, может быть ещё что-то третье.
Стандартные терминалы часто буксуют на этой достаточно простой задаче, и связано это со следующими моментами:
- Данные могут быть бинарными и содержать непечатаемые символы;
- Данные могут быть «размазаны» между несколькими пакетами;
- Нужен нам, как правило, не весь входной поток, а строго определённый блок (а значит, простым перенаправлением потока в файл проблема тоже решается не совсем чисто).
IO Ninja выгодно отличается наличием лога в виде «шестнадцатеричной простыни» со склеиванием входящих пакетов – это позволяет выполнить именно то, что нам надо.
Выделяем нужный блок данных (поглядывая, если надо, на статус-бар – там отображается смещение и длина выделенного блока), сохраняем в файл, и потом используем. Например, пересылаем его по другой сессии:
Приём TCP соединений с помощью TCP Listener
Выше мы видели, как с помощью TCP Listener можно организовать перенаправление, чтобы можно было подсоединяться к последовательному устройству по TCP. Однако изначальным назначением плагина TCP Listener является не это, а работа в качестве server-side TCP терминала (в частности, для отладки клиентской стороны TCP соединения).
Создаём новую сессию TCP Listener, выбираем интерфейс и порт, и запускаем наш сервер. После приёма входящего соединения от клиента с терминалом можно работать как обычно.
Отметим, что в TCP Listener также имеется возможность выбора: принимать или нет новые входящие соединения, если соединение уже имеется в наличии. Данная опция может быть крайне полезной в ситуациях, когда клиент устанавливает множество вторичных соединений на один и тот же адрес (как, например, многие web-браузеры)
Прослушивание TCP соединений с помощью TCP Proxy
IO Ninja включает в себя плагин Network Sniffer – основанный на PCap сетевой сниффер для прослушивания сетевых соединений. Однако, в ряде случаев значительно удобнее использовать другой встроенный плагин, а именно TCP Proxy.
TCP Proxy – это комбинация TCP Connection и TCP Listener, которая позволяет организовать посредника для TCP соединений. Удобство данного подхода заключается в том, что он сразу даёт чистый лог потоков данных в реальном времени (вместо лога в виде пакетов, из которых потоки данных надо ещё потом восстановить). Помимо этого, данная модель работает и там, где прослушивание с помощью сниффера может быть затруднительно (с определёнными моделями сетевых свичей, Wi-Fi карточек и т.д.)
Создаём сессию TCP Proxy, конфигурируем серверную и клиентскую стороны и запускаем наш прокси-сервер. Любое подсоединение к данному серверу породит вторичное подсоединение с клиентской стороны нашего прокси, при этом все данные принятые на клиентской стороне, будет переданы на серверную и наоборот. В этом смысле TCP Proxy напоминает связывание сессий, но специально заточенное под TCP и вследствие этого более удобное.
Отладка Windows Named Pipes
IO Ninja может быть использована в качестве инструмента для отладки достаточно распространённого подхода к IPC (Inter-Process Communication) в Windows – named pipes. В частности, так общаются некоторые наши Windows-драйвера с сопутствующими сервисами и приложениями.
Для эмуляции серверной стороны вашего приложения (той, где вызывается ConnectNamedPipe), запустите Named Pipe Listener. Данный плагин позволяет принимать входящие named pipe-соединения, которые будут исходить от вашего клиентского приложения/сервиса.
После установления соединения вы можете общаться с клиентом, анализируя лог полученных запросов и отсылая ему ответные пакеты (созданные, например, в строителе пакетов).
Для эмуляции клиентской стороны (той, где вызывается CreateFile) используется плагин Generic File.
Помимо отладки named pipes (или FIFOs в *nix), данный плагин также может быть использован для чтения и записи в драйверы нестандартных устройств.
Кратко коснёмся вопроса прослушивания named pipes. Предположим, имеется приложение или драйвер, использующие pipes для IPC. Если вы можете каким-то образом настраивать адрес named pipe на клиентской стороне, то появляется возможность прослушивания pipe-соединений с помощью посредника (аналогично TCP Proxy).
Как именно?
Пусть отлаживаемая система устанавливает pipe соединение на \\.\pipe\debuggee_pipe_server. Выбираем какое-нибудь незанятое имя pipe, например, \\.\pipe\my_pipe_proxy. Настраиваем клиентскую сторону отлаживаемой системы на этот наш \\.\pipe\my_pipe_proxy. В IO Ninja открываем пару Pipe Listener и Generic File, связываем их. В Pipe Listener прописываем \\.\pipe\my_pipe_proxy, жмём Listen. В Generic File прописываем \\.\pipe\debuggee_pipe_server, жмём Open. Посредник готов.
Со временем в будущих версиях IO Ninja будет также добавлено полноценное прослушивание named pipes без организации man-in-the-middle (в качестве первого приближения, скорее всего, через user-mode API hooking, а впоследствии – через file system filter).
Отправка «битых» фреймов для тестирования
Необходимость в отправке «битых» или иным образом специально сформированных Ethernet фреймов встречается не столь часто и может казаться относящейся, скорее, к разряду экзотики. Тем не менее данный функционал востребован в ряде вполне себе реальных сценариев. Например, в нашей практике это было необходимо во время отладки реализации TCP/IP стека у производимых нашей компанией встраиваемых модулей; другой реалистичной областью приложения могут быть задачи, стоящие перед специалистами по сетевой безопасности, разработчиками firewall-ов и т.д.
Открываем сессию Network Sniffer, выбираем интерфейс и фильтр захвата, запускаем захват. В строителе пакетов подготавливаем необходимый фрейм – например, можно воспользоваться встроенной библиотекой шаблонов пакетов TCP/IP, или же просто скопировать какой-то из захваченных фреймов в шестнадцатеричный редактор и подправить нужные поля.
Нажимаем Send, и любовно составленный нами фрейм отправляется выполнять боевое задание!
Заключение
Данный список сценариев использования IO Ninja далеко не полон, но, в принципе, достаточен для демонстрации общей картинки. Помимо этого, он абсолютно честен – все описанные выше функции родились из практических нужд, возникавших при разработке наших продуктов.
В следующей части статьи мы перейдём к с самому интересному – к программируемости IO Ninja и открываемых этим новых возможностях.
Ivan_83
Современные протоколы для обнаружения в сети используют мультикаст, вместо броадкаста.
И про IPv6 поддержку у вас ни слова.
vovkos Автор
Несомненно, много чего ещё можно и нужно добавлять. Писали нинзю мы прежде всего под себя и свои собственные потребности. Так как наши встраиваемые модули в настоящий момент работают на IPv4 и не поддерживают мультикастовые группы, то и в нинзе эти вопросы остро пока не стояли (вообще я большой сторонник принципа «you ain't gonna need it»).
На каком уровне вы ожидаете поддержку IPv6? Парсинг и отображение IPv6-адресов допилим в ближайших релизах. Насколько актуальны мультикасты в плагине UDP Socket?
На самом деле, это была одна из целей публикации на хабре — обсудить акутальность и приоритет новых фич для дальнейшего развития продукта.
Ivan_83
Я не ожидаю, просто обратил внимание что такого функционала нет.
IPv6 — ещё же и сокеты создавать, подключатся, принимать соединения.
Мультикаст — присоединение к группе, отправка сообщений, приём.
vovkos Автор
Да вроде бы кардинальных изменений в работе с сокетами быть не должно (AF_INET->AF_INET6, sockaddr_in->sockaddr_in6, ну и обработка парсинга и форматирования IPv6 адресов). С мультикастами тоже посылка и приём поменяться вроде не должны, а вот настройку присоединения к группе надо добавить.
Впрочем, вполне мог что-то пропустить — практического опыта программирования ни IPv6, ни мультикастов у меня нет (но есть ощущение, что любые проблемы тут можно решить без глобальных переделок).
В любом случае соглашусь, что поддержку IPv6 надо для приличия допилить.
Ivan_83
sockaddr -> sockaddr_storage, это портабельное решение с запасом на будущее.
С парсингом кажется тоже особых проблем нет, как минимум с отображением: WSAAddressToStringW(), WSAStringToAddressW()
С мультикастом всё просто, но в винде есть особенность: он принимается либо в зависимости от роутинга 224/4 либо от того куда прибинден сокет. В линуксе/бсд есть расширенное апи (в винде не смотрел, может тоже есть), оно позволяет явно задать интерфейс куда отправлять IGMP трафик, и соответственно с которым работать.
www.netlab.linkpc.net/download/software/TCPterm
Не достающее брать тут: www.netlab.linkpc.net/download/software/SDK
Немного сокетной специфики тут: www.netlab.linkpc.net/download/software/SDK/SocketFunctions.h
Осторожно: код вырвиглазный, и IPv6 там кажется не доделан, но адреса оно отображает :)
vovkos Автор
Спасибо за инфу и ссылки, покопаюсь в ближайшее время. Вполне возможно, поддержка IPv6 и мультикастов будет в следующем релизе.