Как я связал компьютеры и пользователей с портами сетевых устройств в программе для мониторинга 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


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

    • +12
    • 4,8k
    • 2
    Network MACMonitor
    19,52
    Компания
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 2

      0
      а можно узнать цели написания программы?
        0
        Программа была написана с целью экономии времени при решении проблем, связанных с сетью.

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое