Каждый плагин может использоваться в нескольких экземплярах с различными конфигурациями. Конфигурация экземпляра плагина описывается в ветке |
Плагин предназначен для маршрутизации запросов к другим экземплярам плагинов этого же агента. Для этого в 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 | Флаг, отражающий необходимость загрузки записи о данной сессии в основную БД Гидры. По умолчанию загружаются все сессии — данный флаг имеет смысл явно указывать только для «гостевых» сессий, для которых в Гидре нет подходящих профилей оборудования. |
Ядро плагина по очереди (сверху вниз) проверяет каждый шаблон ответа на возможность его применения: если условие применения выполняется, для формирования ответа используется этот шаблон, если нет — ядро переходит к проверке условия для следующего.
В условиях применения шаблона можно использовать данные подобранной ядром плагина записи о сессии, которые доступны через системную переменную $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 $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 $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
, то такая сессия архивируется. Архивные сессии игнорируются при обработке пакетов аккаунтинга и, в частности, не могут быть восстановлены из состояния Завершена по таймауту.
Во избежание неконтролируемого роста базы данных кэша из неё удаляются устаревшие данные, которые более не будут использоваться агентом: