Logo Search packages:      
Sourcecode: netams version File versions  Download package

st_radius.c

/*************************************************************************
***   Authentication, authorization, accounting + firewalling package
***   Copyright 1998-2002 Anton Vinokurov <anton@netams.com>
***   Copyright 2002-2008 NeTAMS Development Team
***   This code is GPL v3
***   For latest version and more info, visit this project web page
***   located at http://www.netams.com
***
*************************************************************************/
/* $Id: st_radius.c,v 1.29 2008-02-23 08:35:02 anton Exp $ */

#ifdef USE_LIBRADIUS

#include "netams.h"
#include "st_any.h"

extern "C" {
      #include "radlib/radlib.h"
      #include "radlib/radlib_vs.h"
}

//////////////////////////////////////////////////////////////////////////
#define ST_RADIUS_DEFAULT_TIMEOUT       5
#define ST_RADIUS_DEFAULT_RETRY         3
//////////////////////////////////////////////////////////////////////////
/*  this module will take RAW data messages from processor service, 
 *  and send it to radius server, accounting packets
 *  to specifiy radius server, we have to set hostname, password and 
 *  port parameters. default is "localhost, secret, 1813". username and dbname
 *  has no effect. other message types are not processed.
 */
//////////////////////////////////////////////////////////////////////////
class RADIUS_Storage: public Storage {
      public:
            char *hostname;
            unsigned short port;
            char *password;

            unsigned short retry; // for st_radius
            unsigned short timeout; // for st_radius
            struct in_addr nas_ip; // for st_radius
            unsigned pid; // for st_radius

            unsigned num_raw;

            RADIUS_Storage(storage_type type, u_char id);
            ~RADIUS_Storage();

            void ShowCfg(struct cli_def *cli, u_char flags);
            int ProcessCfg(struct cli_def *cli, char **argv, int argc, u_char no_flag);
            int StoreMSG(Message *msg);

            int SaveFile(char *filename, st_conn_type type) {return 0;};

};
//////////////////////////////////////////////////////////////////////////
Storage* InitRadiusStorage(storage_type st_type, u_char instance) {
      return (Storage*) new RADIUS_Storage(st_type, instance);
}
//////////////////////////////////////////////////////////////////////////
int     radSendAccounting(Message_Store *, RADIUS_Storage *);
//////////////////////////////////////////////////////////////////////////
RADIUS_Storage::RADIUS_Storage(storage_type type, u_char id):Storage(type, id) {
      retry=ST_RADIUS_DEFAULT_RETRY;
      timeout=ST_RADIUS_DEFAULT_TIMEOUT;
      hostname=password=NULL;
      port=0;
      num_raw=0;

      pid = getpid();
      nas_ip.s_addr=INADDR_ANY;

      char name[80];
      if (gethostname(name, 256)!=0) {
            aLog(D_WARN, "gethostname: %d (%s)\n", h_errno, strerror(h_errno));
            return;
      }
      struct hostent *hp;
      hp = gethostbyname(name);
      if (hp==NULL) {
            herror("gethostbyname:");
            aLog(D_ERR, "gethostbyname: %d (%s)\n", h_errno, strerror(h_errno));
            return;
      }
      memcpy((char*)&nas_ip.s_addr, hp->h_addr_list[0], hp->h_length);
      inet_ntop(AF_INET, &(nas_ip), name, 256);
      aDebug(DEBUG_STORAGE, "RADIUS: Our NAS-IP-Address will be %s\n", name);

}

RADIUS_Storage::~RADIUS_Storage() {
      if(password) aFree(password);
      if(hostname) aFree(hostname);
}

