#!/usr/bin/perl
#
# From: Kelly Yancey <kbyanc@posi.net>
# Date: Mon, 23 Mar 1999 17:05:10 -0500 (EST)
#
# Somewhere along the line radiusreport and been renamed into radreport,
# as that is how I found it listed on Livingston's (Lucent) web site.
# I decided to keep the name since it is shorter :)
#
# See CHANGELOG (below) for changes
#
# --------------------------------------------------------------------------
#
# From: Vikas Aggarwal <vikas@navya.com>
# Date: Thu, 19 Feb 1998 20:43:25 -0500 (EST)
#
# I have modified the 'radiusreport' code that is available from
# www.tibus.net so that it can:
#
# - handle records from multiple NAS's (ala AimQuest)
# - print port usage
# - HTML output
# - prevent duplicate records in accounting (e.g. Cisco was sending
# a Login START and another PPP START and the accounting was
# getting really messed up).
# - etc.etc. (see comments)
#
# I have sent this to the original author (Paul Gregg), but have not heard
# back from him, so I am sending directly to Carl also. I think that the
# changes are pretty useful.
#
#!/usr/local/bin/perl5
#
# $Header: /usr/local/src/radius/RCS/radiusreport,v 1.3 1998/02/20 01:36:19 kbyanc Exp $
#
# This is a modified version of the radiusreport 0.3b5 code available
# from http://www.tibus.net/pgregg/projects/radiusreport/
#
## This version modified by Vikas Aggarwal, vikas@navya.com, feb 1998
## (see changelog below)
#
# For detailed report (-H for HTML)
# radiusreport -P -tqa -f /var/adm/radacct/xyz/detail
# For summary report
# radiusreport -S -P -f /var/adm/radacct/xyz/detail
##
## CHANGELOG
# Feb98/vikas@navya.com
# - added P and H options for Port usage and HTML output
# - added S option for Summary only
# - added D option for using DBM type storage (requires DBlib)
# - added N option for report on specific NAS ip address only
# - now handles records from multiple terminal servers (e.g. AimQuest)
# - all users option enabled by default
# - added code to prevent duplicate accounting records e.g. the Cisco
# sends a Start on login and another Start on enabling PPP with
# different session ID's.
# - now uses localtime() instead of ctime().
# - deleted Multiple Login code (did not tell more than 2 anyway)
#
# Mar99/kbyanc@posi.net
# - fixed year in port report to correctly list dates in 4 digit
# since localtime returns years since 1900 (former would have
# displayed "100" in the year 2000).
# - added maximum hourly usage to the port summary
# - added ability to compensate for lost Stop records
# (does not seem to interfere with vikas's duplicate accounting
# check although my Cisco AS5200s don't exhibit the behavior he
# describes).
# - stopped erroniously counting telnet logins in port usage stats
# - added support for NAS-IP-Address record
# - added T option to produce total port usage report
# - added C option to only use data from records matching
# a certain Calling-Station-Id
# - added p option to include Calling-Station-Id information in
# user reports
# - fixed some ommisions in the usage display
# - fixed width of header in user reports (now resizes based on content)
#
# Feb00/kbyanc@posi.net
# - fixed some cosmetic year 2000 bugs
#
# --------------------------------------------------------------------------
# radiusreport - Extract information from Radius 2.0 detail log
#
# Author: Paul Gregg <pgregg@tibus.net>
# Date: 1 May 1997
# Summary: Radius, User's activity, Port usage,
# Version: 0.3 - beta 5 (messy code)
# Copyright: 1997, Paul Gregg <pgregg@tibus.net>
# Copy Policy: Free to copy and distribute provided all headers are left
# intact and no charge is made for this program. I would
# appreciate copies of any modifications to the script.
# Inspiration: userlog radius parser script by
# Dave Andersen <angio@aros.net> / Joe Hartley <jh@brainiac.com>
# I got fed up of trying to hack my mods into it ;-)
#
# Supported: Livingston Radius V2.0+, V1.16
# Merit Radius
# Ascend Radius
# Dale Reed's RadiusNT
#
# Comments on this extremly welcomed
#
# Usage:
# radiusreport --help
# radiusreport [-tbahrqc] [-i a.b.c.d] [-l username|all]
# -f detailfile[:detailfile]
# Flags:
# -t Report on total online time
# -b Report on total bandwidth passed per session
# -q Report on how the connection was dropped
# -p Report on the caller's phone number
# -h Suppress report header information
# -a Do 'Average use' report at end
# -r Provide a list of accounts in the users file and their last login time
# -l username is the radius username you wish a report on
# -o If you use "-l all" and you specify -o directory then the reports
# will be placed here instead of sending them to stdout.
# -f detailfile is the path/filename of any detail file which may or
# may not be compressed (.Z or .gz). Multiple details files may be
# separated by a colon.
# -i ipaddress will produce a report on users using a specific IP address.
# or -i 0 to report on all logins.
# -c Work out call charge by the Telco.
# -d mon[:mon] Only report on this month (or months). mon can be in
# format 'Jan' or '01' or '1'. Multiple months are separated by colon
# characters ':'. (Caveat: Logins which roll over months are included)
# -P produce port usage report per NAS -vikas
# -T produce total port usage report summarizing all NASs -kbyanc
# -H HTML table output -vikas
# -S Summary only -vikas
# -D dbm storage
# -N <ipaddr> to process data for a specific NAS ip address only.
# -C <regex> to process records with Calling-Station-Id matching
# the given expression only.
#
#
# Todo - Suggestions welcome.
# radiusreport [-l username|all] [-f detailfile[:detailfile]]
# [-t yyyy[mm[dd]][-yyyy[mm[dd]]]] [-m x..y]
# Additional Flags
# -? Only report on the specified year/month/day (or in the yymmdd range)
# -? Produce a modem usage table
#require "ctime.pl";
require "timelocal.pl"; # -vikas
use POSIX;
# Program and File locations
$USERS = "/etc/raddb/users"; # Hard coded as it is unlikely to change
# gzcat - 'cat for .gz / gzip files'
# If you don't have gzcat and do have gzip then use: ln gzip gzcat
$GZCAT = "/usr/local/bin/gunzip -c";
# zcat - 'cat for .Z / compressed files'
$ZCAT = "/usr/bin/zcat";
# Do we want to print dates in Euro or US format?
# Euro is DD/MM/YY US is MM/DD/YY (You can use YYYY if you want)
$DATE_FORMAT = "MM/DD/YYYY";
# Timestamp definitions for wierd Radius versions.
# For versions of radius which log Timestamp = data this is not used
# Others need this defined so RadiusReport knows how to extract your record
# times.
# Keys are: DAY MON MDAY HH MM SS YEAR. MON can accept 'Jun', 6 or 06
# Livingston Radius V1.16+, RadiusNT, Metit Radius:
# e.g. Record stamp of type: Tue Jul 1 00:28:34 1997
$RECORD_DATE_FMT = "DAY MON MDAY HH:MM:SS YEAR";
# Ascend Radius:
# e.g. Record stamp of type: 23-07-1997 00:02:55
#$RECORD_DATE_FMT = "MDAY-MON-YEAR HH:MM:SS";
# Do you want to report multiple logins to the system - tracking down shared
# accounts.
$REPORT_MULTIPLE_LOGINS = 1;
# users file format
# This is used by parts of radiusreport to extract usernames 'real names'
# If your users file supports it.
# My users file has a line before each record in the form:
# #* username:Real Name
# This enables me to quickly extract a complete list of users and real names.
# I'd be interested in knowing what other people use.
$HAVE_NICE_USERS=0;
#### You should not have to modify anything below here
@weekdays = ( "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" );
%weekhash = ( "Sun", 0, "Mon", 1, "Tue", 2, "Wed", 3, "Thu", 4,
"Fri", 5, "Sat", 6 );
@months = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" );
%monthshash = ( "Jan", 0, "Feb", 1, "Mar", 2, "Apr", 3, "May", 4, "Jun", 5,
"Jul", 6, "Aug", 7, "Sep", 8, "Oct", 9, "Nov", 10, "Dec", 11);
$allsessions = "";
$syncsize = 500; # number of records before we dump to dbm-disk
#User Display Format: You can customise the output display here
$display = "_DATE_ _LOGIN_ _LOGOUT_ _ONTIME_ _PORT_";
if ( $DATE_FORMAT =~ /YYYY/ ) {
$dispwidths{'_DATE_'} = "%-10.10s";
} else {
$dispwidths{'_DATE_'} = "%-8.8s";
}
$dispwidths{'_LOGIN_'} = "%-8.8s";
$dispwidths{'_LOGOUT_'} = "%-8.8s";
$dispwidths{'_ONTIME_'} = "%-7s";
$dispwidths{'_PORT_'} = "%-6.6s";
$dispwidths{'_BANDWDT_'} = "%-13s";
$dispwidths{'_TOTHRS_'} = "%-7.7s";
$usage = "Type: $0 --help";
$DEBUG = 0;
if (! $ARGV[0] ) {
die "Usage: $usage\n";
}
#Extract all command line arguments
$args=1;
while ($args) {
$flag = shift(@ARGV);
if ($flag eq "--help") { &help; exit; }
if (substr($flag, 0, 1) eq '-') {
if ($flag =~ /[tbharPHSD]/) {
$arg{'t'} = TRUE if ($flag =~ /t/); # show time totals
$arg{'b'} = TRUE if ($flag =~ /b/); # show bytes totals
$arg{'q'} = TRUE if ($flag =~ /q/); # show termination cause
$arg{'p'} = TRUE if ($flag =~ /p/); # show caller's phone number
$arg{'h'} = TRUE if ($flag =~ /h/); # supress header/footer
$arg{'a'} = TRUE if ($flag =~ /a/); # show average usage data
$arg{'r'} = TRUE if ($flag =~ /r/); # user list and last logins
$arg{'P'} = TRUE if ($flag =~ /P/); # Port usage
$arg{'T'} = TRUE if ($flag =~ /T/); # Port usage total
$arg{'H'} = TRUE if ($flag =~ /H/); # HTML output
$arg{'S'} = TRUE if ($flag =~ /S/); # Summary only per user
$arg{'D'} = TRUE if ($flag =~ /D/); # use DBM for temp storage
} else {
$arg{substr($flag, 1, 1)} = shift(@ARGV);
}
} else {
die "Usage: $usage\n Error in $flag - not a valid flag.\n";
}
$args = 0 if (!$ARGV[0]);
}
if ( (!defined($arg{'f'})) ) {
die "Stop - missing argument: -f <datafile>\n$usage\n";
}
if ( ! ( defined($arg{'l'}) || defined($arg{'i'}) || defined($arg{'r'}) ) ) {
$arg{'l'} = 'all'; # all users by default
# die "Stop - missing argument: l or i\n$usage\n";
}
$arg{'h'} = TRUE if ( defined($arg{'S'}) ); # -vikas
# HTML strings -vikas
if (defined($arg{'H'})) {
$H_HDR1 = '<HR><CENTER><H1>'; $h_HDR1 = '</H1></CENTER>';
$H_USRHDR = '<HR><H3><FONT COLOR=\"#000077">';
$h_USRHDR = '</FONT></H3>';
$H_TBL = '<TABLE BORDER=1>'; $h_TBL = '</TABLE>';
$H_TR = '<TR>' ; $h_TR = '</TR>';
$H_TH = '<TH>' ; $h_TH = '</TH>';
$H_TD = '<TD>' ; $h_TD = '</TD>';
$H_I = '<I>' ; $h_I = '</I>';
$H_B = '<B>' ; $h_B = '</B>';
$H_P = '<P>' ; $h_P = '</P>' ;
print "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n";
print "<HTML>\n <HEAD>\n <TITLE>Radius Log</TITLE>\n </HEAD>\n\n";
print "<BODY bgcolor=\"ffffff\">\n";
printf ("<P>Report generated at %s</P>\n", scalar localtime);
print "<H2>Table of Contents</H2>\n<UL>\n";
if (!defined($arg{'S'})) {
print "<A href=\"#userdetails\">User Details</A> <P>\n";
}
print "<A href=\"#portusage\">Port Usage</A> <P>\n";
print "<A href=\"#summary\">User Summary</A> <P>\n";
print "</UL><hr>\n";
}
# Generate the sprintf string from above $display
$display_format = $display;
for (keys(%dispwidths)) {
$display_format =~ s/$_/${H_TD}$dispwidths{$_}${h_TD}/g;
}
#Flag checking.
if ($DEBUG) {
print "DEBUG: Flags:\n";
foreach $flag (keys(%arg)) {
print " $flag - $arg{$flag}\n";
}
}
if (defined($arg{'r'})) {
# read in the users file so we can extract all users and initialise the
# last seen variable,
&get_user_list($USERS);
}
@detailfiles = split(/:/, $arg{'f'});
foreach $file (@detailfiles) {
print "DEBUG: Reading detail file: $file\n" if ($DEBUG eq 3);
&read_detailfile($file);
}
# Reports section
$send_output = "STDOUT";
if ( defined($arg{'l'}) ) {
if (defined($arg{'H'})) { print "<A name=\"userdetails\"></A>" ;}
if ($arg{'l'} eq "all") {
$send_output = ( (defined($arg{'o'})) ? "$arg{'o'}" : "STDOUT" );
print "Sending reports to: $send_output\n" if ($DEBUG eq 1);
@users_to_report = sort keys(%userlist);
} else {
@users_to_report = ( $arg{'l'} );
}
for $ureports (@users_to_report) {
user_report($ureports);
}
}
if ( defined($arg{'i'}) ) {
&ip_address_report($arg{'i'});
}
if ( defined($arg{'r'}) ) {
&last_on_report();
}
## Print port usage -vikas
if ( defined($arg{'P'}) ) {
&port_report();
}
## Print total port usage -kbyanc
if ( defined($arg{'T'}) ) {
&total_port_report();
}
## Print summary report -vikas
&summary_report();
## cleanup dbm stuff
if (defined($arg{'D'})) {
untie %DB;
unlink ($tdbfile);
}
exit 0;
## The port usage per hour is stored in $portsinuse{$nasid}{$hour}
## -vikas
sub port_report {
# ---------------
my $nasid;
for $nasid (sort keys %portsinuse)
{
my($cumuports, $portdiff, $maxports) = (0, 0, 0);
# first, compute sum of all logins and logouts we have logged
for $np (sort keys %{ $portsinuse{$nasid} }) {
$cumuports += $portsinuse{$nasid}{$np};
}
# portdiff is the number of people who were logged in when logging started
# computed from number of people currently logged in minus total logins we know of
$portdiff = $curlogins{$nasid} - $cumuports;
if (defined($arg{'H'})) { print "<A name=\"portusage\"></A>" ;}
my $nasipnum = pack('C4', split(/\./, $nasid));
my $AF_INET = 2;
# if (defined (AF_INET)) { $AF_INET = AF_INET };
my $nasname = gethostbyaddr($nasipnum, $AF_INET);
$nasname = $nasid if (!defined($nasname));
print "\n\n${H_HDR1}PORT USAGE for ${nasname} (${nasid})${h_HDR1}\n";
if (! defined($arg{'H'})) { print "----------\n" ;}
print "Current Ports in use= $curlogins{$nasid}\n";
print "${H_TBL}${H_TR}${H_TH}Date ${h_TH}${H_TH} Hour ${h_TH}${H_TH} Ports in Use ${h_TH}${H_TH} Max Ports ${h_TH}${h_TR}\n";
$cumuports = $portdiff;
for $np (sort keys %{ $portsinuse{$nasid} }) {
my @timestr = localtime($np);
$maxports = $cumuports+$maxportsinuse{$nasid}{$np};
$cumuports += $portsinuse{$nasid}{$np};
printf "${H_TR}${H_TD}%s %2d, %-4.4d ${h_TD}${H_TD} %02d ${h_TD}${H_TD} %10d ${h_TD}${H_TD} %7d ${h_TD}${h_TR}\n",
$months[$timestr[4]], $timestr[3], $timestr[5]+1900, $timestr[2], $cumuports, $maxports;
# push @{ $wkvals[$timestr[6]][$timestr[2]] }, $cumuports;
}
# print "----Hour----";
# for (0..6) { print " $weekdays[$_]"; }
# for $j (0..23) {
# printf "\n %02d ", $j;
# for $i (0..6) { print " @{ $wkvals[$i][$j] } "; }
# }
print "$h_TBL\n";
}
}
## Compute totals across all NAS's
sub total_port_report {
# ---------------
my $nasid;
my $nascount = 0;
my $totallogins = 0;
my %globusage;
my %globmaxusage;
for $nasid (sort keys %portsinuse)
{
my($cumuports, $portdiff, $maxports) = (0, 0, 0);
# update counters
$nascount++;
$totallogins += $curlogins{$nasid};
# compute sum of all logins and logouts we have logged
for $np (sort keys %{ $portsinuse{$nasid} }) {
$cumuports += $portsinuse{$nasid}{$np};
}
# portdiff is the number of people who were logged in when logging started
# computed from number of people currently logged in minus total logins we know of
$portdiff = $curlogins{$nasid} - $cumuports;
$cumuports = $portdiff;
for $np (sort keys %{ $portsinuse{$nasid} }) {
$maxports = $cumuports+$maxportsinuse{$nasid}{$np};
$cumuports += $portsinuse{$nasid}{$np};
# compute totals across NASs
$globusage{$np} += $cumuports;
$globmaxusage{$np} += $maxports;
}
}
# now we have the information to display...
print "\n\n${H_HDR1}TOTAL PORT USAGE${h_HDR1}\n";
print "Current Ports in use= $totallogins\n";
print "${H_TBL}${H_TR}${H_TH}Date ${h_TH}${H_TH} Hour ${h_TH}${H_TH} Ports in Use ${h_TH}${H_TH} Max Ports ${h_TH}${h_TR}\n";
for $np (sort keys %globusage) {
my @timestr = localtime($np);
printf "${H_TR}${H_TD}%s %2d, %-4.4d ${h_TD}${H_TD} %02d ${h_TD}${H_TD} %10d ${h_TD}${H_TD} %7d ${h_TD}${h_TR}\n",
$months[$timestr[4]], $timestr[3], $timestr[5]+1900, $timestr[2], $globusage{$np}, $globmaxusage{$np};
}
print "$h_TBL\n";
}
sub summary_report {
# ------------------
if (defined($arg{'H'})) { print "<A name=\"summary\"></A>" ;}
print "\n${H_HDR1}TOTAL USAGE REPORTS ${h_HDR1}\n";
if (! defined($arg{'H'})) { print "------------------\n" ;}
if (defined(@users_to_report)) {
print "Total number of unique users= $#users_to_report\n";
}
print "${H_TBL}${H_TR}${H_TH} USER ${h_TH}${H_TH} Total Hrs ${h_TH}${H_TH} Avg/Day ${h_TH}${H_TH} Avg/Sess ${h_TH}${h_TR}\n";
for (sort { $usertotals{$b} <=> $usertotals{$a} } keys %usertotals)
{
my ($t, $avgd, $avgs) = split(/\t/, $usertotals{$_});
if($t < 0) {
printf ("${H_TR}${H_TD}%14s ${h_TD}${H_TD} %s ${h_TD}${H_TD} %s ${h_TD}${H_TD} %s${h_TD}${h_TR}\n",
$_ , "unknown", "unknown", "unknown" );
}
else {
printf ("${H_TR}${H_TD}%14s ${h_TD}${H_TD} %s ${h_TD}${H_TD} %s ${h_TD}${H_TD} %s${h_TD}${h_TR}\n",
$_ , &convert_secs_to_hours($t), &convert_secs_to_hours($avgd),
&convert_secs_to_hours($avgs) );
}
}
print "${h_TBL}\n";
}
# This subroutine does the calculation also, so we need to call this
# everytime.
sub user_report {
#----------------
my $luser = shift;
return if ( $luser eq "" );
# my $sess = $userlist{$luser} || defined($arg{'r'});
my $sess;
if (defined ($arg{'D'})) {$sess = $DB{"U_$luser"}; }
else { $sess = $userlist{$luser}; }
chop($sess);
my @sessionsl = split(/:/, $sess);
my @sessions = sort { $starttimestamp{$a} <=> $starttimestamp{$b} } @sessionsl;
my $session = "";
my $total_time = 0;
my $total_in = 0;
my $total_out = 0;
my $first_time = 0;
my $last_time = 0;
my $previous_session_time = 0;
my $telco_cost = 0;
my $avgperday = 0; # average seconds per day
my $avgperses = 0; # average seconds per session
my $width = 0; # width of header bar
$output=( ($send_output ne "STDOUT") ? "$send_output/$luser" : $send_output );
print "Generating report: $luser -> $output\n" if ($DEBUG eq 1);
if ($output eq "STDOUT") {
open (OUT, ">-") || die "Can't open stdout: $!\n";
} else {
open(OUT, ">$output") || die "Can't open file $output: $!\n";
}
if (!defined($arg{'h'}) ) {
print OUT ("\n${H_USRHDR}Radius Log Report for: $luser ${h_USRHDR}\n");
print OUT ("${H_TBL}${H_TR}${H_TH} Date ${h_TH}${H_TH} Login ${h_TH}${H_TH} Logout ${h_TH}${H_TH} Ontime ${h_TH}${H_TH} Port "); $width=42;
if ($arg{'b'}) { print OUT ("${h_TH}${H_TH} BW-In/Out "); $width+=14; }
if ($arg{'t'}) { print OUT ("${h_TH}${H_TH} Total "); $width+=8; }
if ($arg{'c'}) { print OUT ("${h_TH}${H_TH} Cost "); $width+=8; }
if ($arg{'p'}) { print OUT ("${h_TH}${H_TH} Calling Phone "); $width+=15; }
if ($arg{'q'}) { print OUT ("${h_TH}${H_TH} Closed "); $width+=17; }
print OUT ("${h_TH}${h_TR}\n");
print OUT (("-" x $width) . "\n") if (! defined($arg{'H'}));
}
for $session (@sessions) {
my $nasid = $1 if ($session =~ /^.*_(.*)$/); # extract NasID
&get_session_data($session); # from DBM table
$curlogins{$nasid} = 0 if (! defined($curlogins{$nasid}) ); # -vikas
if (($first_time eq 0) || ($starttimestamp < $first_time)) {
# Locate the 'first' timestamp for this user.
$first_time = $starttimestamp;
}
if (($last_time eq 0) || ($starttimestamp > $last_time)) {
# Locate the 'last' timestamp for this user.
$last_time = $starttimestamp;
}
$start_date = getdate($starttimestamp);
$start_time = gettime($starttimestamp);
if (! defined($stoptimestamp) || $stoptimestamp eq "" || $stoptimestamp == 0 ) {
# no stop record, is possible that stop record was lost or else they are
# are still logged in. We should try to figure out which is the case. -kbyanc
if($recordstartstop{$session} == 2) {
$end_time = "unknown";
}
else {
$end_time = " - now -";
++$curlogins{$nasid}; # -vikas
$stoptimestamp = time;
}
}
else {
$end_time = gettime($stoptimestamp);
}
$duplicate_login = (($stoptimestamp < $previous_session_time) ? 1 : 0);
$previous_session_time = $stoptimestamp;
$port_pair = sprintf("%1.1s%-s", $nasporttype, $nasport);
$in_out = &calculate_in_out($acctinputoctets, $acctoutputoctets);
$total_time += ( $acctsessiontime / 60 );
$total_in += $acctinputoctets;
$total_out += $acctoutputoctets;
#Standard line. Date StartT EndTime Ontime Port
if (! defined($arg{'S'})) { # summary only
$line = sprintf($display_format, $start_date, $start_time, $end_time,
&convert_secs_to_mins($acctsessiontime),
$port_pair);
$line .= " ${H_TD}" . sprintf($dispwidths{'_BANDWDT_'}, $in_out) . "${h_TD}" if ($arg{'b'});
$line .= " ${H_TD}" . sprintf($dispwidths{'_TOTHRS_'}, &convert_secs_to_hours($total_time)) . "${h_TD}" if ($arg{'t'});
if ($arg{'c'}) {
my $session_cost = &calculate_cost($starttimestamp,
$stoptimestamp, $nasporttype);
$telco_cost += $session_cost;
$line .= " ${H_TD}" . sprintf(" %5.5s ", $session_cost) . "${h_TD}";
}
$line .= " ${H_TD}" . sprintf(" %12s ", $caller) . "${h_TD}" if ($arg{'p'});
$line .= " ${H_TD}" . getterminatecause($acctterminatecause) . "${h_TD}" if ($arg{'q'});
# print OUT "${H_TR}<td colspan=3>Multiple login here:</td>${h_TR}\n" if (($duplicate_login eq 1) && ($REPORT_MULTIPLE_LOGINS eq 1));
print OUT "${H_TR}$line${h_TR}\n";
} # ! defined summary only
} # end for @sessions
print "${h_TBL}" if (! defined ($arg{'S'}));
$avgperses = $total_time/($#sessions == -1 ? 1 : $#sessions + 1);
$avgperday = ($last_time - $first_time)/(3600 * 24); # Number of days
$avgperday = $total_time / ($avgperday < 1 ? 1 : $avgperday);
$usertotals{$luser} = "$total_time\t$avgperday\t$avgperses"; #store
if (! defined($arg{'h'})) {
print OUT (("-" x $width) . "\n") if (! defined($arg{'H'}));
if ( $arg{'t'} ) {
printf OUT ("${H_P}${H_B} Total Hours: %s ${h_B}\n",
&convert_secs_to_hours($total_time) );
}
if ( $arg{'a'} ) {
printf OUT ("${H_P} Average Online times:${H_I} %s per day, %s per session ${h_I}\n",
&convert_secs_to_hours($avgperday),
&convert_secs_to_hours($avgperses));
}
if ( $arg{'b'} ) {
printf OUT ("${H_P} Total Data transferred In/Out:${H_I} %s ${h_I}\n",
&calculate_in_out($total_in, $total_out) );
}
if ( $arg{'c'} ) {
printf OUT ("${H_P} Total Telephone charges for period:${H_I} %s %s ${h_I}\n",
$currency, (int($telco_cost*100))/100);
}
}
#close(OUT);
}
sub ip_address_report {
# ---------------------
my $ipaddress = shift;
my $sess = "";
if ($ipaddress == "0") {
# $sess = $allsessions;
$sess = keys %recordstartstop;
print "IP address usage report.\n";
}
else {
if (defined ($arg{'D'})) {$sess = $DB{"I_$ipaddress"}; }
else {$sess = $ipaddresslist{"$ipaddress"}; }
print "IP address usage report for $ipaddress\n";
}
chop($sess);
#print "Sessions: $sess\n";
my @sessionsl = split(/:/, $sess);
my @sessions = sort { $starttimestamp{$a} <=> $starttimestamp{$b} } @sessionsl
;
my $session = "";
print "Date Login Logout User Ontime Port IP address\n";
print "--------------------------------------------------------------\n";
for $session (@sessions) {
&get_session_data($session);
next if ( $framedipaddress == "" );
$start_date = getdate($starttimestamp);
if ( $starttimestamp ) {
$start_time = gettime($starttimestamp);
} else {
$start_time = "?unknown";
}
if ( $stoptimestamp ) {
$end_time = gettime($stoptimestamp);
} else {
$end_time = "still on";
}
$port_pair = sprintf("%1.1s%-s", $nasporttype, $nasport);
$line = sprintf("%-10.10s %-8.8s %-8.8s %-8.8s %-8.8s %-5.5s %-15.15s",
$start_date, $start_time, $end_time, $username,
&convert_secs_to_mins($acctsessiontime),
$port_pair, $framedipaddress );
print "$line\n";
}
print "------------------------------------------------\n";
}
sub last_on_report {
print "Complete summary of All users last logged in times\n";
print "Username Real Name Last time on.\n";
print "===============================================================\n";
for $id (sort(keys(%allusers))) {
if ($lastlogtime{$id} gt 0 ) {
$laston = getdate($lastlogtime{$id});
} else {
$laston = "-";
}
printf "%-8s %-40.40s %-10s\n", $id, $allusers{$id}, $laston;
}
}
sub getterminatecause {
my $reason = shift;
# search on AltaVista for Ascend-Disconnect-Cause
%asnd_list = (11, "Carrier-Loss", 20, "Quit", 21, "Idle",
43, "Chap-failure", 45, "User-Request", 46, "User-Request",
47, "No-NCP",
100, "Timeout", 185, "Remote-Hangup");
if ($reason =~ /^\d+/) { # Ascend disconnect numbers
my $str = $asnd_list{$reason};
$reason = $str if ($str ne "");
}
return "" if ($reason eq "User-Request" || $reason eq "Remote-Hangup" ||
$reason eq "Quit");
return $reason;
}
sub getdate {
my $ltime = shift;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($ltime);
my $datestr = $DATE_FORMAT;
$mday = sprintf("%-2.2d", $mday);
$mon = sprintf("%-2.2d", ++$mon);
$year2 = sprintf("%-4.4d", $year + 1900);
$year = sprintf("%-2.2d", $year % 100);
$datestr =~ s/DD/$mday/e;
$datestr =~ s/MM/$mon/e;
$datestr =~ s/YYYY/$year2/e;
$datestr =~ s/YY/$year/e;
#return sprintf("%-2.2d/%-2.2d/%-2.2d", $mday, ++$mon, $year);
return $datestr;
}
sub gettime {
my $ltime = shift;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($ltime);
return sprintf("%-2.2d:%-2.2d:%-2.2d", $hour, $min, $sec);
}
sub convert_secs_to_mins {
my $ltime = shift;
return sprintf("%3dm%2.2ds", int($ltime / 60), ($ltime - ( int($ltime / 60) * 60) ));
}
sub convert_secs_to_hours {
my $ltime = shift;
return sprintf("%3dh%2.2dm", int($ltime / 60), ( $ltime - (int($ltime / 60)*60)));
}
sub convert_octets_to_usage {
my $num = shift;
my $ret = "";
$num = $num / 1024; # num is Kb now
if ($num > 1048576) {
# Shit > 1Gb in a session
return sprintf ("%s.%sG", int($num/1048576), int(($num-(int($num/1048576)*1048576))/104857.6));
} else {
if ($num > 1024) {
# More than 1 Mb
#return sprintf ("%3.1sM", $num/1024);
return sprintf ("%s.%sM", int($num/1024), int(($num-(int($num/1024)*1024))/102.4));
} else {
return sprintf ("%s.%sK", int($num), int( ($num - int($num)) * 10));
}
}
}
sub calculate_in_out {
my $in = shift;
my $out = shift;
return sprintf("%s/%s", &convert_octets_to_usage($in), &convert_octets_to_usage($out));
}
sub init {
# initialise all data structures
@userlist = ();
}
sub read_record {
#----------------
my $keepreading = 1;
@record = ();
print "new record\n" if ($DEBUG eq 3);
while ($keepreading) {
$_ = <IN>;
print "$_" if ($DEBUG eq 3);
if ( /^$/ ) {
$keepreading = 0;
} else {
#push (@lines, $_);
$record[++$#record] = $_;
}
}
##return @lines;
}
sub process_record {
#-------------------
#my @lines = shift;
$AcctSessionId = ""; $UserName = ""; $NasPort=""; $NasPortType="";
$AcctStatusType=""; $AcctSessionTime=""; $AcctInputOctets="";
$AcctOutputOctets=""; $AcctTerminateCause=""; $ServiceType="";
$FramedProtocol=""; $FramedIPAddress=""; $Timestamp=""; $AcctDelayTime="";
foreach (@record) { # Collect data
s/^\s+//; #Strip leading spaces.
print " -> $_" if ($DEBUG eq 3);
chomp;
if (s/Acct-Session-Id = //) {
$AcctSessionId = $_ ;
return if ($AcctSessionId eq "00000000"); # invalid sessionID
}
$UserName = $_ if s/User-Name = //;
$NasPort = $_ if s/NAS-Port = //;
$NasPortType = $_ if s/NAS-Port-Type = //;
if (s/(NAS-Identifier)|(NAS-IP-Address) = //) {
$NasIdent = $_ ;
return if (defined($arg{'N'}) && ! /$arg{'N'}/); # not interested
}
# check to see if match Calling-Station-Id -kbyanc
if (s/Calling-Station-Id = //) {
$caller = $_;
$caller =~ s/\"//g;
return if (defined($arg{'C'}) && ! /$arg{'C'}/);
}
$AcctStatusType = $_ if s/Acct-Status-Type = //;
$AcctSessionTime = $_ if s/Acct-Session-Time = //;
$AcctInputOctets = $_ if s/Acct-Input-Octets = //;
$AcctOutputOctets = $_ if s/Acct-Output-Octets = //;
$AcctTerminateCause = $_ if s/Acct-Terminate-Cause = //;
$AcctTerminateCause = $_ if s/Ascend-Disconnect-Cause = //;
$AcctDelayTime = $_ if s/Acct-Delay-Time = //;
$ServiceType = $_ if s/Service-Type = //;
$FramedProtocol = $_ if s/Framed-Protocol = //;
$FramedIPAddress = $_ if s/Framed-Address = //;
$FramedIPAddress = $_ if s/Framed-IP-Address = //;
$Timestamp = $_ if s/Timestamp = //;
}
# Check to see if a Calling-Station-Id field was found when required -kbyanc
return if ( (defined($arg{'C'}) ) && (! defined($caller) ) );
# Check for a valid Timestamp - if none, generate one from record stamp
# Use timelocal() -vikas
if ($Timestamp == "") {
my $recdate = $record[0];
chomp $recdate;
if($recdate =~ /^\s*(\w{3})\s(\w{3})\s{1,2}(\d{1,2})\s(\d{2}):(\d{2}):(\d{2})\s(\d{4})$/ &&
(grep {$1 eq $_} @weekdays) && (grep {$2 eq $_} @months) )
{
$Timestamp = timelocal($6, $5, $4, $3, $monthshash{$2}, $7-1900);
}
}
# $DEBUG && print STDERR "Timestamp= $Timestamp\n";
# Remove "" marks from $AcctSessionId and $UserName
$UserName =~ s/\"//g;
$AcctSessionId =~ s/\"//g;
$AcctSessionId .= "_$NasIdent"; # append NAS Ident, -vikas
# avoid dup records for the same port number,,, -vikas
my $nasportid = "$NasIdent" . "_$NasPort" ;
# And correct the Timestamp backwards if there was an accounting delay
$Timestamp -= $AcctDelayTime;
return if ($Timestamp <= 0);
# Skip this is we arn't interested in this guy
return if (defined($arg{'l'}) && ($arg{'l'} ne "all") && ($UserName ne $arg{'l'}));
# Skip this if we aren't interested in the month
if ( defined ($arg{'d'}) ) {
my $interested = 0;
if ($AcctStatusType eq "Start") {
my $tmpm = $arg{'d'};
my @mons = split(/:/, $tmpm); # user specified on cmd line
my $mon = "";
for $tmpm (@mons) {
if ( ($tmpm > 0) && ($tmpm < 13) ) { #Tis a number, convert to txt.
$mon = $months[$tmpm - 1];
} else {
$mon = $tmpm;
}
my ($ssec,$smin,$shour,$smday,$smon,$syear,$swday,$syday,$sisdst) =
localtime($Timestamp);
$interested = 1 if ($mon eq $months[$smon]);
}
return if (! $interested);
}
}
## look at Nas + Port, and skip record if we already have a login or
# logout for this Nas+port (avoid two successive entries) -vikas
if (defined($ison{$nasportid}))
{
if(($ison{$nasportid} ne "0") && ($ison{$nasportid} ne "$AcctSessionId")) {
# in the event we get a start or stop record which doesn't match
# the session ID of the session which we thought was on the port,
# we must assume the appropriate record was lost in transit.
# In either event, we need to close the previous session.
# -kbyanc
my $oldsession;
$oldsession = $ison{$nasportid};
$recordstartstop{$oldsession} = 2; # indicate the session is closed
$acctinputoctets{$oldsession} = 0;
$acctoutputoctets{$oldsession} = 0;
$stoptimestamp{$oldsession} = $Timestamp;
# $acctsessiontime{$oldsession} = $stoptimestamep{$oldsession} - $starttimestamp{$oldsession};
$acctsessiontime{$oldsession} = 0;
$acctterminatecause{$oldsession} = "<No Record>";
--$portsinuse{$NasIdent}{$Timestamp - ($Timestamp % 3600)} unless ($NasPort eq "");
}
## following added by vikas, replaced by kbyanc
# return if ($AcctStatusType eq "Start" && $ison{$nasportid} ne "0");
# return if ($AcctStatusType eq "Stop" &&
# $ison{$nasportid} ne "$AcctSessionId");
}
# Store in data structures.
$userlist{$UserName} = "" if ( ! defined( $userlist{$UserName} ) );
$ipaddresslist{"$FramedIPAddress"} = "" if ( ! defined( $ipaddresslist{"$FramedIPAddress"} ) );
$recordstartstop{$AcctSessionId} = 0 if ( ! defined($recordstartstop{$AcctSessionId}) );
print ":$AcctSessionId - $AcctStatusType:\n" if ($DEBUG eq 2);
if ( $AcctStatusType eq "Start" )
{
# Check if we have already got a Start or Stop record for this.
return if ($recordstartstop{$AcctSessionId} > 0);
$ison{$nasportid} = $AcctSessionId;
my $hour = $Timestamp - ($Timestamp % 3600);
++$portsinuse{$NasIdent}{$hour} unless ($NasPort eq ""); # -vikas
# find the peak usage level during the hour... -kbyanc
$maxportsinuse{$NasIdent}{$hour} = $portsinuse{$NasIdent}{$hour}
unless $portsinuse{$NasIdent}{$hour} <= $maxportsinuse{$NasIdent}{$hour};
# $allsessions .= "$AcctSessionId:";
# Build up a list of session IDs for this user
$userlist{$UserName} .= "$AcctSessionId:";
# Add this session to the ipaddresslist record
$ipaddresslist{"$FramedIPAddress"} .= "$AcctSessionId:";
$username{$AcctSessionId} = $UserName;
$caller{$AcctSessionId} = $caller;
$nasport{$AcctSessionId} = $NasPort;
$nasporttype{$AcctSessionId} = $NasPortType;
$framedipaddress{$AcctSessionId} = $FramedIPAddress;
$starttimestamp{$AcctSessionId} = $Timestamp;
$lastlogtime{$UserName} = $Timestamp if ($Timestamp ge $lastlogtime{$UserName});
# recordstartstop is set to 1 in Start, and 2 in Stop
$recordstartstop{$AcctSessionId} = 1;
}
else { # STOP record has everything we need, prefer this data
print ";" if ($DEBUG eq 3);
$ison{$nasportid} = "0"; # port is off
return if ($recordstartstop{$AcctSessionId} == 2); # seen STOP record
# keep track of number of ports in use -vikas
--$portsinuse{$NasIdent}{$Timestamp - ($Timestamp % 3600)} unless ($NasPort eq ""); # -vikas
if ($recordstartstop{$AcctSessionId} == 0) # Not seen Start yet
{
# Build up a list of session IDs for this user
$userlist{$UserName} .= "$AcctSessionId:";
# Add this session to the ipaddresslist record
$ipaddresslist{"$FramedIPAddress"} .= "$AcctSessionId:";
}
$allsessions .= "$AcctSessionId:";
$username{$AcctSessionId} = $UserName;
$caller{$AcctSessionId} = $caller;
$nasport{$AcctSessionId} = $NasPort;
$nasporttype{$AcctSessionId} = $NasPortType;
$framedipaddress{$AcctSessionId} = $FramedIPAddress;
$acctinputoctets{$AcctSessionId} = $AcctInputOctets;
$acctoutputoctets{$AcctSessionId} = $AcctOutputOctets;
$acctsessiontime{$AcctSessionId} = $AcctSessionTime;
$stoptimestamp{$AcctSessionId} = $Timestamp;
$acctterminatecause{$AcctSessionId} = $AcctTerminateCause;
$starttimestamp{$AcctSessionId} = $Timestamp - $AcctSessionTime;
$lastlogtime{$UserName} = $Timestamp if ($Timestamp ge $lastlogtime{$UserName});
$recordstartstop{$AcctSessionId} = 2;
}
}
sub read_detailfile {
#--------------------
my $filename = shift;
my @record = ();
my $recordnum = 0;
if ($DEBUG eq 3) { print "DEBUG: Reading records";}
if ( $filename =~ /.gz$/ ) {
open (IN, "$GZCAT $filename |") || warn "read_detailfile(\"$filename\"): $!\n";
} else {
if ( $filename =~ /.Z$/ ) {
open (IN, "$ZCAT $filename |") || warn "read_detailfile(\"$filename\"): $!\n";
} else {
open (IN, "<$filename") || warn "read_detailfile(\"$filename\"): $!\n";
}
}
$valid_input = (eof(IN) ? 0 : 1);
while($valid_input) {
$valid_input = 0 if (eof(IN));
if ($DEBUG eq 3) { print "-Reading Record-\n"; }
&read_record;
print "$AcctSessionId" if ($DEBUG eq 3);
if ($DEBUG eq 3) { print "-Process Record-\n"; }
&process_record;
if ( (++$recordnum % $syncsize) == 0) {&dump_dbm() ;}
}
&dump_dbm();
}
sub help {
print <<EOHELP;
radreport - Radius Reporting tool.
----------------------------------
radreport will:
. produce reports on individual or all users in the radius log file
. produce reports on IP number usage
. calculate data transferred in any one session
. provide online time analysis for user logins
. provide NAS port usage reports
Usage: $usage
e.g.
$0 -tqa -l all -f /usr/adm/radacct/myts/detail
Flags:
Flags without arguments (may all be specified in one 'flag' e.g. -tba)
-t Show a runtime total of online time
-b Show a runtime total of data transferred in/out.
-a Show 'average' usage data.
-q Show how connection was terminated
-p Show caller's phone number
-c Work out call charge by the Telco.
-h Suppress header and footer data ( like /usr/bin/w -h )
-r Produce a list of users and their last login time.
-P Produce a port usage report per NAS
-T Produce a port usage report summarizing all NASs
-D use temporary DBM storage (for large amounts of data)
-H HTML output
-l userid Produce a 'user' usage report.
-l all Produce a 'user' usage report for all users.
-o /tmp/dir Do the above but put the reports into this directory
-N a.b.c.d report for NASid equal to a.b.c.d ip-address only
-C regex report for Calling-Station-Id matching regex only
-i a.b.c.d Produce a 'ip' usage report.
-f file Analyse radius detail 'file'. Multiple files may be
specified by separating them with a : i.e. file1:file2
radiusreport will take compressed files.
-d mon[:mon] Only report on this month (or months). mon can be in
formay 'Jan' or '01' or '1'. Multiple months are separated by colon
characters ':'. (Caveat: Logins which roll over months are included)
EOHELP
}
sub get_user_list {
#-------------------
my $usersfile = shift;
open(IN, "<$usersfile") || die "users files: $userfile not found.\n";
if ($HAVE_NICE_USERS) {
while (<IN>) {
if (s/^#\* //) { # Line is a username entry.
($user,$name) = split(/:/);
chop $name;
$allusers{$user}=$name; # Remember the 'account's 'Real owner name'
$lastlogtime{$user}=0; # Initialise the owner's 'last logged on' stat
}
}
} else {
while (<IN>) {
if (/Password =/) { # Line is a username entry.
($user, $name) = split(/(\s)/);
$name = "";
$allusers{$user}=$user;
$lastlogtime{$user}=0;
}
}
}
close(IN);
}
sub calculate_cost {
#-------------------
# Function to calculate the cost of a connection
# Arguments are the start and stop timestamp.
my $stime = shift;
my $etime = shift;
my $porttype = shift;
#Make assumptions on how long call establishment takes
$stime = $stime - 20 if ($porttype eq "Async");
$stime = $stime - 3 if ($porttype eq "ISDN");
$stime = $stime - 3 if ($porttype eq "ISDN-V120");
my ($ssec,$smin,$shour,$smday,$smon,$syear,$swday,$syday,$sisdst) =
localtime($stime);
my ($esec,$emin,$ehour,$emday,$emon,$eyear,$ewday,$eyday,$eisdst) =
localtime($etime);
# Telco 'minimum' charge per call - In the UK (BT) this is 5p (or 0.05 UKP)
my $min_cost = 0.050;
# Setup the times that costs change and what cost it is
# The following defines the call times and costs for each day.
# the format if the define is: StartHour:Min=CostPerMin
# multiple time based charge bands are separated by |
$cost{'0'} = "0=0.010";
$cost{'1'} = "0=0.017|8:00=0.040|18:00=0.017";
$cost{'2'} = "0=0.017|8:00=0.040|18:00=0.017";
$cost{'3'} = "0=0.017|8:00=0.040|18:00=0.017";
$cost{'4'} = "0=0.017|8:00=0.040|18:00=0.017";
$cost{'5'} = "0=0.017|8:00=0.040|18:00=0.017";
$cost{'6'} = "0=0.010";
$callcost = 0;
$currency = "=A3";
#$currency = "\$";
#printf "$swday:$ewday:$etime:$stime:%s\n", $etime - $stime;
$callcost = calc_sub_cost( $stime, $etime );
$callcost = $min_cost if ($callcost lt $min_cost);
return $callcost;
}
sub calc_sub_cost {
# -----------------
my $start_sec = shift;
my $stop_sec = shift;
#print "calc_sun_cost($start_sec, $stop_sec) called...\n";
#printf "[%s -> %s]\n", ctime($start_sec), ctime($stop_sec);
my ($ssec,$smin,$shour,$smday,$smon,$syear,$swday,$syday,$sisdst) =
localtime($start_sec);
my ($esec,$emin,$ehour,$emday,$emon,$eyear,$ewday,$eyday,$eisdst) =
localtime($stop_sec);
my $day_start_secs = ( $ssec + ($smin * 60) + ($shour * 3600) );
my $day_stop_secs = ( $esec + ($emin * 60) + ($ehour * 3600) );
my $day_end_secs = 86400;
if ( ($swday eq $ewday) && ( ($stop_sec - $start_sec) < 86400 ) ) {
$day_end_secs = $day_stop_secs;
}
#Find cost of start of call
my @tmpcosts = split(/\|/, $cost{$swday});
my @costs = ();
for (@tmpcosts) {
my ($hr, $unit) = split(/\=/);
if ($hr =~ /:/) {
my ($hrs, $mins) = split(/:/, $hr);
$secs = ($hrs * 3600) + ($mins * 60);
} else {
$secs = $hr;
}
$costs{$secs} = $unit;
#print "Rate: $secs : $unit\n";
}
#print "day_start_secs = $day_start_secs\n";
my @tocost = ( 86400 );
for (sort {$b <=> $a} keys(%costs)) {
my $start_cost = $costs{$_};
$tocost[++$#tocost] = $_;
#print "added tocost: $_\n";
last if ( $_ le $day_start_secs );
}
my $call_cost = 0;
for (sort {$a <=> $b} @tocost) {
#print "-------------------\ndoing tocost: $_\n";
if ($_ < $day_start_secs) {
$start_cost = $costs{$_};
next;
}
if ($_ < $day_end_secs) {
#print "-1\n";
$call_cost += (( $_ - $day_start_secs - 1) / 60.0 ) * $start_cost;
#printf "This call duration: %d (%s), cost: %s\n", ( $_ - $day_start_secs - 1), $start_cost, (( $_ - $day_start_secs - 1) / 60.0 ) * $start_cost;
$start_sec += ( $_ - $day_start_secs);
$day_start_secs = $_;
$start_cost = $costs{$_};
} else {
#print "-2\n";
next if ($day_end_secs eq $day_start_secs);
$call_cost += (( $day_end_secs - $day_start_secs - 1) / 60.0 ) * $start_cost;
#printf "This call duration: %d (%s), cost: %s\n", ( $day_end_secs - $day_start_secs - 1), $start_cost, (( $day_end_secs - $day_start_secs - 1) / 60.0) * $start_cost;
$start_sec += ( $day_end_secs - $day_start_secs );
$day_start_secs = $day_end_secs;
$start_cost = $costs{$_};
}
}
#print "$call_cost\n";
if ($start_sec < $stop_sec) {
#print "looping... $start_sec -> $stop_sec\n";
$call_cost += calc_sub_cost($start_sec, $stop_sec);
}
return $call_cost;
}
##
## Have to use DB or GDBM since there are data size restrictions in NDBM
##
use DB_File;
#use GDBM_File;
sub dump_dbm {
#-------------------
my ($key, $val);
$tdbfile = "/tmp/radiusreport$$" ;
return if (! defined ($arg{'D'}) ); # no temp storage to be done
$DEBUG && print STDERR "Doing dump_dbm\n";
if ($dbmopen != 1) {
tie (%DB, "DB_File", $tdbfile, O_RDWR|O_CREAT, 0600, $DB_HASH) ||
die "cannot open $tdbfile $!\n";
$dbmopen = 1;
}
# store userlist{Username}, U_$username session : session : session
for $u (keys %userlist) {
$key = "U_" . "$u" ;
if ($DB{$key} eq undef) { $DB{$key} = $userlist{$u}; }
else { $DB{$key} .= $userlist{$u}; }
undef $userlist{$u};
}
# store ipaddresslist{IPaddr}. I_$ipaddr = session : session : session
for $u (keys %ipaddresslist) {
$key = "I_" . "$u";
if ($DB{$key} eq undef) { $DB{$key} = $ipaddresslist{$u}; }
else { $DB{$key} .= $ipaddresslist{$u}; }
undef $ipaddresslist{$u};
}
# store S_$session -> data for all STOP records.
for $u ( split(/:/, $allsessions) ) {
$key = "S_" . "$u" ;
$DB{$key} = "$username{$u}\t$nasport{$u}\t$nasporttype{$u}\t$framedipaddress{$u}\t$starttimestamp{$u}\t$acctinputoctets{$u}\t$acctoutputoctets{$u}\t$acctsessiontime{$u}\t$stoptimestamp{$u}\t$acctterminatecause{$u}\t$caller{$u}";
undef $username{$u}; undef $nasport{$u}; undef $nasporttype{$u};
undef $framedipaddress{$u}; undef $starttimestamp{$u};
undef $acctinputoctets{$u}; undef $acctoutputoctets{$u};
undef $acctsessiontime{$u}; undef $stoptimestamp{$u};
undef $acctterminatecause{$u}; undef $caller{$u};
}
undef $allsessions;
# tie (%DB, $tdbfile, undef);
# while (($key,$val) = each %DB) { print STDERR "$key = $val\n" ; }
}
sub get_session_data {
# --------------------
my ($sess) = @_ ;
if ( defined ($arg{'D'}) && !defined ($username{$sess}) )
{
($username, $nasport, $nasporttype, $framedipaddress, $starttimestamp,
$acctinputoctets, $acctoutputoctets, $acctsessiontime,
$stoptimestamp, $acctterminatecause, $caller) = split(/\t/, $DB{"S_$sess"});
}
else # not using DBM or if an open record (still logged on)
{
$username = $username{$sess};
$nasport = $nasport{$sess};
$nasporttype = $nasporttype{$sess};
$framedipaddress = $framedipaddress{$sess};
$starttimestamp = $starttimestamp{$sess};
$acctinputoctets = $acctinputoctets{$sess};
$acctoutputoctets = $acctoutputoctets{$sess};
$acctsessiontime = $acctsessiontime{$sess};
$stoptimestamp = $stoptimestamp{$sess};
$acctterminatecause = $acctterminatecause{$sess};
$caller = $caller{$sess};
}
}
syntax highlighted by Code2HTML, v. 0.9.1