Каждый плагин может использоваться в нескольких экземплярах с различными конфигурациями. Конфигурация экземпляра плагина описывается в ветке |
Плагин предназначен для маршрутизации запросов к другим экземплярам плагинов этого же агента. Для этого в 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:
isg-ipoe-by-ip:
call_stack:
# Установка тега с типом запроса
- set_tag_before/request_type
# Отправка отказа в случае возникновения ошибки
- reject_on_error/main
# Игнорирование лишнего аккаунтинга
- check_attr_before/finish_processing_of_unnecessary_accounting
# Аккаунтинг по базовой сессии
- set_tag_before/base-session-accounting
# Авторизация ISG-сервисов вида IPOE-SC-INET-<Rate>-<Burst>
- set_tag_before/auth-internet-access-isg-service
- match_before/get_speed_limit_values_for_internet-access-isg-service
- format_after/set_cisco-service-info_attr_for_internet-access-isg-service
# Добавление префикса ко всем активируемым сервисам
- map_after/add_prefix_to_isg-services |
plugins → base → <plugin_instance_name> → actions
В данной ветви конфигурации содержатся отдельные блоки, определяющие действия ядра плагина для каждого поддерживаемого типа запроса. На текущий момент поддерживаются 4 типа запросов сервера FreeRADIUS:
Общее описание того, что происходит на этих стадиях в самом сервере FreeRADIUS доступно в вики проекта: http://wiki.freeradius.org/guide/Concepts.
authorizeНа данном этапе обработки запроса RADIUS-сервером от агента HARD требуется:
Для этого в действии выполняются:
Параметры подбора профилей оборудования определяются в блоках 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. В качестве критерия фильтра можно указывать тип привязки абонентского оборудования к операторскому, значения атрибутов подбираемого профиля и т. д. |
plugins:
base:
jmx5-qinq:
actions:
authorize:
customer_profile: &customer_profile
set_by: search_cache
query:
MAC-Address: $request.RAD_REQUEST.User-Name.normalize_mac()
provider_profile: &provider_profile
set_by: search_cache
query:
Switch-VLAN: $var.Remote-Circuit-Ids.Remote_Id
Switch-Port-Code: $var.Remote-Circuit-Ids.Circuit_Id
default_bind_type: network_connection |
plugins:
base:
se-ipoe-by-o82:
actions:
authorize:
provider_profile:
set_by: search_cache
query:
Switch-IP: $request.RAD_REQUEST.Agent-Remote-Id.substring(6).unhex()
Switch-Port-Code: $request.RAD_REQUEST.Agent-Circuit-Id.substring(12).to_i(16)
customer_profile:
set_by: set_first_from_provider_profile
filter:
Auth-Scheme: '"DHCP+L2TP"' |
plugins:
base:
l2tp-by-login:
actions:
authorize:
customer_profile: &customer_profile
set_by: search_cache
query:
L2TP-Login: $request.RAD_REQUEST.User-Name.lower().regexp_replace("@.*$|\\\\t|\s")
Auth-Scheme: '"DHCP+L2TP"'
provider_profile: {} |
После подбора профилей, можно формировать ответ. На этом этапе в распоряжении ядра плагина имеются следующие данные:
$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. Как правило используются два основных кода:
|
Ядро плагина по очереди (сверху вниз) проверяет каждый шаблон ответа на возможность его применения: если условие применения выполняется, для формирования ответа используется этот шаблон, если нет — ядро переходит к проверке условия для следующего.
Формирование ответа, включая выбор шаблона, может выполняться не самим ядром плагина, а специальным фильтром |
В блоках |
plugins:
base:
isg-ipoe-by-ip:
actions:
authorize:
reply: &default_reply
# Авторизация ISG-сервисов вида IPOE-SC-INET-<Rate>-<Burst>
- condition: $context.has_tag?("auth-internet-access-isg-service") and $request.RAD_REQUEST.User-Name.like?("^IPOE-SC-INET(-\d+){2}$")
template:
RAD_CHECK: &default_rad_check
# Добавляем все атрибуты из блока RAD_CHECK запроса, кроме «правильного» пароля
'*': $request.RAD_CHECK.except("Cleartext-Password")
# Идентификация абонентского оборудования выполняется по IP-адресу, а для сервисов вовсе не нужна.
# Поэтому для FreeRADIUS передаём в качестве «правильного» пароль из запроса.
Cleartext-Password: $request.RAD_REQUEST.User-Password
RAD_REPLY:
Cisco-AVPair:
- '"subscriber:accounting-list=HYDRA-IPOE"'
- '"ip:traffic-class=in access-group name IPOE-ACL-ALL-TRAFF priority 1000"'
- '"ip:traffic-class=out access-group name IPOE-ACL-ALL-TRAFF priority 1000"'
Acct-Interim-Interval: '"300"'
result: $rlm.OK
# Оборудование не подобралось - отказ
- condition: $customer_profile.null?()
template:
RAD_CHECK:
Auth-Type: '"Reject"'
RAD_REPLY:
Reply-Message: '"Incorrect IP address"'
result: $rlm.NOTFOUND
# Всё в порядке
- condition: $customer_profile.attributes.try("Internet-Access-Service-State") == "SERV_STATE_Provision"
template:
RAD_CHECK:
<<: *default_rad_check
RAD_REPLY: &ok_rad_reply
Cisco-AVPair: '"subscriber:accounting-list=HYDRA-IPOE"'
Acct-Interim-Interval: '"300"'
Idle-Timeout: '"86400"'
Cisco-Account-Info: $customer_profile.attributes.ISG-IPoE-Services.split(",")
result: $rlm.OK
# Доступ заблокирован
- template:
RAD_CHECK:
<<: *default_rad_check
RAD_REPLY:
<<: *ok_rad_reply
Cisco-Account-Info:
- '"IPOE-SC-REDIRECT"'
- '"IPOE-SC-OPENGARDEN"'
result: $rlm.OK |
authenticateНа данном этапе RADIUS-сервер от агента HARD требуется подготовить атрибуты ответа, которые сервер отправит в случае успешной аутентификации модулем pap, eap, mschap и т.п. Для этого в действии выполняются:
Подбор профилей и шаблоны ответов настраиваются аналогично действию authorize. Как правило, критерии подбора профилей и шаблоны ответов используются те же, что и в authorize — чтобы их не повторять в конфигурации, рекомендуется применять такие элементы YAML-формата как якори и ссылки.
Проверка количества сессий выполняется в разрезе профилей оборудования следующим образом:
Simultaneous-Use среди подобранных абонентского и операторского профилей. Если такой атрибут в обоих профилях отсутствует или пуст, проверка не выполняется.simultaneous-limit-exceeded.Проверка наличия данного может быть использована как для выбора шаблона ответа, так и в after-фильтрах. Это позволяет, например, не отказывать в авторизации «лишним» сессиям, а отправлять для них особый набор атрибутов.
plugins:
base:
l2tp-by-login:
actions:
authorize:
...
authenticate:
customer_profile:
# Критерии подбора абонентского профиля идентичны таковым в authorize
<<: *customer_profile
provider_profile: {}
reply:
# Достигнуто ограничение на количество одновременных сессий
- condition: $context.has_tag?('simultaneous-limit-exceeded')
template:
RAD_REPLY:
Reply-Message: '"You are already logged in"'
result: $rlm.REJECT
# Фиксированный внешний IP-адрес
- condition: ' $customer_profile.attributes.try("Internet-Access-Service-Status") == "SERV_STATE_Provision"
and $customer_profile.attributes.Real-IP-Address.ip4?()'
template:
RAD_REPLY:
Acct-Interim-Interval: '"300"'
Cisco-AVPair:
- '"ip:vrf-id=REAL"'
- '"ip:ip-unnumbered=loopback221"'
Class: $customer_profile.attributes.L2TP-Class.coalesce("7")
Framed-IP-Address: $customer_profile.attributes.Real-IP-Address
Idle-Timeout: '"86400"'
result: $rlm.OK
# Динамический внутренний IP-адрес
- condition: $customer_profile.attributes.try("Internet-Access-Service-Status") == "SERV_STATE_Provision"
template:
RAD_REPLY:
Acct-Interim-Interval: '"300"'
Cisco-AVPair:
- '"ip:vrf-id=NAT"'
- '"ip:ip-unnumbered=loopback220"'
Class: $customer_profile.attributes.L2TP-Class.coalesce("5")
Framed-Pool: '"NAT-1"'
Idle-Timeout: '"86400"'
result: $rlm.OK
# Доступ заблокирован (недостаточно средств)
- template:
RAD_REPLY:
Acct-Interim-Interval: '"600"'
Cisco-AVPair:
- '"ip:vrf-id=NOPAY"'
- '"ip:ip-unnumbered=loopback222"'
Cisco-Service-Info: '"QU;256000;9600;9600;D;256000;9600;9600"'
Framed-Pool: '"FREE-DNAT"'
Idle-Timeout: '"86400"'
mpd-limit:
- '"out#100=all shape 256000 pass"'
- '"in#100=all shape 256000 pass"'
Session-Timeout: '"86400"'
result: $rlm.OK |
post_authНа данном этапе обработки запросов они передаются сервером FreeRADIUS в агент HARD, как правило, только при работе в режиме DHCP-cервера. Также может применяться для выполнения дополнительных обработок ответа перед отправкой его сервером FreeRADIUS.
Примером такой обработки является вызов хука для отправки в очередь сообщения, содержащего динамический IP-адрес, выдаваемый сервером FreeRADIUS. Если пул динамических IP-адресов реализован на стороне RADIUS-сервера, то выдача адреса из такого пула выполняется сервером в начале этапа пост-аутентификации. В этот момент серверу уже известно, нужно ли выдавать динамический IP-адрес, и если нужно, то из какого пула.
Операции выполняются те же, что и в действии authorize:
Критерии подбора профилей и шаблоны ответов настраиваются аналогично действию authorize.
plugins:
base:
dhcp-by-o82:
actions:
post_auth:
provider_profile:
set_by: search_cache
query:
Switch-IP: $request.RAD_REQUEST.DHCP-Relay-Remote-Id.substring(6).unhex()
Switch-Port-Code: $request.RAD_REQUEST.DHCP-Relay-Circuit-Id.substring(12).to_i(16)
customer_profile:
set_by: set_first_from_provider_profile
filter:
Auth-Scheme: '"DHCP+L2TP"'
reply:
# Всё в порядке
- condition: ' $customer_profile.present?()
and $customer_profile.attributes.DHCP-IP-Address.ip4?()
and $customer_profile.attributes.DHCP-Gateway-IP.ip4?()
and $customer_profile.attributes.DHCP-Subnet-Mask.ip4_mask?()'
template:
RAD_REPLY:
DHCP-Domain-Name-Server:
- '"192.168.11.15"'
- '"192.168.11.16"'
DHCP-IP-Address-Lease-Time: '"86400"'
DHCP-Router-Address: $customer_profile.attributes.DHCP-Gateway-IP
DHCP-Subnet-Mask: $customer_profile.attributes.DHCP-Subnet-Mask
DHCP-Your-IP-Address: $customer_profile.attributes.DHCP-IP-Address
result: $rlm.OK
# Профиль абонентского оборудования не подобрался - отказ
- condition: $customer_profile.null?()
template:
RAD_REPLY: {}
reject_reason: '"Customer equipment profile not found // Option 82"'
result: $rlm.REJECT
# В профиле нет маски/адреса/шлюза - отказ
- template:
RAD_REPLY: {}
reject_reason: '"Not valid customer equipment profile // Option 82"'
result: $rlm.REJECT |
Данное действие предназначено для обработки всех запросов аккаунтинга.
Дата и время события аккаунтинга определяются по атрибуту Event-Timestamp с учётом задержки пакета, указанной в атрибуте Acct-Delay-Time. Формат даты и времени задаётся в ключе plugins → base → <plugin_instance_name> → actions → accounting → event_timestamp → format и по умолчанию соответствует локали en_US.UTF-8. Правила преобразования и описания формата идентичны таковым у метода datetime.strptime в Python.
Для каждого полученного пакета аккаунтинга вычисляется уникальный внешний идентификатор: как 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-формата как якори и ссылки.
Запрос с первым пакетом аккаунтинга по сессии дополнительно маркируется тегом |
Обновление и запись новых сведений о сессии выполняется в соответствии с настраиваемым шаблоном. Шаблоны сессий определяются как последовательность и размещаются в ключе 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. Это позволяет, например, настраивать выбор шаблона сессии по данным профилей оборудования, которые были подобраны при обработке первого пакета аккаунтинга по сессии.
plugins:
base:
l2tp-by-login:
actions:
authorize:
...
authenticate:
...
accounting:
# Абонентский профиль подбирается так же, как и при авторизации
customer_profile:
<<: *customer_profile
# Операторский профиль не используется
provider_profile: {}
session:
# Набор атрибутов для формирования уникального внешнего идентификатора сессии
unique_id_attributes: [User-Name, NAS-IP-Address, Framed-IP-Address, NAS-Port]
# Шаблоны сессий
templates:
# Сессия с доступом в Интернет
- condition: ' $customer_profile.attributes.try("Service-State-Code") == "SERV_STATE_Provision"
or $prev_session.attributes.try("Service-State-Code") == "SERV_STATE_Provision"'
attributes: &session_attributes
Calling-Station-Id: $request.RAD_REQUEST.try("Calling-Station-Id")
Called-Station-Id: $request.RAD_REQUEST.try("Called-Station-Id")
Framed-IP-Address: $request.RAD_REQUEST.try("Framed-IP-Address")
NAS-Identifier: $request.RAD_REQUEST.NAS-Identifier
NAS-IP-Address: $request.RAD_REQUEST.NAS-IP-Address
Service-State-Code: $customer_profile.attributes.try("Service-State-Code")
Session-Template: '"Full access session"'
User-Name: $request.RAD_REQUEST.User-Name
# Тарификация потоковых услуг передачи данных
# Счётчики в пакетах приходят относительно сервера доступа — необходимо инвертировать направление для абонента
services:
# Услуга «Интернет-трафик вх.»
- service_id: 40213701
value: $request.RAD_REQUEST.try("Acct-Output-Octets", "0").to_i() + 4 * $request.RAD_REQUEST.try("Acct-Output-Gigawords", "0").to_i().gigabytes()
unit: bytes
# Услуга «Интернет-трафик исх.»
- service_id: 40213501
value: $request.RAD_REQUEST.try("Acct-Input-Octets", "0").to_i() + 4 * $request.RAD_REQUEST.try("Acct-Input-Gigawords", "0").to_i().gigabytes()
unit: bytes
# Гостевые сессии незарегистрированных абонентов — не нужно загружать в Гидру
- condition: ' $customer_profile.null?()
and $prev_session.customer_profile_id.empty?()'
attributes:
<<: *session_attributes
Session-Template: '"Guest session"'
load_to_hydra: false
# Сессии с ограниченным доступом — не нужно тарифицировать услуги
- attributes:
<<: *session_attributes
Session-Template: '"Restricted session"'
services: {} |
plugins:
base:
isg-ipoe-by-ip:
actions:
authorize:
...
authenticate:
...
accounting:
# Абонентский профиль подбирается так же, как и при авторизации: по IP-адресу абонентского оборудования
customer_profile:
<<: *customer_profile
# Операторский профиль не используется
provider_profile: {}
session:
templates:
# Базовая сессия
- condition: $request.RAD_REQUEST.try("Cisco-Service-Info").empty?()
attributes: &session_attributes
User-Name: $request.RAD_REQUEST.User-Name
NAS-IP-Address: $request.RAD_REQUEST.NAS-IP-Address
NAS-Port-Id: $request.RAD_REQUEST.NAS-Port-Id
Cisco-AVPair: $request.RAD_REQUEST.Cisco-AVPair
Cisco-Service-Info: $request.RAD_REQUEST.try("Cisco-Service-Info")
# Сервисная сессия доступа в Интернет
- condition: $request.RAD_REQUEST.Cisco-Service-Info.like?("^NIPOE-SC-(INET|NIGHT)-.+$")
attributes:
# Набор сохраняемых атрибутов тот же, что и для базовой сессии
<<: *session_attributes
services:
# Услуга «Интернет-трафик исх.»
- service_id: 40213501
value: $request.RAD_REQUEST.try("Acct-Input-Octets", "0").to_i() + 4 * $request.RAD_REQUEST.try("Acct-Input-Gigawords", "0").to_i().gigabytes()
unit: bytes
# Услуга «Интернет-трафик вх.»
- service_id: 40213701
value: $request.RAD_REQUEST.try("Acct-Output-Octets", "0").to_i() + 4 * $request.RAD_REQUEST.try("Acct-Output-Gigawords", "0").to_i().gigabytes()
unit: bytes
service_profile:
# Идентификатор шаблона абонентских профилей «IPoE - Доступ к сети Интернет»
template_id: 25244901
# Сервисная сессия доступа к локальной сети с учётом трафика
- condition: $request.RAD_REQUEST.Cisco-Service-Info.like?("^NIPOE-SC-(LOCAL|PRIVATE)$")
attributes:
# Набор сохраняемых атрибутов тот же, что и для базовой сессии
<<: *session_attributes
services:
# Услуга «Локальный трафик исх.»
- service_id: 40214001
value: $request.RAD_REQUEST.try("Acct-Input-Octets", "0").to_i() + 4 * $request.RAD_REQUEST.try("Acct-Input-Gigawords", "0").to_i().gigabytes()
unit: bytes
# Услуга «Локальный трафик вх.»
- service_id: 40214201
value: $request.RAD_REQUEST.try("Acct-Output-Octets", "0").to_i() + 4 * $request.RAD_REQUEST.try("Acct-Output-Gigawords", "0").to_i().gigabytes()
unit: bytes
service_profile:
# Идентификатор шаблона абонентских профилей «IPoE - Доступ к локальной сети»
template_id: 25245101
# Прочие сервисные сессии, для которых тарификация услуг не требуется
- attributes:
# Набор сохраняемых атрибутов тот же, что и для базовой сессии
<<: *session_attributes
service_profile:
# Идентификатор шаблона абонентских профилей «IPoE - Доступ к локальной сети»
template_id: 25245101 |
Пакеты аккаунтинга, в которых атрибут Acct-Status-Type имеет значение Accounting-On или Accounting-Off, могут отправляться сервером доступа при его запуске или перед остановкой. Они используются для того чтобы RADIUS-сервер на основании одного пакета мог корректно завершить все имеющиеся в его базе сессии данного сервера доступа.
Для обработки таких пакетов в конфигурации плагина задаётся набор атрибутов сессий, которые должны быть завершены при обработке данного on/off-пакета. В ключе plugins → base → <plugin_instance_name> → actions → accounting → on_off_attributes указывается список пар key:value, где key — наименование атрибута сессии, а value — значение данного атрибута.
При настройке обработки |
Массовая обработка записей о сессиях может выполняться длительное время, поэтому она выполняется в асинхронном режиме. Ядро плагина сохраняет время получения пакета и указанные в конфигурации атрибуты для завершения сессий в коллекцию accounting базы данных кэша, а сама обработка сессий выполняется отдельным процессом.
plugins:
base:
ran-by-login:
actions:
authorize:
...
authenticate:
...
accounting:
session:
templates:
- attributes:
NAS-IP-Address: $request.RAD_REQUEST.NAS-IP-Address
User-Name: $request.RAD_REQUEST.User-Name
on_off_attributes:
NAS-IP-Address: $request.RAD_REQUEST.NAS-IP-Address |
Для каждого действия в ключе 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-сервером. Наиболее частые причины появления таких сессий:
|
Записи о пакетах данного типа выбираются из коллекции accounting базы данных кэша. Для каждой записи выполняется перевод в состояние Завершена всех сессий, удовлетворяющих следующим условиям:
Если с момента последнего обновления сессии прошло больше дней, чем указано в ключе plugins → base → <plugin_instance_name> → actions → accounting → session → lookup → timed_out_days, то такая сессия архивируется. Архивные сессии игнорируются при обработке пакетов аккаунтинга и, в частности, не могут быть восстановлены из состояния Завершена по таймауту.
Во избежание неконтролируемого роста базы данных кэша из неё удаляются устаревшие данные, которые более не будут использоваться агентом: