воскресенье, 10 ноября 2019 г.

Контроль работоспособности DHCP-сервера в Zabbix

Как-то раз на работе потребовалось поставить на контроль DHCP-сервер. Сделать это нужно было, как обычно, срочно. Пока я делал, заказчики постоянно "держали руку на пульсе", интересовались результатами и поторапливали. Пытался воспользоваться различными утилитами командной строки, но в итоге наиболее пригодным вариантом оказалось написание собственного скрипта на python с использованием библиотеки ScaPy, благо в интернете можно найти примеры подобных скриптов. Собирались испытать скрипт на одном DHCP-сервере, а потом поставить на контроль ещё несколько десятков.

Года через два наткнулся на этот забытый скрипт. Раз уж он никому не нужен, то можно попытаться довести его до ума и поделиться им. Забрал скрипт домой и стал экспериментировать на виртуалках. Пока доводил скрипт до ума, на работе снова возникла необходимость поставить на контроль один DHCP-сервер, никак не связанный с теми, для которых скрипт первоначально писался.

Принципы работы DHCP

Для начала ознакомимся немого с принципами работы DHCP.

Выдача настроек по DHCP происходит в следующей последовательности:
  1. клиент, желающий получить настройки, посылает широковещательный запрос DHCPDISCOVERY, при помощи которого пытается обнаружить доступные DHCP-серверы,
  2. сервер откликается на запрос DHCPDISCOVERY и отвечает пакетом DHCPOFFER, в котором предлагает клиенту использовать определённый IP-адрес,
  3. клиент отправляет серверу запрос DHCPREQUEST, в котором просит закрепить за ним указанный IP-адрес,
  4. сервер отвечает клиенту пакетом DHCPACK, в котором подтверждает, что IP-адрес закреплён за клиентом. Если сервер по каким-то причинам не может закрепить за клиентом указанный им IP-адрес, то отвечает пакетом DHCPNAK.
Для продления аренды ранее выданного сервером IP-адреса клиент использует запросы DHCPREQUEST, указывая в запросе ранее выданный ему IP-адрес.

Также протоколом предусмотрены пакеты DHCPDECLINE и DHCPINFO.

При помощи DHCPDECLINE клиент может сообщить серверу, что предложенный им IP-адрес уже используется.

Если клиенту не нужен IP-адрес от DHCP-сервера, то вместо запроса DHCPREQUEST клиент может отправить запрос DHCPINFORM для запроса дополнительных сетевых параметров. Так же как и в ответ на запрос DHCPREQUEST, на запрос DHCPINFORM сервер отвечает пакетом DHCPACK.

Если клиент хочет вернуть IP-адрес DHCP-серверу, он может отправить серверу запрос DHCPRELEASE. Если сервер получит такой запрос, он помечает IP-адрес как свободный. Протоколом не предусмотрен ответ на запросы DHCPRELEASE, поэтому невозможно убедиться в том, что сервер получил и обработал запрос.

Описание скрипта dhcp.py

А теперь перейдём к делу. Для контроля работоспособности DHCP-сервера был подготовлен скрипт dhcp.py, принимающий следующие аргументы:
  • имя сетевого интерфейса, за которым находится контролируемый DHCP-сервер,
  • MAC-адрес клиента, который будет использоваться в запросах к DHCP-серверу. По умолчанию - MAC-адрес сетевого интерфейса,
  • IP-адрес, который ожидается получить от DHCP-сервера. По умолчанию клиент будет принимать любой IP-адрес,
  • IP-адреса DHCP-серверов, ответ от которых ожидается получить. Если на пути между клиентом и DHCP-сервером имеются DHCP-релеи, то тут нужно указывать настоящие IP-адреса серверов, а не IP-адреса релеев. Можно указать несколько IP-адресов, разделив их двоеточиями. По умолчанию принимаются ответы от любых DHCP-серверов,
  • время ожидания ответа, по умолчанию составляет 2 секунды.
Обязательно для указания только имя интерфейса. Все остальные настройки не обязательны и могут быть опущены.

