Logo Search packages:      
Sourcecode: yardradius version File versions

radlast.c

/*
 * Copyright (c) Cristian Gafton <gafton@sorosis.ro>, 1997.
 *                                              All rights reserved
 *
 * Copyright (C) Francesco Lovergine <francesco@lovergine.com>, 1999-2002.
 *                                              All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, and the entire permission notice in its entirety,
 *    including the disclaimer of warranties.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote
 *    products derived from this software without specific prior
 *    written permission.
 * 4. Any modification to the program, as well as redistribution in binary
 *    or derived source form must be advertised to the author.
 *
 * ALTERNATIVELY, this product may be distributed under the terms of
 * the GNU Public License, in which case the provisions of the GPL are
 * required INSTEAD OF the above restrictions.  (This clause is
 * necessary due to a potential bad interaction between the GPL and
 * the restrictions contained in a BSD-style copyright.)
 *
 * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

static char rcsid[] = "$Id: radlast.c,v 1.5 2002/01/21 09:08:54 kiavik Exp $";

# define __MAIN__

#include    "yard.h"
#include    "global.h"

char *progname = NULL;
char username[USERNAME_MAX];

static int brief = 0;
static int extended = 0;

static const char *port_type_str(int type)
{
    switch (type) {
      case 0:
          return "ASYN";
      case 1:
          return "SYNC";
      case 2:
          return "ISDN";
      case 3:
          return "V120";
      case 4:
          return "V110";
      default:
          return "UNKN";
    }
    /* not reached */
    return "Unknown";
}

static const char * proto_type_str(int proto)
{
    switch (proto) {
      case P_TELNET:
          return "TELN";
      case P_RLOGIN:
          return "RLOG";
      case P_TCP_CLEAR:
          return "DATA";
      case P_PORTMASTER:
          return "PM";
      case P_PPP:
          return "PPP";
      case P_SLIP:
          return "SLIP";
      case P_CSLIP:
          return "CSLP";
      default:
          return "UNK";
    }
    /* not reached */
    return "UNK";
}


static int parse_width(char **format)
{
  int width=0;
  char *endstr;

  if ( isdigit(**format) || **format=='+' || **format=='-' )
    {
    width=(int)strtol(*format,&endstr,10);
    *format=endstr;
    }
  return width;
}

/*
 *    Function: parse_formatstr()
 *    Purpose: parse a -F format string and outputs as required all
 *           radlast fields.
 *
 *    Format tokens are:
 *          %l    Username
 *          %p    Port ID
 *          %a    NAS ip address
 *          %k    Port type
 *          %c    Client ip address
 *          %d    Date in ctime format
 *          %t    Online time in secs
 *          %T    Online time in HH:MM:SS format
 *          %i    Input traffic in bytes
 *          %I    Input traffic in KBytes
 *          %o    Output traffic in bytes
 *          %O    Output traffic in KBytes
 *          %m    Total traffic in bytes
 *          %M    Total traffic in KBytes
 *          %s    Input speed in bps (or UNKNOWN)
 *          %S    Output speed in bps (or UNKNOWN)
 *          %A    NAS called id (or UNKNOWN)
 *          %#    Client calling id (or UNKNOWN)
 *          \n \t \\ \% %% As obvious :-)
 *
 *    Tokens can include an integer signed value for alignment with
 *    the same sense of printf() format value.
 */

static void parse_formatstr( char *formatstr,radlast rl )
{
  char port_str[100];
  char nas_ip[100];
  char client_ip[100];
  char fstr[100];
  char *str_time;
  int  width;
  char *ptr;
  time_t login_time;


  if ( formatstr == NULL ) return;

  memset(port_str, 0, sizeof(port_str));
  memset(nas_ip, 0, sizeof(nas_ip));
  memset(client_ip, 0, sizeof(client_ip));
  login_time = rl.ut_time;
  str_time = ctime(&login_time); str_time[19] = '\0';

  snprintf(port_str, 
         sizeof(port_str), 
           "%4.4s-%02d",
           port_type_str(rl.ent.port_type),
           rl.ent.port);
  ipaddr2str(nas_ip, sizeof(nas_ip), rl.nas_ip);
  ipaddr2str(client_ip, sizeof(client_ip), rl.client_ip);

  while ( *formatstr )
    {
    switch ( *formatstr )
      {
      case '%':
        formatstr++;
        width=parse_width(&formatstr);
        if (width) snprintf(fstr,sizeof(fstr),"%%%d",width);
        else strcpy(fstr,"%");
      switch (*formatstr)
        {
        case 'l':
          strcat(fstr,"s"); printf(fstr,rl.login); 
          break;
        case 'p':
          strcat(fstr,"s"); printf(fstr,port_str); 
          break;
        case 'a':
          strcat(fstr,"s"); printf(fstr,nas_ip); 
          break;
        case 'k':
          strcat(fstr,"s"); printf(fstr,proto_type_str(rl.ent.proto)); 
          break;
        case 'c':
          strcat(fstr,"s"); printf(fstr,client_ip); 
          break;
        case 'd':
          strcat(fstr,"s"); printf(fstr,str_time); 
          break;
        case 't':
          strcat(fstr,"ld"); printf(fstr,rl.length); 
          break;
        case 'T':
          ptr=fstr+50;
          snprintf(ptr,sizeof(fstr)/2,"%dh:%dm:%ds",
               (int)(rl.length/3600),
                   (int)((rl.length%3600)/60),
                   (int)((rl.length%3600)%60)); 
          strcat(fstr,"s");
          printf(fstr,ptr);
          break;
        case 'i':
          strcat(fstr,"ld"); printf(fstr,rl.inb); 
          break;
        case 'I':
          strcat(fstr,"ldKB"); printf(fstr,rl.inb/1024); 
          break;
        case 'o':
          strcat(fstr,"ld"); printf(fstr,rl.outb); 
          break;
        case 'O':
          strcat(fstr,"ldKB"); printf(fstr,rl.outb/1024); 
          break;
        case 'm':
          strcat(fstr,"ld"); printf(fstr,rl.outb+rl.inb); 
          break;
        case 'M':
          strcat(fstr,"ldKB"); printf(fstr,(rl.outb+rl.inb)/1024); 
          break;
        case 's':
          if (rl.rxrate) {
            strcat(fstr,"d"); printf(fstr,rl.rxrate); 
          }
          else {
            strcat(fstr,"s"); printf(fstr,"NONE");
          }
          break;
        case 'S':
          if (rl.txrate) {
            strcat(fstr,"d"); printf(fstr,rl.txrate); 
          }
          else {
            strcat(fstr,"s"); printf(fstr,"NONE");
          }
          break;
        case 'A':
          strcat(fstr,"s"); 
          printf(fstr,strlen(rl.calledid)?rl.calledid:"NONE"); 
          break;
        case '#':
          strcat(fstr,"s"); 
          printf(fstr,strlen(rl.callingid)?rl.callingid:"NONE"); 
          break;
        case '%':
          putchar('%');
        default:
          break;
        }
        break;
      case '\\':
        formatstr++;
        switch(*formatstr)
        {
        case 'n':
          printf("\n");
          break;
        case 't':
          printf("\t");
          break;
        case 'r':
          printf("\r");
          break;
        case '\\':
        default:
          printf("\\");
          break;
        }
        break;
      default:
      putchar(*formatstr);
      break;
      }
    formatstr++;
    }
}

/*
 *    Function: parse_header()
 *    Purpose: parse a -H header string 
 *
 *    Format tokens are:
 *          \n \t \r \\ As obvious :-)
 */

static void parse_header( char *header )
{
   while (*header) {
      switch (*header) {
      case '\\':
        header++;
        switch(*header)
        {
        case 'n':
          printf("\n");
          break;
        case 't':
          printf("\t");
          break;
        case 'r':
          printf("\r");
          break;
        case '\\':
        default:
          printf("\\");
          break;
        }
        break;
      default:
      putchar(*header);
      break;
      }
    header++;
    }
}

static void print_entry(radlast rad_last)
{
  if (extended)
    if (brief) parse_formatstr("%l/%p/%a/%k/%c/%d/%T/%I/%O/%M/%s/%S/%A/%#\n",
                          rad_last);
    else parse_formatstr( 
                "\nUsername = %l\n"
                "Port-Number = %p\n"
                "NAS-IP = %a\n"
                "Service-Type = %k\n"
                "User-IP = %c\n"
                "Date = %d\n"
                "Session-Time = %T\n"
                "Input-Traffic = %I\n"
                "Output-Traffic = %O\n"
                "Total-Traffic = %M\n"
                "Rx-Speed = %s\n"
                "Tx-Speed = %S\n"
                "NAS-CLI = %A\n"
                "User-CLI = %#\n",rad_last );
  else /* !extended */
      if (brief)
          parse_formatstr("%l/%p/%a/%k/%c/%d/%T\n",rad_last);
      else
          parse_formatstr( 
                    "\nUsername = %l\n"
                    "Port-Number = %p\n"
                    "NAS-IP = %a\n"
                    "Service-Type = %k\n"
                    "User-IP = %c\n"
                    "Date = %d\n"
                    "Session-Time = %T\n",rad_last);
}

static void radlast_usage(void)
{
    printf("\nUsage: %s <option>\n\nValid options are:\n", progname);
    printf("\t-a <acct_dir>\tthe radius accounting files directory\n");
    printf("\t-F <format>\tcustom output format\n");
    printf("\t-H <format>\tcustom header\n");
    printf("\t-c\t\tshow records in cronological order\n");
    printf("\t-u <username>\tget username database entry\n");
    printf("\t-f <filename>\tuse this radlast logfile instead\n");
    printf("\t-h\t\tthis help screen\n");
    printf("\t-m <month>\treport statistics for <month>\n");
    printf("\t-y <year>\treport statistics for <year>\n");
    printf("\t-b\t\tsingle row output\n");
    printf("\t-x\t\textended info (include traffic and CLIs)\n\n");
    exit(-1);
}

static void fatal_func(const char *msg) {
    fprintf(stderr, "FATAL ERROR: %s\n",msg);
    return;
}

int main(int argc, char **argv)
{
    radlast rad_last;
    int fd;
    static char filename[PATH_MAX];
    int flag;
    int month;
    int year;
    time_t crt_time;
    struct tm *time_info;
    int file_arg = 0;
    int month_arg = 0;
    int year_arg = 0;
    int user_arg = 0;
    const char *radacct_dir;
    int cronologic = 0;
    char *format=NULL;
    char *header=NULL;
    extern char *optarg;
    
    crt_time = time(NULL);
    time_info = localtime(&crt_time);
    month = time_info->tm_mon + 1;                        
    year = 1900+time_info->tm_year;
    memset(&rad_last, 0, sizeof(radlast));
    memset(filename, 0, sizeof(filename));
    memset(username, 0, sizeof(username));
    
    progname = argv[0];
    radacct_dir = RADACCT_DIR;
    
    while ((flag = getopt(argc, argv, "a:F:H:cu:f:by:m:xh")) != EOF) {
      char *cp;
      switch (flag) {
          case 'a':
            radacct_dir = optarg;
            break;
          case 'F':
            format = optarg;
            break;
          case 'H':
            header = optarg;
            break;
          case 'c':
            cronologic++;
            break;
          case 'u':
            strncpy(username, optarg, USERNAME_MAX);
            user_arg++;
            break;
          case 'f':
            if (month_arg || year_arg) {
                fatal_func("you cannot specify a filename and a month number");
                radlast_usage();
            }
            strncpy(filename, optarg, PATH_MAX);
            file_arg++;
            break;
            case 'b':
            brief++;
            break;
          case 'y':
            if (file_arg) {
                    fatal_func("you can not specify a year and a filename");
                radlast_usage();
            }
            year = strtol(optarg, &cp, 10);
            if (*cp) {
                fatal_func("year should be a number\n");
                radlast_usage();
            }
            if (year < 1970) {
                fatal_func("year should be greater than 1970\n");
                radlast_usage();
            }
            year_arg++;
            break;
          case 'm':
            if (file_arg) {
                    fatal_func("you can not specify a month number and a filename");
                radlast_usage();
            }
            month = strtol(optarg, &cp, 10);
            if (*cp) {
                /* not a number ... */
                fatal_func("month should be a number\n");
                radlast_usage();
            }
            if ((month < 1) || (month > 12)) {
                fatal_func("month should be between 1 and 12\n");
                /* not a valid month */
                radlast_usage();
            }
            month_arg++;
            break;
          case 'x':
            extended++;
            break;
          case 'h':
          default:
            radlast_usage();
      }
    }

    if (!file_arg)
      snprintf(filename, sizeof(filename),"%s/%d/%s-%02d", 
              radacct_dir, year, RADIUS_LAST, month);
    
    if ((fd = open(filename, O_RDONLY)) >= 0) {
      off_t seekpos = 0;
      
      if (!cronologic)
          seekpos = lseek(fd, -sizeof(radlast), SEEK_END);
      if ( format != NULL && header != NULL ) parse_header(header); 
      while ((seekpos >= 0) &&
             read(fd, &rad_last, sizeof(radlast)) == sizeof(radlast)) {
          if (user_arg && strncmp(username, rad_last.login, USERNAME_MAX)) {
            memset(&rad_last, 0, sizeof(rad_last));
            if (!cronologic)
                seekpos = lseek(fd, -2*sizeof(radlast), SEEK_CUR);
            continue;
          }
          if ( format != NULL ) parse_formatstr(format,rad_last);
          else print_entry(rad_last);
          memset(&rad_last, 0, sizeof(rad_last));
          if (!cronologic)
            seekpos = lseek(fd, -2*sizeof(radlast), SEEK_CUR);
      }
    } else {
      fprintf(stderr, "Cannot open the radlast log file: %s\n",filename);
      exit(-1);
    }
    exit(0);
}

void rad_exit(int code)
{
      exit(code);
}

Generated by  Doxygen 1.6.0   Back to index