#!/usr/bin/perl #!/usr/bin/perl ############################################################# ############################################################# # # # Perl Script for Resend lost Accouting packet to portaone Ra # Perl Script for Resend lost Accouting packet to portaone Ra # # # Modified on 110324 by yannick.vaucher@switzernet.com # Modified on 110324 by yannick.vaucher@switzernet.com # # # Switzernet(c)2011 # Switzernet(c)2011 # # ############################################################# ############################################################# # my modules # my modules use strict; use strict; use warnings; use warnings; use Sys::Syslog; use Sys::Syslog; use POSIX; use POSIX; use Config::IniFiles; use Config::IniFiles; use Authen::Radius; use Authen::Radius; use Switch; use Switch; use DBI; use DBI; use Date::Manip; use Date::Manip; use Time::Local; use Time::Local; ############################################################# ############################################################# # Setting # Setting my $lock_file = '/var/run/ast-resend-lost.pid'; my $lock_file = '/var/run/ast-resend-lost.pid'; my $runas_user = 'root'; my $runas_user = 'root'; my $config_dir = '/etc/astrad/config'; my $config_dir = '/etc/astrad/config'; ############################################################# ############################################################# # Globals # Globals my ($dbh_Rad,$Rad_connected); my ($dbh_Rad,$Rad_connected); my ($DB_NAME_Rad,$DB_HOST_Rad,$DB_USER_Rad,$DB_PASS_Rad); my ($DB_NAME_Rad,$DB_HOST_Rad,$DB_USER_Rad,$DB_PASS_Rad); my ($RADIUS_Server,$RADIUS_Secret); my ($RADIUS_Server,$RADIUS_Secret); my @select_rad; my @select_rad; my $isel =0; | my $isel = 0; | my $consecutive_failed_tries= 0; > my $request; > my $base_interval=2; #Enable debug #Enable debug use constant DEBUG => 0; use constant DEBUG => 0; ############################################################# ############################################################# # 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 } } } } 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-resend-lost.pl: Una open(PID, "> $lock_file") || die "ast-resend-lost.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-resend-lost', 'cons,pid', 'daemon'); openlog('ast-resend-lost', 'cons,pid', 'daemon'); syslog('notice', "Ast-Res: Resend lost Accounting packets syslog('notice', "Ast-Res: Resend lost Accounting packets } } ############################################################# ############################################################# # 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-Res: Caught a SIG$sig - shutting down syslog('crit', "Ast-Res: Caught a SIG$sig - shutting down $dbh_Rad->disconnect if $Rad_connected; $dbh_Rad->disconnect if $Rad_connected; unlink $lock_file or syslog('crit', "Ast-Res: Unable to c unlink $lock_file or syslog('crit', "Ast-Res: Unable to c closelog(); closelog(); exit; exit; } } ############################################################# ############################################################# # FUNCTION # FUNCTION ############################################################# ############################################################# # sample '09:16:05 GMT Sat Dec 11 2004' # sample '09:16:05 GMT Sat Dec 11 2004' sub format_date_sql_2_gmt { sub format_date_sql_2_gmt { my ($sql_date) = @_; my ($sql_date) = @_; my $date = &ParseDate($sql_date); my $date = &ParseDate($sql_date); my $gmt_date = &Date_ConvTZ($date,"","GMT"); my $gmt_date = &Date_ConvTZ($date,"","GMT"); return &UnixDate($gmt_date, "%H:%M:%S GMT %a %b %e %Y"); return &UnixDate($gmt_date, "%H:%M:%S GMT %a %b %e %Y"); } } ############################################################# ############################################################# # Load config from mysql.conf # Load config from mysql.conf 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 ; $RADIUS_Server= $conf->val('MASTER_RD','RADIUS_SERVER'); $RADIUS_Server= $conf->val('MASTER_RD','RADIUS_SERVER'); $RADIUS_Secret= $conf->val('MASTER_RD','RADIUS_SECRET'); $RADIUS_Secret= $conf->val('MASTER_RD','RADIUS_SECRET'); $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'); return 1; return 1; } } ############################################################# ############################################################# > # sample '2004-12-11 09:16:05' > sub format_date_sql { > my ($date) = @_; > > if ($date eq 0) { > return "NULL"; > } else { > return strftime("%Y-%m-%d %H:%M:%S", localtime($date) > } > } > ############################################################# # Astrad Radius DB connect # Astrad Radius 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_Ra $dbh_Rad = DBI->connect_cached("DBI:mysql:$DB_NAME_Ra $DB_USER_Rad, $DB_PASS $DB_USER_Rad, $DB_PASS if( $dbh_Rad ) { if( $dbh_Rad ) { $Rad_connected = 1; $Rad_connected = 1; $cop=0; $cop=0; syslog('info', 'Ast-Res: Connected to Astrad Radi syslog('info', 'Ast-Res: Connected to Astrad Radi return 1; return 1; } else { } else { if ($Rad_connected) { if ($Rad_connected) { syslog('err', 'Ast-Res: Could not connect to syslog('err', 'Ast-Res: Could not connect to $cop=1; $cop=1; } } $Rad_connected = 0; $Rad_connected = 0; syslog('info', "Ast-Res: Connection to Astrad Rad syslog('info', "Ast-Res: Connection to Astrad Rad $cop++ if $cop; $cop++ if $cop; return 0 if ($cop>=3); return 0 if ($cop>=3); } } sleep 1; sleep 1; } } } } ############################################################# ############################################################# # Load register request from Astrad Reg. DB # Load register request from Astrad Reg. DB sub load_lost_rad { sub load_lost_rad { return -1 if (!Rad_connect()); return -1 if (!Rad_connect()); my $cop=0; my $cop=0; > $isel = 0; > undef @select_rad; my $request="SELECT h323_connect_time, h323_disconnect_ti my $request="SELECT h323_connect_time, h323_disconnect_ti h323_disconnect_cause, nas_ip_address, u h323_disconnect_cause, nas_ip_address, u calling_station_id, called_station_id, c calling_station_id, called_station_id, c h323_setup_time, h323_conf_id, h323_remo | h323_setup_time, h323_conf_id, h323_remo FROM radius_packets_Failed "; FROM radius_packets_Failed "; > $request .= "WHERE last_send < NOW() "; $request .= "ORDER BY id LIMIT 100;"; $request .= "ORDER BY id LIMIT 100;"; my $sth = $dbh_Rad->prepare($request); my $sth = $dbh_Rad->prepare($request); return -1 if (!$sth->execute()); return -1 if (!$sth->execute()); while (my $result = $sth->fetchrow_hashref) { while (my $result = $sth->fetchrow_hashref) { ${$select_rad[$isel]}[0] = $result->{h323_connect_ti ${$select_rad[$isel]}[0] = $result->{h323_connect_ti ${$select_rad[$isel]}[1] = $result->{h323_disconnect ${$select_rad[$isel]}[1] = $result->{h323_disconnect ${$select_rad[$isel]}[2] = $result->{acct_session_ti ${$select_rad[$isel]}[2] = $result->{acct_session_ti ${$select_rad[$isel]}[3] = $result->{h323_disconnect ${$select_rad[$isel]}[3] = $result->{h323_disconnect ${$select_rad[$isel]}[4] = $result->{nas_ip_address} ${$select_rad[$isel]}[4] = $result->{nas_ip_address} ${$select_rad[$isel]}[5] = $result->{user_name}; ${$select_rad[$isel]}[5] = $result->{user_name}; ${$select_rad[$isel]}[6] = $result->{calling_station ${$select_rad[$isel]}[6] = $result->{calling_station ${$select_rad[$isel]}[7] = $result->{called_station_ ${$select_rad[$isel]}[7] = $result->{called_station_ ${$select_rad[$isel]}[8] = $result->{call_id}; ${$select_rad[$isel]}[8] = $result->{call_id}; ${$select_rad[$isel]}[9] = $result->{h323_setup_time ${$select_rad[$isel]}[9] = $result->{h323_setup_time ${$select_rad[$isel]}[10] = $result->{h323_conf_id}; ${$select_rad[$isel]}[10] = $result->{h323_conf_id}; ${$select_rad[$isel]}[11] = $result->{h323_remote_add ${$select_rad[$isel]}[11] = $result->{h323_remote_add ${$select_rad[$isel]}[12] = $result->{id}; ${$select_rad[$isel]}[12] = $result->{id}; > ${$select_rad[$isel]}[13] = $result->{send_counter}; $isel++; $isel++; } } if (DEBUG) { if (DEBUG) { syslog('info', "Ast-Res: request = $request"); syslog('info', "Ast-Res: request = $request"); syslog('info', "Ast-Res: sth->rows = ".$sth->rows); syslog('info', "Ast-Res: sth->rows = ".$sth->rows); syslog('info', "Ast-Res: isel = $isel"); syslog('info', "Ast-Res: isel = $isel"); } } $sth->finish; $sth->finish; > return 0 if ($isel == 0); return 1; return 1; } } ############################################################# ############################################################# # Send lost radius packet to portaone server # Send lost radius packet to portaone server sub send_lost_rad { sub send_lost_rad { return 0 if (!$isel); | return 0 if ($isel == 0); my $r = new Authen::Radius(Host => $RADIUS_Server, Secret | my ($cop,$cc,$successsend)=(0,0,0); > if ($isel > 0) { > my $r = new Authen::Radius(Host => $RADIUS_Server, Secret if( !defined $r ) { if( !defined $r ) { syslog('crit', "Ast-Res: RADIUS host $RADIUS_Server E syslog('crit', "Ast-Res: RADIUS host $RADIUS_Server E return -1; return -1; } } my $request = "DELETE FROM radius_packets_Failed WHERE h3 | $request = "DELETE FROM radius_packets_Failed WHERE id IN my ($cop,$cc)=(0,0); | while ($cop < $isel && $cc == 0) { while ($cop < $isel) { < $r->clear_attributes(); $r->clear_attributes(); my $disco_str_time = ${$select_rad[$cop]}[1]; my $disco_str_time = ${$select_rad[$cop]}[1]; my ($year, $month, $day, $hour, $min, $sec) = ($disco my ($year, $month, $day, $hour, $min, $sec) = ($disco #syslog('info', 'Debug-Ast ' . $year . " " . $month . < my $disco_time = timelocal( $sec, $min, $hour, $day, my $disco_time = timelocal( $sec, $min, $hour, $day, my $delay_time = time() - $disco_time; my $delay_time = time() - $disco_time; syslog('info', "Debug-Ast: " . $delay_time . " = " . syslog('info', "Debug-Ast: " . $delay_time . " = " . $r->add_attributes ( $r->add_attributes ( { Name => 'Acct-Status-Type', Value => 'Stop' }, { Name => 'Acct-Status-Type', Value => 'Stop' }, { Name => 'h323-call-origin', Value => 'originate { Name => 'h323-call-origin', Value => 'originate { Name => 'h323-connect-time', Value => format_da { Name => 'h323-connect-time', Value => format_da { Name => 'h323-disconnect-time', Value => format { Name => 'h323-disconnect-time', Value => format { Name => 'Acct-Session-Time', Value => ${$select { Name => 'Acct-Session-Time', Value => ${$select { Name => 'h323-disconnect-cause', Value => ${$se { Name => 'h323-disconnect-cause', Value => ${$se { Name => 'h323-call-type', Value => 'VoIP' }, { Name => 'h323-call-type', Value => 'VoIP' }, { Name => 'Cisco-AVPair', Value => 'session-proto { Name => 'Cisco-AVPair', Value => 'session-proto { Name => 'NAS-IP-Address', Value => ${$select_ra { Name => 'NAS-IP-Address', Value => ${$select_ra { Name => 'User-Name', Value => ${$select_rad[$co { Name => 'User-Name', Value => ${$select_rad[$co { Name => 'Calling-Station-Id', Value => ${$selec { Name => 'Calling-Station-Id', Value => ${$selec { Name => 'Called-Station-Id', Value => ${$select { Name => 'Called-Station-Id', Value => ${$select { Name => 'Cisco-AVPair', Value => 'call-id='.${$ { Name => 'Cisco-AVPair', Value => 'call-id='.${$ { Name => 'h323-setup-time', Value => format_date { Name => 'h323-setup-time', Value => format_date { Name => 'Cisco-AVPair', Value => 'h323-conf-id= { Name => 'Cisco-AVPair', Value => 'h323-conf-id= { Name => 'h323-remote-address', Value => ${$sele { Name => 'h323-remote-address', Value => ${$sele { Name => 'Acct-Delay-Time', Value => $delay_tim { Name => 'Acct-Delay-Time', Value => $delay_tim ); ); $r->send_packet (ACCOUNTING_REQUEST) and my $type = $ $r->send_packet (ACCOUNTING_REQUEST) and my $type = $ if (defined $type) { if (defined $type) { $request = $request . "'".${$select_rad[$cop]}[10 | $request = $request . "'".${$select_rad[$cop]}[12 $cc=1; | $consecutive_failed_tries = 0; > $successsend++; > } else { > ${$select_rad[$cop]}[13]++; > ${$select_rad[$cop]}[14] = format_date_sql(ceil($ > $consecutive_failed_tries++; > $cc=-2; > my $errCode=Authen::Radius::get_error(); > my $errCodeMsg = 'Unknown'; > $errCodeMsg=$errCode." (".Authen::Radius::strerro > syslog('crit', "Ast-Res: Error ".$errCodeMsg." se > my $request2 = "UPDATE radius_packets_Failed SET > print $request2."\n" if DEBUG; > my $sth = $dbh_Rad->prepare($request2); > $sth->execute(); > $sth->finish; > undef $sth; } } $cop++; | $cop++; } } syslog('info', "Ast-Res: isel = $isel") if (DEBUG); | $isel = $cop; return 0 if (!$cc); < $request = substr($request,0,-1) . " );"; $request = substr($request,0,-1) . " );"; syslog('info', "Ast-Res: request = $request") if (DEBUG); syslog('info', "Ast-Res: request = $request") if (DEBUG); > } else { > $successsend++; > $isel = 0 - $isel; > } > if ($successsend > 0) { > print $request."\n" if DEBUG; my $sth = $dbh_Rad->prepare($request); my $sth = $dbh_Rad->prepare($request); if ($sth->execute()) { if ($sth->execute()) { $sth->finish; | $sth->finish; return 1; | return $cc; } } return -1; | syslog('crit', "Ast-Res: Error deleting from table ".$sth > syslog('info', "Ast-Res: request = ".$request); > return -3; > } > return -1; } } ############################################################# ############################################################# # main() # main() ############################################################# ############################################################# > #TODO: Add fields to mysql of last attempt and do a select us > #TODO: Verify if the h323 id already exists before adding it > #TODO: Verify in which conditions we have repeated calls in t > Authen::Radius->load_dictionary; Authen::Radius->load_dictionary; load_config(); load_config(); while ( 1 ) { | my $sleep_time = 0; switch (load_lost_rad()) { | LINE: while ( 1 ) { case 1 { syslog('info', "Ast-Res: Successfully selec < case 0 { syslog('info', "Ast-Res: Empty selection fr < case -1 { syslog('crit', "Ast-Res: Error in Radius My < } < if ($isel == 0) { if ($isel == 0) { undef @select_rad; | switch (load_lost_rad()) { sleep 5; | case 1 { syslog('info', "Ast-Res: Successfully selec $isel = 0; | case 0 { syslog('info', "Ast-Res: Empty selection fr next; | case -1 { syslog('crit', "Ast-Res: Error in Radius My > } } } switch (send_lost_rad()) { switch (send_lost_rad()) { case 1 { syslog('info', "Ast-Res: Successfully sendi | case 0 { syslog('info', "Ast-Res: Successfully sendi case 0 { syslog('info', "Ast-Res: Error in Sending l | case -1 { syslog('info', "Ast-Res: Error in Sending l case -1 { syslog('crit', "Ast-Res: Error Connection") | case -2 { syslog('info', "Ast-Res: Error in Sending l > case -3 { syslog('crit', "Ast-Res: Error executing qu } } sleep 1; < } } ############################################################# ############################################################# # END # END ############################################################# #############################################################