Алгоритм работы скрипта следующий:
  • через указанный интерфейс отправляется запрос DHCPDISCOVERY с указанным MAC-адресом или MAC-адресом интерфейса,
  • в течение таймаута принимаются пакеты DHCPOFFER,
  • если пакетов DHCPOFFER не поступило, выполнение скрипта прерывается,
  • если указан ожидаемый IP-адрес, то проверяется, что в DHCPOFFER предложен именно этот IP-адрес. Если DHCP-сервер предложил другой IP-адрес, то выполнение скрипта прерывается,
  • если указан список IP-адресов DHCP-серверов, то проверяется, что в DHCPOFFER указан IP-адрес одного из ожидаемых DHCP-серверов. Если получен ответ от другого DHCP-сервера, то выполнение скрипта прерывается,
  • отправляется запрос DHCPREQUEST с просьбой выдать в аренду предложенный IP-адрес,
  • в течение таймаута принимаются пакеты DHCPACK,
  • если пакетов DHCPACK не поступило, выполнение скрипта прерывается,
  • отправляется запрос DHCPRELEASE на возврат арендованного IP-адреса.
Коды ошибок скрипта, которые он выдаёт на стандартный вывод:
  1. указанный сетевой интерфейс не существует,
  2. неправильный MAC-адрес,
  3. нет ответа DHCPOFFER,
  4. неправильный пакет DHCPOFFER,
  5. получен ответ от нежелательного DHCP-сервера,
  6. предложен нежелательный IP-адрес,
  7. нет ответа DHCPACK,
  8. неправильный пакет DHCPACK.
Для работы скрипту необходимы привилегии пользователя root, но Zabbix работает под простым пользователем, поэтому придётся воспользоваться sudo. Если использовать скрипт dhcp.py как скрипт внешнего опроса, то для его запуска через sudo потребуется создать ещё один скрипт. Но такое решение не кажется мне красивым. Я решил вызывать скрипт dhcp.py через Zabbix-агента, для чего понадобится настроить в конфигурации агента UserParameter, где найдётся место и для sudo.

Настройка Zabbix-агента

Сначала установим пакет sudo, если он ещё не установлен:
# apt-get install sudo
И выдадим пользователю zabbix, от имени которого работает Zabbix-агент, права запускать скрипт dhcp.py с правами пользователя root:
Defaults:zabbix !requiretty
zabbix ALL=(ALL) NOPASSWD:/etc/zabbix/dhcp.py *
Теперь положим скрипт dhcp.py в каталог /etc/zabbix и выдадим права запускать его:
# chmod +x /etc/zabbix/dhcp.py
В конфигурации Zabbix-агента в файле /etc/zabbix/zabbix_agentd.conf добавим строчку:
UserParameter=dhcp[*],/usr/bin/sudo /etc/zabbix/dhcp.py "$1" "$2" "$3" "$4" "$5"
После изменения конфигурации Zabbix-агента, его нужно перезапустить:
# systemctl restart zabbix-agent

Шаблоны для Zabbix

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

Также я подготовил два варианта шаблона:
  • Template_App_DHCP.xml - шаблон для использования с Zabbix-агентом, работающим в обычном, пассивном режиме,
  • Template_App_DHCP_Active.xml - шаблон для использования с Zabbix-агентом, работающим в активном режиме.
В шаблоне имеются макросы, при помощи которых можно настроить элемент данных, который контролирует состояние DHCP-сервера. Указано только одно значение по умолчанию для имени интерфейса - eth0, т.к. этот аргумент обязателен для указания.

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

К этому элементу данных присоединено 8 триггеров, два из которых имеют высокую важность, т.к. свидетельствуют о неработоспособности DHCP-сервера или о появлении чужого DHCP-сервера. Остальные триггеры имеют уровень важности "Предупреждение":

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

Для примера я настроил контроль исправности DHCP-сервера на своём домашнем компьютере. В виртуальную машину с Zabbix проброшен интерфейс ens7, смотрящий в локальную сеть с DHCP-сервером. На интерфейсе отсутствуют сетевые настройки, используется он только для контроля исправности DHCP-сервера. На уровне сетевого узла созданы макросы, переопределяющие значения по умолчанию, определённые в шаблоне:

В последних данных можно увидеть числовое значение результата проверки DHCP-сервера и короткий текст, позволяющий быстро понять, какой именно результат получен:

Использованные материалы

Комментариев нет: