DHCP + SQL СУБД. На примере PostgreSQL.

Старт собственного проекта

В связи с высокой востребованностью DHCP сервера, умеющего работать напрямую с SQL СУБД, а так же некоторой ущербностью решения в виде патча к ISC DHCP (сложность поддержки и апгрейда) мною решено написать полноценный кроссплатформенный DHCP сервер изначально ориентированный на работу с SQL СУБД.
На данный момент проект на начальной стадии реализации. Обсуждение возможного функционала находится тут.

Мотивация

При использовании в локальной сети протокола DHCP для выдачи конфигурационной информации клиентам, очень часто используется ISC DHCP, так как он удовлетворяет всем требованиям в случае, если конфигурация DHCP статична, например отсутствует привязка IP адресов к MAC адресам клиентов, либо новые клиенты появляются редко, либо клиенты редко изменяют MAC адреса (т.е. редко меняют оборудование). В противном случае возникает необходимость очень часто изменять текстовый файл конфигурации и перезапускать сервер, что может оказаться мягко говоря не очень удобно, и уж точно - совсем не интересно. В данной статье освещается один из вариантов решения данной проблемы при помощи написания патча для dhcpd входящего в дистрибутив ISC DHCP. Стоит отметить, что в последних версиях сервера появилась возможность подключения его к внешним хранилищам (LDAP). Однако возможности предоставляемые реализуемый патчем намного более широки, потому что можно хранить базу DHCP практически в любой СУБД, которые поддерживаются сервером FreeRADIUS. Следовательно - практически в любой из распространённых сегодня СУБД с поддержкой процедурного программирования.

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

Полагаю что вам известно как работает обычный DHCP сервер, в частности - dhcpd. Если это не так - в интернете существует масса материалов посвящённых данному вопросу, рекомендую для начала обратиться к ним.
В приведённом патче в код dhcpd добавлены функции, позволяющие преобразовывать DHCP запросы от клиентов в сообщения RADIUS-Access-Request и отправлять их к RADIUS серверу. А так же производить обратные действия - преобразовывать полученные ответы RADIUS сервера в DHCP сообщения и отправлять их DHCP клиентам.

Возможности модифицированного dhcpd

Поддерживаемые платформы: Linux, FreeBSD.
Кроме основной функции (связывания dhcpd с SQL БД) патч даёт ряд полезных возможностей:

  1. Вся конфигурация DHCP находится в SQL БД и может быть динамически изменена без перезапуска dhcpd или FreeRADIUS. Это так же относится к логике обработки DHCP запросов сервером БД.
  2. Кэширование DHCP информации.
    Получение клиентом DHCP конфигурационной информации (IP адреса и прочего) обычно состоит из 2х запросов: DHCPDISCOVER - отправляется клиентом для обнаружения доступных DHCP серверов в сети; DHCPREQUEST - отправляется к выбранному DHCP серверу для получения от него конфигурацинного набора данных. Если конфигурация успешно получена, то впоследствии DHCP клиент отправляет только DHCPREQUEST к тому же серверу. В случае включённого кэширования (по умолчанию) dhcpd отправляет запрос к RADIUS серверу, а соответственно и БД, только при получении DHCPDISCOVER от клиента, либо по истечении времени жизни записи DHCP кэша (задаётся в настройках). На практике это в несколько раз снижает нагрузку на сервер БД.
    Если необходимо что бы клиент получил обновлённую информацию из БД (например ему сменили IP адрес), то достаточно перезапустить процесс инициализации сети. Например выключить/включить сетевое подключение. В этом случае клиент вновь пошлёт DHCPDISCOVER. Соответственно dhcpd отправит запрос к RADIUS серверу и получит обновлённую информацию.
    Эту функцию можно отключить через конфигурационный файл dhcpd.
  3. Предотвращение перегрузки БД.
    Механизм предотвращения перегрузки сервера БД чрезмерно частыми запросами, например: флудом DHCPDISCOVER, возникающим при образования "петли" в сегменте сети, либо в результате действий злоумышленника. Ограничивается частота поступления запросов, как от отдельных клиентов, так и суммарная от всех клиентов. В случае превышения пороговых значений, новые DHCP запросы игнорируются. Максимальная частота запросов настраивается в конфигурационном файле.
  4. Резервирование используемых RADIUS серверов.
    В случае отказа основного (заданного первым) сервера, и при наличии резервного (их может быть несколько), dhcpd переключается на резервный, переодически совершая попытки использовать основной сервер. Переключение резервных серверов закольцовано: в случае падения используемого в текущий момент времени резервного сервера dhcpd переключается на следующий, при достижении последнего - переключается на первый по списку. Список серверов задаётся в конфигурационном файле.
  5. Механизм обновления статической привязки IP адресов к MAC адресам в ARP таблице хоста, на котором запущен dhcpd (например этот хост работает маршрутизатором в сети и осуществляет авторизацию клиентов по MAC адресу). Включается опцией в конфигурационном файле. На данный момент работает только под Linux.
  6. Возможность отправки произвольных DHCP опций из клиентских запросов на сервер RADIUS. Например опции 82, типа запроса, запрашиваемого адреса и т.д. Можно использовать для привязки IP адреса к порту коммутатора, выдачи различных параметров клиентам и т.п. Список отправляемых на RADIUS сервер опций задаётся в конфигурационном файле.

Поддерживаемые опции DHCP

В принципе ограничения на список поддерживаемых нету, т.к. dhcpd может передать клиенту любую информацию полученную по запросу от RADIUS сервера. Список доступных для FreeRADIUS опций можно увидеть в словаре dictionary.dhcp. Для непосредственной передачи DHCP клиентам предназначены опции имеющие значения меньше 256 (т.е. код опции помещается в одном байте). Опции имеющие бОльшие значения являются служебными и изменять их значения не рекомендовано. Так же стоит учесть что опции с кодами больше 256 в принципе не могут быть переданы DHCP клиентам в неизменном виде т.к. поле "код опции" протокола DHCP имеет длину в 1 байт.

Оговорка касательно поддержки DHCP в сервере FreeRADIUS

Возможно вам известно о том что создатели FreeRADIUS решили включить поддержку протокола DHCP в свой сервер. На данный момент поддержка DHCP находится на стадии эксперементального тестирования, весьма ограничена и строжайше не рекомендована к практическому применению.

Необходимое программное обеспеченье

Для организации работы DHCP через модифицированный dhcpd потребуется следующий софт:

  1. Исходные коды ISC DHCP версии 3.0.7
  2. Поддерживающая процедурное программирование СУБД, с которой способен работать FreeRADIUS. В примере использована PostgreSQL.
  3. FreeRADIUS (версия 2.0.4 или выше).

Если вы по какой-либо причине не можете использовать FreeRADIUS версии 2.0.4 (или выше), то можете ознакомиться с устаревшей на данный момент реализацией через dhcrelay поддерживающей любой стандартный RADIUS сервер.

Настройка FreeRADIUS

Предполагается что FreeRADIUS уже установлен, если это не так, то рекомендую обратиться к руководству по его установке в вашей ОС.
Через файл dictionary находящийся в конфигурационном каталоге необходимо подключить дополнительный файл словаря dictionary.dhcp. Внимание! Данный файл не идентичен файлу dictionary.dhcp поставляемому вместе с FreeRADIUS. Файл из поставки нужно либо заменить данным, либо не подключать.
Изменения конфигурационных файлов:

  1. В файле sql.conf, указать адрес сервера, тип используемой СУБД - "postgresql", имя базы данных - "dhcp", имя пользователя - "radius". Присвоить следующие значения переменным: authcheck_table = "dhcpcheck"; authreply_table = "dhcp_reply".
  2. В файле "sites-available/default" в секции authorize раскоментировать (либо добавить) строчку содержащую директиву sql и закоментировать все остальные.
  3. В файле sql/postgresql/dialup.conf запрос group_membership_query нужно закоментировать; заменить SQL запросы authorize_check_query и authorize_reply_query на:
authorize_check_query = "SELECT id, UserName, Attribute, Value, ':=' AS Op \
	FROM ${authcheck_table} \
	WHERE id = (SELECT get_id('%{SQL-User-Name}', %{NAS-Port}, btrim('%{DHCP-Message-Type}', '0x')::int2)) \
	ORDER BY id"
authorize_reply_query = "SELECT id, client_hw_addr, Attribute, Value, ':=' AS Op \
        FROM ${authreply_table} \
        WHERE client_hw_addr = '%{SQL-User-Name}' AND server_addr = %{NAS-Port} \
UNION \
        SELECT id, NULL AS client_hw_addr, Attribute, Value, ':=' AS Op \
        FROM interfaces \
        WHERE client_subnet = \
                ( \
                        SELECT client_subnet FROM dhcp_reply \
                                WHERE client_hw_addr = '%{SQL-User-Name}' \
                                AND server_addr = %{NAS-Port} \
                                AND attribute = 'DHCP-Your-IP-Address' \
                        LIMIT 1 \
                ) \
        ORDER BY id"

После этого остаётся добавить IP адрес хоста на котором будет запущен модифицированный dhcpd в файл clients.conf.

Сборка dhcpd

Пропатчим и соберём dhcpd:

$ wget http://ftp.isc.org/isc/dhcp/dhcp-3.0.7.tar.gz
$ tar -xf dhcp-3.0.7.tar.gz
$ wget http://www.netpatch.ru/projects/dhcp2radius/dhcp2radius-3.0.7-v3.patch.tar.bz2
$ tar -xf dhcp2radius-3.0.7-v3.patch.tar.bz2
$ patch -p0 < dhcp2radius-3.0.7-v3.patch
$ cd dhcp-3.0.7
$ ./configure
$ make

Если всё прошло удачно, то в каталоге work.linux-2.2/server/ появится исполняемый файл dhcpd.

Создание базы данных

Для создания DHCP базы данных нужно выполнить скрипт create_dhcp_db.sql от пользователя postgresql.

$ psql -f create_dhcp_db.sql

В результате выполнения скрипта будут созданы пользователь "radius", база данных "dhcp", необходимые таблицы, индексы и представления, а также функция get_id().
get_id() вызывается сервером RADIUS из запроса authorize_check_query при обработке авторизации клиента, т.е. при попытке получить DHCP клиентом конфигурационную информацию. В качестве параметров ей передаются: строковое представление MAC адреса клиента запросившего конфигурационную информацию - RADIUS атрибут UserName, IP адрес интерфейса на котором агент пересылки получил DHCP запрос от клиента, представленный как 4хбайтовое беззнаковое число - RADIUS атрибут NAS-Port и тип DHCP запроса - атрибут DHCP-Message-Type. Использование функции необходимо в случае наличия пула динамических IP адресов не привязанных к конкретным MAC адресам. Если в сети все IP адреса жёстко привязаны к MAC адресам клиентов, то в запросе authorize_check_query можно использовать непосредственное сопоставление поля username MAC адресу клиента, и поля server_addr IP адресу интерфейса, на котором получен DHCP запрос.

Заполнение базы данных

Для того что бы полученная система начала работать, необходимо заполнить базу данных DHCP информацией конфигурации обслуживаемых подсетей и хостов. С подробностями обработки запросов добавления данных в БД можно ознакомиться изучив скрипты:

  • add-subnet.pl - скрипт вносящий информацию об обслуживаемой подсети.
  • add-client.pl - скрипт добавляющий IP адрес имеющий жёсткую привязку к MAC адресу конкретного DHCP клиента.
  • add-dyn-client.pl - скрипт добавляющий IP адрес не имеющий привязки к MAC адресу DHCP клиента.

Запустив их без параметров можно получить информацию о принимаемых аргументах:

$ ./add-subnet.pl
Usage: ./add-subnet.pl Default-GW GIAddr NetMask Server-ID 
	Interface-ID Domain-Name Lease-Time Client-Subnet [DNS-1] [DNS-2] [DNS-3]
$ ./add-client.pl
Usage: ./add-client.pl Cient-IP MAC-address Server-IP Client-Subnet
$ ./add-tmp-client.pl
Usage: ./add-tmp-client.pl Cient-IP Server-IP Client-Subnet

Разумеется что данные скрипты не предназначены для постоянного использования и приведены только с целью показать пример работы с БД. Интерфейс доступа к распространённым СУБД поддерживается практически всеми средами программирования и разработки и оставляется на ваше усмотрение. Более подробная информация о использовании данных скриптов представлена ниже, в примере настройки и использования системы. Общий принцип заполнения БД при добавлении в неё информации об обслуживаемых dhcpd хостах и подсетях приведён в разделе "Структура базы данных".

Конфигурирование dhcpd

Модифицированный dhcpd поддерживает ряд новых опций глобальной секции конфигурационного файла, обеспечивающих настройку работы с FreeRADIUS:

  • use-dhcp2radius - возможные значения true|false. Если данная опция отсутствует или равна false, то dhcpd работает в обычном режиме игнорируя все остальные опции конфигурационного файла относящиеся к работе с FreeRADIUS (начинаются со слова "radius").
  • radius-servers - список RADIUS серверов, через запятую. Обязательный параметр.
  • radius-port - номер порта RADIUS сервера. По умолчанию - 1812.
  • radius-secret - кодовое слово для доступа к RADIUS серверу. Не длиннее 16 символов. Обязательный параметр.
  • radius-password - пароль для DHCP клиентов. В примере используется "dhcpuser". Обязательный параметр.
  • radius-server-restore - время (в секундах) спустя которое производится попытка переключиться на основной сервер если dhcpd работает на резервном сервере. Если этот параметр не указан, то попытки переключения на основной сервер после его падения не производятся.
  • radius-cache-maxlen - максимальная длина кэша ответов RADIUS сервера. По умолчанию - 3000.
  • radius-cache-ttl - время жизни (в секундах) узлов кэша. По умолчанию - сутки.
  • radius-client-freq - максимально допустимая частота поступления DHCP запросов от отдельного клиента. По умолчанию - 4/сек.
  • radius-freq-summ - суммарная частота поступления DHCP запросов от всех клиентов. По умолчанию - 10.
  • radius-update-arp - обновлять статическую ARP-таблицу ядра хоста на котором запущен dhcpd в случае смены привязки MAC->IP. На данный момент работает только под Linux. Возможные значения true|false. По умолчанию - false.
  • radius-allow-cache - разрешить кэшированние ответов RADIUS сервера. В таком случае запрос на RADIUS сервер посылается только если клиент отправляет DHCPDISCOVER (инициализация сети), либо если истекает время жизни записи кэша хранящего информацию для клиента запращивающего адрес. Возможные значения true|false.
  • radius-allow-dynamic-cache - разешить кэширование клиентов не имеющих статической привязки MAC->IP. Не рекомендуется использовать, о причинах рассказано ниже. Возможные значения true|false. По умолчанию отключено.
  • radius-use-mac-delimiter - разделять байты MAC адреса двоеточием в запросах Access-Request если true. По умолчанию - false.
  • radius-send-opts-to-srv - набор кодов DHCP опций из запросов клиентов, отправляемых на RADIUS сервер. коды указываются в hex-формате, через двоеточие.

Кроме этого в dhcpd добавлен ключ командной строки -I. Параметром этого ключа является имя интерфейса на котором игнорируются DHCP запросы и принимаются только ответы RADIUS-сервера. Опция необходима если несколько dhcpd на разных хостах слушают интерфейсы в одном и том же сегменте, для получения ответов RADIUS-сервера, но на запросы DHCP клиентов должен отвечать только один из них.

Кэширование и динамические клиенты.
По умолчанию, в случае получения DHCP запроса от динамического клиента (т.е. не имеющего привязки MAC->IP) кэширование ответа RADIUS сервера не производится. Это связано с тем, что любой IP адрес из БД, не имеющий привязки к MAC адресу, может быть выдан любому DHCP клиенту по истечении срока аренды. Если кэшировать информацию о динамических DHCP клиентах в dhcpd то может сложиться следующая ситуация:
Динамический клиент сделал запрос и получил некоторый IP-адрес со сроком аренды 2 часа (например). Если закэшировать этот запрос в dhcpd, то спустя почти 2 часа (а точнее - спустя время равное Renewing Time) при посылке клиентом пакета DHCPREQUEST для продления срока аренды адреса, dhcpd отправит клиенту информацию из кэша без отправки RADIUS запроса. Сервер БД не обновит информацию о том, что данный IP адрес продолжает использваться тем же клиентом. Как следcтвие, спустя 2 часа с момента начала аренды, сервер БД сочтёт что данный IP адрес свободен и выдаст его следующему динамическому клиенту в той же подсети. В итоге это приведёт к конфликту IP адресов. Если же не кэшировать информацию о динамических клиентах, то при каждом DHCPREQUEST будет производиться посылка RADIUS запроса на сервер и в БД будет происходить обновление информации о том что данный IP адрес выдан в аренду и всё ещё используется. Это гарантирует невозможность повторной выдачи данного IP адреса какому-либо другому клиенту.

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

В качестве примера возьмём две тестовые подсети расположенные в разных физических сегментах:
1) 10.7.7.0/24 - подсеть обслуживается dhcpd непосредственно. Агент пересылки не используется.
2) 10.10.11.0/24 - подсеть обслуживается через агента пересылки (dhcrelay). Кроме того эта подсеть имеет алиасный сегмент 10.10.110.0/24.
Сервер dhcpd запущен на хосте с одним сетевым интерфейсом и IP адресом на нём - 10.7.7.1. Агент пересылки запущен на хосте имеющем 2 сетевых интерфеса: первый с IP адресом 10.10.10.11; второй с адресами 10.10.11.11 и 10.10.110.11 - именно на нём принимаются запросы от DHCP клиентов. FreeRADIUS и PostgreSQL работают на том же хосте что и dhcpd. Обмен данными производится через loopback интерфейс. Последний пункт совершенно не принципиален - все серверы могут работать на разных хостах.

В приведённых примерах считается что сервер PostgreSQL находится на одном хосте с выполняемыми скриптами add-subnet.pl, add-client.pl и add-dyn-client.pl, расположенными в текущем каталоге.
Предполагается что FreeRADIUS уже настроен как указано выше.
Приступим к настройке работоспособной конфигурации:

  1. Создаём БД:
    $ psql -f create_dhcp_db.sql
    Скрипт create_dhcp_db.sql вы можете скачать в разделе downloads. Напоминаю что все действия с psql желательно производить от имени системного пользователя postgres.
  2. Добавляем в неё обслуживаемые подсети:
    $ ./add-subnet.pl 10.7.7.1 0.0.0.0 255.255.255.0 10.7.7.1 10.7.7.1 local 3600 10.7.7.0 10.7.7.1
    $ ./add-subnet.pl 10.10.11.11 10.10.11.11 255.255.255.0 10.7.7.1 10.10.11.11 local 3600 10.10.11.0 10.7.7.1
    $ ./add-subnet.pl 10.10.110.11 10.10.11.11 255.255.255.0 10.7.7.1 10.10.11.11 local 3600 10.10.110.0 10.7.7.1
    При выполнении скрипт выводит SQL-запросы, и если они выполнены без ошибок, сообщение: OK. В противном случае выводится описание ошибки.
    Описание переданных скрипту параметров (для первого случая):
    • Default-GW (10.7.7.1) - шлюз по умолчанию для клиентов данной подсети.
    • GIAddr (0.0.0.0) - IP адрес агента пересылки, если он используется для данной подсети. Указан во второй и третьей команде. Если не используется - должен быть заполнен нолями.
    • NetMask (255.255.255.0) - маска подсети для DHCP клиентов.
    • Server-ID (10.7.7.1) - идентификатор DHCP сервера. Обычно это поле содержит основной IP адрес DHCP сервера.
    • Interface-ID - первичный IP адрес интерфейса на который будут приходить запросы от DHCP клиентов данной подсети. Равен IP адресу интерфейса который прослушивает DHCP сервер либо агент пересылки.
    • Domain-Name (local) - имя домена DHCP клиентов данной подсети.
    • Lease-Time (3600) - время на которое клиенту выдаётся в аренду набор конфигурационных данных.
    • Client-Subnet (10.7.7.0) - IP адрес клиентов данной подсети.
    • [DNS-1] [DNS-2] [DNS-3] (10.7.7.1) - DNS сервер. Не обязательный параметр.
      Обычно в современных реализациях DNS резолверов поддерживается до 3х DNS серверов, но вы можете указать больше - поле DHCP-Domain-Name-Server хранится в виде параметра с типом octets и ограничено только максимальным размером поля данных БД.
    Обратите внимание что в случае добавления алиасного сегмента в качестве Interface-ID нужно указать первичный (а не алиасный!) IP адрес интерфеса получающего DHCP запросы.
  3. Добавим динамических клиентов (без привязки MAC->IP) 10.7.7.200, 10.10.11.200 и 10.10.110.200 для соответствющих подсетей:
    $ ./add-dyn-client.pl 10.7.7.200 10.7.7.1 10.7.7.0
    $ ./add-dyn-client.pl 10.10.11.200 10.10.11.11 10.10.11.0								
    $ ./add-dyn-client.pl 10.10.110.200 10.10.11.11 10.10.110.0
    Описание переданных скрипту параметров (для первого случая):
    • Cient-IP (10.7.7.200) - IP адрес выдаваемый DHCP клиенту.
    • Server-IP (10.7.7.1) - первичный IP адрес интерфейса прослушиваемого сервером DHCP в данной подсети.
    • Client-Subnet (10.7.7.0) - IP адрес подсети DHCP клиента.
    При добавлении клиентов (как динамических так и статических) параметр Server-IP должен быть равен первичному (не алиасному!) IP адресу интерфейса на котором сервер (или агент пересылки) получил запрос - обратите на это внимание в третьей команде. Динамический клиент добавляется для алиасной подсети 10.10.110.0/24, но IP адрес сервера (в данном случае агента пересылки) указывается первичный - 10.10.11.11.
  4. Добавим статического клиента (с привязкой MAC->IP) для подсети 10.7.7.0/24:
    $ ./add-client.pl 10.7.7.100 0003ff2c5290 10.7.7.1 10.7.7.0
    Описание переданных скрипту параметров:
    • Cient-IP (10.7.7.100) - IP адрес выдаваемый DHCP клиенту.
    • MAC-address (0003ff2c5290) - MAC адрес к которому привязывается данный IP адрес. Обратите внимание что MAC адрес записывается в БД без каких-либо преобразований. Это значит что если вы разделите октеты адреса двоеточиями, то и в БД адрес будет сохранён с двоеточиями. Следовательно в файле dhcpd.conf будет необходимо использовать опцию "radius-use-mac-delimiter true".
    • Server-IP (10.7.7.1) - первичный IP адрес интерфейса прослушиваемого сервером DHCP в данной подсети.
    • Client-Subnet (10.7.7.0) - IP адрес подсети DHCP клиента.
    Статического клиента для подсети 10.10.11.0/24 мы добавим позже, с целью проверить возможность динамической смены конфигурации через SQL БД.
  5. Создадим конфигурационный файл для dhcpd:
    ddns-update-style interim;
    
    use-dhcp2radius true;
    radius-servers localhost;
    radius-secret dhcpdsecret;
    radius-password dhcpuser;
    #radius-server-restore 1000;
    #radius-port 1812;
    #radius-client-freq 4;
    #radius-freq-summ 10;
    #radius-cache-ttl 86400;
    #radius-update-arp false;
    #radius-cache-maxlen 3000;
    #radius-allow-cache true;
    #radius-allow-dynamic-cache false;
    #radius-use-mac-delimiter false;
    radius-send-opts-to-srv 35;
    Так же, создадим пустой файл для записи информации о выданных адресах:
    $ touch dhcpd.leases
    Фактически в него не будет записываться ни какой информации.

Минимально необходимая для работы системы конфигурация создана. Предполагается что вы находитесь в каталоге исходных кодов dhcp-3.0.7, в нём же создан файл конфигурации.

Запуск

# ./work.linux-2.2/server/dhcpd -d -cf dhcpd.conf -lf dhcpd.leases eth1 lo
Internet Systems Consortium DHCP Server V3.0.7
Copyright 2004-2008 Internet Systems Consortium.
Patched by Chebotarev Roman. Home page: http://www.netpatch.ru/dhcp2radius.html
Patch version info: RADIUS to DHCP patch (dhcp2radius) v 0.1 2009.06.15
All rights reserved.
For info, please visit http://www.isc.org/sw/dhcp/
PATCH: dhcp2radius ability is enabled.
Wrote 0 leases to leases file.
Listening on LPF/lo/
Sending on   LPF/lo/
Listening on LPF/eth1/00:02:44:75:77:e4
Sending on   LPF/eth1/00:02:44:75:77:e4
Sending on   Socket/fallback/fallback-net

Подобный результат обозначает что dhcpd успешно запущен и ожидает запросов от клиентов.
Ключ -d задан для наглядности - dhcpd не переходит в режим демона и результаты обработки DHCP запросов можно просмотреть в консоли не читая файла логов.

ВАЖНО: dhcpd должен слушать не только интерфейс на который приходят DHCP запросы, но и интерфейс на который приходят RADIUS ответы. В нашем случае, это loopaback интерфейс (lo).

Обслуживание динамическсого клиента

Запустим в тестовой подсети 10.10.11.0/24 обслуживаемой агентом пересылки (dhcrelay) DHCP клиента с MAC адресом 00:03:ff:15:52:90 (не имеет привязки к IP адресу). Разумеется агент пересылки должен быть настроен на наш DHCP сервер. О том как dhcpd обработал запросы клиента можно судить по его выводу на консоль:

Convert DHCPDISCOVER 00:03:ff:15:52:90/10.10.11.11 to RADIUS and forwarded to 127.0.0.1
Convert RADIUS-reply for 00:03:ff:15:52:90 in DHCPOFFER (IP: 10.10.11.200) and forwarded to 10.10.11.11
Convert DHCPREQUEST 00:03:ff:15:52:90/10.10.11.11 to RADIUS and forwarded to 127.0.0.1
Convert RADIUS-reply for 00:03:ff:15:52:90 in DHCPACK (IP: 10.10.11.200) and forwarded to 10.10.11.11

Клиенту 00:03:ff:15:52:90 успешно выдан конфигурационный набор данных включающий IP адрес 10.10.11.200 - адрес для динамических клиентов. В первой и третьей строках кроме MAC адреса клиента так же указан IP адрес агента пересылки (/10.10.11.11) получившего DHCP запрос непосредственно от клиента. В случае если агент пересылки не используется, через слеш указывается имя интерфейса на котором был получен запрос. Это будет показано в следующем примере.

Обслуживание статического клиента

Запускаем DHCP клиента c MAC адресом 00:03:ff:2c:52:90 (привязан к IP адресу 10.7.7.100) в подсети 10.7.7.0/24 и смотрим вывод dhcpd:

Convert DHCPDISCOVER 00:03:ff:2c:52:90/eth1 to RADIUS and forwarded to 127.0.0.1
Convert RADIUS-reply for 00:03:ff:2c:52:90 in DHCPOFFER (IP: 10.7.7.100) and sended to 10.7.7.100
Received DHCPREQUEST (00:03:ff:2c:52:90/eth1) found in dhcpd cache.
Creating DHCPACK (IP: 10.7.7.100) for 00:03:ff:2c:52:90/eth1 and sended to 10.7.7.100

Как и ожидалось - клиент получил IP адрес 10.7.7.100.
Стоит обратить особое внимание на работу dhcpd с кэшем DHCP. По умолчанию dhcpd кэширует ответы RADIUS сервера только для клиентов имеющих статическую привязку MAC->IP. В третьей строчке примера сообщается что ответ для клиента найден в кэше dhcpd. Благодаря этому повторный запрос к RADIUS серверу производиться не будет и сообщение DHCPACK формируется из кэша. Данный подход позволяет многократно снизить нагрузку на сервер БД. В следующий раз запрос к RADIUS серверу будет отправлен либо при получении DHCPDISCOVER (клиент начал новую инициализацию сети), либо в случае истечения срока жизни записи кэша.

Динамическое обновление информации в БД

Добавим привязку MAC->IP для динамического клиента 00:03:ff:15:52:90 из подсети 10.10.11.0/24, который уже получил IP адрес 10.10.11.200. IP адрес присвоим из алиасного сегмента (10.10.110.0/24).

$ ./add-client.pl 10.10.110.100 00:03:ff:15:52:90 10.10.11.11 10.10.110.0

Теперь запустим процесс обновления IP адреса на этом клиенте и изучим вывод dhcpd:

Convert DHCPREQUEST 00:03:ff:15:52:90/10.10.11.11 to RADIUS and forwarded to 127.0.0.1
Convert RADIUS-reply for 00:03:ff:15:52:90 in DHCPNAK (IP: 0.0.0.0) and forwarded to 10.10.11.11
Convert DHCPDISCOVER 00:03:ff:15:52:90/10.10.11.11 to RADIUS and forwarded to 127.0.0.1
Convert RADIUS-reply for 00:03:ff:15:52:90 in DHCPOFFER (IP: 10.10.110.100) and forwarded to 10.10.11.11
Received DHCPREQUEST (00:03:ff:15:52:90/10.10.11.11) found in dhcpd cache.
Creating DHCPACK (IP: 10.10.110.100) for 00:03:ff:15:52:90/eth1 and forwarded to 10.10.11.11

По умолчанию в dhcpd отключено кэширование информации динамических клиентов, поэтому запрос DHCPREQUEST обязательно вызывает обращение RADIUS серверу. После получения новой информации из RADIUS (фактически из БД) dhcpd сравнивает IP адрес в RADIUS-ответе с IP адресом который запросил клиент. Теперь они различаются - мы сделали привязку данного MAC адреса к IP адресу 10.10.110.100. После этого dhcpd отвечает DHCP клиенту DHCPNAK (вторая строка), что означает запрет на дальнейшее использование IP адреса 10.10.11.200. Клиент получив DHCPNAK перезапускает инициализацию сети и получает новый IP адрес (строки с третьей по шестую).

Отсутствие свободных динамических адресов

В подсети 10.7.7.0/24 есть один свободный IP адрес для динамического клиента. Попытаемся получить IP адрес двумя DHCP клиентами:

Convert DHCPDISCOVER 00:18:ad:db:57:5d/eth1 to RADIUS and forwarded to 127.0.0.1
Convert RADIUS-reply for 00:18:ad:db:57:5d in DHCPOFFER (IP: 10.7.7.200) and sended to 10.7.7.200
Convert DHCPREQUEST 00:18:ad:db:57:5d/eth1 to RADIUS and forwarded to 127.0.0.1
Convert RADIUS-reply for 00:18:ad:db:57:5d in DHCPACK (IP: 10.7.7.200) and sended to 10.7.7.200
Convert DHCPDISCOVER 00:9a:2c:dc:63:3e/eth1 to RADIUS and forwarded to 127.0.0.1
RADIUS server 127.0.0.1 reject DHCP client 00:9a:2c:dc:63:3e from 10.7.7.1

Первый клиент с MAC адресом 00:18:ad:db:57:5d успешно получает единственный свободный IP адрес 10.7.7.200. Это можно увидеть в первых 4х строках лога dhcpd. Второй клиент (MAC адрес 00:9a:2c:dc:63:3e) так же пытается получить IP адрес о чём свидетельствует 5я строка лога. Но в БД уже нет не занятых IP адресов для динамических клиентов, потому RADIUS сервер отвечает сообщением Access-Reject. Об этом сообщается в последней строке лога.

Интерфейс взаимодействия с FreeRADIUS

На случай если у вас возникнет желание самостоятельно сконфигурировать FreeRADIUS и dhcpd для работы со своей БД - приведу принцип взаимодействия между ними.

Запрос к RADIUS серверу

Каждый из запросов dhcpd к FreeRADIUS формируется как Access-Request и обязательно содержит следующие аттрибуты:

  • User-Name - MAC адрес клиента представленный как строка шестнадцатиричных цифр. Если конфигурационная опция radius-use-mac-delimiter равна true - байты разделяются двоеточием.
  • User-Password - пароль для доступа. Един для всех клиентов, задаётся из конфигурационного файла.
  • NAS-Port - сновной (не алиасный!) IP адрес интерфейса на котором получен DHCP запрос. Представлен как как 4хбайтовое целое. Если был использован агент пересылки - IP адрес агента пересылки.

В дополнение к этому, при помощи опции radius-send-opts-to-srv, вы можете задать список передаваемых на RADIUS сервер DHCP опций из запроса клиента. Каждая опция представяляется соответствующим ей атрибутом из словаря dictionary.dhcp. Если указанные опции не найдены в запросе DHCP клиента - на сервер отсылаются только обязательные атрибуты. В примере выше на сервер отсылается тип DHCP запроса клиента (DHCPDISCOVER или DHCPREQUEST) - шестнадцатиричный код 0x35.
Все атрибуты отсылаемые на RADIUS сервер являются Vendor Specific атрибутами (VSA).

Ответ RADIUS сервера

После проведеня операций выборки из БД и выполнения каких-либо служебных SQL функций FreeRADIUS сервер в зависимости от ситуации отвечает либо Access-Acept - авторизация успешна и клиенту выдан конфигурационный набор DHCP данных, либо Access-Reject - по какой-то причине клиенту невозможно выдать конфигурацию (обычно - нет свободных адресов).
Если авторизация успешна, то ответ сервера должен содержать ряд обязательных атрибутов:

  • DHCP-DHCP-Server-Identifier - идентификатор (IP адрес) хоста на котором работает dhcpd. Передаётся как 4хбайтное число.
  • DHCP-Your-IP-Address - предлагаемый клиенту IP адрес. Передаётся как 4хбайтное число.
  • DHCP-Client-Hardware-Address - MAC адрес клиента для которого предназначен конфигурационный набор данных. Передаётся как последовательность из 6ти байт.
  • DHCP-Interface-Index - первичный IP адрес интерфейса сервера либо агента пересылки, обслуживающего подсеть клиента. Должен соответствовать значению NAS-Port в запросе клиента. Передаётся как 4хбайтное число.
  • DHCP-Gateway-IP-Address - этот атрибут необходим если подсеть обслуживается через DHCP агента пересылки. Передаётся как 4хбайтное число.
    Если агент пересылки для данной подсети не используется - должен быть равен нулю (0.0.0.0), либо отсутствовать.

Кроме этого в запрос могут (и должны) быть включены необязательные атрибуты из словаря dictionary.dhcp, преобразуемые dhcpd в соответствующие опции DHCP.

В случае если авторизация неудачна, например закончились свободные адреса для динамических клиентов, либо произошла какая-то внутренняя ошибка FreeRADIUS или БД - отправляется стандартный Access-Reject. Отправка каких-либо дополнительных атрибутов не требуется.

Структура базы данных

Далее приведено описание используемых таблиц, представлений и функции (get_id()) базы данных, применяемой для обслуживания DHCP клиентов в примере.

Таблица interfaces - используется для хранения информации об обслуживаемых подсетях. Содержит данные общие для всех клиентов конкретной подсети. Поля таблицы:

  • id - идентификатор записи. Заполняется автоматически, средствами СУБД.
  • server_addr - первичный IP адрес интерфейса получающего DHCP запросы. Для повышения производительности выборки представлен как 32-хбитное число.
  • client_subnet - IP адрес подсети клиента. Так же представлен как 32-хбитное число.
  • attribute - атрибут из словаря dictionary.dhcp.
  • value - значение соответствующего атрибута. Если значение содержит данные для которых нет стандартного типа RADIUS, то оно передаётся как строка байт (тип octets) и должно предваряться символами 0x. Например - список IP адресов DNS серверов содержит: 10.0.0.1, 10.10.0.1. Итоговое значение поля value будет 0x0a0000010a0a0001.
    Если собрать FreeRADIUS с поддержкой DHCP, то будет доступен модификатор типа array, но в тестовой БД он не используется в целях совместимости с бинарными сборками распространённых дистрибутивов.

Клиенту запросившему конфигурацию выдаются все атрибуты, значение поля client_subnet которых, равно IP адресу подсети клиента. IP адрес подсети клиента предварительно получают запросом из представления dhcp_reply, выборкой по значению полей server_addr и client_hw_addr.
Общий вид запроса для добавления нового атрибута в таблицу:

INSERT INTO interfaces (server_addr, attribute, value, client_subnet)
	values(<server-IP-address>, '<RADIUS-VSA-Name>', '<Attribute-Value>', <subnet-IP-address>)

Пример добавления идентификатора сервера 10.7.7.1 (атрибут DHCP-DHCP-Server-Identifier) для подсети 10.10.11.0/24 и IP адресом интерфейса 10.10.11.11:

INSERT INTO interfaces (server_addr, attribute, value, client_subnet)
	values(168430347, 'DHCP-DHCP-Server-Identifier', '10.7.7.1', 168430336)

Как было написано ранее - IP адрес интерфейса и подсети перед добавлением в БД преобразуются в 4-хбайтовые числа. 10.10.11.11 - 168430347 и 10.10.10.0 - 168430336. Преобразование можно выполнить стандартной функцией inet_aton(), либо простым скриптом.

