#!/usr/bin/perl #!/usr/bin/perl ############################################################# ############################################################# # # # Perl Script for Radius Accounting # Perl Script for Radius Accounting # Switzernet(c)2011 # Switzernet(c)2011 # # ############################################################# ############################################################# # my modules # my modules use strict; use strict; use warnings; use warnings; use Asterisk::Manager; use Asterisk::Manager; use Sys::Syslog; use Sys::Syslog; use POSIX; use POSIX; use Config::IniFiles; use Config::IniFiles; use Authen::Radius; use Authen::Radius; use DBI; use DBI; use Switch; use Switch; use threads; use threads; use threads::shared; use threads::shared; #Enable debug #Enable debug use constant DEBUG => 0; use constant DEBUG => 0; > use Data::Dumper; > local $Data::Dumper::Indent = 0; > > #WARNING Variables set by AGI are not correctly read from thi > ############################################################# ############################################################# # Setting # Setting my $lock_file = '/var/run/ast-rad-acc.pid'; my $lock_file = '/var/run/ast-rad-acc.pid'; my $lock_control = '/var/run/ast-control.pid'; my $lock_control = '/var/run/ast-control.pid'; my $runas_user = 'root'; my $runas_user = 'root'; my $monitor_dir = '/var/spool/asterisk/monitor'; my $monitor_dir = '/var/spool/asterisk/monitor'; my $config_dir = '/etc/astrad/config'; my $config_dir = '/etc/astrad/config'; ############################################################# ############################################################# # Globals # Globals my %channels; my %channels; my ($ast_hostname,$ast_username,$ast_password); my ($ast_hostname,$ast_username,$ast_password); my ($rad_serv, $rad_sec, $nas_ip); my ($rad_serv, $rad_sec, $nas_ip); my ($DB_NAME_Rad,$DB_HOST_Rad,$DB_USER_Rad,$DB_PASS_Rad,$dbh_ my ($DB_NAME_Rad,$DB_HOST_Rad,$DB_USER_Rad,$DB_PASS_Rad,$dbh_ my ($CustomerType,$lconf,$astman,$ast_connected,$thr); my ($CustomerType,$lconf,$astman,$ast_connected,$thr); my $t_event : shared; my $t_event : shared; > my @event_list; ############################################################# ############################################################# # Initialization # Initialization ############################################################# ############################################################# # Check if already running # Check if already running # # if( -e $lock_file ) { if( -e $lock_file ) { open(PID,$lock_file); open(PID,$lock_file); my $pid=; my $pid=; close PID; close PID; chomp $pid; chomp $pid; if( !-e "/proc/$pid" ) { if( !-e "/proc/$pid" ) { print STDERR "Lock file present, but no proce print STDERR "Lock file present, but no proce die "Can't delete lock file $lock_file\n" if die "Can't delete lock file $lock_file\n" if print STDERR "Lock file has been removed.\n"; print STDERR "Lock file has been removed.\n"; } else { } else { die "Lockfile present, another copy is punnin die "Lockfile present, another copy is punnin } } } } load_config(); load_config(); my ($name, $passwd, $uid, $gid) = getpwnam($runas_user) or di my ($name, $passwd, $uid, $gid) = getpwnam($runas_user) or di ############################################################# ############################################################# # set C locale # set C locale POSIX::setlocale(LC_ALL, "C"); POSIX::setlocale(LC_ALL, "C"); ############################################################# ############################################################# # Become daemon # Become daemon my $pid; my $pid; if( !defined($pid = fork()) ) { if( !defined($pid = fork()) ) { die "cannot fork: $!"; die "cannot fork: $!"; } elsif ($pid) { } elsif ($pid) { # Create lockfile, and finish parent process # Create lockfile, and finish parent process # # open(PID, "> $lock_file") || die "ast-rad-acc.pl: Una open(PID, "> $lock_file") || die "ast-rad-acc.pl: Una print PID "$pid"; print PID "$pid"; close PID; close PID; chown $uid, $gid, $lock_file; chown $uid, $gid, $lock_file; exit; exit; } else { } else { # daemon # daemon setpgrp(); setpgrp(); select(STDERR); $| = 1; select(STDERR); $| = 1; select(STDOUT); $| = 1; select(STDOUT); $| = 1; openlog('ast-rad-acc', 'cons,pid', 'daemon'); openlog('ast-rad-acc', 'cons,pid', 'daemon'); syslog('notice', "Ast-Rad ast-rad-acc: accounting for syslog('notice', "Ast-Rad ast-rad-acc: accounting for } } ############################################################# ############################################################# # Install signall handler # Install signall handler $SIG{INT} = \&safe_exit; $SIG{INT} = \&safe_exit; $SIG{QUIT} = \&safe_exit; $SIG{QUIT} = \&safe_exit; $SIG{TERM} = \&safe_exit; $SIG{TERM} = \&safe_exit; $SIG{HUP} = \&load_config; $SIG{HUP} = \&load_config; ############################################################# ############################################################# # Drop privileges # Drop privileges setuid($uid); setuid($uid); $< = $uid; $< = $uid; $> = $uid; $> = $uid; ############################################################# ############################################################# # Signal Handlers # Signal Handlers sub safe_exit { sub safe_exit { my($sig) = @_; my($sig) = @_; syslog('crit', "Ast-Rad: Caught a SIG$sig - shutting down syslog('crit', "Ast-Rad: Caught a SIG$sig - shutting down $astman->disconnect if $ast_connected; $astman->disconnect if $ast_connected; $dbh_Rad->disconnect if $Rad_connected; $dbh_Rad->disconnect if $Rad_connected; unlink $lock_file or syslog('crit', "Ast-Rad: Unable to c unlink $lock_file or syslog('crit', "Ast-Rad: Unable to c closelog(); closelog(); exit; exit; } } ############################################################# ############################################################# # FUNCTION # FUNCTION ############################################################# ############################################################# # Load config # Load config sub load_config { sub load_config { my $conf=Config::IniFiles->new(-file => "$config_dir/swit my $conf=Config::IniFiles->new(-file => "$config_dir/swit return 0 if !defined $conf ; return 0 if !defined $conf ; $rad_serv = $conf->val('MASTER_RD','RADIUS_SERVER'); $rad_serv = $conf->val('MASTER_RD','RADIUS_SERVER'); $rad_sec = $conf->val('MASTER_RD','RADIUS_SECRET'); $rad_sec = $conf->val('MASTER_RD','RADIUS_SECRET'); $nas_ip = $conf->val('GLOBAL','NAS_IP'); $nas_ip = $conf->val('GLOBAL','NAS_IP'); $DB_NAME_Rad = $conf->val('ASTER_DB','DB_NAME'); $DB_NAME_Rad = $conf->val('ASTER_DB','DB_NAME'); $DB_HOST_Rad = $conf->val('ASTER_DB','DB_HOST'); $DB_HOST_Rad = $conf->val('ASTER_DB','DB_HOST'); $DB_USER_Rad = $conf->val('ASTER_DB','DB_USER'); $DB_USER_Rad = $conf->val('ASTER_DB','DB_USER'); $DB_PASS_Rad = $conf->val('ASTER_DB','DB_PASS'); $DB_PASS_Rad = $conf->val('ASTER_DB','DB_PASS'); $ast_hostname = $conf->val('Manager','AMI_PERMIT'); $ast_hostname = $conf->val('Manager','AMI_PERMIT'); $ast_username = $conf->val('Manager','AMI_USER'); | $ast_username = $conf->val('Manager','AMI_USER2'); $ast_password = $conf->val('Manager','AMI_SECRET'); | $ast_password = $conf->val('Manager','AMI_SECRET2'); return 1; return 1; } } ############################################################# ############################################################# # sample '09:16:05 GMT Sat Dec 11 2004' # sample '09:16:05 GMT Sat Dec 11 2004' sub format_date_gmt { sub format_date_gmt { my ($date) = @_; my ($date) = @_; return strftime "%H:%M:%S GMT %a %b %e %Y", gmtime($date) return strftime "%H:%M:%S GMT %a %b %e %Y", gmtime($date) } } ############################################################# ############################################################# # sample '2004-12-11 09:16:05' # sample '2004-12-11 09:16:05' sub format_date_sql { sub format_date_sql { my ($date) = @_; my ($date) = @_; if ($date eq 0) { if ($date eq 0) { return "NULL"; return "NULL"; } else { } else { return strftime("%Y-%m-%d %H:%M:%S", localtime($date) return strftime("%Y-%m-%d %H:%M:%S", localtime($date) } } } } ############################################################# ############################################################# # Astrad Rad. DB connect # Astrad Rad. DB connect sub Rad_connect { sub Rad_connect { my $cop=0; my $cop=0; $Rad_connected = 1; $Rad_connected = 1; while( 1 ) { while( 1 ) { $cop++; $cop++; $dbh_Rad = DBI->connect_cached("DBI:mysql:$DB_NAME_Rad;ho $dbh_Rad = DBI->connect_cached("DBI:mysql:$DB_NAME_Rad;ho if( $dbh_Rad ) { if( $dbh_Rad ) { $Rad_connected = 1; $Rad_connected = 1; $cop=0; $cop=0; syslog('info', 'Ast-Rad: Connected to Astrad Rad. DB! syslog('info', 'Ast-Rad: Connected to Astrad Rad. DB! return 1; return 1; } else { } else { if ($Rad_connected) { if ($Rad_connected) { syslog('err', 'Ast-Rad: Could not connect to syslog('err', 'Ast-Rad: Could not connect to $cop=1; $cop=1; } } $Rad_connected = 0; $Rad_connected = 0; syslog('info', "Ast-Rad: Connection to Astrad Rad syslog('info', "Ast-Rad: Connection to Astrad Rad $cop++ if $cop; $cop++ if $cop; return 0 if ($cop>=3); return 0 if ($cop>=3); } } sleep 1; sleep 1; } } } } ############################################################# ############################################################# # Insert into the Failed radius packets Table # Insert into the Failed radius packets Table sub Failed_radius_packet { sub Failed_radius_packet { my (%data) = @_; | my (%data) = @_; return 0 if (!Rad_connect()); | return 0 if (!Rad_connect()); $data{'CDR(CustomerType)'}="" if (!defined($data{'CDR(Cus | $data{'CDR(CustomerType)'}="" if (!defined($data{'CDR(Custo my $request="INSERT INTO radius_packets_Failed ( | my $request="INSERT INTO radius_packets_Failed (" h323_connect_time, h323_disconnect_time, acct | ."h323_connect_time, h323_disconnect_time, ac called_station_id, call_id, h323_setup_time, | ."called_station_id, call_id, h323_setup_time VALUES | ."last_send, send_counter, status) " ('".format_date_sql($data{'LINK_START'})."',' | ."VALUES " '$data{'H323_disconnect_cause'}','$data{'NAS_ | ."('".$data{'H323_connect_time'}."','".$data{ '".format_date_sql($data{'CALL_START'})."','$ | ."','".$data{'nas_ip_address'}."','".$data{'u '".format_date_sql($data{'reception_date'})." | ."','".$data{'call_id'}."','".$data{'H323_set > ."','".$data{'creation_date'}."','".$data{'re my $sth = $dbh_Rad->prepare($request); my $sth = $dbh_Rad->prepare($request); if ($sth->execute()) { if ($sth->execute()) { $sth->finish; $sth->finish; syslog('info', "Ast-Rad: Request = $request") if (DEB syslog('info', "Ast-Rad: Request = $request") if (DEB return 1; return 1; } } return 0; return 0; } } ############################################################# ############################################################# # thread control # thread control sub AMI_control { sub AMI_control { syslog('info', 'Ast-Rad: Thread: Start AMI Control') if (DEBU syslog('info', 'Ast-Rad: Thread: Start AMI Control') if (DEBU my ($l_event,$cop) = (0,0); my ($l_event,$cop) = (0,0); while ( 1 ) { while ( 1 ) { $l_event = time(); $l_event = time(); syslog('info', "Ast-Rad: Thread: Time Events -> Last = $t syslog('info', "Ast-Rad: Thread: Time Events -> Last = $t > #TODO if connection to asterisk is lost the script should if ($l_event - $t_event > 400) { if ($l_event - $t_event > 400) { syslog('crit', "Ast-Rad: Thread: Asterisk PBX is prob syslog('crit', "Ast-Rad: Thread: Asterisk PBX is prob safe_exit(); safe_exit(); } } $cop=0 if ($l_event - $t_event < 4); $cop=0 if ($l_event - $t_event < 4); $cop++; $cop++; syslog('info', "Ast-Rad: Thread: AMI Control sleep $cop") syslog('info', "Ast-Rad: Thread: AMI Control sleep $cop") sleep 2; sleep 2; } } } } ############################################################# ############################################################# # AMI connect # AMI connect sub AMI_connect { sub AMI_connect { $astman = new Asterisk::Manager; $astman = new Asterisk::Manager; $astman->user($ast_username); $astman->user($ast_username); $astman->secret($ast_password); $astman->secret($ast_password); $astman->host($ast_hostname); $astman->host($ast_hostname); $t_event = time(); $t_event = time(); my $cop=0; my $cop=0; $ast_connected = 1; $ast_connected = 1; while( 1 ) { while( 1 ) { $cop++; $cop++; if( $astman->connect ) { if( $astman->connect ) { $ast_connected = 1; $ast_connected = 1; $cop=0; $cop=0; syslog('info', 'Ast-Rad: Connected to Asterisk!') if syslog('info', 'Ast-Rad: Connected to Asterisk!') if $thr = threads->new(\&AMI_control); $thr = threads->new(\&AMI_control); $astman->setcallback('DEFAULT', \&status_callback); $astman->setcallback('DEFAULT', \&status_callback); eval { $astman->eventloop; }; eval { $astman->eventloop; }; } } else { else { if ($ast_connected) { if ($ast_connected) { syslog('err', 'Ast-Rad: Could not connect to Aste syslog('err', 'Ast-Rad: Could not connect to Aste $cop=1; $cop=1; } } $ast_connected = 0; $ast_connected = 0; syslog('info', "Ast-Rad: SLEEP $cop"); syslog('info', "Ast-Rad: SLEEP $cop"); $cop++ if $cop; $cop++ if $cop; return 0 if ($cop>=3); return 0 if ($cop>=3); } } sleep 1; sleep 1; } } } } ############################################################# ############################################################# # # sub status_callback { sub status_callback { my (%event) = @_; | my (%unfiltered_event) = @_; return unless defined(%event); | my $status = 0; $t_event = time(); | return if not (%unfiltered_event); foreach (keys %event) { | $t_event = time(); syslog('debug', "$_: ". $event{$_} . "\n" ) | foreach (keys %unfiltered_event) { } | next if ($_ eq ''); syslog('debug', "\n") if (DEBUG); | push(@event_list, [$_, $unfiltered_event{$_}]); | } for ($event{'Event'}) { | my @event_pos; $event{'CallerIDNum'} = $1 if defined $event{ | for my $i ( 0 .. $#event_list) { | push(@event_pos, $i) if ($event_list[$i][0] eq 'Event'); /Newchannel/i && do { | } syslog('crit', "Event\n") if (DEBUG); | #Remove lines prior to first event foreach (keys %event) { | my $offset=0; syslog('crit', "$_ => $event{ | if ($event_pos[0] != 0) { } | shift(@event_list); | $offset++; $channels{$event{'Channel'}} = { | } 'CALLERID' => $event{'CallerI | while ($#event_pos > 0) { 'UNIQUEID' => $event{'Uniquei | my @filtered_event; 'CALL_START' => time(), | print "\n" if (DEBUG); 'CALL_ORIGIN' => 'originate', | for (my $i = 0; $i < ($event_pos[1]-$offset) ; $i++) { 'LINK_START' => time(), | my $addtolist = 1; 'LINK_END' => time(), | $addtolist = 0 if ($event_list[0][1] eq 'PeerStatus'); 'CALL_TYPE' => 'VoIP', | push(@filtered_event, [$event_list[0][0],$event_list[0] 'CALL_PROTOCOL' => 'sipv2', | print "['".$event_list[0][0]."','".$event_list[0][1]."' 'CALL_ID' => $event{'Uniqueid | shift(@event_list); 'RADIUS_Server' => $rad_serv, | } 'RADIUS_Secret' => $rad_sec, | if ($filtered_event[0][0] eq 'Event') { 'NAS_IP_Address' => $nas_ip, | print "Executing event in filtered_event ".$filtered_ev 'Remoteip' => $nas_ip | switch ($filtered_event[0][1]) { }; | case "Newchannel" { | #['Event','Newchannel'] $channels{$event{'Channel'}}{'Remotei | #['Privilege','call,all'] }; | #['Channel','SIP/41215500331-00000013'] | #['Context','fromaccount'] /Newexten/i && do { | #['CallerIDName','41215500331'] if( defined $event{'Application'} && | #['Uniqueid','91.121.122.64-1324372616.19'] my ( $_var, $_val ) = split(/ | #['ChannelState',''] if($_var eq 'CDR(accountcode) | #['ChannelStateDesc','Down'] $channels{$event{'Cha | #['CallerIDNum','41215500331'] } else { | #['Value','sip:41215500331@192.168.1.121:5060'] $channels{$event{'Cha | $channels{$filtered_event[2][1]} = { } | 'CALLERID' => $filtered_event[8][1], | 'UNIQUEID' => $filtered_event[5][1], #if($_var eq 'CDR(CustomerTyp | 'CALL_START' => time(), # $CustomerType= $_val | 'LINK_START' => time(), #} | 'LINK_END' => time(), } | 'CALL_TYPE' => 'VoIP', | 'CALL_PROTOCOL' => 'sipv2', if (defined $event{'Extension'} && $e | 'CALL_ID' => $filtered_event[5][1], $channels{$event{'Channel'}}{ | 'RADIUS_Server' => $rad_serv, } | 'RADIUS_Secret' => $rad_sec, }; | 'NAS_IP_Address' => $nas_ip, | 'NAS-Port' => '5060', /^Link$/i && do { | 'Remoteip' => $nas_ip my $channel1 = $event{'Channel1'}; | }; my $channel2 = $event{'Channel2'}; | $channels{$filtered_event[2][1]}{'Remoteip'} = $1 i return unless $channels{$channel1}; | } $channels{$channel1}{'LINK_START'} = | case "Newstate" { $channels{$channel2}{'LINK_START'} = | #['Event','Newstate'] | #['Privilege','call,all'] syslog('info', 'Link without uniqueid | #['Channel','SIP/41215500331-00000013'] syslog('info', 'Link without channeld | #['CallerIDName','41215500331'] syslog('info', 'Link on undefined cha | #['Uniqueid','91.121.122.64-1324372616.19'] | #['ChannelStateDesc','Up'] return unless($channel1 && $channels{ | #['ChannelState','6'] }; | #['CallerIDNum','41215500331'] | } /Unlink/i && do { | case "Newexten" { my $channel = $event{'Channel1'}; | #['Event','Newexten'] return unless $channels{$channel}; | #['Privilege','dialplan,all'] $channels{$event{'Channel1'}}{'LINK_E | #['Channel','SIP/41215500331-00000011'] $channels{$event{'Channel2'}}{'LINK_E | #['Context','fromaccount'] | #['Extension','0215502419'] syslog('info', 'UnLink without unique | #['Uniqueid','91.121.122.64-1324369709.17'] syslog('info', 'UnLink without channe | #['Application','Set'] syslog('info', 'UnLink on undefined c | #['AppData','CDR(CustomerType)=SipAuth'] | #['Priority','2'] return unless($channel && $channels{$ | if (defined $filtered_event[7][1] && $filtered_even }; | my $channel = $filtered_event[2][1]; | $channels{$channel}{'DNID'} = $1 if (defined $fil /Hangup/i && do { | my ( $_var, $_val ) = split(/=/, $filtered_event[ my $channel = $event{'Channel'}; | if ( $_val ne '') { return unless $channels{$channel}; | if($_var eq 'CDR(accountcode)') { $channels{$channel}{'CALL_END'} = tim | $channels{$channel}{'ACCOUNTCODE'} = $_val; $channels{$channel}{'CAUSE'} = 16; | print '$channels{'.$channel.'}{ACCOUNTCODE} = $channels{$channel}{'CAUSE'} = $event | } else { $channels{$channel}{'CAUSE'} = 0 if ! | $channels{$channel}{$_var} = $_val; | print '$channels{'.$channel.'}{'.$_var.'} = ' send_acc('Stop',%{$channels{$channel} | if ( $_var eq 'H323_ID') { delete $channels{$channel}; | syslog('debug', "H323 dec: ".$channels{$cha }; | $channels{$channel}{'H323_ID'}=sprintf("%08 | syslog('debug', "H323 hex: ".$channels{$cha /Newstate/i && do { | } if( defined $event{'State'} && $event | } send_acc('Start',%{$channels{ | } } | } }; | } | case "NewAccountCode" { /Dial/i && do { | #['Event','NewAccountCode'] my $channel1 = $event{'Source'}; | #['Privilege','call,all'] my $channel2 = $event{'Destination'}; | #['Channel','SIP/91.121.151.75-00000014'] syslog('crit', "DIAL: $channel1 -> $c | #['Uniqueid','91.121.122.64-1324372618.20'] | #['Channel2','SIP/91.121.151.75-00000014'] syslog('crit', "H323 dec: $channels{$ | #['Bridgestate','Link'] # my ($a,$b,$c,$d) = ($1,$2,$3,$4) if $ | } # $channels{$channel1}{'H323_ID'}=sprin | case "Link" { $channels{$channel1}{'H323_ID'}=sprin | #Link does not seem to appear in the new version of asterisk syslog('crit', "H323 hex: $channels{$ | # my $channel1 = $event{'Channel1'}; | # my $channel2 = $event{'Channel2'}; $channels{$channel1}{'VLEG'} = $chann | # return unless $channels{$channel1}; $channels{$channel1}{'CALL_ORIGIN'} = | # $channels{$channel1}{'LINK_START'} = # $channels{$channel1}{'CALL_ID'} = $ch | # $channels{$channel2}{'LINK_START'} = $channels{$channel1}{'CALL_ID'} = $ev | # $channels{$channel1}{'ACCOUNTCODE'} = | # syslog('info', 'Link without uniqueid | # syslog('info', 'Link without channeld # $channels{$channel2}{'CLEG'} = $chann | # syslog('info', 'Link on undefined cha $channels{$channel2}{'CALL_ID'} = $ch | # $channels{$channel2}{'ACCOUNTCODE'} = | # return unless($channel1 && $channels{ $channels{$channel2}{'CALLERID'} = $c | } $channels{$channel2}{'DNID'} = $chann | case "VarSet" { $channels{$channel2}{'H323_ID'} = $ch | #['Event','VarSet'] }; | #['Privilege','dialplan,all'] | #['Channel','SIP/41215500331-00000011'] /Shutdown/i && do { | #['Uniqueid','91.121.122.64-1324369709.17'] syslog('info', "Asterisk Shutdown"); | #['Variable','SIPURI'] safe_exit(); | #['Value','astrad.switzernet.com'] | if (defined $filtered_event[5][0] && defined $filte }; | $channels{$filtered_event[2][1]}{$filtered_event | print '$channels{'.$filtered_event[2][1].'}{'.$f /Reload/i && do { | } syslog('info', "Asterisk Reload"); | } load_config(); | case "Bridge" { }; | #['Event','Bridge'] | #['Privilege','call,all'] } | #['Uniqueid2','91.121.122.64-1324372618.20'] > #['Channel1','SIP/41215500331-00000013'] > #['Bridgetype','core'] > #['Uniqueid1','91.121.122.64-1324372616.19'] > #['CallerID1','41215500331'] > #['CallerID2','0215502419'] > #['Value','SIP/91.121.151.75-00000014'] > if (defined $filtered_event[8][1]) { > my $channel1 = $filtered_event[3][1]; > my $channel2 = $filtered_event[8][1]; > $channels{$channel1}{'LINK_START'} = time(); > $channels{$channel1}{'CHANNEL2'} = $channel2; > $channels{$channel2}{'CHANNEL1'} = $channel1; > $channels{$channel2}{'LINK_START'} = time(); > $channels{$channel1}{'CALL_ORIGIN'} = 'an > print 'Call '.$channel1." answered. Sendi > send_acc('Start',%{$channels{$channel1}}); > } > } > case "Unlink" { > #['Event','Unlink'] > #['Privilege','call,all'] > #['Uniqueid2','91.121.122.64-1324372618.20'] > #['Channel1','SIP/41215500331-00000013'] > #['Uniqueid1','91.121.122.64-1324372616.19'] > #['CallerID1','41215500331'] > #['CallerID2','0215502419'] > #['Value','9'] > my $channel = $filtered_event[3][1]; > last unless $channels{$channel}; > $channels{$channel}{'LINK_END'} = time(); > $channels{$channels{$channel}{'CHANNEL2'}}{'LINK_EN > } > case "Hangup" { > #['Event','Hangup']; > #['Privilege','call,all']; > #['Channel','SIP/91.121.117.76-00000060']; > #['Cause','16']; > #['ConnectedLineName','41215500331']; > #['ConnectedLineNum','41215500331']; > #['CallerIDName','']; > #['Uniqueid','91.121.122.64-1324045271.96']; > #['CallerIDNum','0215502419']; > #['Cause-txt','Normal Clearing']; > my $channel = $filtered_event[2][1]; > $channel = $channels{$channel}{'CHANNEL1'} if (defi > last if !defined $channels{$channel}; > last if !defined $channels{$channel}{'H323_ID'}; > $channels{$channel}{'CALL_END'} = time(); > $channels{$channel}{'CAUSE'} = 0; > $channels{$channel}{'CAUSE'} = $filtered_event[3][1 > if (defined($channels{$channel}{'CALL_ORIGIN'}) && > if (defined $channels{$channel}{'CHANNEL2'}) { > print 'Call '.$channel."->".$channels{$channel} > delete $channels{$channels{$channel}{'CHANNEL2' > delete $channels{$channels{$channel}{'CHANNEL2' > } else { > print 'Call '.$channel." disconnected. Sending > } > send_acc('Stop',%{$channels{$channel}}); > } > $channels{$channel}{'CALL_ORIGIN'} = 'originate'; > print 'Call '.$channel." disconnected. Sending ".$c > send_acc('Stop',%{$channels{$channel}}); > delete $channels{$channel}{'CHANNEL2'}; > delete $channels{$channel}; > } > case "Dial" { > #['Event','Dial']; > #['DestUniqueID','91.121.122.64-1324045271.96']; > #['Privilege','call,all']; > #['Destination','SIP/91.121.117.76-00000060']; > #['Channel','SIP/41215500331-0000005f']; > #['SubEvent','Begin']; > #['Dialstring','41215502419@91.121.117.76']; > #['ConnectedLineName','']; > #['ConnectedLineNum','']; > #['CallerIDName','41215500331']; > #['UniqueID','91.121.122.64-1324045269.95']; > #['CallerIDNum','41215500331']; > if ($filtered_event[3][0] ne 'Destination' || $filt > print "End dial\n" if (DEBUG); > last; > } > my $channel1 = $filtered_event[4][1]; > my $channel2 = $filtered_event[3][1]; > syslog('debug', "DIAL: $channel1 -> $channel2") if > $channels{$channel1}{'VLEG'} = $channel2; > $channels{$channel1}{'CALL_ORIGIN'} = 'originate'; > $channels{$channel1}{'ACCOUNTCODE'} = $channels{$ch > $channels{$channel2}{'ACCOUNTCODE'} = $channels{$ch > $channels{$channel1}{'CALL_ID'} = $filtered_eve > $channels{$channel2}{'CALL_ID'} = $channels{$ch > $channels{$channel2}{'CALLERID'} = $channels{$ch > $channels{$channel2}{'DNID'} = $channels{$ch > $channels{$channel2}{'H323_ID'} = $channels{$ch > $channels{$channel1}{'LINK_START2'} = time(); > $channels{$channel2}{'LINK_START2'} = time(); > print "Sending ".$channels{$channel1}{'CALL_ORIGIN' > send_acc('Start',%{$channels{$channel1}}); > } > case "Shutdown" { > syslog('info', "Asterisk Shutdown"); > safe_exit(); > } > case "Reload" { > syslog('info', "Asterisk Reload"); > load_config(); > } > } > } > undef @filtered_event; > shift(@event_pos); > } > return; } } ############################################################# ############################################################# # # sub send_acc { sub send_acc { my ($acc_type,%cdr) = @_; my ($acc_type,%cdr) = @_; my $cause="null"; my $cause="null"; my $remote; my $remote; my $duration=0; my $duration=0; my $date=0; my $date=0; return if $cdr{'H323_ID'} =~ /(\d+)-(\d+)-(\d+)-(\d+) | return if $cdr{'H323_ID'} =~ /(\d+)-(\d+)-(\d+)-(\d+) | return if !defined $cdr{'CDR(CustomerType)'}; my $r = new Authen::Radius(Host => $cdr{'RADIUS_Serve | $cdr{'CALL_ORIGIN'} = 'originate' if( !defined $cdr{' > my $r = new Authen::Radius(Host => $cdr{'RADIUS_Serve if( !defined $r ) { if( !defined $r ) { syslog('crit', "RADIUS host $cdr{'RADIUS_Serv syslog('crit', "RADIUS host $cdr{'RADIUS_Serv > print "RADIUS host ".$cdr{'RADIUS_Server'}." return; return; } } $r->clear_attributes(); $r->clear_attributes(); #print ("\nSend Acc : Type=$acc_type H323_ID=$cdr{'H3 | return if ($acc_type ne 'Start' && $acc_type ne 'Stop switch($acc_type) { | print ("Sending Radius ".$cdr{'CALL_ORIGIN'}."->".$ac case 'Start' { | my $CSI = $cdr{'DNID'}; $r->add_attributes ( | # $CSI = $cdr{'PBCLD'} if ($cdr{'CALL_ORIGIN'} eq "ori { Name => 'Acct-Status-Type', | $CSI = $cdr{'VDNID'} if ($cdr{'CALL_ORIGIN'} eq "orig { Name => 'h323-call-origin', < ); < } < case 'Stop' { < # TODO why? < $cause = $cdr{'CAUSE'}-6; < $cause = 0 if $cause<0; < < $r->add_attributes ( < { Name => 'Acct-Status-Type', < { Name => 'h323-call-origin', < { Name => 'h323-connect-time' < { Name => 'h323-disconnect-ti < { Name => 'Acct-Session-Time' < { Name => 'h323-disconnect-ca < ); < $duration=$cdr{'LINK_END'} - $cdr{'LI < } else { < syslog('crit', "Bad ACC_STATUS_TYPE s < return; < } < } < < $r->add_attributes ( $r->add_attributes ( { Name => 'h323-call-type', Value => $cdr{'CA | { Name => 'Acct-Status-Type', Value => $acc_type { Name => 'Cisco-AVPair', Value => "session-p | { Name => 'h323-call-origin', Value => $cdr{'CALL { Name => 'NAS-IP-Address', Value => $cdr{'NA | { Name => 'h323-call-type', Value => $cdr{'CALL { Name => 'User-Name', Value => $cdr{'ACCOUNT | { Name => 'Cisco-AVPair', Value => "h323-sess { Name => 'Calling-Station-Id', Value => $cdr | { Name => 'NAS-IP-Address', Value => $cdr{'NAS_ { Name => 'Called-Station-Id', Value => $cdr{ | { Name => 'NAS-Port', Value => $cdr{'NAS- { Name => 'Cisco-AVPair', Value => "call-id=$ | { Name => 'User-Name', Value => $cdr{'ACCO { Name => 'h323-setup-time', Value => format_ | { Name => 'Calling-Station-Id', Value => $cdr{'CALL { Name => 'Cisco-AVPair', Value => "h323-conf | { Name => 'Called-Station-Id', Value => $CSI }, > { Name => 'Cisco-AVPair', Value => "call-id=" > { Name => 'Cisco-AVPair', Value => "Acct-Sess > { Name => 'Cisco-AVPair', Value => "Acct-Dela > { Name => 'h323-setup-time', Value => format_dat > { Name => 'Cisco-AVPair', Value => "h323-conf ); ); > if ($acc_type eq 'Stop') { > # TODO why? > $cause = $cdr{'CAUSE'}-6; > $cause = 0 if $cause<0; > $r->add_attributes ( > { Name => 'h323-disconnect-time', Value => form > { Name => 'Acct-Session-Time', Value => $cdr{'L > { Name => 'h323-disconnect-cause', Value => $ca > #TODO h323-voice-quality > ); > $r->add_attributes ( { Name => 'h323-ivr-out', Va > $duration=$cdr{'LINK_END'} - $cdr{'LINK_START'}; > } if (defined $cdr{'Remoteip'} && $cdr{'Remoteip'} ne $ | $remote = $cdr{'NAS_IP_Address'}; $r->add_attributes ( { Name => 'h323-remote-a | if ($cdr{'CALL_ORIGIN'} eq "originate") { $remote=$cdr{'Remoteip'}; | if ($cdr{'ROUTEIP'} eq $cdr{'NAS_IP_Address'}) { } else { | $remote = 'sip-ua'; if ($cdr{'CALL_ORIGIN'} eq "originate") { | } else { $r->add_attributes ( { Name => 'h323- | $remote = $cdr{'ROUTEIP'}; $remote='sip-ua'; | } } else { | $r->add_attributes ( { Name => 'h323-ivr-out', Valu $r->add_attributes ( { Name => 'h323- | $cdr{'Dial_Info'} =~ m/L\((\d+):/; $remote=$cdr{'NAS_IP_Address'}; | #The maximum duration of the call is on the wrong field to an } | $r->add_attributes ( { Name => 'h323-ivr-out', } | $r->add_attributes ( { Name => 'h323-connect-time', > #TODO alert-timepoint when call starts ringing if start > } else { > $remote = $cdr{'RECVIP'}; > $r->add_attributes ( { Name => 'h323-connect-time', > $r->add_attributes ( { Name => 'Cisco-AVPair', Va > } > $r->add_attributes ( { Name => 'h323-remote-address', $date=time; $date=time; if ($acc_type eq 'Start') { if ($acc_type eq 'Start') { $r->send_packet (ACCOUNTING_REQUEST); | $r->send_packet (ACCOUNTING_REQUEST); } else { } else { $r->send_packet (ACCOUNTING_REQUEST) and my $ | $r->send_packet (ACCOUNTING_REQUEST) and my $type = | if (!defined $type) { my %data = %cdr; | my %data; $data{'Acct_Session_Time'}=$duration; | $data{'H323_setup_time'} = format_date_sql( $data{'H323_disconnect_cause'}=$cause; | $data{'H323_connect_time'} = format_date_sql( $data{'H323_remote_address'}=$remote; | $data{'H323_disconnect_time'} = format_date_sql( $data{'creation_date'}=$date; | $data{'Acct_Session_Time'} = $cdr{'LINK_END'} $data{'last_send'}=time; | $data{'H323_disconnect_cause'} = $cause; $data{'send_counter'}=1; | $data{'nas_ip_address'} = $cdr{'NAS_IP_Add | $data{'user_name'} = $cdr{'ACCOUNTCOD if (!defined $type) { | $data{'call_id'} = $cdr{'CALL_ID'}; $data{'reception_date'}=0; | $data{'H323_conf_id'} = $cdr{'H323_ID'}; $data{'STATUS'}=0; | $data{'H323_remote_address'} = $remote; syslog('crit', "Ast-Rad: No response | $data{'call_profile'} = ""; Failed_radius_packet(%data); | $data{'call_profile'} = $cdr{'CDR(Custom } else { | $data{'creation_date'} = format_date_sql( $data{'reception_date'}=time; | $data{'reception_date'} = format_date_sql( $data{'STATUS'}=1; | $data{'last_send'} = format_date_sql( syslog('crit', "Ast-Rad: Good respons | $data{'send_counter'} = 1; } | $data{'status'} = 0; > $data{'Calling-Station-Id'} = $cdr{'CALLERID'} > $data{'Called-Station-Id'} = $CSI; > $data{'reception_date'}=0; > $data{'STATUS'}=0; > syslog('crit', "Ast-Rad: No response from RADIUS > print "Ast-Rad: No response from RADIUS server!\n > #TODO sometimes it adds several times the same call > Failed_radius_packet(%data); > } else { > print "Ast-Rad: Ast-Rad: Good response from RADIU > syslog('crit', "Ast-Rad: Good response from RADIU > } } } } } ############################################################# ############################################################# # main() # main() ############################################################# ############################################################# # Load Radius dictionary # Load Radius dictionary Authen::Radius->load_dictionary; Authen::Radius->load_dictionary; $lconf=0; $lconf=0; while ( 1 ) { while ( 1 ) { if (!$lconf && !load_config()) { if (!$lconf && !load_config()) { syslog('crit', "Ast-Rad: Config file error!"); syslog('crit', "Ast-Rad: Config file error!"); next; next; } } $lconf=1; $lconf=1; if (!AMI_connect()) { if (!AMI_connect()) { syslog('crit', "Ast-Rad: Error in Astrerisk Manager c syslog('crit', "Ast-Rad: Error in Astrerisk Manager c $lconf=0; $lconf=0; sleep 1; sleep 1; } } } } ############################################################# ############################################################# # END # END ############################################################# #############################################################