Как я связал компьютеры и пользователей с портами сетевых устройств в программе для мониторинга Network MACMonitor

в 8:49, , рубрики: Блог компании Network MACMonitor, Программирование, разработка программного обеспечения, Сетевые технологии, системное администрирование

Я разработчик программы для мониторинга сети Network MACMonitor.

В процессе развития программы возникла задача: определить за какими компьютерами работают пользователи и связать эту информацию с портами сетевых устройств. В этой статье хочу написать, как мне удалось это сделать.

image

Начал я с простых рассуждений: чтобы связать пользователя с портом сетевого устройства, предварительно необходимо связать компьютер, за которым работает пользователь, с этим портом. Поскольку программа Network MACMonitor позволяет находить mac адреса на портах сетевых устройств, то было решено связать компьютеры с портами с помощью mac адресов. Далее необходимо связать пользователей с компьютерами. Эту информацию можно получить, если каким-либо образом опросить компьютеры.

Мне виделось два варианта решения этой задачи:

  1. Написать Windows агент и опрашивать его с помощью программы Network MACMonitor;
  2. Использовать Windows Management Instrumentation (WMI).

У варианта с Windows агентом есть ряд минусов, которые для меня были существенными:

  • разработка безопасного протокола сетевого взаимодействия Windows агента c программой Network MACMonitor;
  • необходимость предварительной установки агента на компьютеры;
  • использование другого языка программирования (я пишу на Java), так как считаю Java не подходящим для написания агента: в связи с достаточно большим потреблением виртуальной памяти и необходимостью установки JRE на все компьютеры.

Из-за всех вышеперечисленных минусов я решил остановиться на варианте с использованием WMI.

Разработка WMI клиента

Так как программа Network MACMonitor написана на Java я попытался найти готовую кроссплатформенную Java библиотеку, которая реализует функциональность WMI клиента. И тут меня ждало разочарование — такой библиотеки нет. Все существующие библиотеки — это либо обертки над Windows утилитами, либо (библиотека j-Interop) требуют дополнительной манипуляции с реестром (смена владельца и разрешений на ветки реестра) для активации WMI через удаленный реестр. Поскольку для Java полностью рабочей библиотеки не оказалось я решил найти библиотеку либо WMI клиента, написанного на любом другом языке программирования. И нашел один WMI клиент для Linux. Скачав и проверив его работу, я понял, что опрос Windows компьютеров из-под Linux возможен.

Раз это возможно, я решил написать свою библиотеку на чистом Java, которая бы позволила опросить компьютер по WMI.

Для написания библиотеки необходима была четкая документация по работе протокола WMI. Оказалось, что такая документация есть и она находится в свободном доступе.

Подготовку к написанию библиотеки я начал с рассмотрения сетевого стека протокола WMI.

Протокол Спецификации
Windows Management Instrumentation (WMI) MS-WMI, MS-WMIO
Distributed Component Object Model (DCOM) MS-DCOM
Remote Procedure Call (RPC) MS-RPCE
Transmission Control Protocol (TCP) -
Internet Protocol (IP) -

Для корректной работы WMI необходимо, чтобы все уровни стека были реализованы.

Поскольку WMI на Java не реализован, я перешел к следующему протоколу в стеке — DCOM. И тут мне повезло. Хотя вышеупомянутая библиотека j-Interop не реализует функциональность WMI, но DCOM функциональность в ней реализована. Значит осталось написать реализацию WMI протокола, то есть написать реализацию спецификаций MS-WMI и MS-WMIO.

Начал я с реализации спецификации MS-WMIO, которая отвечает за формат кодирования данных в сетевых пакетах протокола WMI. Из спецификации я узнал, что при кодировании данных используется расширенная спецификация синтаксиса Бэкуса-Наура (ABNF, RFC 5234). В спецификации MS-WMIO полностью описан формат кодирования с использованием ABNF. Известно, что если есть грамматика, описанная в ABNF, то возможно создать парсер этой грамматики. В интернете я нашел генератор парсеров ABNF для Java и на вход подал ему грамматику, взятую из спецификации. Поскольку сгенерированный парсер работал со строками, а MS-WMIO описывает бинарный формат кодирования, была идея просто заменить в сгенерированном парсере строки на массивы байт, а символы на байты. Но посмотрев количество файлов, где необходима была замена, а также узнав из спецификации MS-WMIO, что иногда потребуется работа с битами, я понял, что исправить сгенерированный парсер будет очень сложно, и решил отказаться от этой идеи. Подумал, что написать парсер с нуля будет быстрее. И вот парсер был готов.

Но как проверить, что парсер написан корректно, если пока не реализована спецификация MS-WMI, которая отвечает за функционирование протокола WMI? Тут мне помог Wireshark – анализатор сетевого трафика. Сделав запросы WMI стандартными средствами Windows (wbemtest), предварительно отключив шифрование, я получил сетевые пакеты и сохранил их в бинарные файлы. Эти файлы уже возможно было использовать в качестве тестовых данных для парсера.

Когда парсер был протестирован и были исправлены найденные ошибки, я приступил к реализации спецификации MS-WMI, которая описывает работу протокола WMI.

Спецификация MS-WMI делится на серверную и клиентскую. Мною была частично реализована клиентская часть, в объеме необходимом для опроса компьютера по WMI. В этой части мне также понадобился Wireshark, но уже для анализа последовательности сетевых пакетов при WMI опросе.

Попытка получения необходимых данных с помощью WMI

После написания WMI библиотеки, стала задача ее использования в программе Network MACMonitor. Возник вопрос: какие данные следует получать с компьютеров? Я подумал, что нужно получить имя компьютера, домен, операционную систему, время включения, mac адреса, ip адреса, активных пользователей, которые работают за компьютером.

Но возникла очень важная проблема: как однозначно идентифицировать компьютер при WMI опросе? Я рассмотрел следующие варианты:

  • mac адрес, возможна смена, возможна неуникальность;
  • имя компьютера и домен (рабочая группа), возможна смена, неуникальность (для рабочей группы);
  • серийный номер жесткого диска, где установлена операционная система, необходимы права администратора при WMI опросе, уникальность не проверял, но подозреваю, что возможна неуникальность;
  • серийный номер материнской платы, возможна неуникальность, причем достаточно часто;
  • идентификатор компьютерной системы (свойство UUID WMI класса Win32_ComputerSystemProduct), возможна неуникальность, причем достаточно часто;
  • время установки операционной системы, лучший из всех вариантов, но возможна неуникальность при клонировании системы, либо при разворачивании из образа.

Ни один вариант не позволяет однозначно идентифицировать компьютер, поэтому я остановился на идентификации компьютера по трем параметрам:

  • серийному номеру материнской платы, 
  • идентификатору компьютерной системы,
  • времени установки операционной системы.

Конечно три этих параметра могут совпадать у разных компьютеров, но реже, чем один из них.

Так же была предпринята попытка получить активных пользователей с помощью стандартного WMI класса: Win32_LogonSession. Тут появилась первая проблема: оказалось, что Win32_LogonSession показывает все пользовательские сессии, даже те, которые уже завершились. Я стал думать, как отфильтровать активные сессии от завершившихся. Нашел что это можно сделать с помощью класса Win32_SessionProcess, который связывает экземпляры классов Win32_LogonSession с Win32_Process. Если ссылка на сессию присутствует в списке экземпляров класса Win32_SessionProcess (есть хотя бы один процесс с идентификатором этой сессии), то она активна. Далее возник вопрос о том, как связать сессию с пользователем. Это можно сделать, используя класс Win32_LoggedOnUser, который связывает экземпляры классов Win32_LogonSession и Win32_UserAccount. Осталось только получить экземпляры класса Win32_UserAccount, которые предоставляют подробную информацию о пользователе.

image

Но тут меня ждало разочарование. При удаленном использовании WMI оказалось, что при попытке получения экземпляров класса Win32_UserAccount, возможно получить только локальных пользователей компьютера. То есть получилось, что стандартными средствами WMI, невозможно узнать какие пользователи активны на компьютере.

Разработка WMI провайдера.

В связи с невозможностью однозначной идентификации компьютеров и невозможностью получения информации об активных пользователях с использованием стандартных классов WMI было решено расширить функциональность WMI. Сделать это можно описав свои WMI классы в MOF файле и написав WMI провайдер для получения экземпляров этих классов.

Были описаны два новых WMI класса: NMBY_InstallInfo – для идентификации компьютера и NMBY_LogonSession – для определения активных пользователей компьютера.

image

Затем был написан WMI провайдер с помощью которого можно получить экземпляры этих классов.

К провайдеру были поставлены дополнительные требования:

  • работа на системе без .NET;
  • работа на операционной системе Windows XP и выше;
  • возможность получения информации с использованием неадминистративной учетной записи.

Поэтому провайдер был написан на C++ с использованием WinApi.

В процессе написания провайдера возникли трудности в связи с малым количеством и качеством документации по этой теме, но несмотря на это провайдер был успешно написан.

Написанный провайдер доступен на странице скачивания. Его можно установить и использовать бесплатно.

Итог

В итоге с помощью программы Network MACMonitor стало возможно:

  • связать пользователей c компьютерами;

image

  • связать компьютеры с портами сетевых устройств;

image

  • связать порты сетевых устройств с компьютерами и пользователями;

image

  • просмотреть историю регистрации пользователей на компьютерах.

image

Сайт программы

Автор: sviato_slav

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js