int RADIUS_Storage::ProcessCfg(struct cli_def *cli, char **param, int argc, u_char no_flag) {
      if (STRARG(param[0], "host")) {
            if(hostname) aFree(hostname);
            hostname=set_string(param[1]);
            cli_error(cli, "hostname is set to %s", hostname);
      }
      else if (STRARG(param[0], "port")) {
            port=strtol(param[1], NULL, 10);
            cli_error(cli, "port is set to %u", port);
      }
      else if (STRARG(param[0], "password")) {
            if(password) aFree(password);
            password=set_string(param[1]);
            cli_error(cli, "password is set to %s", password);
      }
      else if (STRARG(param[0], "retry")) {
            retry=strtol(param[1], NULL, 10);
            cli_error(cli, "radius packet retry count is set to %u", retry);
      }
      else if (STRARG(param[0], "timeout")) {
            timeout=strtol(param[1], NULL, 10);
            cli_error(cli, "radius packet timeout is set to %u", timeout);
      }
      else if (STRARG(param[0], "nas-ip")) {
            if (inet_aton(param[1], &(nas_ip)))
                  cli_error(cli, "radius nas-ip is set to %s", param[1]);
            else nas_ip.s_addr=INADDR_ANY;
      } else
            return CLI_ERROR;
      
      return CLI_OK;
}

void RADIUS_Storage::ShowCfg(struct cli_def *cli, u_char flags){
      cli_print(cli, "type radius");
      if (hostname) cli_print(cli, "host %s", hostname);
      if (password) cli_print(cli, "password %s", (flags&CFG_NO_PASSWORDS)?"***":password);
      if (port && port!=1813) cli_print(cli, "port %u", port);
      if (timeout!=ST_RADIUS_DEFAULT_TIMEOUT) cli_print(cli, "timeout %u", timeout);
      if (nas_ip.s_addr!=INADDR_ANY) {
            char name[80];
            inet_ntop(AF_INET, &(nas_ip), name, 256);
            cli_print(cli, "nas-ip %s", name);
      }
      if (retry!=ST_RADIUS_DEFAULT_RETRY) cli_print(cli, "retry %u", retry);
}
//////////////////////////////////////////////////////////////////////////
int RADIUS_Storage::StoreMSG(Message *msg){
      Message_Store *smsg = (Message_Store*)msg;
      
      if(msg == NULL) {
            aDebug(DEBUG_STORAGE, "RADIUS->NET/raw %u messages\n", num_raw);
            num_raw=0;
            return 1;
      }

      if (is_running==0 && global_return_code!=0) { timeout=0, retry=0; } // if we are finishing, speed up purge
            
      switch (smsg->prefix){
            case 'F':
                  /*
                   * here RADIUS udp packet creation and forwarding code should go
                   * next line is an example of what we can send there
                   * fprintf(raw, "%u,%u,%u,%u,%llu,%llu\n", smsg->netunit, smsg->ap, smsg->data->from, smsg->ts, smsg->data->in, smsg->data->out);
                   */
                  if( !radSendAccounting( smsg, this ) )
                      aLog(D_WARN, "Can not send RADIUS accounting request\n");
                  else
                      num_raw++;
                  break;
            case 'H':
            case 'D':
            case 'W':
            case 'M':
                  /*
                   * skip other types
                   */
                  break;
      }
      return 1;
}

/*
    RADIUS code begins here. So, what attributes should we send?
    Standard attributes:
      User-Name
      NAS-IP-Address
      NAS-Port-Id
      NAS-Port-Type
      Acct-Status-Type
      Acct-Authentic
      Service-Type
      Acct-Session-Id
      Framed-IP-Address
      Acct-Input-Gigawords
      Acct-Output-Gigawords
      Acct-Input-Octets
      Acct-Output-Octets
      Acct-Session-Time
    VSA Attributes (NetAMS dictionary):
      Acct-Policy-Name
*/

#ifndef UINT32_MAX
#define     UINT32_MAX  0xFFFFFFFFU
#endif

