Pull to refresh

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

Reading time6 min
Views5.6K

Я разработчик программы для мониторинга сети 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


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

Tags:
Hubs:
+12
Comments2

Articles

Information

Website
macmonitor.by
Registered
Founded
Employees
1 employee (me only)
Location
Беларусь