Каждый плагин может использоваться в нескольких экземплярах с различными конфигурациями. Конфигурация экземпляра плагина описывается в ветке plugins
→ <plugin_name>
→ <plugin_instance_name>
, где <plugin_name>
— наименование плагина, а <plugin_instance_name>
— наименование конкретного его экземпляра.
Плагин proxy
Плагин предназначен для маршрутизации запросов к другим экземплярам плагинов этого же агента. Для этого в Perl-модуле hard.pm
сервера FreeRADIUS указывается экземпляр плагина proxy, в конфигурации которого определяются все необходимые маршруты.
Правила маршрутизации запросов
plugins
→ proxy
→ <plugin_instance_name>
→ routes
Каждый маршрут описывается в виде пары ключ-значение:
- ключ — имя экземпляра плагина, которому будет передан запрос;
- значение — вычисляемое выражение, определяющее необходимость применения данного маршрута.
Использован будет первый маршрут, для которого соответствующее выражение вернёт истину. Если ни один из описанных маршрутов не может быть применён, запрос будет передан плагину, указанному в ключе plugins
→ proxy
→ <plugin_instance_name>
→ default
конфигурации.
Пример конфигурации
plugins: proxy: dhcp: routes: base/dhcp-o82: $request.RAD_REQUEST.try("DHCP-Relay-Circuit-Id").present?() base/dhcp-ip-private: $request.RAD_REQUEST.DHCP-Client-IP-Address.private_ip4?() default: "base/dhcp-ip-public"
В данном случае агент HARD имеет три активных экземпляра плагина base
, предназначенных для разных схем авторизации абонентов. При этом для всех схем используется один общий экземпляр FreeRADIUS в режиме DHCP-сервера. В нём указан плагин proxy/dhcp
агента HARD. Плагин proxy/base
выбирает обработчика каждого полученного запроса следующим образом:
- Если в запросе присутствует атрибут
DHCP-Relay-Circuit-Id
, запрос передаётся на обработку экземпляруdhcp-o82
плагинаbase
. Результат обработки отправляется в FreeRADIUS. - Если в запросе присутствует атрибут
DHCP-Client-IP-Address
(но нетDHCP-Relay-Circuit-Id
) и в нём указан частный IP-адрес, запрос передаётся на обработку экземпляруdhcp-o82
плагинаbase
. Результат обработки отправляется в FreeRADIUS.
Плагин base
Данный плагин предназначен для непосредственной обработки запросов, поступающих от сервера FreeRADIUS.
Стэк обработки запроса
plugins
→ base
→ <
→ plugin_instance_name
>call_stack
Определяет порядок вызова рабочим процессом фильтров для обработки поступившего запроса:
- Вызываются фильтры в прямом (сверху вниз) порядке, при этом пропускаются
after
-фильтры. - Запрос обрабатывается ядром плагина: выполняется действие, соответствующее типу запроса и формируется ответ.
- Вызываются фильтры в обратном (снизу вверх) порядке, при этом пропускаются
before
-фильтры.
Действия ядра плагина
plugins
→ base
→ <plugin_instance_name>
→ actions
В данной ветви конфигурации содержатся отдельные блоки, определяющие действия ядра плагина для каждого поддерживаемого типа запроса. На текущий момент поддерживаются 4 типа запросов сервера FreeRADIUS:
- Авторизация.
- Аутентификация.
- Пост-аутентификация.
- Аккаунтинг.
Общее описание того, что происходит на этих стадиях в самом сервере FreeRADIUS доступно в вики проекта: http://wiki.freeradius.org/guide/Concepts.
Авторизация — действие authorize
На данном этапе обработки запроса RADIUS-сервером от агента HARD требуется:
- Определить, известно ли ему абонентское оборудование, запросившее доступ.
- Предоставить RADIUS-серверу корректный пароль для выполнения аутентификации.
Для этого в действии выполняются:
- Подбор профилей оборудования.
- Формирование ответа.
Подбор профилей оборудования
Параметры подбора профилей оборудования определяются в блоках plugins
→ base
→ <plugin_instance_name>
→ actions
→ authorize
→ customer_profile
и plugins
→ base
→ <plugin_instance_name>
→ actions
→ authorize
→ provider_profile
для профилей абонентского и операторского оборудования соответственно. Подобранные профили записываются в системные переменные $customer_profile
и $provider_profile
, а идентификатор привязки абонентского профиля к операторскому — в переменную $bind_id
.
Данные блоки имеют одинаковую структуру:
Ключ | Допустимые значения | Описание |
---|---|---|
|
| Поиск профиля в кэше (MongoDB). Поиск выполняется в соответствии с критериями, указанными в ключе Если оба профиля подбираются с использованием этого метода, системная переменная |
set_first_from_customer_profile | Профиль операторского оборудования извлекается из ранее подобранного профиля абонентского оборудования. В ключе filter определяются критерии отбора операторских профилей, а из удовлетворяющих фильтру профилей выбирается первый. | |
set_first_from_provider_profile | Профиль абонентского оборудования извлекается из ранее подобранного профиля операторского оборудования. В ключе filter определяются критерии отбора абонентских профилей, а из удовлетворяющих фильтру профилей выбирается первый. Данный метод, обычно используется для схемы доступа, в которой абонентское оборудование идентифицируется по данным операторского оборудования, к которому оно подключено: DHCP Option 82, Q-in-Q VLAN и т. д. При этом дополнительная фильтрация может использваться для проверки MAC-адреса абонентского оборудования, или ограничения профилей соответствующим нужной схеме доступа шаблоном, если одновременно используется несколько схем. | |
query | Одна или несколько пар key:value | Запрос для поиска профиля в кэше. Используется только с Несмотря на то, что эти пары задаются не последовательностью, их порядок имеет значение. При запуске, агент формирует в БД кэша недостающие индексы для оптимизации работы с ней. Индексы для подбора профилей формируются с учётом порядка ключей в данном блоке. В связи с этим для оптимальной работы рекомендуется располагать ключи В качестве |
filter | Одна или несколько пар key:value | Фильтр для отбора вложенных профилей. Используется только с set_first_from_customer_profile или set_first_from_provider_profile в качестве значения set_by . В качестве критерия фильтра можно указывать тип привязки абонентского оборудования к операторскому, значения атрибутов подбираемого профиля и т. д. |
Формирование ответа
После подбора профилей, можно формировать ответ. На этом этапе в распоряжении ядра плагина имеются следующие данные:
- Обрабатываемый запрос в
$request
. - Профиль абонентского оборудования в
$customer_profile
. - Профиль операторского оборудования в
$provider_profile
. - Идентификатор привязки абонентского оборудования к операторскому в
$bind_id
. - Установленные
before
-фильтрами пользовательские переменные в словаре$var
и теги в$context
.
Все эти сведения об авторизуемом оборудовании могут использоваться в вычисляемых выражениях как для выбора шаблона ответа, так и для заполнения атрибутов выбранного шаблона конкретными значениями.
Шаблоны ответов определяются как последовательность и размещаются в ключе plugins
→ base
→ <plugin_instance_name>
→ actions
→ authorize
→ reply
конфигурации плагина. Элементы данной последовательности имеют следующую структуру:
Ключ | Допустимые значения | Описание |
---|---|---|
condition | Логическое вычисляемое выражение | Условие применения шаблона: шаблон выбирается, если вычисляемое выражение из данного ключа вернуло истину, либо не задано. |
| Пары | Шаблон блока
|
| Пары | Шаблон блока RAD_REPLY ответа на запрос, где key — наименование RADIUS-атрибута ответа, а value — вычисляемое выражение, результат которого станет значением этого атрибута. В качестве value могут использоваться как единичные выражения, так и последовательности таких выражений. Последовательности выражений применяются для атрибутов, допускающих множественные значения, таких как, например, Cisco-AVPair . |
| Значение из словаря $rlm | Числовой код результата обработки запроса. Набор кодов и их предназначение описаны в вики проекта FreeRADIUS. Как правило используются два основных кода:
|
Ядро плагина по очереди (сверху вниз) проверяет каждый шаблон ответа на возможность его применения: если условие применения выполняется, для формирования ответа используется этот шаблон, если нет — ядро переходит к проверке условия для следующего.
Формирование ответа, включая выбор шаблона, может выполняться не самим ядром плагина, а специальным фильтром render_reply_after
. При наличии такого фильтра в стэке обработки запроса, ядро плагина не формирует ответ, а только подбирает профили оборудования. Это позволяет провести дополнительные вычисления и проверки с помощью after
-фильтров и уже на основании их результатов формировать ответ.
В блоках RAD_CHECK
и RAD_REPLY
шаблонов ответа можно использовать специальный ключ '*'
. Значением такого ключа должно быть вычисляемое выражение, возвращающее словарь «Наименование RADIUS-атрибута — Его значение». При наличии такой записи, плагин добавит в ответ все атрибуты из этого словаря. Если некоторые атрибуты при этом необходимо исключить, следует в выражение добавить метод except
.
Аутентификация — действие authenticate
На данном этапе RADIUS-сервер от агента HARD требуется подготовить атрибуты ответа, которые сервер отправит в случае успешной аутентификации модулем pap, eap, mschap и т.п. Для этого в действии выполняются:
- Подбор профилей оборудования.
- Проверка ограничения количества одновременных сессий.
- Формирование ответа.
Подбор профилей и шаблоны ответов настраиваются аналогично действию authorize
. Как правило, критерии подбора профилей и шаблоны ответов используются те же, что и в authorize
— чтобы их не повторять в конфигурации, рекомендуется применять такие элементы YAML-формата как якори и ссылки.
Ограничение количества одновременных сессий
Проверка количества сессий выполняется в разрезе профилей оборудования следующим образом:
- Разрешённое количество сессий определяется как наибольшее значение атрибута
Simultaneous-Use
среди подобранных абонентского и операторского профилей. Если такой атрибут в обоих профилях отсутствует или пуст, проверка не выполняется. - К базе данных кэша делается запрос для подсчёта текущего количества активных сессий. Учитываются только сессии, привязанные к подобранным ранее профилям оборудования, и находящиеся в активном состоянии: Начата или Обновлена.
- Если текущее количество сессий больше или равно разрешённому, запрос маркируется тегом
simultaneous-limit-exceeded
.
Проверка наличия данного может быть использована как для выбора шаблона ответа, так и в after
-фильтрах. Это позволяет, например, не отказывать в авторизации «лишним» сессиям, а отправлять для них особый набор атрибутов.
Пост-аутентификация — действие post_auth
На данном этапе обработки запросов они передаются сервером FreeRADIUS в агент HARD, как правило, только при работе в режиме DHCP-cервера. Также может применяться для выполнения дополнительных обработок ответа перед отправкой его сервером FreeRADIUS.
Примером такой обработки является вызов хука для отправки в очередь сообщения, содержащего динамический IP-адрес, выдаваемый сервером FreeRADIUS. Если пул динамических IP-адресов реализован на стороне RADIUS-сервера, то выдача адреса из такого пула выполняется сервером в начале этапа пост-аутентификации. В этот момент серверу уже известно, нужно ли выдавать динамический IP-адрес, и если нужно, то из какого пула.
Операции выполняются те же, что и в действии authorize
:
- Подбор профилей оборудования.
- Формирование ответа.
Критерии подбора профилей и шаблоны ответов настраиваются аналогично действию authorize
.
Аккаунтинг — действие accounting
Данное действие предназначено для обработки всех запросов аккаунтинга.
Дата и время события аккаунтинга определяются по атрибуту Event-Timestamp
с учётом задержки пакета, указанной в атрибуте Acct-Delay-Time
. Формат даты и времени задаётся в ключе plugins
→ base
→ <plugin_instance_name>
→ actions
→ accounting
→ event_timestamp
→ format
и по умолчанию соответствует локали en_US.UTF-8
. Правила преобразования и описания формата идентичны таковым у метода datetime.strptime
в Python.
Аккаунтинг по сессиям: Start, Stop, Interim-Update
Для каждого полученного пакета аккаунтинга вычисляется уникальный внешний идентификатор: как MD5-хэш от строки из разделённых точкой с запятой внешнего идентификатора сессии (атрибут Acct-Session-Id
) и значений атрибутов, перечисленных в ключе plugins
→ base
→ <plugin_instance_name>
→ actions
→ accounting
→ session
→ unique_id_attributes
.
По уникальному внешнему идентификатору выполняется поиск имеющейся неархивной записи о сессии в коллекции sessions
базы данных кэша. Если подходящая запись найдена, она обновляется данными из пакета, если нет — пакет аккаунтинга считается первым по сессии и создаётся новая запись о сессии.
Схема поиска сессий
На схеме t1 - момент начала поиска сессии. От момента t1 до (t1 - ... → accounting → session → lookup → hours) (синий интервал) подбирается активная сессия (сессия, не закртая по таймауту), сессия закртая по таймауту ищется на интервале от t1 до (t1 - ... → accounting → session → lookup → timed_out_days) (не отмечен на схеме). Зеленый интервал - интервал, в котором batch закрыл сессии, обычно этот интервал и синий интервал поиска не закрытых по таймауту сессий - пересекаются (в крайнем случае - идут встык). Если по каким либо причинам batch не работал определенное время, между этими интервалами возникнет пробел, сессия, попавшая в этот пробел не подберется, и создастся ее дубль. Для разрешения таких ситуаций к интервалу подбора активных сессий добавляется ... → accounting → session → lookup → additional_hours (обозначен красным не схеме).
При обработке первого пакета аккаунтинга по сессии ядро плагина подбирает профили абонентского и операторского оборудования в соответствии с критериями, указанными в ключах customer_profile
и provider_profile
блока plugins
→ base
→ <plugin_instance_name>
→ actions
→ accounting
. Эти профили фиксируются в сессии и используются для определения её типа при загрузке в основную БД Гидры. Подбор профилей настраивается аналогично действию authorize
. Как правило, критерии подбора профилей используются те же, что и в действии authorize
— чтобы их не повторять в конфигурации, рекомендуется применять такие элементы YAML-формата как якори и ссылки.
Запрос с первым пакетом аккаунтинга по сессии дополнительно маркируется тегом new-session
. Наличие данного тега можно проверять, например, при вызове хука для отправки в очередь сообщения, отражающего факт начала новой сессии. Это может использоваться для формирования команд управления с отдельно стоящим шейпером, который не взаимодействует с сервером доступа.
Обновление и запись новых сведений о сессии выполняется в соответствии с настраиваемым шаблоном. Шаблоны сессий определяются как последовательность и размещаются в ключе plugins
→ base
→ <plugin_instance_name>
→ actions
→ accounting
→ session
→ templates
конфигурации плагина. Элементы данной последовательности имеют следующую структуру:
Ключ | Допустимые значения | Описание |
---|---|---|
condition | Логическое вычисляемое выражение | Условие применения шаблона: шаблон выбирается, если вычисляемое выражение из данного ключа вернуло истину, либо не задано. |
attributes | Пары key:value | Перечень атрибутов сессии, которые необходимо сохранить в записи о ней. Здесь Атрибуты сессии вычисляются и сохраняются только при обработке первого пакета аккаунтинга по данной сессии. Помимо этих атрибутов, при обработке Stop-пакета в отдельный параметр сессии записывается значение атрибута |
| Пары key:value . | Шаблон ответа, где key — наименование RADIUS-атрибута ответа, а value — вычисляемое выражение, результат которого станет значением этого атрибута. В качестве value могут использоваться как единичные выражения, так и последовательности таких выражений. Последовательности выражений применяются для атрибутов, допускающих множественные значения, таких как, например, Cisco-AVPair . |
services | Последовательность структур из трёх полей:
| Перечень услуг, которые необходимо тарифицировать в рамках данной сессии:
Как правило, в рамках одной сессии тарифицируется две детализированных потоковых услуги: для входящего направления трафика и для исходящего. Для вычисления количества по счётчикам
|
| Целое число | Данный параметр применяется только при использовании на сервором доступа сервисной модели, при которой аккаунтинг приходит отдельно для базовой сесии абонента и для предоставляемых в рамках неё сервисов. Для шаблонов сервисных сессий в нём необходимо указать идентфикатор дочернего шабона абонентских профилей, который соответствует данному сервису. Тип такой сервисной сессии будет выбран на основании указанного сервисного шаблона. |
load_to_hydra | true , false | Флаг, отражающий необходимость загрузки записи о данной сессии в основную БД Гидры. По умолчанию загружаются все сессии — данный флаг имеет смысл явно указывать только для «гостевых» сессий, для которых в Гидре нет подходящих профилей оборудования. |
Ядро плагина по очереди (сверху вниз) проверяет каждый шаблон ответа на возможность его применения: если условие применения выполняется, для формирования ответа используется этот шаблон, если нет — ядро переходит к проверке условия для следующего.
В условиях применения шаблона можно использовать данные подобранной ядром плагина записи о сессии, которые доступны через системную переменную $prev_session
. Это позволяет, например, настраивать выбор шаблона сессии по данным профилей оборудования, которые были подобраны при обработке первого пакета аккаунтинга по сессии.
Пакеты Accounting-On и Accounting-Off
Пакеты аккаунтинга, в которых атрибут Acct-Status-Type
имеет значение Accounting-On
или Accounting-Off
, могут отправляться сервером доступа при его запуске или перед остановкой. Они используются для того чтобы RADIUS-сервер на основании одного пакета мог корректно завершить все имеющиеся в его базе сессии данного сервера доступа.
Для обработки таких пакетов в конфигурации плагина задаётся набор атрибутов сессий, которые должны быть завершены при обработке данного on/off
-пакета. В ключе plugins
→ base
→ <plugin_instance_name>
→ actions
→ accounting
→ on_off_attributes
указывается список пар key:value
, где key
— наименование атрибута сессии, а value
— значение данного атрибута.
При настройке обработки on/off
-пакетов необходимо убедиться, что сохранение указанных в ключе on_off_attributes
атрибутов сессий настроено в блоке plugins
→ base
→ <plugin_instance_name>
→ actions
→ accounting
→ session
→ templates
→ attributes
.
Массовая обработка записей о сессиях может выполняться длительное время, поэтому она выполняется в асинхронном режиме. Ядро плагина сохраняет время получения пакета и указанные в конфигурации атрибуты для завершения сессий в коллекцию accounting базы данных кэша, а сама обработка сессий выполняется отдельным процессом.
Хуки
Для каждого действия в ключе plugins
→ base
→ <plugin_instance_name>
→ actions
→ <action_name>
→ hooks
можно указать список хуков, которые будут выполнены ядром плагина по окончании обработки запроса.
Элементами списка являются строки формата <hook_type>/<hook_instance_name>
, где <hook_type>
— тип хука, а <hook_instance_name>
— наименование экземпляра хука.
Настройка самих хуков описана в отдельной статье: Хуки.
Загрузка сведений о сессиях в БД Гидры
Отложенная обработка данных аккаунтинга выполняется при запуске отдельного процесса агента HARD в режиме batch
. Как правило, эта операция выполняется с использованием планировщика, который запускает процесс с интервалом, например, 3 минуты:
# HARD RADIUS accounting loader */3 * * * * hard /opt/hydra/hard/init/hard.sh -f /etc/hydra/hard batch &>/dev/null
Если при запуске процесс загрузки аккаунтинга обнаруживает другой работающий в том же режиме процесс агента, он записывает в лог информацию об этом и завершается.
Записи о сессиях для загрузки выбираются из коллекции sessions
базы данных кэша — загружаются только те записи, которые были обновлены с момента последней загрузки. Для каждой записи о сессии при загрузке в БД Гидры подбирается Тип сессии. Выбор типа выполняется по соответствию шаблонов абонентского и операторского профилей, указанных в типе сессии, профилям оборудования, которые были подобраны ядром плагина при обработке первого пакета аккаунтинга по данной сессии. Если при обработке аккаунтинга по сессии использовался шаблон с указанным в ключе service_profile
→ template_id
идентификатором дочернего шаблона абонентских профилей, то тип сессии подбирается с использованием этого шаблона вместо привязанного абонентского профиля.
Записи о сессия загружаются в таблицу EP_SESSIONS
основной базы данных Гидры. Сведения о потреблённых услугах, которые необходимо протарифицировать, загружаются в таблицу EX_DATA_COLLECT
, записи из которой обрабатываются заданием «Обработка данных RADIUS-аккаунтинга сессий в провижининге».
Информация о сеансе загрузки сессий и услуг записывается в коллекцию load_seances
базы данных кэша. Помимо непосредственно загрузки сессий и данных об услугах, агент HARD в данном режиме выполняет дополнительные массовые обработки данных о сессиях в своём кэше, описанные ниже.
Закрытие «зависших» сессий по таймауту
Если с момента последнего обновления записи о сессии прошло больше часов, чем указано в ключе plugins
→ base
→ <plugin_instance_name>
→ actions
→ accounting
→ session
→ lookup
→ hours
конфигурации плагина, сессия переводится в состояние Завершена по таймауту, в качестве даты и времени завершения такой сессии проставляются текущие дата и время. Завернные по таймауту сессии не учитываются при проверке во время аутентификации ограничения на количество одновременных сессий. Если по такой сессии, пока она не заархивирована, придёт пакет аккаунтинга, она будет восстановлена и обновлена в соответствии с данными этого пакета.
Наличие сессий в состоянии Завершена по таймауту является симптомом проблем RADIUS-взаимодействия между сервером доступа и RADIUS-сервером. Наиболее частые причины появления таких сессий:
- Отключение или перезагрузка сервера доступа, при которой он не отправляет на RADIUS-сервер пакет
Accounting-On
илиAccounting-Off
. Решение — настроить сервер доступа на отправку таких пакетов. - Некорректно заданное в конфигурации агента значение таймаута завершения сессий. Рекомендуется в качестве значения указывать 1.5-2.5 используемого интервала аккаунтинга (атрибут
Acct-Interim-Interval
), для того чтобы даже потеря одного пакета аккаунтинга не приводила к завершению сессии по таймауту. Если же таймаут окажется меньше интервала аккаунтинга, то большинство все сессий будет постоянно завершаться по таймауту. - Различные сетевые проблемы, из-за которых часть пакетов аккаунтинга не доходят до RADIUS-сервера. Решение зависит от характера проблемы, для локализации которой, обычно, анализируются логи RADIUS-сервера, сервера доступа и снимаемые между этими серверами дампы RADIUS-взаимодействия.
Обработка пакетов Accounting-On и Accounting-Off
Записи о пакетах данного типа выбираются из коллекции accounting
базы данных кэша. Для каждой записи выполняется перевод в состояние Завершена всех сессий, удовлетворяющих следующим условиям:
- Сессия активна, то есть находится в состоянии Начата или Обновлена.
- Время последнего пакета аккаунтинга по сессии меньше времени on/off-пакета.
- Атрибуты on/off-пакета, сохранённые при его получении, имеются среди атрибутов сессии, причём значения соответствующих атрибутов совпадают.
Архивация старых сессий
Если с момента последнего обновления сессии прошло больше дней, чем указано в ключе plugins
→ base
→ <plugin_instance_name>
→ actions
→ accounting
→ session
→ lookup
→ timed_out_days
, то такая сессия архивируется. Архивные сессии игнорируются при обработке пакетов аккаунтинга и, в частности, не могут быть восстановлены из состояния Завершена по таймауту.
Очистка кэша от неактуальных записей
Во избежание неконтролируемого роста базы данных кэша из неё удаляются устаревшие данные, которые более не будут использоваться агентом:
- Неактивные профили оборудования и привязки абонентского оборудования к операторскому.
- Архивные сессии, которые были загружены в основную базу данных Гидры.
- Обработанные записи о пакетах Accounting-On и Accounting-Off.
- Сеансы загрузки сессий и услуг в основную базу данных Гидры.