int   radSendAccounting(Message_Store *msg, RADIUS_Storage *st) {
      struct rad_handle *rh;
      int               is_error, attribute;
      char              session_id[33];
      char              oid[8];
      NetUnit                 *unit;

      if((unit = (NetUnit*)Units->getById(msg->netunit)) == NULL) {
          aLog(D_ERR, "Unknown unit %06X\n", msg->netunit);
          return 0;
      }
      
      if((rh = rad_acct_open()) == NULL) {
          aLog(D_WARN, "Unable to construct accounting request\n");
          return 0;
      }
      
      if(rad_add_server(rh, st->hostname?st->hostname:"localhost", st->port, st->password?st->password:"", st->timeout, st->retry) == -1) {
          aLog(D_WARN, "Unable to configure servers\n");
          rad_close( rh );
          return 0;
      }

      if(rad_create_request(rh, RAD_ACCOUNTING_REQUEST) == -1) {
          aLog(D_WARN, "Unable to create attributes space\n");
          rad_close( rh );
          return 0;
      }

      is_error = 1;
      while( 1 ) {
          
          /* basic info */
          if(rad_put_int(rh, (attribute = RAD_ACCT_STATUS_TYPE), RAD_STOP)) break;
          /* constructing session id */
          sprintf(session_id, "%05u-%10lu-%s", st->pid, (u_long)msg->ts, unit->name);
          if(rad_put_string(rh, (attribute = RAD_ACCT_SESSION_ID), session_id)) break;

            // instead of name, put OID (name goes onto session id
          sprintf(oid, "%06X", msg->netunit);
          if(rad_put_string(rh, (attribute = RAD_USER_NAME), oid)) break;

            // for USERS and HOSTS, put IP address as optional parameter
            if (unit->type==NETUNIT_USER) {
                  if(rad_put_addr(rh, (attribute = RAD_FRAMED_IP_ADDRESS), ((NetUnit_user*)unit)->ip)) break;
            }
            else if (unit->type==NETUNIT_HOST) {
                  if(rad_put_addr(rh, (attribute = RAD_FRAMED_IP_ADDRESS), ((NetUnit_host*)unit)->ip)) break;
            }
            // type 55 is for Event-Timestamp (standard)
          if(rad_put_int(rh, (attribute = RAD_EVENT_TIMESTAMP), msg->ts)) break;

          // policy goes to Filter-Id
          sprintf(oid, "%06X", msg->ap);
          if(rad_put_string(rh, (attribute = RAD_FILTER_ID), oid)) break;

          if(rad_put_addr(rh, (attribute = RAD_NAS_IP_ADDRESS), st->nas_ip)) break;
          /* for the time present port is unknown for us */
          if(rad_put_int(rh, (attribute = RAD_NAS_PORT), 0)) break;
          
          if(rad_put_int(rh, (attribute = RAD_SERVICE_TYPE), RAD_FRAMED)) break;
          /* Do we really need Framed-Protocol???
          if(rad_put_int(rh, (attribute = RAD_FRAMED_PROTOCOL), RAD_PPP)) break;
          */
          if(rad_put_int(rh, (attribute = RAD_NAS_PORT_TYPE), RAD_VIRTUAL)) break;
          if(rad_put_int(rh, (attribute = RAD_ACCT_TERMINATE_CAUSE), RAD_TERM_HOST_REQUEST)) break;

          /* session time is insignificant for us */
          if(rad_put_int(rh, (attribute = RAD_ACCT_SESSION_TIME), (u_int32_t)(msg->ts - msg->data->from)) == -1) break;
          if(rad_put_int(rh, (attribute = RAD_ACCT_INPUT_GIGAWORDS), (u_int32_t)(msg->data->in / UINT32_MAX)) == -1) break;
          if(rad_put_int(rh, (attribute = RAD_ACCT_OUTPUT_GIGAWORDS), (u_int32_t)(msg->data->out / UINT32_MAX)) == -1) break;
          if(rad_put_int(rh, (attribute = RAD_ACCT_INPUT_OCTETS), (u_int32_t)(msg->data->in % UINT32_MAX)) == -1) break;
          if(rad_put_int(rh, (attribute = RAD_ACCT_OUTPUT_OCTETS), (u_int32_t)(msg->data->out % UINT32_MAX)) == -1) break;
      
          if(rad_send_request(rh) != RAD_ACCOUNTING_RESPONSE)
            aLog(D_ERR, "Can not send radius request for OID %06X\n", msg->netunit);
      
          is_error = 0;
          break;
      }
      
      if( is_error )
          aLog(D_ERR, "Can not store attribute %d\n", attribute);

      rad_close( rh );
      return 1;
}

#endif

Generated by  Doxygen 1.6.0   Back to index