#!/usr/bin/perl ########################################################################## # # # Perl Script for send keep alive udp packets # # Created on 110627 by oussama.hammami@switzernet.com # # Switzernet(c)2011 # # # ########################################################################## # my modules use strict; use warnings; use Sys::Syslog; use POSIX; use Config::IniFiles; use Switch; use DBI; use Date::Manip; use Time::Local; use Net::RawIP; use threads; use threads::shared; ########################################################################## # Setting my $lock_file = '/var/run/ast-send-empty.pid'; my $runas_user = 'root'; my $config_dir = '/etc/astrad/config'; ########################################################################## # Globals my ($dbh,$DB_NAME,$DB_HOST,$DB_USER,$DB_PASS); my %peers; my %peers_info; ########################################################################## # Initialization # ########################################################################## # Check if already running if( -e $lock_file ) { open(PID,$lock_file); my $pid=<PID>; close PID; chomp $pid; if( !-e "/proc/$pid" ) { print STDERR "Lock file present, but no process with pid=$pid.\n"; die "Can't delete lock file $lock_file\n" if !unlink $lock_file; print STDERR "Lock file has been removed.\n"; } else { die "Lockfile present, another copy is punning pid=$pid\n"; } } my ($name, $passwd, $uid, $gid) = getpwnam($runas_user) or die "$runas_user not in passwd file";; ########################################################################## # set C locale POSIX::setlocale(LC_ALL, "C"); ########################################################################## # Become daemon my $pid; if( !defined($pid = fork()) ) { die "cannot fork: $!"; } elsif ($pid) { # Create lockfile, and finish parent process open(PID, "> $lock_file") || die "ast-notify-send.pl: Unable to create lockfile $lock_file\n"; print PID "$pid"; close PID; chown $uid, $gid, $lock_file; exit; } else { # daemon setpgrp(); select(STDERR); $| = 1; select(STDOUT); $| = 1; openlog('ast-notify-send', 'cons,pid', 'daemon'); syslog('notice', "Ast-Empty: Resend lost Accounting packets for Asterisk started"); } ########################################################################## # Install signall handler $SIG{INT} = \&safe_exit; $SIG{QUIT} = \&safe_exit; $SIG{TERM} = \&safe_exit; $SIG{HUP} = \&load_config; ########################################################################## # Drop privileges setuid($uid); $< = $uid; $> = $uid; ########################################################################## # Signal Handlers sub safe_exit { my($sig) = @_; syslog('crit', "Ast-Empty: Caught a SIG - shutting down"); $dbh->disconnect if $dbh; unlink $lock_file or syslog('crit', "Ast-Empty: Unable to create lockfile $lock_file\n"); closelog(); exit; } ########################################################################## # FUNCTION # ########################################################################## # Load config from mysql.conf sub load_config { my $conf=Config::IniFiles->new(-file => "$config_dir/switzer.conf"); return 0 if !defined $conf ; $DB_NAME = $conf->val('ASTER_DB','DB_NAME'); $DB_HOST = $conf->val('ASTER_DB','DB_HOST'); $DB_USER = $conf->val('ASTER_DB','DB_USER'); $DB_PASS = $conf->val('ASTER_DB','DB_PASS'); return 1; } ########################################################################## # Astrad Radius DB connect sub DB_connect { my $cop=0; while( 1 ) { $cop++; $dbh = DBI->connect_cached("DBI:mysql:$DB_NAME;host=$DB_HOST",$DB_USER, $DB_PASS); if( $dbh ) { syslog('info', 'Ast-Empty: Connected to Astrad DB'); return 1; } else { syslog('info', "Ast-Empty: Connection to Astrad DB failed -> SLEEP $cop"); return 0 if ($cop>=3); } sleep $cop; } } ########################################################################## # Load register request from Astrad Reg. DB sub load_peers { DB_connect(); my $result; my $request="SELECT username,contact FROM location3;"; syslog('info', "Ast-Empty: request = $request"); my $sth = $dbh->prepare($request); return 0 if (!$sth->execute()); syslog('info', "Ast-Empty: sth->rows = ".$sth->rows); $peers{$result->{username}}=$result->{contact} while ($result = $sth->fetchrow_hashref); $sth->finish; return 1; } ########################################################################## sub send_empty { my ($phone_ip,$port,$acc)=@_; my $ipid = int rand 5000 + 100; my ($a,$p,$f); $SIG{'KILL'} = sub { threads->exit(); }; $a = new Net::RawIP({udp=>{}}); $a->set({ ip => { saddr => '94.23.225.212', daddr => $phone_ip, id => $ipid, frag_off => 0, tos => 0, protocol => 0x11 }, udp => { source => 5060, dest => $port, len => 9, data=> chr(0)} # chr(0) }); while (1) { $a->send(0,1); sleep 15; } } ########################################################################## sub kill_thr { my $acc=shift; foreach my $thr (threads->list) { if ($thr->tid && !threads::equal($thr, threads->self) && $thr->tid==$peers_info{$acc}{'tid'}) { $thr->kill('KILL')->detach(); } } } ########################################################################## sub set_tid { foreach my $pr (keys %peers) { if ($peers{$pr} =~ /^sip:\s*([^@]*)@([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}):([0-9]+)$/) { my $thr = threads->new(\&send_empty,$2,$3,$1); ($peers_info{$1}{'ip'},$peers_info{$1}{'port'},$peers_info{$1}{'tid'})=($2,$3,$thr->tid()); } } return 1; } ########################################################################## sub check_thr { foreach my $pr (keys %peers_info) { if ($peers{$pr}) { delete($peers{$pr}); } else { kill_thr($pr); delete($peers_info{$pr}); } } return 1; } ########################################################################## # main() # ########################################################################## load_config(); while (load_peers() && check_thr() && set_tid() ) { sleep 15; undef(%peers); } exit; safe_exit(); ########################################################################## # END # ##########################################################################