forum.bitel.ru
http://forum.bitel.ru/

Создание сессии или подключения только по Access-Request
http://forum.bitel.ru/viewtopic.php?f=44&t=11484
Страница 1 из 1

Автор:  vdd [ 30 мар 2016, 16:59 ]
Заголовок сообщения:  Создание сессии или подключения только по Access-Request

Есть оборудование, отсылающее только RADIUS Access-Request и Netflow.
IP адрес также выделяется оборудованием и присылается в Access-Request.
Поиск сервиса осуществляется по User-Name.

Можно ли в обработчике радиус-протокола, или каким-либо другим способом создать сессию или подключение для того, что бы Netflow трафик привязался к сервису?

Проверены варианты:

1. connection.start.fromAccept=1
Результат: запись в таблице inet_connection создается с пустым ipAddress , netflow трафик не привязывается, не создает сессии.

2. Отправлять Accounting с помощью RadiusClienta из обработчика протокола для штатной процедуры создания сессии.
Результат: утечка ресурсов в BGInetAccess (https://forum.bitel.ru/viewtopic.php?f=44&t=11480)

Известны варианты:
1. Забить на радиус. - Не хотелось бы, так как другие варианты управления хуже.
2. Создать имитатор полноценного радиус-клиента. - Можно, но "бритва Оккама" душит.

Автор:  Amir [ 30 мар 2016, 19:08 ]
Заголовок сообщения:  Re: Создание сессии или подключения только по Access-Request

Можно попробовать попросить стартовать сессию InetAccounting, т.к. как это примерно делается при работе DHCP-сервера:
Код:

import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.Resource;
import javax.naming.NameNotFoundException;

import org.apache.log4j.Logger;

import ru.bitel.bgbilling.kernel.container.managed.ServerContext;
import ru.bitel.bgbilling.kernel.container.resource.ResourceManager;
import ru.bitel.bgbilling.kernel.network.dhcp.DhcpProtocolHandler;
import ru.bitel.bgbilling.kernel.network.radius.RadiusAttributeSet;
import ru.bitel.bgbilling.kernel.network.radius.RadiusDictionary;
import ru.bitel.bgbilling.kernel.network.radius.RadiusListenerWorker;
import ru.bitel.bgbilling.kernel.network.radius.RadiusPacket;
import ru.bitel.bgbilling.kernel.network.radius.RadiusProtocolHandler;
import ru.bitel.bgbilling.kernel.network.radius.RadiusSession;
import ru.bitel.bgbilling.modules.inet.access.Access;
import ru.bitel.bgbilling.modules.inet.access.sa.ProtocolHandlerAdapter;
import ru.bitel.bgbilling.modules.inet.api.common.AccessCodes;
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.api.common.bean.InetServType;
import ru.bitel.bgbilling.modules.inet.radius.InetNas;
import ru.bitel.bgbilling.modules.inet.radius.InetRadiusSessionParams;
import ru.bitel.bgbilling.modules.inet.radius.RadiusAccessRequestHandler;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.ParameterMap;
import ru.bitel.common.function.ThrowingRunnable;

public class MyProtocolHandler
   extends ProtocolHandlerAdapter
   implements
   RadiusProtocolHandler, DhcpProtocolHandler, RadiusAccessRequestHandler
{
   private static final Logger logger = Logger.getLogger( MyProtocolHandler.class );

   private static final ExecutorService executor = Executors.newFixedThreadPool( 10 );

   @Resource(name = "access")
   private Access access;

   private int deviceId;

   @Override
   public void init( Setup setup, int moduleId, InetDevice inetDevice, InetDeviceType inetDeviceType, ParameterMap deviceConfig )
      throws Exception
   {
      super.init( setup, moduleId, inetDevice, inetDeviceType, deviceConfig );

      this.deviceId = inetDevice.getId();

      ServerContext ctx = new ServerContext( setup, moduleId, 0 );
      ctx.init();
      try
      {
         ResourceManager rm = new ResourceManager();
         rm.inject( ctx, this, moduleId );

         ctx.commit();
      }
      catch( NameNotFoundException ex )
      {}
      catch( Exception ex )
      {
         logger.error( ex.getMessage(), ex );
      }
      finally
      {
         ctx.destroy();
      }
   }

   @Override
   public void beforeAuthentication( ServerContext context, RadiusListenerWorker<InetNas> req, RadiusSession<InetNas, InetRadiusSessionParams> radiusSession, RadiusPacket request, RadiusPacket response )
      throws Exception
   {}

   @Override
   public boolean addResponseAttributes( ServerContext context, InetServType inetServType, InetServ inetServ, RadiusPacket response, String realm, Map<String, RadiusAttributeSet> realmAttributeMap, RadiusAttributeSet inetServAttributes, Set<Integer> inetOptionSet )
      throws Exception
   {
      return false;
   }

   @Override
   public void afterAuthorization( ServerContext conext, RadiusListenerWorker<InetNas> req, RadiusSession<InetNas, InetRadiusSessionParams> radiusSession, RadiusPacket request, RadiusPacket response )
      throws Exception
   {
      if( response.getCode() != RadiusPacket.ACCESS_ACCEPT )
      {
         return;
      }

      int accessCode = radiusSession.errorCode;

      InetServ serv = (InetServ)req.getRadiusSession().login;

      InetConnection connection = new InetConnection();
      connection.setDeviceId( deviceId );
      connection.setDevicePort( serv.getInterfaceId() );
      connection.setCircuitId( req.getCircuitId() );

      connection.setContractId( req.getContractId() );
      connection.setServId( serv.getId() );
      connection.setAcctSessionId( request.getStringAttribute( -1, RadiusDictionary.Acct_Session_Id, "UNDEF" ) );
      connection.setCallingStationId( request.getStringAttribute( -1, RadiusDictionary.Calling_Station_Id, "" ) );
      connection.setIpResourceId( req.getIpResourceId() );
      connection.setInetAddressBytes( req.getIpAddress() );
      connection.setAccessCode( accessCode );
      connection.setDeviceState( (accessCode != AccessCodes.AUTHORIZATION_SUCCEEDED) ? InetServ.STATE_DISABLE : InetServ.STATE_ENABLE );
      connection.setConnectionStart( new Date() );

      executor.execute( (ThrowingRunnable)() -> {
         
         access.connectionManager.accountingStart( serv, connection, 4000 );
      } );
   }
}

Автор:  Amir [ 30 мар 2016, 19:13 ]
Заголовок сообщения:  Re: Создание сессии или подключения только по Access-Request

В данном случае обработчику процессора протокола я добавил implements RadiusAccessRequestHandler
и теперь можно использовать дополнительные три метода. Использую afterAuthorization во-первых, потому что там доступно больше данных,
во-вторых, потому что preprocess/postprocessRequest в случае EAP может вызываться несколько раз до того как произойдет Access-Accept.
executor.execute использую, чтобы сам старт выполнялся асинхронно уже в другом потоке (чтобы не дожидаясь создания сессии отправить Access-Accept).

Это пример, не факт что сразу заработает, но в принципе так должно работать тоже.

Автор:  vdd [ 30 мар 2016, 19:53 ]
Заголовок сообщения:  Re: Создание сессии или подключения только по Access-Request

Понял, спасибо. Не получится стабильного решения с автоАккоунтингом - попробую этот вариант.

Страница 1 из 1 Часовой пояс: UTC + 5 часов [ Летнее время ]
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/