Таблица static_clients - используется для хранения IP адресов клиентов имеющих статическую привязку MAC->IP. Поля таблицы:

  • id - идентификатор записи. Заполняется автоматически, средствами СУБД. Не может быть NULL.
  • client_addr - IP адрес клиента. Представлен строкой в стандартном точечном формате. Не может быть NULL.
  • client_hw_addr - MAC адрес клиента. Представлен строкой шестнадцатиричных цифр. Если используется разделитель в виде двоеточия - задавайте в конфигурационном файле radius-use-mac-delimiter true;. Не может быть NULL.
  • client_subnet - IP адрес подсети клиента представленный как 4-хбайтное число.
  • server_addr - IP адрес интерфейса получающего DHCP запросы в данной сети. Представлен как 4-хбайтное число. Не может быть NULL.
  • end_lease - время окончания срока аренды IP адреса. Для статических IP адресов значение данного поля не имеет значения - адрес может быть выдан только одному клиенту чей MAC адрес записан в поле client_hw_addr.

Таблица dynamic_clients - используется для хранения динамических IP адресов, выдающихся клиентам не имеющим привязки MAC->IP. Поля таблицы аналогичны полям таблицы static_clients за исключением поля client_hw_addr которое может быть NULL если данный IP адрес свободен для выдачи.

Представление (VIEW) dhcpcheck - используется для проверки возможности выдачи DHCP клиенту IP адреса. Запрос представления смотрите в скрипте создания БД. Поля представления:

  • id - идентификатор записи. Заполняется автоматически, средствами СУБД.
  • username - содержит MAC адрес клиента либо значение unregister, для динамических клиентов.
  • attribute - всегда содержит значение User-Password.
  • op - всегда содержит значение :=.
  • value - содержит пароль для DHCP клиентов. В примере всегда равен dhcpuser.
  • server_addr - IP адрес интерфейса получающего DHCP запросы в данной сети. Представлен как 4-хбайтное число. Для динамических клиентов - всегда равен 0.

Представление (VIEW) dhcp_reply - используется для выборки IP адреса предлагаемого DHCP клиенту пославшему запрос. Создаётся из данных таблиц static_clients и dynamic_clients, поля представления аналогичны полям этих таблиц. Запрос представления смотрите в скрипте создания БД.

Функция get_id() - используется вместе с представлением dhcpcheck для проверки возможности выдачи DHCP клиенту IP адреса. Параметры функции:

  • 1. MAC address - MAC адрес клиента запросившего конфигурацию.
  • 2. Server IP address - IP адрес интерфейса получившего DHCP запрос. Представлен как 4-хбайтное число.
  • 3. Message type - тип DHCP запроса. Представлен как 2хбайтовое (smallint) число. На данный момент функция поддерживает DHCPDISCOVER & DHCPREQUEST.

Возвращаемое значение:

  • Для статических клиентов - значение поля id записи содержащей IP адрес клиента из таблицы static_clients.
  • Если клиент не найден в статических - попытка выделить для него адрес из dynamic_clients. Если удалось выделить динамический адрес - возвращает 0.
  • Если данная подсеть (определяется по второму параметру функции) не обслуживается, либо передан не обрабатываемый тип запроса (3й параметр функции) - возвращает -1.
  • Если подсеть обслуживается, но клиент не является статическим и нет возможности выделить динамический адрес - возвращает -2.

В случае возвращения отрицательных значений FreeRADIUS сервер отвечает Access-Reject.

Сообщения об ошибках

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

  • WARN: Invalid autentificator in RADIUS. BOOTREPLY aborted. - обычно возникает в случае дублирования RADIUS запросов посылаемых dhcpd. В случае большой активности DHCP клиентов данные сообщения могут появляються достаточно часто, что свидетельствует о высокой степени загруженности RADIUS сервера (или, скорее всего - сервера БД). Данные сообщения носят информационный характер и в случае не слишком большой частоты появления их можно игнорировать.
  • Сообщения свидетельствующие о наличии DHCP флуда в сегменте:
    ERROR: Exceed maximum DHCP queries per second - 350/sec (30/sec)
    ERROR: Drop DHCPDISCOVER from 00:8f:d9:a0:6d:48/eth0 !
    INFO: Can't processed DHCP packet.

    Возникает при превышении порогового значения максимально допустимого числа запросов в секунду (в приведённом случае - 30) от всех DHCP клиентов. Следствием этого будет блокировка преобразования DHCP запросов в RADIUS запросы во избежание перегрузки сервера БД. Блокироваными окажутся запросы от всех DHCP клиентов обслуживаемых данным процессом dhcpd. Сообщения начнут передаваться на RADIUS сервер как только частота их поступления снизится до максимально допустимой.
    ERROR: Exceed maximum DHCP queries per second (163.2/sec) for host 00:2c:fa:5f:e5:40/eth0. Maximum: 4/sec. Drop request.
    INFO: Can't processed DHCP packet.

    Возникает при превышении максимально допустимого числа запросов в секунду от одного клиента. Приводит к игнорированию DHCP запросов только для данного клиента. Запросы от остальных DHCP клиентов будут обрабатываться в штатном режиме.
  • RADIUS server 127.0.0.1 reject DHCP client 00:9a:2c:dc:63:3e from 10.7.7.1 - обычно возникает в случае запроса от клиента не внесённого в БД и одновременного остутствия свободных динамических адресов для подсети этого клиента.
    Гораздо реже - может свидетельствовать о внутренних проблемах и ошибках БД. В таком случае появление подобных сообщений будет носить массовый характер.

Все возникшие пожелания и предложения можно (или даже нужно) сообщить в гостевую или на и статья будет скорректированна, если это будет уместно.




Вернуться в "Проекты"