ISG, схема со стартом сессии и ее авторизацией по IP, выдача адресов на основе option82 (Конфигурация BGBilling'а)
Материал из BiTel WiKi
Survivor (Обсуждение | вклад) м |
Amir (Обсуждение | вклад) |
||
(12 промежуточных версий не показаны.) | |||
Строка 40: | Строка 40: | ||
| [[Файл:ISG-INET-0015.jpg|200px|thumb|left|Типы устройств: Switch (уровень доступа)]] | | [[Файл:ISG-INET-0015.jpg|200px|thumb|left|Типы устройств: Switch (уровень доступа)]] | ||
|} | |} | ||
- | и | + | |
+ | Для полной интеграции DHCP и ISG сессий, необходимо установить в тип устройства ASR ISG вместо стандартного ru.bitel.bgbilling.modules.inet.dyn.device.cisco.ISGServiceActivator его измененный вариант (на скриншоте 'Типы устройств: ASR ISG (BRAS)' он указан как ru.bitel.bgbilling.modules.inet.dyn.device.cisco.ISGIPServiceActivator): | ||
+ | <source lang="java">import java.util.List; | ||
+ | |||
+ | import javax.annotation.Resource; | ||
+ | |||
+ | import org.apache.log4j.Logger; | ||
+ | |||
+ | import ru.bitel.bgbilling.modules.inet.access.Access; | ||
+ | import ru.bitel.bgbilling.modules.inet.access.InetConnectionRuntime; | ||
+ | import ru.bitel.bgbilling.modules.inet.access.sa.ServiceActivator; | ||
+ | import ru.bitel.bgbilling.modules.inet.access.sa.ServiceActivatorEvent; | ||
+ | import ru.bitel.bgbilling.modules.inet.api.common.bean.InetConnection; | ||
+ | import ru.bitel.bgbilling.modules.inet.api.common.bean.InetDevice; | ||
+ | import ru.bitel.bgbilling.modules.inet.api.common.bean.InetDeviceType; | ||
+ | import ru.bitel.bgbilling.modules.inet.api.common.bean.InetServ; | ||
+ | import ru.bitel.bgbilling.modules.inet.dyn.device.cisco.ISGServiceActivator; | ||
+ | import ru.bitel.bgbilling.server.util.Setup; | ||
+ | import ru.bitel.common.ParameterMap; | ||
+ | import ru.bitel.common.inet.IpAddress; | ||
+ | |||
+ | public class ISGServiceActivatorDhcp | ||
+ | extends ISGServiceActivator | ||
+ | implements ServiceActivator | ||
+ | { | ||
+ | private static final Logger logger = Logger.getLogger( ISGServiceActivatorDhcp.class ); | ||
+ | |||
+ | @Resource(name = "access") | ||
+ | private Access access; | ||
+ | |||
+ | public ISGServiceActivatorDhcp() | ||
+ | { | ||
+ | super(); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * {@inheritDoc} | ||
+ | */ | ||
+ | @Override | ||
+ | public Object init( Setup setup, int moduleId, InetDevice device, InetDeviceType deviceType, ParameterMap deviceConfig ) | ||
+ | throws Exception | ||
+ | { | ||
+ | super.init( setup, moduleId, device, deviceType, deviceConfig ); | ||
+ | |||
+ | // по умолчанию закрытие - logoff | ||
+ | this.closeMode = deviceConfig.getInt( "sa.radius.connection.close.mode", CLOSE_MODE_SUBSCR_COMMAND ); | ||
+ | // по умолчанию, при переключении состояния из отлючен во включен и withoutBreak=false делаем тоже самое, что и при обычном закрытии сессии | ||
+ | this.closeEnableMode = deviceConfig.getInt( "sa.radius.connection.close.enableMode", this.closeMode ); | ||
+ | |||
+ | // никакой работы с вторичной авторизацией (InetDhcpHelperProcessor/InetRadiusHelperProcessor) нет | ||
+ | this.closeRemoveFromKeyMap = deviceConfig.getInt( "sa.radius.connection.close.removeFromKeyMap", 0 ) > 0; | ||
+ | |||
+ | // при закрытии соединения не отправляем дополнительно запросы на отключение сервисов | ||
+ | this.disableServicesOnClose = deviceConfig.getInt( "sa.radius.connection.close.disableServices", 0 ) > 0; | ||
+ | |||
+ | logger.debug( this.closeMode ); | ||
+ | |||
+ | return null; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public Object connectionModify( ServiceActivatorEvent e ) | ||
+ | throws Exception | ||
+ | { | ||
+ | logger.debug( "connectionModify" ); | ||
+ | |||
+ | if( e.getConnection().getDeviceId() != this.deviceId ) | ||
+ | { | ||
+ | logger.debug( "Skip " + e.getConnection() + " " + this.deviceId ); | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | return super.connectionModify( e ); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public Object connectionClose( ServiceActivatorEvent e ) | ||
+ | throws Exception | ||
+ | { | ||
+ | logger.debug( "connectionClose" ); | ||
+ | |||
+ | if( e.getConnection().getDeviceId() != this.deviceId ) | ||
+ | { | ||
+ | logger.debug( "Skip " + e.getConnection() + " " + this.deviceId ); | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | return super.connectionClose( e ); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public Object onAccountingStart( ServiceActivatorEvent e ) | ||
+ | throws Exception | ||
+ | { | ||
+ | return super.onAccountingStart( e ); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public Object onAccountingStop( ServiceActivatorEvent e ) | ||
+ | throws Exception | ||
+ | { | ||
+ | logger.info( "onAccountingStop" ); | ||
+ | |||
+ | final InetConnection dhcpConnection = e.getConnection(); | ||
+ | // ISG соединение - не обрабатываем | ||
+ | if( dhcpConnection.getDeviceId() == deviceId ) | ||
+ | { | ||
+ | return super.onAccountingStop( e ); | ||
+ | } | ||
+ | |||
+ | if( connectionClose( dhcpConnection, dhcpConnection.getServId() ) ) | ||
+ | { | ||
+ | return super.onAccountingStop( e ); | ||
+ | } | ||
+ | |||
+ | List<InetServ> childrenServs = e.getNewInetServ().getChildren(); | ||
+ | if( childrenServs != null ) | ||
+ | { | ||
+ | for( InetServ serv : childrenServs ) | ||
+ | { | ||
+ | if( connectionClose( dhcpConnection, serv.getId() ) ) | ||
+ | { | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return super.onAccountingStop( e ); | ||
+ | } | ||
+ | |||
+ | private boolean connectionClose( InetConnection dhcpConnection, int servId ) | ||
+ | throws Exception | ||
+ | { | ||
+ | List<InetConnectionRuntime> connectionRuntimeList = access.connectionManager.getByServId( servId ); | ||
+ | if( connectionRuntimeList == null ) | ||
+ | { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | for( InetConnectionRuntime connectionRuntime : connectionRuntimeList ) | ||
+ | { | ||
+ | final InetConnection isgConnection = connectionRuntime.connection; | ||
+ | if( isgConnection.getId() != dhcpConnection.getId() && isgConnection.getDeviceId() == deviceId && | ||
+ | IpAddress.equals( isgConnection.getInetAddressBytes(), dhcpConnection.getInetAddressBytes() ) ) | ||
+ | { | ||
+ | super.connectionClose( isgConnection, closeMode, null ); | ||
+ | return true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | }</source> | ||
+ | |||
+ | Создаем тип сервиса INTERNET: | ||
{| | {| | ||
| [[Файл:ISG-INET-0010.jpg|200px|thumb|left|Сервис INTERNET, типы устройств]] | | [[Файл:ISG-INET-0010.jpg|200px|thumb|left|Сервис INTERNET, типы устройств]] | ||
|} | |} | ||
+ | Указываем в конфигурации типа сервиса: | ||
+ | |||
+ | # не выдавать IP-адрес в Framed-IP-Address в Access-Accept-пакете | ||
+ | serv.radius.noAddress=1 | ||
+ | |||
Создаем сами устройства (соответствующих типов): | Создаем сами устройства (соответствующих типов): | ||
{| | {| | ||
Строка 87: | Строка 246: | ||
<param name="mq.url" value="failover:(tcp://localhost:61616)"/> | <param name="mq.url" value="failover:(tcp://localhost:61616)"/> | ||
<param name="mq.user" value="bill"/> | <param name="mq.user" value="bill"/> | ||
- | <param name="mq.pswd" value=" | + | <param name="mq.pswd" value="***"/> |
<!-- id модуля --> | <!-- id модуля --> | ||
Строка 190: | Строка 349: | ||
в <param name="rootDeviceId" value="'''1'''"/> цифра '''1''' - это ID устройства Access+Accounting. | в <param name="rootDeviceId" value="'''1'''"/> цифра '''1''' - это ID устройства Access+Accounting. | ||
- | Запускаем, подключаем клиента и вот результат: | + | Далее ставим ''BGInetAccounting сервер для модуля Inet'' (выполняет функции RADIUS-аккаунтинга). Конфиг (файл inet-accounting.xml): |
+ | <source lang="bash"> | ||
+ | <?xml version="1.0" encoding="UTF-8"?> | ||
+ | <application context="accounting"> | ||
+ | <!-- Уникальное имя приложения --> | ||
+ | <param name="app.name" value="BGInetAccounting"/> | ||
+ | <!-- Уникальный числовой id приложения --> | ||
+ | <param name="app.id" value="10102"/> | ||
+ | |||
+ | <!-- Параметры подключения к БД --> | ||
+ | <param name="db.driver" value="com.mysql.jdbc.Driver"/> | ||
+ | <param name="db.url" value="jdbc:mysql://127.0.0.1/bgbilling?useUnicode=true&characterEncoding=Cp1251&allowUrlInLocalInfile=true&zeroDateTimeBehavior=convertToNull&jdbcCompliantTruncation=false&queryTimeoutKillsConnection=true&connectTimeout=1000"/> | ||
+ | <param name="db.user" value="bill"/> | ||
+ | <param name="db.pswd" value="***"/> | ||
+ | <param name="db.validationTimeout" value="10"/> | ||
+ | |||
+ | <!-- Параметры подключения к MQ --> | ||
+ | <param name="mq.url" value="failover:(tcp://localhost:61616)"/> | ||
+ | <param name="mq.user" value="bill"/> | ||
+ | <param name="mq.pswd" value="***"/> | ||
+ | |||
+ | <!-- id модуля --> | ||
+ | <param name="moduleId" value="2"/> | ||
+ | <!-- id корневого устройства --> | ||
+ | <param name="rootDeviceId" value="1"/> | ||
+ | |||
+ | <!-- Внутренняя переменная приложения, не изменять --> | ||
+ | <param name="commonIdentifierName" value="rootDeviceId"/> | ||
+ | |||
+ | <!-- Параметры сохранения radius-пакетов в файлы логов --> | ||
+ | <!-- Директория, в которую сохранять radius логи --> | ||
+ | <param name="datalog.radius.dir" value="data/radius" /> | ||
+ | <!-- Размер блока данных в файле лога, также размер буфера на лог файл --> | ||
+ | <param name="datalog.radius.chunk.size" value="524288" /> | ||
+ | <!-- Сжимать radius логи: 0 - не сжимать, 1 - zlib --> | ||
+ | <param name="datalog.radius.compression.type" value="1" /> | ||
+ | |||
+ | <!-- Создание Accounting --> | ||
+ | <bean name="accounting" class="ru.bitel.bgbilling.modules.inet.accounting.Accounting"/> | ||
+ | |||
+ | <context name="radius"> | ||
+ | <!-- Cоздание процессора radius-пакетов --> | ||
+ | <bean name="radiusProcessor" class="ru.bitel.bgbilling.modules.inet.radius.InetRadiusHelperProcessor"/> | ||
+ | |||
+ | <!-- Служебный ScheduledExecutorService, необходимый для dataLogger --> | ||
+ | <scheduledExecutorService name="hrlydtlggr" corePoolSize="1"/> | ||
+ | |||
+ | <!-- Cоздание dataLogger, сохраняющего radius-пакеты на диск (только один экземпляр) --> | ||
+ | <bean name="radiusDataLogger" class="ru.bitel.bgbilling.modules.inet.radius.RadiusHourlyDataLogger"> | ||
+ | <param name="scheduledExecutor">hrlydtlggr</param> | ||
+ | </bean> | ||
+ | |||
+ | <!-- Cоздание слушателя radius-пакетов на порту с передачей ему процессора и dataLogger --> | ||
+ | <bean name="radiusListener" class="ru.bitel.bgbilling.modules.inet.radius.InetRadiusListener"> | ||
+ | <constructor> | ||
+ | <!-- Хост (интерфейс), на котором будет открыт сокет. Если пусто - на всех --> | ||
+ | <param name="host" value=""/> | ||
+ | <!-- Порт, на котором будет открыт сокет --> | ||
+ | <param name="port" value="1813"/> | ||
+ | <!-- Размер буфера приема слушателя --> | ||
+ | <param name="recvBufferSize">1 * 1024 * 1024</param> | ||
+ | <!-- Рекомендуемый SO_RCVBUF сокета --> | ||
+ | <param name="soRCVBUF"></param> | ||
+ | <!-- Количество потоков-обработчиков --> | ||
+ | <param name="threadCount">10</param> | ||
+ | <!-- Максимальное количество пакетов в очереди на обработку --> | ||
+ | <param name="maxQueueSize">200</param> | ||
+ | <!-- Передача процессора --> | ||
+ | <param name="processor">radiusProcessor</param> | ||
+ | <!-- Режим работы, RadiusListener.Mode.accounting --> | ||
+ | <param name="mode">RadiusListener.Mode.accounting</param> | ||
+ | <!-- Передача setup --> | ||
+ | <param name="setup">setup</param> | ||
+ | <!-- Передача dataLogger --> | ||
+ | <param name="dataLogger">radiusDataLogger</param> | ||
+ | </constructor> | ||
+ | </bean> | ||
+ | </context> | ||
+ | </application> | ||
+ | </source> | ||
+ | |||
+ | Запускаем BGInetAccess и BGInetAccounting, подключаем клиента и вот результат: | ||
{| | {| | ||
| [[Файл:ISG-INET-0027.jpg|200px|thumb|left|Монитор (активные сессии договора)]] | | [[Файл:ISG-INET-0027.jpg|200px|thumb|left|Монитор (активные сессии договора)]] | ||
Строка 201: | Строка 441: | ||
access.group=1 | access.group=1 | ||
- | # | + | # Типы устройств - NAS-ов |
#radius.deviceTypeIds=3,4 | #radius.deviceTypeIds=3,4 | ||
- | # | + | # Типы устройств, являющиеся dhcp relay (нужно указывать все типы устройств-коммутаторы, через которые передается DHCP-пакет или же оставить значение пустым) |
#dhcp.relay.deviceTypeIds= | #dhcp.relay.deviceTypeIds= | ||
- | # | + | # Привязка DHCP и ISG сессий по IP-адресу - здесь указывается тип устройства ASR ISG |
radius.key.deviceTypeIds=3 | radius.key.deviceTypeIds=3 | ||
- | # | + | # Количество потоков на worker'а |
accounting.worker.1.thread.count=1 | accounting.worker.1.thread.count=1 | ||
- | #тарификатор: | + | # тарификатор: |
- | #минимальная сумма трафика, при которой тарифицировать соединение | + | # минимальная сумма трафика, при которой тарифицировать соединение |
accounting.worker.1.tariffication.1.minDeltaAmount=0 | accounting.worker.1.tariffication.1.minDeltaAmount=0 | ||
- | #пауза между заданиями тарификации | + | # пауза между заданиями тарификации |
accounting.worker.1.tariffication.1.delay=1 | accounting.worker.1.tariffication.1.delay=1 | ||
- | #максимальное количество тарифицируемых соединений за задание | + | # максимальное количество тарифицируемых соединений за задание |
accounting.worker.1.tariffication.1.batchSize=100 | accounting.worker.1.tariffication.1.batchSize=100 | ||
- | #трекер (обработка сессий без наработки): | + | # трекер (обработка сессий без наработки): |
- | #пауза между заданиями трекинга | + | # пауза между заданиями трекинга |
accounting.worker.1.tracking.1.delay=2 | accounting.worker.1.tracking.1.delay=2 | ||
- | #максимальное количество проверенных соединений за задание | + | # максимальное количество проверенных соединений за задание |
accounting.worker.1.tracking.1.batchSize=100 | accounting.worker.1.tracking.1.batchSize=100 | ||
- | # | + | # Количество потоков на worker'а |
accounting.worker.2.thread.count=1 | accounting.worker.2.thread.count=1 | ||
- | #сброс в базу трафиков и наработки | + | # сброс в базу трафиков и наработки |
- | #минимальная наработка, при которой сбрасывать соединения в базу | + | # минимальная наработка, при которой сбрасывать соединения в базу |
accounting.worker.2.flushing.1.minDeltaAccount=0 | accounting.worker.2.flushing.1.minDeltaAccount=0 | ||
- | #пауза между заданиями сброса в базу | + | # пауза между заданиями сброса в базу |
accounting.worker.2.flushing.1.delay=2 | accounting.worker.2.flushing.1.delay=2 | ||
- | #максимальное количество сброшенных соединений в базу за задание | + | # максимальное количество сброшенных соединений в базу за задание |
accounting.worker.2.flushing.1.batchSize=500 | accounting.worker.2.flushing.1.batchSize=500 | ||
- | # | + | # Количество потоков на worker'а |
accounting.worker.3.thread.count=1 | accounting.worker.3.thread.count=1 | ||
- | #завершатель соединений | + | # завершатель соединений |
- | #пауза между заданиями | + | # пауза между заданиями |
accounting.worker.3.finishing.1.delay=2 | accounting.worker.3.finishing.1.delay=2 | ||
- | #максимальное количество сброшенных соединений в базу за задание | + | # максимальное количество сброшенных соединений в базу за задание |
accounting.worker.3.finishing.1.batchSize=500 | accounting.worker.3.finishing.1.batchSize=500 | ||
connection.start.fromAccept=1 | connection.start.fromAccept=1 | ||
- | #таймаут перевода соединения в статус suspended при остутствии радиус пакетов | + | # таймаут перевода соединения в статус suspended при остутствии радиус пакетов |
connection.suspend.timeout=900 | connection.suspend.timeout=900 | ||
- | #таймаут закрытия соединения при остутствии радиус пакетов (не складывается с connection.suspend.timeout) | + | # таймаут закрытия соединения при остутствии радиус пакетов (не складывается с connection.suspend.timeout) |
connection.close.timeout=1300 | connection.close.timeout=1300 | ||
- | #таймаут перевода соединения в статус suspended при остутствии радиус пакетов (для сессий с ограниченным доступом) | + | # таймаут перевода соединения в статус suspended при остутствии радиус пакетов (для сессий с ограниченным доступом) |
connection.disable.suspend.timeout=900 | connection.disable.suspend.timeout=900 | ||
- | #таймаут закрытия соединения при остутствии радиус пакетов (не складывается с connection.suspend.timeout, для сессий с ограниченным доступом) | + | # таймаут закрытия соединения при остутствии радиус пакетов (не складывается с connection.suspend.timeout, для сессий с ограниченным доступом) |
connection.disable.close.timeout=1300 | connection.disable.close.timeout=1300 | ||
- | # | + | # таймаут завершения соединения после стоп-пакета (обычно используется для ожидания запоздавших Netflow-пакетов) |
connection.finish.timeout=5 | connection.finish.timeout=5 | ||
Строка 278: | Строка 518: | ||
dhcp.option82.agentRemoteId.position=0 | dhcp.option82.agentRemoteId.position=0 | ||
- | # Поиск сервиса Inet по | + | # Поиск сервиса Inet по устройству и интерфейсу |
dhcp.servSearchMode=1 | dhcp.servSearchMode=1 | ||
# выдавать тот же IP адрес, что при открытом доступе | # выдавать тот же IP адрес, что при открытом доступе | ||
dhcp.disable.mode=1 | dhcp.disable.mode=1 | ||
+ | |||
+ | # при появлении нового DISCOVER закрываем предыдущую сессию в биллинге | ||
+ | #dhcp.connection.closeOnNew=1 | ||
# Отключаем проверку пароля | # Отключаем проверку пароля | ||
Строка 311: | Строка 554: | ||
# Коды ошибок, при которых вместо reject выдавать accept с заданными атрибутами | # Коды ошибок, при которых вместо reject выдавать accept с заданными атрибутами | ||
- | #(пользователю выдается серый адрес и устанавливается HTTP-редирект) | + | # (пользователю выдается серый адрес и устанавливается HTTP-редирект) |
#radius.disable.accessCodes=1,2,3,4,10,11,12,46 | #radius.disable.accessCodes=1,2,3,4,10,11,12,46 | ||
# атрибуты, выдаваемые при rejectToAccept | # атрибуты, выдаваемые при rejectToAccept | ||
Строка 390: | Строка 633: | ||
# выдавать тот же IP адрес, что при открытом доступе | # выдавать тот же IP адрес, что при открытом доступе | ||
dhcp.disable.mode=1 | dhcp.disable.mode=1 | ||
+ | |||
+ | # при появлении нового DISCOVER закрываем предыдущую сессию в биллинге | ||
+ | #dhcp.connection.closeOnNew=1 | ||
# Берем адрес из Access-Request | # Берем адрес из Access-Request | ||
Строка 555: | Строка 801: | ||
#Опция ISG-5MBPS | #Опция ISG-5MBPS | ||
radius.inetOption.2.attributes=cisco-avpair=ip:traffic-class=in access-group 101 priority 201;cisco-avpair=ip:traffic-class=out access-group 102 priority 201;cisco-SSG-Service-Info=QU;;5120000;;384000;;768000;;D;;5120000;;960000;;1920000 | radius.inetOption.2.attributes=cisco-avpair=ip:traffic-class=in access-group 101 priority 201;cisco-avpair=ip:traffic-class=out access-group 102 priority 201;cisco-SSG-Service-Info=QU;;5120000;;384000;;768000;;D;;5120000;;960000;;1920000 | ||
- | </ | + | </source> |
Во вторых - на сервер устанавливаем еще одну копию ''BGInetAccess сервер для модуля Inet'' (переименовав его из BGInetAccess, к примеру, в BGInetServiceAccess) и в нем указываем в качестве root-устройства вершину второй иерархии: Service Auth (типа Access+Accounting): | Во вторых - на сервер устанавливаем еще одну копию ''BGInetAccess сервер для модуля Inet'' (переименовав его из BGInetAccess, к примеру, в BGInetServiceAccess) и в нем указываем в качестве root-устройства вершину второй иерархии: Service Auth (типа Access+Accounting): | ||
<source lang="bash"> | <source lang="bash"> | ||
Строка 580: | Строка 826: | ||
<param name="mq.url" value="failover:(tcp://localhost:61616)"/> | <param name="mq.url" value="failover:(tcp://localhost:61616)"/> | ||
<param name="mq.user" value="bill"/> | <param name="mq.user" value="bill"/> | ||
- | <param name="mq.pswd" value=" | + | <param name="mq.pswd" value="***"/> |
<!-- id модуля --> | <!-- id модуля --> | ||
Строка 651: | Строка 897: | ||
Запускаем и получаем второй radius-сервер (на порту 1811). | Запускаем и получаем второй radius-сервер (на порту 1811). | ||
- | Теперь нужно завести | + | Создаем новый тип сервиса (не путать с ISG сервисами, те - назначаются на ISG сессию на циске, а эти - нечто вроде аккаунтов для доступа к услугам в BGBilling'е), который и будет описывать как биллингу авторизовывать радиус запросы с логинами равными именам ISG сервисов: |
+ | {| | ||
+ | | [[Файл:ISG-INET-0036.jpg|200px|thumb|left|Типы сервисов: ISG Service (конфигурация)]] | ||
+ | | [[Файл:ISG-INET-0037.jpg|200px|thumb|left|Типы сервисов: ISG Service (типы устройств)]] | ||
+ | |} | ||
+ | |||
+ | Теперь нужно завести отдельный договор, в котором для устройства ''Access+Accounting: Service Auth'' (вершина второй иерархии устройств, к которой и привязан второй радиус) будут созданы сервисы (типа ISG Service) с логинами равными именами ISG сервисов: | ||
+ | {| | ||
+ | | [[Файл:ISG-INET-0033.jpg|200px|thumb|left|Договор ISG_SERVICE, сервисы]] | ||
+ | | [[Файл:ISG-INET-0034.jpg|200px|thumb|left|Договор ISG_SERVICE, сервис ISG-5MBPS]] | ||
+ | |} | ||
+ | В результате, второй радиус сервер будет отвечать ACCESS-ACCEPT для запросов от BRAS'а, в которых логин=имя ISG сервиса. | ||
+ | |||
+ | Теперь осталось только привязать к этому сервису (не к ISG сервису, а к сервису договора, с логином сервиса равным имени ISG сервиса) соответствующую опцию: | ||
+ | {| | ||
+ | | [[Файл:ISG-INET-0035.jpg|200px|thumb|left|Договор ISG_SERVICE, сервис ISG-5MBPS, опции]] | ||
+ | |} | ||
+ | Описание этой опции (тело ISG сервиса) радиус найдет у дочернего к ''Access+Accounting: Service Auth'' устройства R31_ASR1002 в конфигурации его типа (''ASR ISG Service Auth''), и ответит BRAS'у: | ||
+ | <source lang="bash"> | ||
+ | Packet type: Access-Accept | ||
+ | Identifier: 98 | ||
+ | Authenticator: {FB C8 D2 33 9D EC CF 10 04 0A 78 70 21 9A 69 04} | ||
+ | Attributes: | ||
+ | Acct-Interim-Interval=60 | ||
+ | cisco-avpair=subscriber:accounting-list=ipoe-isg-aaa | ||
+ | cisco-avpair=ip:traffic-class=in access-group 101 priority 201 | ||
+ | cisco-avpair=ip:traffic-class=out access-group 102 priority 201 | ||
+ | cisco-SSG-Service-Info=QU;5120000;384000;768000;D;5120000;960000;1920000 | ||
+ | </source> | ||
- | + | Вот и все! |
Текущая версия на 13:44, 4 сентября 2014
Устанавливаем модуль inet_5.2_1118.zip, создаем его в редакторе модулей и услуг, добавляем услуги.
Затем, создаем Опции (имена ISG сервисов), типы трафика и тарифный план (в нем прописываем стоимости типов трафика и подключаем Опции, т.е. ISG сервисы):
Описываем откуда брать информацию о количестве каждого из типов трафика (можно конечно использовать netflow, но я ограничился Acct-Input-Octets и Acct-Output-Octets из radius аккаунтинга, так как тарифов по траффику у меня нет и эта информация нужна всего лишь для статистики):
Далее, создаем пул IP адресов - они должны быть из диапазона адресов интерфейса Loopback52 (на свиче уровня аггрегации), а default gateway должен быть адрес интерфейса Loopback52.
Создаем сервис INTERNET, который будем подключать к договору в биллинге (не путать с ISG сервисом, назначаемым на ISG сессию абонента на циске), чтобы собственно предоставить ему (договору) доступ в интернет через модуль Inet.
Создаем сущность коммутатор, привязываем к ней атрибут адрес (позже пригодится для указания местоположения свичей доступа, чтобы потом хоть как-то ориентироваться что-где):
Создаем типы устройств:
- абстрактный тип Access+Accounting, являющийся верхушкой иерархии всех типов устройств, объединяя их все (в нем прописываются настройки общие для всех типов устройств)
- тип ASR ISG, описывающий BRAS'ы
- тип SW-1, описывающий свичи уровня аггрегации (они же dhcp релеи)
- тип Switch, описывающий свичи уровня доступа (те, которые вставляют option82), привязываем к нему сущность коммутатор.
Для полной интеграции DHCP и ISG сессий, необходимо установить в тип устройства ASR ISG вместо стандартного ru.bitel.bgbilling.modules.inet.dyn.device.cisco.ISGServiceActivator его измененный вариант (на скриншоте 'Типы устройств: ASR ISG (BRAS)' он указан как ru.bitel.bgbilling.modules.inet.dyn.device.cisco.ISGIPServiceActivator):
import java.util.List; import javax.annotation.Resource; import org.apache.log4j.Logger; import ru.bitel.bgbilling.modules.inet.access.Access; import ru.bitel.bgbilling.modules.inet.access.InetConnectionRuntime; import ru.bitel.bgbilling.modules.inet.access.sa.ServiceActivator; import ru.bitel.bgbilling.modules.inet.access.sa.ServiceActivatorEvent; import ru.bitel.bgbilling.modules.inet.api.common.bean.InetConnection; import ru.bitel.bgbilling.modules.inet.api.common.bean.InetDevice; import ru.bitel.bgbilling.modules.inet.api.common.bean.InetDeviceType; import ru.bitel.bgbilling.modules.inet.api.common.bean.InetServ; import ru.bitel.bgbilling.modules.inet.dyn.device.cisco.ISGServiceActivator; import ru.bitel.bgbilling.server.util.Setup; import ru.bitel.common.ParameterMap; import ru.bitel.common.inet.IpAddress; public class ISGServiceActivatorDhcp extends ISGServiceActivator implements ServiceActivator { private static final Logger logger = Logger.getLogger( ISGServiceActivatorDhcp.class ); @Resource(name = "access") private Access access; public ISGServiceActivatorDhcp() { super(); } /** * {@inheritDoc} */ @Override public Object init( Setup setup, int moduleId, InetDevice device, InetDeviceType deviceType, ParameterMap deviceConfig ) throws Exception { super.init( setup, moduleId, device, deviceType, deviceConfig ); // по умолчанию закрытие - logoff this.closeMode = deviceConfig.getInt( "sa.radius.connection.close.mode", CLOSE_MODE_SUBSCR_COMMAND ); // по умолчанию, при переключении состояния из отлючен во включен и withoutBreak=false делаем тоже самое, что и при обычном закрытии сессии this.closeEnableMode = deviceConfig.getInt( "sa.radius.connection.close.enableMode", this.closeMode ); // никакой работы с вторичной авторизацией (InetDhcpHelperProcessor/InetRadiusHelperProcessor) нет this.closeRemoveFromKeyMap = deviceConfig.getInt( "sa.radius.connection.close.removeFromKeyMap", 0 ) > 0; // при закрытии соединения не отправляем дополнительно запросы на отключение сервисов this.disableServicesOnClose = deviceConfig.getInt( "sa.radius.connection.close.disableServices", 0 ) > 0; logger.debug( this.closeMode ); return null; } @Override public Object connectionModify( ServiceActivatorEvent e ) throws Exception { logger.debug( "connectionModify" ); if( e.getConnection().getDeviceId() != this.deviceId ) { logger.debug( "Skip " + e.getConnection() + " " + this.deviceId ); return null; } return super.connectionModify( e ); } @Override public Object connectionClose( ServiceActivatorEvent e ) throws Exception { logger.debug( "connectionClose" ); if( e.getConnection().getDeviceId() != this.deviceId ) { logger.debug( "Skip " + e.getConnection() + " " + this.deviceId ); return null; } return super.connectionClose( e ); } @Override public Object onAccountingStart( ServiceActivatorEvent e ) throws Exception { return super.onAccountingStart( e ); } @Override public Object onAccountingStop( ServiceActivatorEvent e ) throws Exception { logger.info( "onAccountingStop" ); final InetConnection dhcpConnection = e.getConnection(); // ISG соединение - не обрабатываем if( dhcpConnection.getDeviceId() == deviceId ) { return super.onAccountingStop( e ); } if( connectionClose( dhcpConnection, dhcpConnection.getServId() ) ) { return super.onAccountingStop( e ); } List<InetServ> childrenServs = e.getNewInetServ().getChildren(); if( childrenServs != null ) { for( InetServ serv : childrenServs ) { if( connectionClose( dhcpConnection, serv.getId() ) ) { break; } } } return super.onAccountingStop( e ); } private boolean connectionClose( InetConnection dhcpConnection, int servId ) throws Exception { List<InetConnectionRuntime> connectionRuntimeList = access.connectionManager.getByServId( servId ); if( connectionRuntimeList == null ) { return false; } for( InetConnectionRuntime connectionRuntime : connectionRuntimeList ) { final InetConnection isgConnection = connectionRuntime.connection; if( isgConnection.getId() != dhcpConnection.getId() && isgConnection.getDeviceId() == deviceId && IpAddress.equals( isgConnection.getInetAddressBytes(), dhcpConnection.getInetAddressBytes() ) ) { super.connectionClose( isgConnection, closeMode, null ); return true; } } return false; } }
Создаем тип сервиса INTERNET:
Указываем в конфигурации типа сервиса:
# не выдавать IP-адрес в Framed-IP-Address в Access-Accept-пакете serv.radius.noAddress=1
Создаем сами устройства (соответствующих типов):
Для свичей доступа указываем местоположение (используя сущность и атрибут адрес):
Теперь осталось привязать сервис INTERNET (выбрав нужный свич уровня доступа и указав правильный номер порта) к договору:
И не забыть про тариф, так как именно через него (помимо определения стоимостей) назначаются ISG сессии (Опции):
Теперь ставим BGInetAccess сервер для модуля Inet (выполняет функции DHCP и RADIUS серверов). Конфиг (файл inet-access.xml):
<?xml version="1.0" encoding="UTF-8"?> <application context="access"> <!-- Уникальное имя приложения --> <param name="app.name" value="BGInetAccess"/> <!-- Уникальный числовой id приложения --> <param name="app.id" value="10101"/> <!-- Параметры подключения к БД --> <param name="db.driver" value="com.mysql.jdbc.Driver"/> <param name="db.url" value="jdbc:mysql://127.0.0.1/bgbilling?useUnicode=true&characterEncoding=Cp1251&allowUrlInLocalInfile=true&zeroDateTimeBehavior=convertToNull&jdbcCompliantTruncation=false&queryTimeoutKillsConnection=true&connectTimeout=1000"/> <param name="db.user" value="bill"/> <param name="db.pswd" value="***"/> <param name="db.validationTimeout" value="10"/> <!-- Параметры подключения к MQ --> <param name="mq.url" value="failover:(tcp://localhost:61616)"/> <param name="mq.user" value="bill"/> <param name="mq.pswd" value="***"/> <!-- id модуля --> <param name="moduleId" value="2"/> <!-- id корневого устройства --> <param name="rootDeviceId" value="1"/> <!-- Типы фейковых устройств, являющихся аккаунтинг серверами --> <param name="accounting.deviceTypeIds" value="1"/> <!-- Внутренняя переменная приложения, не изменять --> <param name="commonIdentifierName" value="rootDeviceId"/> <!-- Параметры сохранения логов данных --> <!-- Директория, в которую сохранять radius логи --> <param name="datalog.radius.dir" value="data/radius" /> <!-- Размер блока данных в файле лога, также размер буфера на лог файл --> <param name="datalog.radius.chunk.size" value="262144" /> <!-- Сжимать radius логи: 0 - не сжимать, 1 - zlib --> <param name="datalog.radius.compression.type" value="1" /> <!-- Директория, в которую сохранять flow логи --> <param name="datalog.dhcp.dir" value="data/dhcp" /> <!-- Размер блока данных в файле лога, также размер буфера на лог файл --> <param name="datalog.dhcp.chunk.size" value="131072" /> <!-- Сжимать flow логи: 0 - не сжимать, 1 - zlib --> <param name="datalog.dhcp.compression.type" value="1" /> <!-- Создание Access --> <bean name="access" class="ru.bitel.bgbilling.modules.inet.access.Access" /> <context name="radius"> <!-- Cоздание процессора radius-пакетов --> <bean name="radiusProcessor" class="ru.bitel.bgbilling.modules.inet.radius.InetRadiusHelperProcessor"/> <!-- Служебный ScheduledExecutorService, необходимый для dataLogger --> <scheduledExecutorService name="hrlydtlggr" corePoolSize="1" /> <!-- Cоздание dataLogger, сохраняющего radius-пакеты на диск (только один экземпляр) --> <bean name="radiusDataLogger" class="ru.bitel.bgbilling.modules.inet.radius.RadiusHourlyDataLogger"> <param name="scheduledExecutor">hrlydtlggr</param> </bean> <!-- Cоздание слушателя radius-пакетов на порту с передачей ему процессора и dataLogger --> <bean name="radiusListener" class="ru.bitel.bgbilling.modules.inet.radius.InetRadiusListener"> <constructor> <!-- Хост (интерфейс), на котором будет открыт сокет. Если пусто - на всех --> <param name="host" value=""/> <!-- Порт, на котором будет открыт сокет --> <param name="port" value="1812"/> <!-- Размер буфера приема слушателя --> <param name="recvBufferSize">512 * 1024</param> <!-- Рекомендуемый SO_RCVBUF сокета --> <param name="soRCVBUF"></param> <!-- Количество потоков-обработчиков --> <param name="threadCount">10</param> <!-- Максимальное количество пакетов в очереди на обработку --> <param name="maxQueueSize">200</param> <!-- Передача процессора --> <param name="processor">radiusProcessor</param> <!-- Режим работы, RadiusListener.Mode.authentication --> <param name="mode">RadiusListener.Mode.authentication</param> <!-- Передача dataLogger --> <param name="dataLogger">radiusDataLogger</param> </constructor> </bean> </context> <context name="dhcp"> <!-- Cоздание процессора dhcp-пакетов --> <bean name="dhcpProcessor" class="ru.bitel.bgbilling.modules.inet.dhcp.InetDhcpProcessor"/> <scheduledExecutorService name="hrlydtlggr" corePoolSize="1" /> <!-- Cоздание dataLogger, сохраняющего dhcp-пакеты на диск --> <bean name="dhcpDataLogger" class="ru.bitel.bgbilling.modules.inet.dhcp.DhcpHourlyDataLogger"> <param name="scheduledExecutor">hrlydtlggr</param> </bean> <!-- Cоздание слушателя dhcp-пакетов на порту с передачей ему процессора и dataLogger --> <bean name="dhcpListener" class="ru.bitel.bgbilling.kernel.network.dhcp.DhcpListener"> <constructor> <!-- Хост (интерфейс), на котором будет открыт сокет. Если пусто - на всех --> <param name="host" value=""/> <!-- Порт, на котором будет открыт сокет --> <param name="port" value="67"/> <!-- Размер буфера приема слушателя --> <param name="recvBufferSize">512 * 1024</param> <!-- Количество потоков-обработчиков --> <param name="threadCount">10</param> <!-- Максимальное количество пакетов в очереди на обработку --> <param name="maxQueueSize">200</param> <!-- Передача процессора --> <param name="processor">dhcpProcessor</param> <!-- Передача dataLogger --> <param name="dataLogger">dhcpDataLogger</param> </constructor> </bean> </context> </application>
Здесь, в <param name="moduleId" value="2"/> цифра 2 - это ID модуля Inet, а
в <param name="rootDeviceId" value="1"/> цифра 1 - это ID устройства Access+Accounting.
Далее ставим BGInetAccounting сервер для модуля Inet (выполняет функции RADIUS-аккаунтинга). Конфиг (файл inet-accounting.xml):
<?xml version="1.0" encoding="UTF-8"?> <application context="accounting"> <!-- Уникальное имя приложения --> <param name="app.name" value="BGInetAccounting"/> <!-- Уникальный числовой id приложения --> <param name="app.id" value="10102"/> <!-- Параметры подключения к БД --> <param name="db.driver" value="com.mysql.jdbc.Driver"/> <param name="db.url" value="jdbc:mysql://127.0.0.1/bgbilling?useUnicode=true&characterEncoding=Cp1251&allowUrlInLocalInfile=true&zeroDateTimeBehavior=convertToNull&jdbcCompliantTruncation=false&queryTimeoutKillsConnection=true&connectTimeout=1000"/> <param name="db.user" value="bill"/> <param name="db.pswd" value="***"/> <param name="db.validationTimeout" value="10"/> <!-- Параметры подключения к MQ --> <param name="mq.url" value="failover:(tcp://localhost:61616)"/> <param name="mq.user" value="bill"/> <param name="mq.pswd" value="***"/> <!-- id модуля --> <param name="moduleId" value="2"/> <!-- id корневого устройства --> <param name="rootDeviceId" value="1"/> <!-- Внутренняя переменная приложения, не изменять --> <param name="commonIdentifierName" value="rootDeviceId"/> <!-- Параметры сохранения radius-пакетов в файлы логов --> <!-- Директория, в которую сохранять radius логи --> <param name="datalog.radius.dir" value="data/radius" /> <!-- Размер блока данных в файле лога, также размер буфера на лог файл --> <param name="datalog.radius.chunk.size" value="524288" /> <!-- Сжимать radius логи: 0 - не сжимать, 1 - zlib --> <param name="datalog.radius.compression.type" value="1" /> <!-- Создание Accounting --> <bean name="accounting" class="ru.bitel.bgbilling.modules.inet.accounting.Accounting"/> <context name="radius"> <!-- Cоздание процессора radius-пакетов --> <bean name="radiusProcessor" class="ru.bitel.bgbilling.modules.inet.radius.InetRadiusHelperProcessor"/> <!-- Служебный ScheduledExecutorService, необходимый для dataLogger --> <scheduledExecutorService name="hrlydtlggr" corePoolSize="1"/> <!-- Cоздание dataLogger, сохраняющего radius-пакеты на диск (только один экземпляр) --> <bean name="radiusDataLogger" class="ru.bitel.bgbilling.modules.inet.radius.RadiusHourlyDataLogger"> <param name="scheduledExecutor">hrlydtlggr</param> </bean> <!-- Cоздание слушателя radius-пакетов на порту с передачей ему процессора и dataLogger --> <bean name="radiusListener" class="ru.bitel.bgbilling.modules.inet.radius.InetRadiusListener"> <constructor> <!-- Хост (интерфейс), на котором будет открыт сокет. Если пусто - на всех --> <param name="host" value=""/> <!-- Порт, на котором будет открыт сокет --> <param name="port" value="1813"/> <!-- Размер буфера приема слушателя --> <param name="recvBufferSize">1 * 1024 * 1024</param> <!-- Рекомендуемый SO_RCVBUF сокета --> <param name="soRCVBUF"></param> <!-- Количество потоков-обработчиков --> <param name="threadCount">10</param> <!-- Максимальное количество пакетов в очереди на обработку --> <param name="maxQueueSize">200</param> <!-- Передача процессора --> <param name="processor">radiusProcessor</param> <!-- Режим работы, RadiusListener.Mode.accounting --> <param name="mode">RadiusListener.Mode.accounting</param> <!-- Передача setup --> <param name="setup">setup</param> <!-- Передача dataLogger --> <param name="dataLogger">radiusDataLogger</param> </constructor> </bean> </context> </application>
Запускаем BGInetAccess и BGInetAccounting, подключаем клиента и вот результат:
Полный конфиг типа устройств Access+Acounting:
access.group=1 # Типы устройств - NAS-ов #radius.deviceTypeIds=3,4 # Типы устройств, являющиеся dhcp relay (нужно указывать все типы устройств-коммутаторы, через которые передается DHCP-пакет или же оставить значение пустым) #dhcp.relay.deviceTypeIds= # Привязка DHCP и ISG сессий по IP-адресу - здесь указывается тип устройства ASR ISG radius.key.deviceTypeIds=3 # Количество потоков на worker'а accounting.worker.1.thread.count=1 # тарификатор: # минимальная сумма трафика, при которой тарифицировать соединение accounting.worker.1.tariffication.1.minDeltaAmount=0 # пауза между заданиями тарификации accounting.worker.1.tariffication.1.delay=1 # максимальное количество тарифицируемых соединений за задание accounting.worker.1.tariffication.1.batchSize=100 # трекер (обработка сессий без наработки): # пауза между заданиями трекинга accounting.worker.1.tracking.1.delay=2 # максимальное количество проверенных соединений за задание accounting.worker.1.tracking.1.batchSize=100 # Количество потоков на worker'а accounting.worker.2.thread.count=1 # сброс в базу трафиков и наработки # минимальная наработка, при которой сбрасывать соединения в базу accounting.worker.2.flushing.1.minDeltaAccount=0 # пауза между заданиями сброса в базу accounting.worker.2.flushing.1.delay=2 # максимальное количество сброшенных соединений в базу за задание accounting.worker.2.flushing.1.batchSize=500 # Количество потоков на worker'а accounting.worker.3.thread.count=1 # завершатель соединений # пауза между заданиями accounting.worker.3.finishing.1.delay=2 # максимальное количество сброшенных соединений в базу за задание accounting.worker.3.finishing.1.batchSize=500 connection.start.fromAccept=1 # таймаут перевода соединения в статус suspended при остутствии радиус пакетов connection.suspend.timeout=900 # таймаут закрытия соединения при остутствии радиус пакетов (не складывается с connection.suspend.timeout) connection.close.timeout=1300 # таймаут перевода соединения в статус suspended при остутствии радиус пакетов (для сессий с ограниченным доступом) connection.disable.suspend.timeout=900 # таймаут закрытия соединения при остутствии радиус пакетов (не складывается с connection.suspend.timeout, для сессий с ограниченным доступом) connection.disable.close.timeout=1300 # таймаут завершения соединения после стоп-пакета (обычно используется для ожидания запоздавших Netflow-пакетов) connection.finish.timeout=5 session.split.onTariffOption=1 session.split.onDeviceState=1
Полный конфиг типа устройств ASR ISG:
# Версия SNMP (по умолчанию 1) snmp.version=2 # SNMP OID, из которого ивлекается значение uptime (1.3.6.1.2.1.1.3.0) snmp.uptimeOid=1.3.6.1.2.1.1.3.0 # По умолчанию для Inet каждое устройство является netflow-агентом, # для оптимизации указываем, что у нас только один netflow-агент flow.agent.type=netflow flow.agent.link={@deviceId}:-1 # Поиск устройства по giaddr и remoteId - 1, # поиск устройства только по giaddr, агентское устройство ищется отдельно, после preprocessDhcpRequest - 2, dhcp.deviceSearchMode=1 # убираем заголовок-длину dhcp.option82.removeHeader=2 # позиция agentRemoteId dhcp.option82.agentRemoteId.position=0 # Поиск сервиса Inet по устройству и интерфейсу dhcp.servSearchMode=1 # выдавать тот же IP адрес, что при открытом доступе dhcp.disable.mode=1 # при появлении нового DISCOVER закрываем предыдущую сессию в биллинге #dhcp.connection.closeOnNew=1 # Отключаем проверку пароля radius.password.verification=0 # Берем адрес из Access-Request radius.address.fromRequest=1 # Код атрибута, из которого извлекать acctSessionId родительской сессии (по умолчанию - из cisco-avpair) #radius.parentAcctSessionId.type=1 # префикс в значении атрибута перед acctSessionId родительской сессии #radius.parentAcctSessionId.prefix=parent-session-id= # код атрибута, из которого извлекать имя сервиса ISG (по умолчанию cisco-SSG-Service-Info) #radius.serviceName.type=251 # префикс в значении атрибута перед именем сервиса ISG (если есть) #radius.serviceName.prefix= # Атрибуты, выдаваемые в Access-Accept radius.realm.default.attributes=Acct-Interim-Interval=60;Idle-Timeout=1300;cisco-avpair=subscriber:accounting-list=ipoe-isg-aaa # Радиус атрибуты, выдаваемые при авторизации для сервисов radius.inetOption.2.attributes=cisco-SSG-Account-Info=AISG-5MBPS radius.inetOption.3.attributes=cisco-SSG-Account-Info=AISG-10MBPS radius.inetOption.4.attributes=cisco-SSG-Account-Info=AISG-LOCAL # Категории ip адресов из ресурсов, из которых будут выдаваться адреса ("пул", указывается во вкладке "IP ресурсы") radius.realm.default.ipCategories=1 # Коды ошибок, при которых вместо reject выдавать accept с заданными атрибутами # (пользователю выдается серый адрес и устанавливается HTTP-редирект) #radius.disable.accessCodes=1,2,3,4,10,11,12,46 # атрибуты, выдаваемые при rejectToAccept radius.disable.attributes=Acct-Interim-Interval=60;cisco-avpair=subscriber:accounting-list=ipoe-isg-aaa;cisco-SSG-Account-Info=AL4REDIRECT;cisco-SSG-Account-Info=AOPENGARDEN #radius.realm.reject.attributes=Acct-Interim-Interval=60;IP-Interface-Name=IP-Interface-Name=ISG-IP-UNAUTH;cisco-SSG-Account-Info=ALOCAL_L4R #категории ip адресов из ресурсов, из которых будут выдаваться адреса для отключенных ("пул", указывается во вкладке "IP ресурсы") radius.disable.ipCategories=2 # Параметры активации сервисов # длина паузы, если возникла ошибка #sa.error.pause=60 # количество заданий за раз #sa.batch.size=20 # время (сек) ожидания завершения всех заданий (при асинхронной работе) #sa.batch.wait=5 # пауза (сек) после обработки заданий #sa.batch.pause=0 # время (сек) ожидания новой задачи перед вызовом disconnect. #sa.batch.waitNext=5 #режим отправки CoA. 1 - команды 0xc и 0xb в одном пакете для каждого сервиса, 2 - атрибуты subscriber:command= в раздельных пакетах для каждого сервиса sa.radius.connection.coa.mode=2 # при отключении посылать команду account-logoff sa.radius.connection.close.mode=3 # не посылать команды на отключение сервисов #sa.radius.connection.close.disableServices=1 # чтобы, если деньги закончились, не закрывал сервисы, а закрывал сразу сессию ISG целиком - 0, иначе - 1 sa.radius.connection.withoutBreak=0 # если dhcp lease time большой, а при положительном балансе доступ нужно дать (даже если адрес сейчас выдан серый), нужно установить 1 #sa.radius.connection.coa.onEnable=0 # откуда при отправке CoA брать атрибуты опций (по умолчанию - те же атрибуты, что выдаются при удачной авторизации) #sa.radius.option.attributesPrefix= sa.radius.connection.attributes=Acct-Session-Id,User-Name,Framed-IP-Address radius.connection.attributes=Acct-Session-Id,User-Name,Framed-IP-Address # атрибуты CoA запроса для прекращения доступа (используется при sa.radius.connection.withoutBreak=1) #sa.radius.disable.attributes= # фиксированные атрибуты, добавляемые в запрос перед отправкой CoA #sa.radius.coa.attributes= # добавлять ли при отправке CoA атрибуты реалма (для default - из radius.realm.default.attributes) #sa.radius.realm.addAttributes=0 # фиксированные атрибуты, добавляемые в запрос перед отправкой PoD #sa.radius.pod.attributes= sa.radius.connection.close.removeFromKeyMap=0 # Лог CoA запросов sa.radius.log=1 #radius.disable.attributes=cisco-avpair=subscriber:accounting-list=ISG-AUTH-1;cisco-SSG-Account-Info=ALOCAL_L4R #radius.serviceName.disable=L4REDIRECT,OPENGARDEN #sa.radius.service.disable=L4REDIRECT,OPENGARDEN #Для автоматического привязывания MAC-адреса к сервису в конфигурации модуля/типа сервиса/устройства/типа устройства можно прописать #serv.macAddress.auto=1 # Пауза между выполнениями команды после ошибки manage.error.pause=5 # Пауза между получением uptime manage.uptime.pause=360 # Пауза после ошибки, возникшей при получении uptime manage.uptime.error.pause=360 # Синхронизировать ли сервисы при обнаружении перезагрузки, 0 - не синхронизировать (по умолчанию), 1 - синхронизировать # (для обнаружения перезагрузки в типе устройства должен быть установлен обработчик управления устройством) #sa.device.sync.onReboot=0 # Вызывать ли при синхронизации для каждого сервиса, 0 - только serviceCreate или 1 (по умолчанию) # сначала serviceCancel, а затем serviceCreate #sa.device.sync.cancelBeforeCreate=1
Здесь нужно обратить внимание на:
# Поиск устройства по giaddr и remoteId - 1, # поиск устройства только по giaddr, агентское устройство ищется отдельно, после preprocessDhcpRequest - 2, dhcp.deviceSearchMode=1 # Поиск сервиса Inet по dhcp.servSearchMode=1 # выдавать тот же IP адрес, что при открытом доступе dhcp.disable.mode=1 # при появлении нового DISCOVER закрываем предыдущую сессию в биллинге #dhcp.connection.closeOnNew=1 # Берем адрес из Access-Request radius.address.fromRequest=1 # Радиус атрибуты, выдаваемые при авторизации для сервисов radius.inetOption.2.attributes=cisco-SSG-Account-Info=AISG-5MBPS radius.inetOption.3.attributes=cisco-SSG-Account-Info=AISG-10MBPS radius.inetOption.4.attributes=cisco-SSG-Account-Info=AISG-LOCAL # чтобы, если деньги закончились, не закрывал сервисы, а закрывал сразу сессию ISG целиком - 0, иначе - 1 sa.radius.connection.withoutBreak=0
В radius.inetOption.2.attributes=cisco-SSG-Account-Info=AISG-5MBPS цифра 2 - это ID соответствующей Опции (ISG-5MBPS).
А это должно быть закомментировано:
# Коды ошибок, при которых вместо reject выдавать accept с заданными атрибутами #(пользователю выдается серый адрес и устанавливается HTTP-редирект) #radius.disable.accessCodes=1,2,3,4,10,11,12,46 # не посылать команды на отключение сервисов #sa.radius.connection.close.disableServices=1 #radius.disable.attributes=cisco-avpair=subscriber:accounting-list=ISG-AUTH-1;cisco-SSG-Account-Info=ALOCAL_L4R #radius.serviceName.disable=L4REDIRECT,OPENGARDEN #sa.radius.service.disable=L4REDIRECT,OPENGARDEN
Полный конфиг типа устройств SW-1:
# Код субопции 82, содержащей VLAN, позиция и длина в субопции dhcp.option82.vlanId.code=1 dhcp.option82.vlanId.position=0 dhcp.option82.vlanId.length=2 dhcp.option82.interfaceId.code=1 dhcp.option82.interfaceId.position=2 dhcp.option82.interfaceId.length=2 dhcp.option.leaseTime=600 # параметры DHCP к сети не привязанные dhcp.option.serverIdentifier=0.0.0.0 #dhcp.option.leaseTime=600 #dhcp.option.timeServer=ntp.bgbilling.ru # параметр DHCP "основной шлюз" для сети #dhcp.net.option.188.191.0.0:255.255.255.0.gate= #dhcp.net.option.188.191.1.0:255.255.255.0.gate= #dhcp.net.option.188.191.2.0:255.255.255.0.gate= #dhcp.net.option.188.191.3.0:255.255.255.0.gate= #dhcp.option.timeOffset=43200 #dhcp.option.domainName=bgbilling.ru
Полный конфиг устройства Access+Acounting:
ip.resource.categoryId=1
Полный конфиг устройства R31_ASR1002:
# Хост для отправки PoD и CoA запросов (по умолчанию - хост, заданный в параметрах устройства Хост/порт) #radius.host=<хост устройства> # порт для отправки PoD и CoA запросов (по умолчанию - порт, заданный в параметрах устройства Хост/порт) radius.port=1700 # идентификатор - Nas-Identifier (по умолчанию - значение из поля Идентификатор параметров устройства) #radius.identifier=<идентификатор устройства> # используемый secret для общения по radius-протоколу (по умолчанию - значение из поля Community/secret параметров устройства) #radius.secret=<community/sercret устройства> sa.radius.secret=*** # Сommunity (по умолчанию из параметра устройства Сommunity/Secret) snmp.community=***
Полный конфиг устройства SW-1:
ip.resource.categoryId=1 vlan.resource.category=1 dhcp.ipCategories=1
Полный конфиг модуля Inet:
# Активные и приостановленные статусы договора contract.status.active.codes=0 contract.status.suspend.codes=3,4 # Проверка цены в тарифе: 0 - проверка отсутсвует, 1 - ошибка только? если у сессии есть трафик определенного типа, # но для него нет цены, 2 - ошибка? если хотя бы для одного типа трафика в привязке типа сервиса нет цены (по умолчанию - 1) #accounting.tariffication.checkPrice=1 # Режим активации учетного периода, если не используется скрипт на событие активации, # 0 (по умолчанию) - активация со дня подключения (старта сессии), 1 - активация с начала месяца. # Следует учитывать, что учетный период является второй величиной при вычислении пропорциональности # в тарифной ветке "Диапазон трафика" #accounting.period.activation.mode=0 # Нужно ли отключать сервис с типом инициации "по трафику", если тариф не найден #serv.disableOnTariffError=0 #Пункты Web - меню web.menuItem1=Отчет по сессиям Inet web.menuItem2=Смена пароля на логины Inet web.menuItem3=none #web.menuItem3=Отчет по трафикам Inet # Параметры автоматической генерации логина для сервиса. # Минимальное значение логина при генерации логина #serv.login.min=1 # Максимальное значение логина при генерации логина (т.е. если в базе присутствуют логины 1,2,3 и 10000000, # то при генерации создастся логин 4, а не 10000001) #serv.login.max=9999999 # Парамерты автоматической генерации пароля для сервиса. Можно указать в конфигурации модуля, конфигурации устройства, конфигурации типа сервиса # (в последнем случае значения будут главнее): # Минимальная длина пароля serv.password.length.min=5 # Максимальная длина пароля serv.password.length.max=16 # Разрешенные символы (используются также при генерации пароля) serv.password.chars=1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz # Описание разрешенных символов, если пользователь ввел другие serv.password.chars.description=В пароле допустимы только цифры и латинские буквы. # Длина для автоматически генерируемого пароля serv.password.length.auto=6 # Используемые символы для автоматически генерируемого пароля (по умолчанию значение берется из параметра serv.password.chars) #serv.password.chars.auto= # Параметры активации карточек модуля card при использовании InetRadiusProcessor, # данные параметры можно указать как в конфигурации модуля, так и в конфигурации устройства. # Код модуля card #card.moduleId= # id услуг активации #card.activate.serviceIds= # Минимальное значение карточного логина используется, чтобы указать, какие числовые логины нужно искать в карточках; # если 0, то ограничение не действует. #card.login.min=0 # Максимальное значение карточного логина используется, чтобы указать, какие числовые логины нужно искать в карточках; # если 0, то ограничение не действует. #card.login.max=0
Вся вышеприведенная конфигурация будет работать только если ISG сервисы будут описаны локально (на BRAS'е). Чтобы загружать сервисы из биллинга (как изначально предполагалось), создаем еще один тип устройств ASR ISG Service Auth (это будет уже второй тип для одного и того же BRAS'а, первый тип был - ASR ISG):
Затем создаем и вторую иерархию устройств:
- еще одно абстрактное устройство типа Access+Accounting: Service Auth
- и второе устройство R31_ASR1002 (BRAS), но уже типа ASR ISG Service Auth
Для чего все это нужно?
Во первых - в новом типе устройств ASR ISG Service Auth описываем ISG сервисы (Опции):
#Опция ISG-5MBPS radius.inetOption.2.attributes=cisco-avpair=ip:traffic-class=in access-group 101 priority 201;cisco-avpair=ip:traffic-class=out access-group 102 priority 201;cisco-SSG-Service-Info=QU;;5120000;;384000;;768000;;D;;5120000;;960000;;1920000
Во вторых - на сервер устанавливаем еще одну копию BGInetAccess сервер для модуля Inet (переименовав его из BGInetAccess, к примеру, в BGInetServiceAccess) и в нем указываем в качестве root-устройства вершину второй иерархии: Service Auth (типа Access+Accounting):
<param name="rootDeviceId" value="3"/>
Полный конфиг (inet-access.xml):
<?xml version="1.0" encoding="UTF-8"?> <application context="access"> <!-- Уникальное имя приложения --> <param name="app.name" value="BGInetServiceAccess"/> <!-- Уникальный числовой id приложения --> <param name="app.id" value="10103"/> <!-- Параметры подключения к БД --> <param name="db.driver" value="com.mysql.jdbc.Driver"/> <param name="db.url" value="jdbc:mysql://127.0.0.1/bgbilling?useUnicode=true&characterEncoding=Cp1251&allowUrlInLocalInfile=true&zeroDateTimeBehavior=convertToNull&jdbcCompliantTruncation=false&queryTimeoutKillsConnection=true&connectTimeout=1000"/> <param name="db.user" value="bill"/> <param name="db.pswd" value="***"/> <param name="db.validationTimeout" value="10"/> <!-- Параметры подключения к MQ --> <param name="mq.url" value="failover:(tcp://localhost:61616)"/> <param name="mq.user" value="bill"/> <param name="mq.pswd" value="***"/> <!-- id модуля --> <param name="moduleId" value="2"/> <!-- id корневого устройства --> <param name="rootDeviceId" value="3"/> <!-- Типы фейковых устройств, являющихся аккаунтинг серверами --> <param name="accounting.deviceTypeIds" value="1"/> <!-- Внутренняя переменная приложения, не изменять --> <param name="commonIdentifierName" value="rootDeviceId"/> <!-- Параметры сохранения логов данных --> <!-- Директория, в которую сохранять radius логи --> <param name="datalog.radius.dir" value="data/radius" /> <!-- Размер блока данных в файле лога, также размер буфера на лог файл --> <param name="datalog.radius.chunk.size" value="262144" /> <!-- Сжимать radius логи: 0 - не сжимать, 1 - zlib --> <param name="datalog.radius.compression.type" value="1" /> <!-- Директория, в которую сохранять flow логи --> <param name="datalog.dhcp.dir" value="data/dhcp" /> <!-- Размер блока данных в файле лога, также размер буфера на лог файл --> <param name="datalog.dhcp.chunk.size" value="131072" /> <!-- Сжимать flow логи: 0 - не сжимать, 1 - zlib --> <param name="datalog.dhcp.compression.type" value="1" /> <!-- Создание Access --> <bean name="access" class="ru.bitel.bgbilling.modules.inet.access.Access" /> <context name="radius"> <!-- Cоздание процессора radius-пакетов --> <bean name="radiusProcessor" class="ru.bitel.bgbilling.modules.inet.radius.InetRadiusProcessor"/> <!-- Служебный ScheduledExecutorService, необходимый для dataLogger --> <scheduledExecutorService name="hrlydtlggr" corePoolSize="1" /> <!-- Cоздание dataLogger, сохраняющего radius-пакеты на диск (только один экземпляр) --> <bean name="radiusDataLogger" class="ru.bitel.bgbilling.modules.inet.radius.RadiusHourlyDataLogger"> <param name="scheduledExecutor">hrlydtlggr</param> </bean> <!-- Cоздание слушателя radius-пакетов на порту с передачей ему процессора и dataLogger --> <bean name="radiusListener" class="ru.bitel.bgbilling.modules.inet.radius.InetRadiusListener"> <constructor> <!-- Хост (интерфейс), на котором будет открыт сокет. Если пусто - на всех --> <param name="host" value=""/> <!-- Порт, на котором будет открыт сокет --> <param name="port" value="1811"/> <!-- Размер буфера приема слушателя --> <param name="recvBufferSize">512 * 1024</param> <!-- Рекомендуемый SO_RCVBUF сокета --> <param name="soRCVBUF"></param> <!-- Количество потоков-обработчиков --> <param name="threadCount">10</param> <!-- Максимальное количество пакетов в очереди на обработку --> <param name="maxQueueSize">200</param> <!-- Передача процессора --> <param name="processor">radiusProcessor</param> <!-- Режим работы, RadiusListener.Mode.authentication --> <param name="mode">RadiusListener.Mode.authentication</param> <!-- Передача dataLogger --> <param name="dataLogger">radiusDataLogger</param> </constructor> </bean> </context> </application>
Запускаем и получаем второй radius-сервер (на порту 1811).
Создаем новый тип сервиса (не путать с ISG сервисами, те - назначаются на ISG сессию на циске, а эти - нечто вроде аккаунтов для доступа к услугам в BGBilling'е), который и будет описывать как биллингу авторизовывать радиус запросы с логинами равными именам ISG сервисов:
Теперь нужно завести отдельный договор, в котором для устройства Access+Accounting: Service Auth (вершина второй иерархии устройств, к которой и привязан второй радиус) будут созданы сервисы (типа ISG Service) с логинами равными именами ISG сервисов:
В результате, второй радиус сервер будет отвечать ACCESS-ACCEPT для запросов от BRAS'а, в которых логин=имя ISG сервиса.
Теперь осталось только привязать к этому сервису (не к ISG сервису, а к сервису договора, с логином сервиса равным имени ISG сервиса) соответствующую опцию:
Описание этой опции (тело ISG сервиса) радиус найдет у дочернего к Access+Accounting: Service Auth устройства R31_ASR1002 в конфигурации его типа (ASR ISG Service Auth), и ответит BRAS'у:
Packet type: Access-Accept Identifier: 98 Authenticator: {FB C8 D2 33 9D EC CF 10 04 0A 78 70 21 9A 69 04} Attributes: Acct-Interim-Interval=60 cisco-avpair=subscriber:accounting-list=ipoe-isg-aaa cisco-avpair=ip:traffic-class=in access-group 101 priority 201 cisco-avpair=ip:traffic-class=out access-group 102 priority 201 cisco-SSG-Service-Info=QU;5120000;384000;768000;D;5120000;960000;1920000
Вот и все!