rendered paste body#!/usr/bin/perl -w
# Radius Accounting
#
use vars qw(%RAD %conf $db %ACCT
%RAD_REQUEST %RAD_REPLY %RAD_CHECK
$begin_time
$nas);
use strict;
use FindBin '$Bin';
require $Bin . '/config.pl';
unshift(@INC, $Bin . '/../', $Bin ."/../Abills/$conf{dbtype}");
require Abills::Base;
Abills::Base->import();
my $begin_time = check_time();
my %acct_mod = ();
require Abills::SQL;
my $sql = Abills::SQL->connect($conf{dbtype}, "$conf{dbhost}", $conf{dbname}, $conf{dbuser}, $conf{dbpasswd});
$db = $sql->{db};
require Acct;
Acct->import();
$acct_mod{'default'} = Acct->new($db, \%conf);
############################################################
# Accounting status types
# rfc2866
my %ACCT_TYPES = ('Start' => 1,
'Stop' => 2,
'Alive' => 3,
'Interim-Update' => 3,
'Accounting-On' => 7,
'Accounting-Off' => 8
);
my %USER_TYPES = ('Login-User' => 1,
'Framed-User' => 2,
'Callback-Login-User' => 3,
'Callback-Framed-User' => 4,
'Outbound-User' => 5,
'Administrative-User' => 6,
'NAS-Prompt-User' => 7,
'Authenticate-Only' => 8,
'Call-Check' => 10,
'Callback-Administrative' => 11,
'Voic' => 12,
'Fax' => 13);
my %ACCT_TERMINATE_CAUSES = (
'User-Request' => 1,
'Lost-Carrier' => 2,
'Lost-Service' => 3,
'Idle-Timeout' => 4,
'Session-Timeout' => 5,
'Admin-Reset' => 6,
'Admin-Reboot' => 7,
'Port-Error' => 8,
'NAS-Error' => 9,
'NAS-Request' => 10,
'NAS-Reboot' => 11,
'Port-Unneeded' => 12,
'Port-Preempted' => 13,
'Port-Suspended' => 14,
'Service-Unavailable' => 15,
'Callback' => 16,
'User-Error' => 17,
'Host-Request' => 18,
'Supplicant-Restart' => 19,
'Reauthentication-Failure' => 20,
'Port-Reinit' => 21,
'Port-Disabled' => 22
);
####################################################################
#test_radius_returns($RAD);
#####################################################################
# Files account section
my $RAD;
if (scalar(keys %RAD_REQUEST ) < 1) {
$RAD = get_radius_params();
if (! defined($RAD->{NAS_IP_ADDRESS})) {
$RAD->{USER_NAME}='-' if (! defined($RAD->{USER_NAME}));
access_deny("$RAD->{USER_NAME}", "Not specified NAS server", 0);
return 1;
}
require Nas;
$nas = Nas->new($db, \%conf);
my %NAS_PARAMS = ('IP' => "$RAD->{NAS_IP_ADDRESS}");
$NAS_PARAMS{NAS_IDENTIFIER}=$RAD->{NAS_IDENTIFIER} if (defined($RAD->{NAS_IDENTIFIER}));
$nas->info({ %NAS_PARAMS });
my $acct;
if ($nas->{errno} || $nas->{TOTAL} < 1) {
access_deny("$RAD->{USER_NAME}", "Unknow server '$RAD->{NAS_IP_ADDRESS}'", 0);
#exit 1;
}
else {
$acct = acct($RAD, $nas);
}
if(defined($acct->{errno})) {
log_print('LOG_ERR', "ACCT [$RAD->{USER_NAME}] $acct->{errstr} ($acct->{sql_errstr})");
}
#$db->disconnect();
}
#*******************************************************************
# acct();
#*******************************************************************
sub acct {
my ($RAD, $nas) = @_;
my $GT = '';
my $r = 0;
if ($RAD->{SERVICE_TYPE} && defined($USER_TYPES{$RAD->{SERVICE_TYPE}}) && $USER_TYPES{$RAD->{SERVICE_TYPE}} == 6) {
log_print('LOG_DEBUG', "ACCT [$RAD->{USER_NAME}] $RAD->{SERVICE_TYPE}");
return 0;
}
my $acct_status_type = $ACCT_TYPES{$RAD->{ACCT_STATUS_TYPE}};
$RAD->{INTERIUM_INBYTE} = 0;
$RAD->{INTERIUM_OUTBYTE} = 0;
$RAD->{INTERIUM_INBYTE2} = 0;
$RAD->{INTERIUM_OUTBYTE2} = 0;
$RAD->{INBYTE2} = 0;
$RAD->{OUTBYTE2} = 0;
#Cisco-AVPair
if ($RAD->{CISCO_AVPAIR}) {
if ($RAD->{CISCO_AVPAIR} =~ /client-mac-address=(\S+)/) {
$RAD->{CALLING_STATION_ID}=$1;
}
if ($RAD->{NAS_PORT} && $RAD->{NAS_PORT} == 0 && ($RAD->{CISCO_NAS_PORT} && $RAD->{CISCO_NAS_PORT} =~ /\d\/\d\/\d\/(\d+)/)) {
$RAD->{NAS_PORT}=$1;
}
}
if (defined($conf{octets_direction}) && $conf{octets_direction} eq 'server') {
$RAD->{INBYTE} = $RAD->{ACCT_INPUT_OCTETS} || 0; # FROM client
$RAD->{OUTBYTE} = $RAD->{ACCT_OUTPUT_OCTETS} || 0; # TO client
if ($nas->{NAS_TYPE} eq 'exppp') {
#reverse byte parameters
$RAD->{INBYTE} = $RAD->{ACCT_OUTPUT_OCTETS} || 0; # FROM client
$RAD->{OUTBYTE} = $RAD->{ACCT_INPUT_OCTETS} || 0; # TO client
$RAD->{INBYTE2} = $RAD->{EXPPP_ACCT_LOCALOUTPUT_OCTETS} || 0; # From client
$RAD->{OUTBYTE2} = $RAD->{EXPPP_ACCT_LOCALINPUT_OCTETS} || 0; # To client
$RAD->{INTERIUM_INBYTE} = $RAD->{EXPPP_ACCT_ITERIUMOUT_OCTETS} || 0;
$RAD->{INTERIUM_OUTBYTE} = $RAD->{EXPPP_ACCT_ITERIUMIN_OCTETS} || 0;
$RAD->{INTERIUM_INBYTE2} = $RAD->{EXPPP_ACCT_LOCALITERIUMOUT_OCTETS} || 0;
$RAD->{INTERIUM_OUTBYTE2} = $RAD->{EXPPP_ACCT_LOCALITERIUMIN_OCTETS} || 0;
}
elsif ($nas->{NAS_TYPE} eq 'lepppd') {
$RAD->{INBYTE} = $RAD->{ACCT_INPUT_OCTETS} || 0; # FROM client
$RAD->{OUTBYTE} = $RAD->{ACCT_OUTPUT_OCTETS} || 0; # TO client
#$RAD->{'INBYTE'} = $RAD->{'PPPD_INPUT_OCTETS_ZONES_0'};
#$RAD->{'OUTBYTE'} = $RAD->{'PPPD_OUTPUT_OCTETS_ZONES_0'};
for(my $i=0; $i<4; $i++) {
if (defined($RAD->{'PPPD_INPUT_OCTETS_ZONES_'.$i})) {
$RAD->{'INBYTE'.($i + 1)} = $RAD->{'PPPD_INPUT_OCTETS_ZONES_'.$i};
$RAD->{'OUTBYTE'.($i + 1)} = $RAD->{'PPPD_OUTPUT_OCTETS_ZONES_'.$i};
}
}
}
}
# From client
else {
$RAD->{INBYTE} = $RAD->{ACCT_OUTPUT_OCTETS} || 0; # FROM client
$RAD->{OUTBYTE} = $RAD->{ACCT_INPUT_OCTETS} || 0; # TO client
if ($nas->{NAS_TYPE} eq 'exppp') {
#reverse byte parameters
$RAD->{INBYTE} = $RAD->{ACCT_INPUT_OCTETS} || 0; # FROM client
$RAD->{OUTBYTE} = $RAD->{ACCT_OUTPUT_OCTETS} || 0; # TO client
$RAD->{INBYTE2} = $RAD->{EXPPP_ACCT_LOCALINPUT_OCTETS} || 0; # From client
$RAD->{OUTBYTE2} = $RAD->{EXPPP_ACCT_LOCALOUTPUT_OCTETS} || 0; # To client
$RAD->{INTERIUM_INBYTE} = $RAD->{EXPPP_ACCT_ITERIUMIN_OCTETS} || 0;
$RAD->{INTERIUM_OUTBYTE} = $RAD->{EXPPP_ACCT_ITERIUMOUT_OCTETS} || 0;
$RAD->{INTERIUM_INBYTE2} = $RAD->{EXPPP_ACCT_LOCALITERIUMIN_OCTETS} || 0;
$RAD->{INTERIUM_OUTBYTE2} = $RAD->{EXPPP_ACCT_LOCALITERIUMOUT_OCTETS} || 0;
}
elsif ($nas->{NAS_TYPE} eq 'lepppd') {
$RAD->{INBYTE} = $RAD->{ACCT_OUTPUT_OCTETS} || 0; # FROM client
$RAD->{OUTBYTE} = $RAD->{ACCT_INPUT_OCTETS} || 0; # TO client
for(my $i=0; $i<4; $i++) {
if (defined($RAD->{'PPPD_INPUT_OCTETS_ZONES_'.$i})) {
$RAD->{'INBYTE'.($i+1)} = $RAD->{'PPPD_OUTPUT_OCTETS_ZONES_'.$i};
$RAD->{'OUTBYTE'.($i+1)} = $RAD->{'PPPD_INPUT_OCTETS_ZONES_'.$i};
}
}
}
}
$RAD->{LOGOUT} = time;
$RAD->{SESSION_START} = (defined($RAD->{ACCT_SESSION_TIME})) ? time - $RAD->{ACCT_SESSION_TIME} : 0;
$RAD->{NAS_PORT} = 0 if (! defined($RAD->{NAS_PORT}));
$RAD->{CONNECT_INFO} = '' if (! defined($RAD->{CONNECT_INFO}));
$RAD->{ACCT_TERMINATE_CAUSE} = (defined($RAD->{ACCT_TERMINATE_CAUSE}) && defined($ACCT_TERMINATE_CAUSES{"$RAD->{ACCT_TERMINATE_CAUSE}"})) ? $ACCT_TERMINATE_CAUSES{"$RAD->{ACCT_TERMINATE_CAUSE}"} : 0;
if ($RAD->{'TUNNEL_SERVER_ENDPOINT:0'} && ! $RAD->{CALLING_STATION_ID}) {
$RAD->{CALLING_STATION_ID}=$RAD->{'TUNNEL_SERVER_ENDPOINT:0'};
}
elsif(! defined($RAD->{CALLING_STATION_ID})) {
$RAD->{CALLING_STATION_ID} = '';
}
# Make accounting with external programs
if (-d $conf{extern_acct_dir}) {
opendir DIR, $conf{extern_acct_dir} or die "Can't open dir '$conf{extern_acct_dir}' $!\n";
my @contents = grep !/^\.\.?$/ , readdir DIR;
closedir DIR;
if ($#contents > 0) {
my $res = "";
foreach my $file (@contents) {
if (-x "$conf{extern_acct_dir}/$file" && -f "$conf{extern_acct_dir}/$file") {
# ACCT_STATUS IP_ADDRESS NAS_PORT
$res = `$conf{extern_acct_dir}/$file $acct_status_type $RAD->{NAS_IP_ADDRESS} $RAD->{NAS_PORT} $nas->{NAS_TYPE}`;
log_print('LOG_DEBUG', "External accounting program '$conf{extern_acct_dir}' / '$file' pairs '$res'");
}
}
if (defined($res)) {
my @pairs = split(/ /, $res);
foreach my $pair (@pairs) {
my ($side, $value) = split(/=/, $pair);
$RAD->{$side} = "$value";
}
}
}
}
my $Acct;
if(defined($ACCT{$nas->{NAS_TYPE}})) {
if (! defined($acct_mod{"$nas->{NAS_TYPE}"})) {
require $ACCT{$nas->{NAS_TYPE}} . ".pm";
$ACCT{$nas->{NAS_TYPE}}->import();
$acct_mod{"$nas->{NAS_TYPE}"} = $ACCT{$nas->{NAS_TYPE}}->new($db, \%conf);
}
$r = $acct_mod{"$nas->{NAS_TYPE}"}->accounting($RAD, $nas);
}
else {
$r = $acct_mod{"default"}->accounting($RAD, $nas);
}
#if(defined($ACCT{$nas->{NAS_TYPE}})) {
# require $ACCT{$nas->{NAS_TYPE}} . ".pm";
# $ACCT{$nas->{NAS_TYPE}}->import();
# $Acct = $ACCT{$nas->{NAS_TYPE}}->new($db, \%conf);
#
#}
#else {
# require Acct;
# Acct->import();
# $Acct = Acct->new($db, \%conf);
# $r = $Acct->accounting($RAD, $nas);
#}
if ($Acct->{errno}) {
access_deny("$RAD->{USER_NAME}", "[$r->{errno}] $r->{errstr}", $nas->{NAS_ID});
}
return $r;
}
#*******************************************************************
# access_deny($user, $message);
#*******************************************************************
sub access_deny {
my ($user, $message, $nas_num) = @_;
log_print('LOG_WARNING', "ACCT [$user] NAS: $nas_num $message");
return 1;
}
1