smeserver-smeadmin/root/usr/bin/smeadmind

1703 lines
84 KiB
Plaintext
Raw Permalink Normal View History

#!/usr/bin/perl -w
# Smeadmin - demon perl collectant les statistiques du systeme
# Copyright (C) 2006
# This file is distributed under the GPL license.
# Landry Breuil <landry@firewall-services.com>, 2006.
# version 1.2 : Pascal Schirrmann <schirrms@schirrms.net>, 2011
#--------------------------------------
#Declaration des dependances/inclusions
use strict;
use warnings;
use DBD::mysql;
use sigtrap;
use RRDs;
use esmith::ConfigDB;
use Mail::Send;
#pour le parsage des dates format TAI64
use Time::TAI64 qw/:tai64/;
#pour l'utilisation de gettext
use POSIX;
use Locale::gettext;
#----------------------------------
#Declaration des variables globales
my $progname='smeadmin';
# si $DEBUG sup<75>rieur <20> 0, affichage d'infos de debug via la fonction debug()
my $DEBUG = 0;
#variables d'environnement du serveur
my ($DomainName,$SystemName,$SystemMode,$InternalInterface,$ExternalInterface,$InternalIP,$ExternalIP,@MailDomainsMatch);
my $SshPort;
#----------------------------------
#hash faisant correspondre la cle (nom du param) a sa valeur [ICI, CE SONT LES VALEURS PAR DEFAUT !!]
#idem dans le panel /etc-e-smith/web/functions/smeadmin
my %params=(
'DbName'=>"smeadmin",
'DbPassword'=>"pass",
'DbUser'=>"smeadmin",
# 'if_internal'=>"eth0",
# 'if_external'=>"eth1",
'ImgFormat'=>"PNG",
'ImgWidth'=>"500",
'ImgHeight'=>"300",
# /sbin/e-smith/db domains keys pour voir les autres domaines du serveur
'OtherMailDomains'=>"",
'PingTarget'=>"www.google.fr",
'hd1'=>"sda",
'hd2'=>"",
'hd3'=>"",
'hd4'=>"",
'hd5'=>"",
'hd6'=>"",
'UseDu'=>"on",
'SensorsTag1'=>"temp1",
'SensorsTag2'=>"temp2",
'SensorsTagFan'=>"fan1",
'SensorsTagFan2'=>"",
'LimitPppoeDisconnect'=>"1",
'LimitPppoeDuration'=>"4",
'LimitVpnDuration'=>"2",
'AlertMailRecipient'=>'admin',
'StatusMailRecipient'=>'admin',
'StatusInterval'=>"3",
'MaxMailIn'=>"1",
'MaxMailOut'=>"1",
'MaxDiskSpace'=>"60",
'MaxCpu'=>"50",
'MaxHwTemp'=>"40",
'MaxHdTemp'=>"40",
'MaxSamba'=>"1",
'MaxSsh'=>"1",
'MaxFtp'=>"1",
'MaxVpn'=>"1");
#----------------------------------------------------------------
#chemins d'acces au repertoires de travail
my $logdir="/var/log/";
my $rrddir="/var/lib/$progname";
my $tmpdir="/var/tmp/smeadmin-state/";
unless ( -d $tmpdir ) { mkdir $tmpdir }
my $logfile="$logdir$progname.log";
my $lockfile="/var/run/$progname.pid";
#tableau des chemins des logs qui nous interessent
#TO SEE
my @logs= ( "clamd/current", # VIRUS ???
"spamd/spamd.log", # SPAMS
"sshd/sshd.log", # ssh connections
"messages", # afpd pppd and others not with dedicated logs
"dhcpd/dhcpd.log", # dhcpd
"qmail/current", # mails IN/OUT
"altqmail/current", # mails OUT
"qpsmtpd/current", # SPAM/VIRUS ??
"sqpsmtpd/current", # SPAM/VIRUS ??
"proftpd/proftpd.log", # start and end of ftp session
"secure", # FTP session with usernam auth
"xferlog"); # file transfer with ftp
#handle bd mySQL
my $bd;
my %mois=("Jan"=>1,"jan"=>1,
"Feb"=>2,"fev"=>2,
"Mar"=>3,"mar"=>3,
"Apr"=>4,"avr"=>4,
"May"=>5,"mai"=>5,
"Jun"=>6,"jun"=>6,
"Jul"=>7,"jul"=>7,
"Aug"=>8,"ao<61>"=>8,
"Sep"=>9,"sep"=>9,
"Oct"=>10,"oct"=>10,
"Nov"=>11,"nov"=>11,
"Dec"=>12,"dec"=>12);
#----------------------------------
# definition des variables pour l'alimentation des rrds
#sensors.rrd => sensors, hddtemp
my ($sensors_temp1,$sensors_temp_hd1,$sensors_temp2,$sensors_temp_hd2,$sensors_fan_speed,$sensors_fan2_speed,$sensors_temp_hd3,$sensors_temp_hd4,$sensors_temp_hd5,$sensors_temp_hd6);
#hd.rrd => df, du
my ($hd_total,$hd_used,$hd_free,$hd_log,$hd_files,$hd_squid,$hd_mysql,$hd_blkread,$hd_blkwrite);
#net.rrd => parse_logs, ping, smbstatus
my ($net_samba,$net_dhcp,$net_mail_in,$net_mail_out,$net_spam);
my ($net_virus,$net_minlatency,$net_avglatency,$net_maxlatency,$net_loss);
#sessions.rrd => netstat
my ($sessions_ftp,$sessions_ssh,$sessions_vpn,$sessions_netbios,$sessions_afp);
#if_loc.rrd => sar
my ($if_loc_bin,$if_loc_bout,$if_loc_pin,$if_loc_pout);
#if_ext.rrd => sar
my ($if_ext_bin,$if_ext_bout,$if_ext_pin,$if_ext_pout);
#cpu.rrd => sar
my ($cpu_total,$cpu_idle,$cpu_system,$cpu_user,$cpu_nice,$cpu_plist,$cpu_runq,$cpu_load1,$cpu_load5,$cpu_load15,$cpu_uptime);
#mem.rrd => sar
my ($mem_memtotal,$mem_memused,$mem_memfree,$mem_memactualused,$mem_memactualfree);
my ($mem_membuffers,$mem_memcache,$mem_swaptotal,$mem_swapused,$mem_swapfree);
#httpd.rrd => ps pidof
my ($httpd_cpu,$httpd_mem,$httpd_nbproc);
#samba.rrd => ps pidof
my ($samba_cpu,$samba_mem,$samba_nbproc);
#afp.rrd => ps pidof
my ($afp_cpu,$afp_mem,$afp_nbproc);
#squid.rrd => ps pidof
my ($squid_cpu,$squid_mem,$squid_nbproc);
#mail_in s?qpsmtpd
# This is the list of plugins we can get stats for
# you can set the regex used to identify a line in the logs
my %denied = (
auth_failed => qr{auth::(auth_imap|auth_cvm_unix_local)\s+90},
dnsbl => qr{(dnsbl\s+90|naughty\s+90\d\s+\(dnsbl\))},
rhsbl => qr{rhsbl\s+90},
uribl => qr{uribl\s+90},
clamav => qr{virus::clam(av|dscan)\s+90},
check_earlytalker => qr{(check_)?earlytalker\s+90},
check_basicheaders => qr{(check_basic)?headers\s+90},
check_goodrcptto => qr{(check_)?goodrcptto\s+90},
check_spamhelo => qr{((check_spam)?helo\s+90|naughty\s+90\d\s+\(helo\))},
fcrdns => qr{fcrdns\s+90},
karma => qr{(karma\s+90|naughty\s+90\d\s+\(karma\))},
spf => qr{(sender_permitted_from|spf_deny)\s+90},
dmarc => qr{dmarc\s+90},
tls_failed => qr{tls\s+90},
resolvable_fromhost => qr{(require_)?resolvable_fromhost}
);
my @others = qw(total_denied spam_denied other_denied spam_queued queued total);
my %cnt;
foreach (keys %denied, @others){
$cnt{$_} = 0;
}
# pour qmail
my ($localqueue,$remotequeue);
my @resultsqm = qw(failure deferral success total);
my %cntqm;
my %cntqmlocal;
foreach (@resultsqm){
$cntqm{$_} = 0;
$cntqmlocal{$_} = 0;
}
# pour altqmail
my ($localaqueue,$remoteaqueue);
my @resultsaqm = qw(failure deferral success total);
my %cntaqm;
my %cntaqmlocal;
foreach (@resultsaqm){
$cntaqm{$_} = 0;
$cntaqmlocal{$_} = 0;
}
my $net_amail_out=0;
#------------------------
#declaration de fonctions
sub debug;
sub readConf;
sub connectBD;
sub deconnectBD;
sub ip2host;
sub ipdot2ipnum;
sub mkmysqldate;
sub parse_logs;
sub seek_log;
sub tell_log;
sub samba_status;
sub get_sensors_hddtemp;
sub get_df_du;
sub get_ping;
sub get_netstat;
sub get_sar;
sub get_proc;
sub update_rrd;
sub mail_alerte;
sub mail_status;
sub execute_sql_query;
#-------------
#Debut du main
if (-e $lockfile)
{
print "Daemon already running, or crashed...\n";
print "PID current : ".$$."\n";
my $oldPID=`cat /var/run/smeadmin.pid`;
print "PID in PID file : " . $oldPID ."\n";
my @listPID=`pgrep smeadmind`;
my $test=`/bin/ps -e | /bin/grep $oldPID | /usr/bin/rev | /bin/cut -c1-10 | /usr/bin/rev|tr -d '\n'`;
if ( $test eq "smeadmind")
{
print "Smeadmind is currently running, with the PID present in its PID file($oldPID).\n";
print "Try 'pgrep smeadmin' to see if the daemon crashed, kill it, then exec 'rm -f $lockfile' before restarting daemon.\n";
exit 1;
}
else
{
print "A PID ($oldPID)and a lock files were found, and no smeadmind deamon seemed running.\n";
print "Thus we are starting this one ($$).\n";
system("kill -9 $oldPID");# we are killing the old one just in case (we have just tested, but we definively do not want two sessions running!)
system("touch $lockfile");# updating lock file
system("echo $$ > /var/run/smeadmin.pid");
}
}
unless (fork)
{
#lock du demon
open FILELOCK,">$lockfile";
print FILELOCK $$;
close FILELOCK;
print "Daemonizing $progname... (pid $$)\n";
#renouvellement du log on conserve 3 versions
unlink("$logfile.3") if -e "$logfile.3";
rename("$logfile.2","$logfile.2") if -e "$logfile.2";
rename("$logfile.1","$logfile.2") if -e "$logfile.1";
rename("$logfile.old","$logfile.2") if -e "$logfile.old";
rename("$logfile","$logfile.1") if -e "$logfile";
#redirection des E/S vers le log
open STDOUT,">>$logfile";
open STDERR,">>$logfile";
open STDIN, "</dev/null";
#trap pour les signaux SIGQUIT & SIGTERM
$SIG{QUIT} = sub { print STDERR "At ".localtime().", SIGQUIT Catched\n"; unlink($lockfile); exit 0; };
$SIG{TERM} = sub { print STDERR "At ".localtime().", SIGTERM Catched\n"; unlink($lockfile); exit 0; };
#trap pour le signal SIGUSR1 (lance par logrotate)=>doit faire un parse_log
# PS le 10Dec2011 : avec le passagepar seek et tell, encore utile ?
$SIG{USR1} = sub { print STDERR "At ".localtime().", SIGUSR1 Catched => parse_logs()\n";
parse_logs();
};
#trap pour le signal SIGHUP (lance par le formulaire cgi de modif de la conf)=>doit re_read_conf
$SIG{HUP} = sub { print STDERR "At ".localtime().", SIGHUP Catched => readConf()\n";
readConf();
};
#init de gettext
setlocale(LC_MESSAGES,"");
bindtextdomain("smeadmin","/usr/share/locale");
textdomain("smeadmin");
print STDERR "Locale:",setlocale(LC_MESSAGES),"\n";
#c'est tout :D
readConf();
#le service vient de demarrer
my $mail = new Mail::Send;
$mail->to("$params{'AlertMailRecipient'}");
$mail->set("From","smeadmin-daemon");
$mail->subject("[SERVICE START] $SystemName : $progname started");
my $body = $mail->open;
print $body "Uptime: ",`/usr/bin/uptime`;
$body->close;
my $cont=0;
while(1)
{
#step 0 let's reread the logs, so we do not need to restart
readConf();
# etape 1 : parsage des logs
parse_logs();
# etape 2 : interrogation des differents sensors
samba_status();
get_sensors_hddtemp();
get_df_du();
get_ping();
get_netstat();
get_sar();
get_proc();
# etape 3 : update des rrds avec toutes les nouvelles donnees
update_rrd();
# etape 4 : envoi des eventuels mails d'alertes
mail_alerte();
mail_status() if ($params{'StatusInterval'} && !($cont % $params{'StatusInterval'}));
sleep(300-time%300);
$cont++;
}
}
#Fin du main
#-----------
#------------------------
#Definition de fonctions
#----------------------------------------------------------------
# debug : archi basique !
sub debug {
if ( $DEBUG ) { print STDERR "@_"; }
}
#DBI:mysql, connecte MOI
sub connectBD
{
$bd=DBI->connect ("DBI:mysql:$params{'DbName'}","$params{'DbUser'}","$params{'DbPassword'}");
if (!defined ($bd)) {print "MYSQL error $DBI::errstr\n";}
}
#----------------------------------------------------------------
#DBI:mysql, deconnecte MOI
sub deconnectBD
{
if (defined ($bd)) {
$bd->disconnect or
warn "MYSQL error $DBI::errstr\n";}
else
{ print "mysql : nothing to disconnect";}
}
#----------------------------------------------------------------
# lecture de la conf dans la db
sub readConf
{
#lecture des parametres contenus dans la db de sme
my $smedb=esmith::ConfigDB->open;
$DomainName = $smedb->get('DomainName')->value;
$SystemName = $smedb->get('SystemName')->value;
$SystemMode = $smedb->get("SystemMode")->value;
$DEBUG = $smedb->get('smeadmind')->prop('DEBUG') || "0";
#on n'a une external ip que si on est en server-passerelle
if ($SystemMode =~ /servergateway/) {
$ExternalIP = $smedb->get("ExternalIP")->value;
$ExternalInterface = $smedb->get("ExternalInterface")->prop('Name');
}
my $InternalIP = $smedb->get("LocalIP")->value;
$InternalInterface = $smedb->get("InternalInterface")->prop('Name');
$SshPort = $smedb->get("sshd")->prop('TCPPort');
my $smeadmindb = $smedb->get('smeadmind') || die "Error opening smeadmind db\n";
foreach my $key (keys(%params)){
$params{$key} = $smeadmindb->prop($key) || '';
}
#lecture de la liste des domaines du serveur, a ajouter a l'option de conf 'OtherMailDomains' => on cree un tableau de domaines/adresses mail
@MailDomainsMatch=`/sbin/e-smith/db domains keys`;
#on enleve les \n qu'a mis SME
chop foreach @MailDomainsMatch;
#on splitte les domaines donnes en params et on les rajoute
push @MailDomainsMatch, split /;/, $params{'OtherMailDomains'};
#on enleve les espaces en debut et en fin
$_=~s/\s+//g foreach @MailDomainsMatch;
print "MailDomainsMatch =";
print " $_" foreach @MailDomainsMatch;
print "\nreadConf() OK !\n";
}
################################################ Pique sur perl-gratuit.com
sub ip2host {
my ($ip)=@_; # adresse IP en argument
# D<>claration des variables utilis<69>es
my ($name,$packaddr,@bytes);
$ip =~ s/^\s+|\s+$//g; # on supprime des espaces <20>ventuels en d<>but et fin de l'IP
@bytes = split (/\./, $ip); # on range dans un tableau, les 4 nombres s<>par<61>s par des points de l'IP
$packaddr = pack ("C4", @bytes); # on encode l'adresse IP, en un entier compact<63>
# on lance la r<>solution de l'adresse IP #
if ($name =gethostbyaddr ($packaddr, 2)) {return $name;}
else {return '';}
}
#conversion d'ip aaa.bbb.ccc.ddd (aaa*16777216)+(bbb*65536)+(ccc*256)+ddd
sub ipdot2ipnum {
return ($_[0]*16777216)+($_[1]*65536)+($_[2]*256)+$_[3];
}
#conversion d'un date format log en date format mysql
sub mkmysqldate {
#entree de la forme mmm ( d|dd) hh:mm:ss)
my($a)=@_;
my $annee=(localtime)[5];
$annee+=1900;
$a =~ /(\w{3})\s{1,2}(\d{1,2}) ([0-9:]{8})/;
return ($annee."-".$mois{$1}."-".$2." ".$3);
}
################################################
# seek_log : ouvre un fichier log, seek a la derniere position connue
sub seek_log {
my ($log) = @_;
# au cas ou un vieux fichier existe : migration
my $dstnom=$log;
$dstnom = substr($dstnom, 9);
$dstnom =~ s/\/[0-9a-zA-Z_\-\.]+//;
$dstnom = "/var/tmp/$dstnom";
if ( -r $dstnom ) {
print "the diff log file $dstnom exists, trying to use it as a seek point...\n";
my (undef, undef, undef, undef, undef, undef, undef, $seek) = stat( $dstnom );
open ( my $fh, "<", $log );
seek ( $fh, $seek, 0);
print "$log seek at position $seek\n";
unlink $dstnom;
return $fh;
}
else {
my $state = $log;
# on remplace les / par des _-
$state =~s/\//_-/g;
$state = "$tmpdir/$state";
if ( -r $log ) {
open ( my $fh, "<", $log);
my (undef, $ino, undef,undef,undef,undef,undef, $size) = stat($log);
if ( -r $state ) {
open (my $fs, "<", $state);
my ($fino, $fseek) = <$fs>;
chomp $fino; chomp $fseek;
close $fs;
if ( $fino =~/^\d+$/ and $fseek =~ /^\d+$/ and $fseek <= $size and $fino == $ino ) {
seek ($fh, $fseek, 0);
debug ("$log : seek en position $fseek\n");
}
else {
debug ("$log : seek impossible : \$fino='$fino' (Num<75>rique) = a \$ino='$ino' ?\n");
debug (" \$fseek='$fseek' (Numerique) <= a \$size='$size' ?\n");
}
}
return $fh;
}
}
}
# tell_log : enregistre la position courante
sub tell_log {
my($log, $fh) = @_;
my $state = $log;
# on remplace les / par des _-
$state =~s/\//_-/g;
$state = "$tmpdir$state";
my $pos = tell($fh);
close $fh;
my (undef, $ino) = stat($log);
open ( my $fs, ">", $state);
print $fs "$ino\n$pos\n";
close $fs;
}
sub parse_logs {
connectBD();
# ici on met a jour volume connexion meme si pas fini si pppoe et si pas trouv<75> de fin dans log
my $smedb=esmith::ConfigDB->open;
my $ppoeif = $smedb->get("ExternalInterface")->prop('Name');
my $ppoemode = $smedb->get("ExternalInterface")->prop('Configuration');
#for sme9 in server-only, the external interface is set to none
#for sme10 we add test we are using pppoe
if ($ppoeif ne 'none' && $ppoemode eq 'pppoe') {
my $recBytes=`cat /proc/net/dev|grep $ppoeif|cut -d ':' -f2|tr -s ' '| sed -e 's/^[ \t]*//'|cut -d ' ' -f1`;
#my $senBytes=`cat /proc/net/dev|grep $ppoeif|tr -s ' '| sed -e 's/^[ \t]*//'|cut -d " " -f9`;
my $senBytes=`cat /proc/net/dev|grep ppp0|cut -d ':' -f2|tr -s ' '| sed -e 's/^[ \t]*//'|cut -d ' ' -f9`;
#my $requete="SELECT pid_pppd FROM pppoe WHERE ORDER DESC LIMIT 1";
#my $rq=$bd->prepare($requete) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete,$bd->errstr));
#$rq->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq->errstr));
#my $pidPppd = $rq->fetchrow_array();
my $pidPppd=`cat /var/run/$ppoeif.pid`;
print "the current pid for pppd is $pidPppd \n";
my $reslt1=execute_sql_query("SELECT * FROM pppoe WHERE pid_pppd='$pidPppd'");
#si on a trouve une ligne ==> update dans pppoe
if ($reslt1 != "0E0") {
my $requete1="UPDATE pppoe SET volume_out=$senBytes, volume_in=$recBytes, fin=now() where pid_pppd=$pidPppd ORDER BY debut DESC LIMIT 1;";
#print "requete a executer : $requete1 \n";
execute_sql_query($requete1);
}
}
# on fait de m<>me pour les conenxions VPN
if ( glob("/var/run/ppp[0-9]*.pid")){
foreach my $mypid (`ls /var/run/ppp[0-9]*.pid`){
$mypid =~ /\/var\/run\/(ppp[0-9]*).pid/;
my $vpnif = $1;
open(FIC,"<$mypid") or die("open: $!");
$mypid = <FIC>;
chomp $mypid;
close FIC;
if ($vpnif ne $ppoeif ) {
my $recBytes=`cat /proc/net/dev|grep $vpnif|cut -d ':' -f2|tr -s ' '| sed -e 's/^[ \t]*//'|cut -d ' ' -f1`;
my $senBytes=`cat /proc/net/dev|grep $vpnif|tr -s ' '| sed -e 's/^[ \t]*//'|cut -d " " -f9`;
my $reslt1=execute_sql_query("SELECT * FROM vpn WHERE pid_pppd='$mypid'");
if ($reslt1 != "0E0") {
my $requete1="UPDATE vpn SET volume_out=$senBytes, volume_in=$recBytes, fin=now() where pid_pppd=$mypid ORDER BY debut DESC LIMIT 1;";
#print "requete a executer : $requete1 \n";
execute_sql_query($requete1);
}
}
}
}
# reset all counter before checking logs
($net_dhcp,$net_mail_in,$net_mail_out,$net_amail_out,$net_spam,$net_virus)=(0,0,0,0,0,0);
foreach (keys %denied, @others){
$cnt{$_} = 0;
}
foreach (@resultsqm){
$cntqm{$_} = 0;
$cntqmlocal{$_} = 0;
}
foreach (@resultsaqm){
$cntaqm{$_} = 0;
$cntaqmlocal{$_} = 0;
}
foreach my $nom (@logs) {
# on recupere un file handle positionn<6E> comme il faut
my $fh = seek_log("$logdir$nom");
unless ( defined $fh ) {
debug( "impossible d'ouvrir le fichier $nom\n");
next;
}
#parsage de la difference entre les 2 logs
#si la difference a donne qqch
#parse SSHD log to catch ssh connections/bruteforce
if ($nom eq "sshd/sshd.log") {
debug "sshd: ";
while ( defined(my $l = <$fh>)) {
chomp $l;
#Match: @TAI64 Accepted password for user from ip port prt mode
# "@4000000043a7f6970980de74 Accepted password for root from 10.246.200.10 port 60693 ssh2"
# "@4000000043a800192a7e131c Accepted publickey for root from 10.246.200.10 port 46322 ssh2"
# SME10
# "Mar 23 16:57:38 sme10 sshd[9666]: Accepted publickey for root from 192.168.12.70 port 60224 ssh2: RSA SHA256:uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu"
if($l =~ /^(@[0-9a-f]{24}) Accepted (password|publickey) for (\w+) from (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/) {
#$1:date $2:methode $3:login $4.$5.$6.$7:ip
#open connexion ssh reussie
my $ip=ipdot2ipnum($4,$5,$6,$7);
my $date=tai2strftime($1,"%F %T");
my $reslt=execute_sql_query("SELECT * FROM ssh WHERE ip='$ip' and debut='$date' and login='$3'");
#si on a trouve pas trouve une ligne ==> insert
debug "SELECT * FROM ssh WHERE ip='$ip' and debut='$date' and login='$3'\n";
execute_sql_query("INSERT INTO ssh VALUES ('$date','$ip','$3','1')") if ($reslt eq "0E0");
next;
}
elsif ($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName sshd\[(\d+)\]: Accepted (password|publickey) for (\w+) from (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/) {
#$1:date $2:methode $3:login $4.$5.$6.$7:ip
#open connexion ssh reussie
my $ip=ipdot2ipnum($5,$6,$7,$8);
my $date=mkmysqldate($1);
debug "SELECT * FROM ssh WHERE ip='$ip' and debut='$date' and login='$4'\n";
my $reslt=execute_sql_query("SELECT * FROM ssh WHERE ip='$ip' and debut='$date' and login='$4'") ;
execute_sql_query("INSERT INTO ssh VALUES ('$date','$ip','$4','1')") if ($reslt eq "0E0");;
next;
}
#Match: @TAI64 Failed password for (|invalid user) user from ip port prt mode
#matche ces 2 lignes
# "@4000000043a7fe82181805ac Failed password for invalid user plop from 127.0.0.1 port 32793 ssh2"
# "@4000000043a7fe892d74219c Failed password for root from 127.0.0.1 port 32794 ssh2"
#on ne matche pas les "Failed publickey" qui precedent generalement un "Accepted password"
if($l =~ /^(@[0-9a-f]{24}) Failed password for(| invalid user) (\w+) from (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/) {
#$1:date $2:erreur $3:login $4.$5.$6.$7:ip
#open connexion ssh rate
my $ip=ipdot2ipnum($4,$5,$6,$7);
my $date=tai2strftime($1,"%F %T");
my $reslt=execute_sql_query("SELECT * FROM ssh WHERE ip='$ip' and debut='$date' and login='$3'");
execute_sql_query("INSERT INTO ssh VALUES ('$date','$ip','$3','0')") if ($reslt eq "0E0");
next;
}
elsif ($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName sshd\[(\d+)\]: Failed for(| invalid user) (\w+) from (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/) {
#$1:date $2:methode $3:login $4.$5.$6.$7:ip
#open connection ssh failed
my $ip=ipdot2ipnum($5,$6,$7,$8);
my $date=mkmysqldate($1);
debug "SELECT * FROM ssh WHERE ip='$ip' and debut='$date' and login='$4'\n";
my $reslt=execute_sql_query("SELECT * FROM ssh WHERE ip='$ip' and debut='$date' and login='$4'");
execute_sql_query("INSERT INTO ssh VALUES ('$date','$ip','$4','0')") if ($reslt eq "0E0");;
next;
}
}
}
#parse PROFTPD logs to catch ftp connections => proftpd/current, secure & xferlog
elsif ($nom eq "secure") {
while (defined(my $l = <$fh>)) {
chomp $l;
#Dec 20 14:45:55 sme7b5 proftpd[27178]: sme7b5.plop.gruiik.org (127.0.0.1[127.0.0.1]) - USER admin: Login successful.
#Dec 20 15:18:23 sme7b5 proftpd[26512]: sme7b5.plop.gruiik.org (127.0.0.1[127.0.0.1]) - ANON anonymous: Login successful.
if( $l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName proftpd\[(\d+)\]: $SystemName \((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\[\3\.\4\.\5\.\6\]\) - (ANON|USER) ([0-9a-z-]+): Login successful\./o) {
#login OK
#$1:date $2:pid proftpd $3.$4.$5.$6:ip $7:""mode"" $8:login
my $date=mkmysqldate($1);
my $ip=ipdot2ipnum($3,$4,$5,$6);
execute_sql_query("INSERT INTO ftp VALUES('$date',date_add('$date',interval 1 day),null,$ip,'$2','$8','1',0,0)");
next;
}
#Dec 7 20:50:53 sme7b5 proftpd[9952]: sme7b5.plop.gruiik.org (10.246.200.10[10.246.200.10]) - USER test: no such user found from 10.246.200.10 [10.246.200.10] to 10.246.200.13:21
#Dec 20 15:15:36 sme7b5 proftpd[23923]: sme7b5.plop.gruiik.org (127.0.0.1[127.0.0.1]) - USER landry (Login failed): Incorrect password.
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName proftpd\[(\d+)\]: $SystemName \((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\[\3\.\4\.\5\.\6\]\) - USER ([0-9a-zA-Z-]+)(: no such user found from| \(Login failed\): Incorrect password\.)/o) {
#login inexistant ou erreur passwd
#$1:date $2:pid proftpd $3.$4.$5.$6:ip $7:login $8:type erreur
my $date=mkmysqldate($1);
my $ip=ipdot2ipnum($3,$4,$5,$6);
execute_sql_query("INSERT INTO ftp VALUES ('$date',null,null,$ip,'$2','$7','0',0,0)");
next;
}
}
}
#ici on matche les fins de connexion ftp (reussies ou non)
elsif ($nom eq "proftpd/proftpd.log") {
while ( defined(my $l = <$fh>)) {
chomp $l;
#@4000000043973d2916bb3c9c tcpsvd: info: end 9952 exit 0
if($l =~ /^(@[0-9a-f]{24}) tcpsvd: info: end (\d+)/) {
#$1=date, $2=pid_proftpd
my $date=tai2strftime($1,"%F %T");
execute_sql_query("UPDATE ftp SET fin='$date', duree=fin-debut where pid_proftpd=$2");
next;
}
}
}
#enfin on matche les volumes transferes pdt les connections
elsif ($nom eq "xferlog") {
while ( defined(my $l = <$fh>)) {
chomp $l;
#Wed Dec 7 20:19:58 2005 0 10.246.200.10 1831631 /home/e-smith/files/ibays/Primary/files/win2.png b _ i r admin ftp 0 * c
#Wed Dec 7 20:19:59 2005 0 10.246.200.10 35759 /home/e-smith/files/ibays/Primary/files/wine.png b _ i r admin ftp 0 * c
if($l =~ /\w{3} (\w{3}\s{1,2}\d{1,2} [0-9:]{8}) \d{4} \d+ (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}) (\d+) [0-9a-zA-Z\.\-\_\/]+ \w \w (\w) (\w) ([A-Z0-9a-z\@_\-]+) ftp/) {
#$1:date $2.$3.$4.$5:ip $6:volume $7:sens $8:loggu<67>/anon ? $9:login
my $date=mkmysqldate($1);
my $ip=ipdot2ipnum($2,$3,$4,$5);
my $requete="UPDATE ftp SET ";
#quand c'est un d(deleted) volume=0 donc osef
if ($7 eq 'o') { $requete.="volume_out=volume_out+$6 "; }
else { $requete.="volume_in=volume_in+$6 "; }
#si l'user est logu<67>
if ($8 eq 'r') { $requete.="where login='$9'"; }
else { $requete.="where login='anonymous'"; }
$requete.=" and connecte='1' and ip=$ip and '$date' >= debut and '$date' <= fin";
execute_sql_query($requete);
next;
}
}
}
#parse clamd/current, qpsmtpd/current & clamd/current to count incoming/outgoing mails, and spam & viruses
elsif ($nom eq "clamd/current") {
while ( defined(my $l = <$fh>)) {
chomp $l;
#@4000000043a81cd520e929cc /var/spool/qpsmtpd/1135090877:4395:0: Eicar-Test-Signature FOUND
if ($l =~ /FOUND/) {$net_virus++;next;}
}
}
elsif ($nom eq "spamd/spamd.log") {
while ( defined(my $l = <$fh>)) {
chomp $l;
#@4000000043a1c3ab1ff72c94 2005-12-15 19:27:29 [4838] i: identified spam (997.2/3.0) for qpsmtpd:1005 in 2.2 seconds, 557 bytes.
# SME10
#Mar 25 18:40:17 sacrum check[12093]: spamd: identified spam (98.8/4.0) for qpsmtpd:1005 in 17.4 seconds, 211566 bytes.
if($l =~ /identified spam/) {$net_spam++;next;}
}
}
elsif ($nom =~ /^qmail\/current$/) {
while ( defined(my $l = <$fh>)) {
# accounting for remote connections
# @400000004994ad092afa867c delivery 96906: success etc...
if ($l =~ m/^\@[0-9a-f]{24} delivery \d+: (success|failure|deferral).*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|CNAME_lookup_failed_temporarily|Sorry,_I_wasn't_able_to_establish_an_SMTP_connection)/i) {
my $result = $1;
$cntqm{$result}++;
next;
}
# accounting for local connections have to be after the remote
if ($l =~ m/^\@[0-9a-f]{24} delivery \d+: (success|failure|deferral).*/i) {
my $result = $1;
$cntqmlocal{$result}++;
next;
}
}
# Calcul des totaux:
foreach (@resultsqm){
$cntqm{total} = $cntqm{total} + $cntqm{$_} if $_ !~ /total/;
$cntqmlocal{total} = $cntqmlocal{total} + $cntqmlocal{$_} if $_ !~ /total/;
}
## add qmail local queue
$localqueue=`find /var/qmail/queue/local/ -type f | wc -l`;
$localqueue=~ s/\D+//g;
### add qmail remote queue
$remotequeue=`find /var/qmail/queue/remote/ -type f | wc -l`;
$remotequeue=~ s/\D+//g;
$net_mail_out=$cntqm{total};
}
elsif ($nom =~ /^altqmail\/current$/) {
while ( defined(my $l = <$fh>)) {
# accounting for remote connections
# @400000004994ad092afa867c delivery 96906: success etc...
if ($l =~ m/^\@[0-9a-f]{24} delivery \d+: (success|failure|deferral).*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|CNAME_lookup_failed_temporarily|Sorry,_I_wasn't_able_to_establish_an_SMTP_connection)/i) {
my $result = $1;
$cntaqm{$result}++;
next;
}
# accounting for local connections have to be after the remote
if ($l =~ m/^\@[0-9a-f]{24} delivery \d+: (success|failure|deferral).*/i) {
my $result = $1;
$cntaqmlocal{$result}++;
next;
}
}
# Calcul des totaux:
foreach (@resultsqm){
$cntaqm{total} = $cntaqm{total} + $cntaqm{$_} if $_ !~ /total/;
$cntaqmlocal{total} = $cntaqmlocal{total} + $cntaqmlocal{$_} if $_ !~ /total/;
}
## add qmail local queue
$localaqueue=`find /var/service/altqmail/root/var/qmail/queue/local/ -type f 2>/dev/null| wc -l` || "0";
$localaqueue=~ s/\D+//g;
### add qmail remote queue
$remoteaqueue=`find /var/service/altqmail/root/var/qmail/queue/remote/ -type f 2>/dev/null| wc -l` ||"0";
$remoteaqueue=~ s/\D+//g;
$net_amail_out=$cntaqm{total};
}
elsif ($nom =~ /^s?qpsmtpd\/current$/) {
while ( defined(my $l = <$fh>)) {
# following code is copy paste from util_parse_mail from Daniel Berteaud for Zabbix monitoring
# just changed $line to $l
# We only want logterse lines like
# @400000004994ad092afa867c 18386 logging::logterse plugin:
# The format can slightly change depending on qpsmtpd version
next unless $l =~ m/^\@[0-9a-f]{24} \d+( \((queue|deny)\))? logging::logterse/;
# Lets count all the message which have been denied 'msg denied before queued'
if ($l =~ m/msg denied before queued/){
$cnt{total_denied}++;
# Now try to find the plugin responsible for the deny
foreach (keys %denied){
if ($l =~ m/$denied{$_}/){
$cnt{$_}++;
}
}
next;
}
# Rejected by spamassassin because spam score is too high
elsif ($l =~ m/spam score exceeded threshold/){
$cnt{spam_denied}++;
next;
}
# Tagged as spam, but kept accepted
elsif ($l =~ m/queued\s+<.*>\s+Yes,\s+(score|hits)=/){
$cnt{spam_queued}++;
next;
}
# Queued, not tagged as spam, those are the clean emails
elsif ($l =~ m/queued\s+<.*>\s+No,\s+(score|hits)=/){
$cnt{queued}++;
next;
}
}
# we try here.. maybe not the best place
$cnt{total}=0;# as we parse qpsmtpd and then sqpsmtpd, we need to start from scratch the count while doint the last one
# Now lets count other_denied, which is total_denied minus
# all the known plugins denied
$cnt{other_denied} = $cnt{total_denied};
foreach (keys %denied){
$cnt{total} = $cnt{total} + $cnt{$_};
$cnt{other_denied} = $cnt{other_denied} - $cnt{$_};
}
# yes we potentially run this twice for nothing at the first run...
foreach (@others){
$cnt{total} = $cnt{total} + $cnt{$_} if ($_ !~ /total/);
}
$net_mail_in=$cnt{spam_queued} + $cnt{queued};
}
elsif ($nom eq "/dhcpd/dhcpd.log") {
while ( defined(my $l = <$fh>)) {
#Baux DHCP
#/var/log/messages:Nov 28 19:34:14 sme7b5 dhcpd: DHCPACK on 192.168.1.250 to 00:e0:4c:39:03:a5 via eth0
#Match: mmm dd hh:mm:ss hostname dhcpd: DHCPACK on ip to mac via eth0
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName dhcpd: DHCPACK on (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}) to ([0-9a-f:]{17}) \(([0-9a-zA-Z-]+)\) via/o) {
#$1:mois jour heure $2.$3.$4.$5:ip $6:mac
my $ip=ipdot2ipnum($2,$3,$4,$5);
my $hostname=ip2host("$2.$3.$4.$5");
my $date=mkmysqldate($1);
my $reslt=execute_sql_query("SELECT * FROM dhcpd WHERE ip='$ip'");
#si on a trouve une ligne ==> update
if ($reslt != "0E0") {
execute_sql_query("UPDATE dhcpd SET mac='$6', hostname='$hostname', debut='$date' WHERE ip='$ip'");
}
#sinon nouvelle ip ==> insert
else {
execute_sql_query("INSERT INTO dhcpd VALUES ('$ip','$6','$hostname','$date')");
}
$net_dhcp++;
next;
}
}
}
elsif ($nom eq "messages") {
while ( defined(my $l = <$fh>)) {
#Connexion afp (beta test ??) 1-ouverture session (548==>port afpovertcp)
#Jul 13 11:50:02 sas afpd[30668]: ASIP session:548(2) from 192.168.150.12:49278(0)
#Match: mmm dd hh:mm:ss hostname afpd[pid]: ASIP session:548(xxxx)?? from ip:port(xx?)
# non change par rapport a sme6admin
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName afpd\[(\d+)\]: ASIP session:\d+\(\d+\) from (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}):\d+/o) {
#$1:mois jour heure $2:pid $3.$4.$5.$6:ip
my $date=mkmysqldate($1);
my $ip=ipdot2ipnum($3,$4,$5,$6);
execute_sql_query("INSERT INTO afp VALUES ('$ip','$date',null,'$2',null,null,null)");
next;
}
#2-login user
#Jul 7 10:46:41 sas afpd[20523]: login sandrine (uid 5000,gid 5000) AFP2.2
#Match: date hostname afpd[pid]: login user
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName afpd\[(\d+)\]: login (\w+) \(uid \d+/o) {
#$1: date $2:pid $3:login
my $debut=mkmysqldate($1);
#pourquoi cette bidouille sur la date ??
#pour retrouver la bonne cnx=>pid et la date du open session
#il doit avoir eu lieu au plus 10sec avant le login
execute_sql_query("UPDATE afp SET login='$3' where pid_afpd=$2 and debut > '$debut' - interval 10 second");
next;
}
#3-logout && data transferred
#pourquoi faire les 2 en mm temps ?? cause des fois logout ou timeout ...
#Jul 7 17:04:08 sas afpd[20523]: 95.88KB read, 3014.84KB written
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName afpd\[(\d+)\]: ([0-9\.]+)KB read, ([0-9\.]+)KB written/o) {
#$1: date $2:pid $3:data read $4: data written
my $fin=mkmysqldate($1);
execute_sql_query("UPDATE afp SET fin='$fin', volume_read=$3, volume_write=$4 where pid_afpd=$2");
next;
}
#Matche des connexions PPPOE
#Changement entre sme6 et sme7 : apparemment, on a l'ip locale avant celle du peer dans les logs => inversion du INSERT et du UPDATE
# in fact if we use the IPCP string remote is there first in SME7, should be the same in SME8
#Jun 9 17:26:29 atlas pppd[5642]: rcvd [IPCP ConfReq id=0xf <addr 10.218.0.7>]
#Jun 9 17:26:29 atlas pppd[5642]: sent [IPCP ConfAck id=0xf <addr 10.218.0.7>]
#Jun 9 17:26:29 atlas pppd[5642]: rcvd [IPCP ConfNak id=0x1 <addr 209.0.239.34>]
#Jun 9 17:26:29 atlas pppd[5642]: sent [IPCP ConfReq id=0x2 <addr 209.0.239.34>]
#Jun 9 17:26:29 atlas pppd[5642]: rcvd [IPCP ConfAck id=0x2 <addr 209.0.239.34>]
#Jun 9 17:26:29 atlas pppd[5642]: local IP address 209.222.239.34
#Jun 9 17:26:29 atlas pppd[5642]: remote IP address 10.248.0.7
#Jun 9 17:26:29 atlas pppd[5642]: Script /etc/ppp/ip-up started (pid 5886)
#Jun 9 17:26:32 atlas esmith::event[5907]: Processing event: ip-up ppp0 38400 209.0.239.34 10.218.0.7 pppoe
#PPPOE ip local
#Jul 14 12:49:58 sas pppd[1878]: rcvd [IPCP ConfAck id=0x2 <addr 213.41.134.153>]
#Match: date hostname pppd[pid]: rcvd [IPCP ConfAck id=0xxx? <addr ip>]
#if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: rcvd \[IPCP ConfAck id=0x\w+ <addr (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})>\]/o)
#if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: rcvd \[IPCP ConfAck id=0x\w+ <addr (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})>\]/o) {
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: local IP address (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/o) {
#$1: date $2:pid $3.$4.$5.$6:ip
my $date=mkmysqldate($1);
my $ip=ipdot2ipnum($3,$4,$5,$6);
execute_sql_query("INSERT INTO pppoe VALUES ('$date',null,null,'$2','$ip',0,null,null)");# (peer can't be null)
next;
}
#PPPOE ip peer
#Jul 14 12:49:58 sas pppd[1878]: sent [IPCP ConfAck id=0x1 <addr 62.12.16.234>]
#Match: date hostname pppd[pid]: sent [IPCP ConfAck id=0xxx? <addr ip>]
#if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: sent \[IPCP ConfAck id=0x\w+ <addr (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})>\]/o)
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: remote IP address (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/o) {
#$1: date $2:pid $3.$4.$5.$6:ip
my $date=mkmysqldate($1);
my $ip=ipdot2ipnum($3,$4,$5,$6);
#faut faire un update, mais soit dans pppoe, soit dans vpn
my $reslt=execute_sql_query("SELECT * FROM pppoe WHERE pid_pppd='$2' ORDER BY debut DESC LIMIT 1");
my $requete="UPDATE ";
#si on a trouve une ligne ==> update dans pppoe
if ($reslt != "0E0") { $requete.="pppoe SET peer='$ip' where pid_pppd=$2 and debut > '$date' - interval 5 second ORDER BY debut DESC LIMIT 1";}
#sinon c une fin de cnx vpn; on fait un guess que deux connexions vpn ont pas eu lieu dans les memes 5 secondes...
else { $requete.="vpn SET vpn_clt='$ip' where pid_pppd=$2 and debut > '$date' - interval 5 second ORDER BY debut DESC LIMIT 1";}
# $requete.="SET peer='$ip' where pid_pppd=$2 and debut > '$date' - interval 5 second ORDER BY debut DESC LIMIT 1";
execute_sql_query($requete);
next;
}
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: local IP address (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/o) {
#$1: date $2:pid $3.$4.$5.$6:ip
my $date=mkmysqldate($1);
my $ip=ipdot2ipnum($3,$4,$5,$6);
#faut faire un update, mais soit dans pppoe, soit dans vpn
my $reslt=execute_sql_query("SELECT * FROM vpn WHERE debut > '$date' - interval 5 second ORDER BY debut DESC LIMIT 1");
my $requete="UPDATE ";
#si on a trouve une ligne ==> update dans vpn
my $smedb=esmith::ConfigDB->open;
my $localif = $smedb->get("LocalIP")->prop('type');
print "IP IF local $localif - IP $3.$4.$5.$6 \n";
if ($reslt != "0E0" && "$3.$4.$5.$6" eq $localif )
{ $requete.="vpn SET vpn_srv='$ip', pid_pppd=$2 WHERE pid_pppd IS NULL and debut > '$date' - interval 5 second ORDER BY debut DESC LIMIT 1";
execute_sql_query($requete);}
next;
}
#VPN ip vpn_srv & pid_pptpd
#old # Jun 25 15:43:31 test pptpd[636]: CTRL: local address = 192.168.2.1
#old: #if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pptpd\[(\d+)\]: CTRL: local address = (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/o) {
#Dec 15 15:59:13 atlas pptpd[19918]: CTRL: Client 24.14.190.157 control connection started
#Dec 15 15:59:13 atlas pptpd[19918]: CTRL: Starting call (launching pppd, opening GRE)
#Dec 15 15:59:13 atlas pppd[19919]: Plugin radius.so loaded.
#Dec 15 15:59:13 atlas pppd[19919]: RADIUS plugin initialized.
#Dec 15 15:59:13 atlas pppd[19919]: pppd 2.4.4 started by root, uid 0
#Dec 15 15:59:13 atlas pppd[19919]: Using interface ppp1
#Dec 15 15:59:13 atlas pppd[19919]: Connect: ppp1 <--> /dev/pts/5
#Dec 15 15:59:17 atlas pppd[19919]: MPPE 128-bit stateless compression enabled
#Dec 15 15:59:18 atlas pppd[19919]: found interface br0 for proxy arp
#Dec 15 15:59:18 atlas pppd[19919]: local IP address 192.168.12.1
#Dec 15 15:59:18 atlas pppd[19919]: remote IP address 192.168.12.250
#Dec 15 15:59:18 atlas esmith::event[19939]: Processing event: ip-up.pptpd ppp1 /dev/pts/5 460800 192.168.12.1 192.168.12.250 pptpd
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pptpd\[(\d+)\]: CTRL: Client (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}) control connection started/o) {
#$1: date $2:pid $3.$4.$5.$6:ip
my $date=mkmysqldate($1);
my $ip=ipdot2ipnum($3,$4,$5,$6);
execute_sql_query("INSERT INTO vpn VALUES ('$date',null,null,$ip,null,0,null,null,null,$2,null)");
next;
}
##VPN ip vpn_clt
##Jun 25 15:43:31 test pptpd[636]: CTRL: remote address = 192.168.2.250
##Dec 15 15:27:33 atlas pppd[15747]: remote IP address 192.168.12.250
##if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pptpd\[(\d+)\]: CTRL: remote address = (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/o) {
# #$1: date $2:pid $3.$4.$5.$6:ip
# my $date=mkmysqldate($1);
# my $ip=ipdot2ipnum($3,$4,$5,$6);
# execute_sql_query("UPDATE vpn SET vpn_clt=$ip where pid_pptpd=$2 and debut > '$date' - interval 5 second ORDER BY debut DESC LIMIT 1");
# next;
#}
##VPN ip client
##Jun 25 15:43:31 test pptpd[636]: CTRL: Client 192.168.185.66 control connection started
#if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pptpd\[(\d+)\]: CTRL: Client (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}) control connection started/o) {
# #$1: date $2:pid $3.$4.$5.$6:ip
# my $date=mkmysqldate($1);
# my $ip=ipdot2ipnum($3,$4,$5,$6);
# execute_sql_query("UPDATE vpn SET ip=$ip where pid_pptpd=$2 and debut > '$date' - interval 5 second ORDER BY debut DESC LIMIT 1");
# next;
#}
##VPN checkip pid_pppd
##Jun 25 15:43:33 test pptpd[637]: CTRL (PPPD Launcher): local address = 192.168.2.1
## does not exist anymore
#if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pptpd\[(\d+)\]: CTRL \(PPPD Launcher\): local address = (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/o) {
# #$1: date $2:pid !!! PPPD !!! $3.$4.$5.$6:ip
# my $date=mkmysqldate($1);
# my $ip=ipdot2ipnum($3,$4,$5,$6);
# execute_sql_query("UPDATE vpn SET pid_pppd=$2 where vpn_srv=$ip and debut > '$date' - interval 5 second ORDER BY debut DESC LIMIT 1");
# next;
#}
##Deprecated !!! Dans sme7, l'auth se fait via Radius, qui ne loggue rien par d<>faut => pas moyen de connaitre simplement le login
##VPN login
##Jun 25 15:43:36 test pppd[637]: CHAP peer authentication succeeded for rv
#if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: CHAP peer authentication succeeded for ([0-9a-z-]+)/o) {
# #$1: date $2:pid $3:login
# my $date=mkmysqldate($1);
# execute_sql_query("UPDATE vpn SET login='$3' where pid_pppd=$2 and debut > '$date' - interval 20 second ORDER BY debut DESC LIMIT 1");
# next;
#}
#PPPOE && VPN !!! temps de connexion
#Jul 15 12:49:58 sas pppd[1878]: Connect time 1440.0 minutes.
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: Connect time ([0-9\.]+) minutes\./o) {
#$1:date $2:pid $3:duree
my $date=mkmysqldate($1);
#faut faire un update, mais soit dans pppoe, soit dans vpn
my $reslt=execute_sql_query("SELECT * FROM pppoe WHERE pid_pppd='$2'");
my $requete="UPDATE ";
#si on a trouve une ligne ==> update dans pppoe
if ($reslt != "0E0") { $requete.="pppoe ";}
#sinon c une fin de cnx vpn
else { $requete.="vpn ";}
$requete.="SET duree=sec_to_time($3*60), fin='$date' where pid_pppd=$2 ORDER BY debut DESC LIMIT 1";
execute_sql_query($requete);
next;
}
#volume transfere
#PPPOE && VPN !!! volume transfere
#Jul 15 12:49:58 sas pppd[1878]: Sent 3786298 bytes, received 26799337 bytes.
if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: Sent (\d+) bytes, received (\d+) bytes\./o) {
#$1:date $2:pid $3:out $4:in
my $date=mkmysqldate($1);
#faut faire un update, mais soit dans pppoe, soit dans vpn
my $reslt=execute_sql_query("SELECT * FROM pppoe WHERE pid_pppd='$2'");
my $requete="UPDATE ";
#si on a trouve une ligne ==> update dans pppoe
if ($reslt != "0E0") { $requete.="pppoe ";}
#sinon c une fin de cnx vpn
else { $requete.="vpn ";}
$requete.="SET volume_out=$3, volume_in=$4 where pid_pppd=$2 and fin > '$date' - interval 5 second ORDER BY debut DESC LIMIT 1";
next;
}
}
}
# lib<69>ration du fichier de log courant, enregistrement de la position
tell_log("$logdir$nom", $fh);
}
deconnectBD();
}
#rewritten
sub execute_sql_query {
my ($requete)=(@_);
if (defined ($bd)) {
my $rq=$bd->prepare("$requete") or
warn "MYSQL error $DBI::errstr\n";
my $rslt=$rq->execute() or
warn "MYSQL error $DBI::errstr\n";
print "RQT MySQL : $requete , Reslt : $rslt/$!\n";
return $rslt;
}
else
{ print "mysql : no active connection to MySQL\n"; return 0;}
}
sub samba_status {
#connexions samba => gros changement depuis sme6 , les devs de samba ont eu la bonne idee de mettre la date de connexion dans une autre option (GRR)
#[root@sme7b5 codaz]# smbstatus -b
#5227 landry landry renton (10.246.200.10)
#5221 landry landry renton (10.246.200.10)
#[root@sme7b5 codaz]# smbstatus -S
#Primary 5227 renton Fri Dec 23 16:05:09 2005
#Primary 5221 renton Fri Dec 23 16:04:46 2005
connectBD();
$net_samba=0;
my $now=localtime;
$now=~ /\w{3} (\w{3}\s{1,2}\d{1,2} [0-9:]{8}) \d{4}/;
$now=mkmysqldate($1);
my @smbstatus1=`/usr/bin/smbstatus -b`;
my @smbstatus2=`/usr/bin/smbstatus -S`;
foreach(@smbstatus1) {
if(/(\d+)\s+([0-9a-z-]+)\s+[0-9a-z-]+\s+([0-9a-zA-Z-_]+)\s+\((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\)/) {
#$1:pid $2:login $3:machine $4,$5,$6,$7:ip
$net_samba++;
my $ip=ipdot2ipnum($4,$5,$6,$7);
my ($pid,$login,$machine)=($1,$2,$3);
#on cherche la date de debut de connexion en faisant la correspondance avec le pid
foreach (@smbstatus2) {
if(/\w+\s+(\d+)\s+\w+\s+\w{3} (\w{3}\s{1,2}\d{1,2} [0-9:]{8}) \d{4}/) {
#$1:pid $2:date
my $date=mkmysqldate($2);
if ($pid eq $1) {
my $reslt=execute_sql_query("SELECT * FROM samba WHERE ip=$ip and login='$login' and machine='$machine'");
#si on a trouve une ligne ==> update
if ($reslt != "0E0") {execute_sql_query("UPDATE samba SET debut='$date',derniere_vue='$now' WHERE ip='$ip' and login='$login' and machine='$machine'");}
#sinon nouvelle ligne ==> insert
else {execute_sql_query("INSERT INTO samba VALUES ($ip,'$login','$machine','$date','$date')");}
}
}
}
}
}
deconnectBD();
}
#fin de la collection des infos destinees a rentrer dans la BDD MySQL
#debut de la collection des infos pour RRDTool => graphes
# reecrit pour mieux supporter differents types de tags et de senseurs
# tagS = hda, hdc, temp1, temp2, fan2, CPU Temp, CPU Fan, etc...... => executer sensors en ligne de commande pour trouver le bon
sub get_sensors_hddtemp {
# $sensors_temp_cpu,$sensors_temp_hd,$sensors_temp_mb,$sensors_fan_speed
#fan2: 3970 RPM (min = 3000 RPM, div = 2)
#temp1: +30<33>C (limit = +60<36>C) sensor = thermistor
#temp2: +46.0<EFBFBD>C (limit = +60<36>C, hysteresis = +50<35>C) sensor = 3904 transistor
($sensors_temp1,$sensors_temp_hd1,$sensors_temp2,$sensors_temp_hd2,$sensors_fan_speed,$sensors_fan2_speed,$sensors_temp_hd3,$sensors_temp_hd4,$sensors_temp_hd5,$sensors_temp_hd6,)
=('U','U','U','U','U','U','U','U','U','U');
my ($tag1,$tag2,$tag3,$tag4,$tag5,$tag6,$tag7,$tag8,$tag9,$tag10)=($params{'SensorsTag1'},$params{'SensorsTag2'},$params{'SensorsTagFan'},
$params{'hd1'},$params{'hd2'},$params{'SensorsTagFan2'},$params{'hd3'},$params{'hd4'},$params{'hd5'},$params{'hd6'});
#a noter que si hddtemp & lm_sensors n'ont pas ete install<6C>s,ca ne plante pas !!
my @sensors=`/usr/bin/sensors -A 2> /dev/null`;
foreach (@sensors) {
if ($tag1 ne "" && (/$tag1:\s+(\+|-)?([0-9.]+).{1,2}C/o)) {$sensors_temp1=$2;}
if ($tag2 ne "" && (/$tag2:\s+(\+|-)?([0-9.]+).{1,2}C/o)) {$sensors_temp2=$2;}
if ($tag3 ne "" && (/$tag3:\s+(\d+) RPM/o)) {$sensors_fan_speed=$1;}
if ($tag6 ne "" && (/$tag6:\s+(\d+) RPM/o)) {$sensors_fan2_speed=$1;}
}
###Now we retrieve data from Hard-drive temp
if ($tag4 ne "") {
my @hddtemp=`/usr/sbin/hddtemp /dev/$tag4 2> /dev/null`;
foreach (@hddtemp) {
#/dev/hda: ExcelStor Technology J680 : 39<33>C ou <20>F
if (/\/dev\/$tag4:.*:\s+(\d+).{1,2}C/o) {$sensors_temp_hd1=$1;}
}
}
if ($tag5 ne "") {
my @hddtemp=`/usr/sbin/hddtemp /dev/$tag5 2> /dev/null`;
foreach (@hddtemp) {
if (/\/dev\/$tag5:.*:\s+(\d+).{1,2}C/) {$sensors_temp_hd2=$1;}
}
}
if ($tag7 ne "") {
my @hddtemp=`/usr/sbin/hddtemp /dev/$tag7 2> /dev/null`;
foreach (@hddtemp) {
if (/\/dev\/$tag7:.*:\s+(\d+).{1,2}C/) {$sensors_temp_hd3=$1;}
}
}
if ($tag8 ne "") {
my @hddtemp=`/usr/sbin/hddtemp /dev/$tag8 2> /dev/null`;
foreach (@hddtemp) {
if (/\/dev\/$tag8:.*:\s+(\d+).{1,2}C/) {$sensors_temp_hd4=$1;}
}
}
if ($tag9 ne "") {
my @hddtemp=`/usr/sbin/hddtemp /dev/$tag9 2> /dev/null`;
foreach (@hddtemp) {
if (/\/dev\/$tag9:.*:\s+(\d+).{1,2}C/) {$sensors_temp_hd5=$1;}
}
}
if ($tag10 ne "") {
my @hddtemp=`/usr/sbin/hddtemp /dev/$tag10 2> /dev/null`;
foreach (@hddtemp) {
if (/\/dev\/$tag10:.*:\s+(\d+).{1,2}C/) {$sensors_temp_hd6=$1;}
}
}
}
sub get_df_du {
($hd_total,$hd_used,$hd_free,$hd_log,$hd_files,$hd_squid,$hd_mysql)=(0,0,0,'U','U','U','U');
# total : taille totale du disque en ko
# used : place utilisee
# free : place libre
# log : place prise par /var/log/
# files : place prise par /home/e-smith/files/
# squid : place prise par /var/spool/squid/
# mysql : place prise par /var/lib/mysql/
my @df=`/bin/df --block-size=1 --local`;
foreach (@df) {
#Filesystem 1-blocks Used Available Use% Mounted on
#/dev/hda3 2812182528 1438830592 1230499840 54% /
#/dev/hda1 99911680 14383104 80369664 16% /boot
#OLD expreg if(/dev\/\S+\s+\d+\s+(\d+)\s+(\d+)\s+\d+\%/) => Cyril's fix
# si on veut ajouter une partition montee ailleurs que / /home ou /boot, patcher l'expreg ici
if(/\s+\d+\s+(\d+)\s+(\d+)\s+\d+\%\s+\/(home.*|boot)?\s+?$/) {
$hd_used+=$1;
$hd_free+=$2;
}
}
$hd_total=$hd_used+$hd_free;
if ($params{'UseDu'} eq "on") {
my @du=`/usr/bin/du -sb /var/log /var/spool/squid /var/lib/mysql /home/e-smith/files`;
foreach (@du) {
#149442560 /var/log
if(/(\d+)\s+\/var\/log/) {$hd_log=$1;}
if(/(\d+)\s+\/home\/e-smith\/files/) {$hd_files=$1;}
if(/(\d+)\s+\/var\/spool\/squid/) {$hd_squid=$1;}
if(/(\d+)\s+\/var\/lib\/mysql/) {$hd_mysql=$1;}
}
}
}
sub get_ping {
($net_minlatency,$net_avglatency,$net_maxlatency,$net_loss)=('U','U','U','U');
#si PingTarget est nul, on prend la gateway par defaut
my $target=$params{'PingTarget'};
if ($target eq "") {
#on determine la gateway par defaut
my @route=`route -n`;
foreach (@route) {
#0.0.0.062.4.16.247 0.0.0.0 UG 0 0 0 ppp0
if(/0\.0\.0\.0\s+(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/){$target="$1.$2.$3.$4";}
}
}
my @ping=`/bin/ping -c 20 -i 0.25 -qnw 7 $target 2> /dev/null`;
foreach (@ping) {
#[root@sme7b5 codaz]# /bin/ping -c 20 -i 0.25 -qnw 7 google.fr
#20 packets transmitted, 20 received, 0% packet loss, time 4768ms
#rtt min/avg/max/mdev = 147.019/160.127/171.536/7.289 ms, pipe 2
if (/(\d+)% packet loss/) {$net_loss=$1;}
if (/(\d+\.\d+)\/(\d+\.\d+)\/(\d+\.\d+)\/\d+\.\d+ ms/) { $net_minlatency=$1/1000; $net_avglatency=$2/1000; $net_maxlatency=$3/1000;}
}
}
sub get_netstat {
($sessions_ftp,$sessions_ssh,$sessions_vpn,$sessions_netbios,$sessions_afp)=(0,0,0,0,0);
# plus simple, plus rapide avec tcp/numeric
# par contre, a surveiller le passage de samba du port 139 a 445
my @netstat=`/bin/netstat --inet --tcp --numeric`;
foreach (@netstat) {
if (/tcp\s+\d+\s+\d+\s\S+:${SshPort}\s+\S+\s+ESTABLISHED/){$sessions_ssh++;}
if (/tcp\s+\d+\s+\d+\s\S+:21\s+\S+\s+ESTABLISHED/){$sessions_ftp++;}
if (/tcp\s+\d+\s+\d+\s\S+:1723\s+\S+\s+ESTABLISHED/){$sessions_vpn++;}
if (/tcp\s+\d+\s+\d+\s\S+:548\s+\S+\s+ESTABLISHED/){$sessions_afp++;}
if (/tcp\s+\d+\s+\d+\s\S+:445\s+\S+\s+ESTABLISHED/){$sessions_netbios++;}
}
#une cnx ssh
#tcp 0 0 10.246.200.13:22 10.246.200.10:37304 ESTABLISHED
#une cnx ftp
#tcp 0 0 10.246.200.13:21 10.246.200.10:47412 ESTABLISHED
#une cnx vpn
#tcp 0 0 192.168.185.74:1723 10.246.200.10:2176 ESTABLISHED
#une cnx netbios
#tcp 0 0 10.246.200.13:445 10.246.200.10:42368 ESTABLISHED
}
#ici on utilise sysstat pour recuperer un maxx de stats sur le fonctionnement du systeme
sub get_sar {
($if_loc_bin,$if_loc_bout,$if_loc_pin,$if_loc_pout)=('U','U','U','U');
($if_ext_bin,$if_ext_bout,$if_ext_pin,$if_ext_pout)=('U','U','U','U');
($cpu_total,$cpu_idle,$cpu_system,$cpu_user)=('U','U','U','U');
($hd_blkread,$hd_blkwrite)=('U','U');
($cpu_nice,$cpu_plist,$cpu_runq,$cpu_load1,$cpu_load5,$cpu_load15,$cpu_uptime)=('U','U','U','U','U','U','U');
($mem_memtotal,$mem_memused,$mem_memfree,$mem_memactualused,$mem_memactualfree)=('U','U','U','U','U');
($mem_membuffers,$mem_memcache,$mem_swaptotal,$mem_swapused,$mem_swapfree)=('U','U','U','U','U');
rename("$rrddir/sadc.bck","$rrddir/sadc.out");
if ( -x '/usr/lib/sa/sadc' ) {
`/usr/lib/sa/sadc 1 1 $rrddir/sadc.out; /usr/lib/sa/sadc 1 1 $rrddir/sadc.bck`;}
else
{`/usr/lib64/sa/sadc 1 1 $rrddir/sadc.out; /usr/lib64/sa/sadc 1 1 $rrddir/sadc.bck`;}
# small change to support sysstat > 5.1
my @sardata;
if ( -x '/usr/bin/sadf' ) { @sardata=`/usr/bin/sadf -- -qrbuS -n DEV $rrddir/sadc.out`; }
# Now we could remove the followed line, since with sme9 it is no more needed
else { @sardata=`/usr/bin/sar -hqrbu -n DEV -f $rrddir/sadc.out`; }
unlink("$rrddir/sadc.out");
foreach (@sardata) {
#print "Ligne courante matchee : $_";
#format de sortie de sar -h
#hostname interval timestamp device/- field value
#test 233 1090416323 eth0 rxpck/s 4,84 Locale FR
#test 233 1090416323 eth0 rxpck/s 4.84 Locale US
#cpu usage %
if(/all\s\%user\s(\d+)(,|\.)(\d+)/){$cpu_user="$1.$3";}
if(/all\s\%nice\s(\d+)(,|\.)(\d+)/){$cpu_nice="$1.$3";}
if(/all\s\%system\s(\d+)(,|\.)(\d+)/){$cpu_system="$1.$3";}
if(/all\s\%idle\s(\d+)(,|\.)(\d+)/){$cpu_idle="$1.$3"; $cpu_total=100-$cpu_idle;}
#bytes r/w
if(/bread\/s\s(\d+)(,|\.)(\d+)/){$hd_blkread="$1.$3";}
if(/bwrtn\/s\s(\d+)(,|\.)(\d+)/){$hd_blkwrite="$1.$3";}
#local net
if(/$InternalInterface\srxpck\/s\s(\d+)(,|\.)(\d+)/o){$if_loc_pin="$1.$3";}
if(/$InternalInterface\stxpck\/s\s(\d+)(,|\.)(\d+)/o){$if_loc_pout="$1.$3";}
if(/$InternalInterface\srxkB\/s\s(\d+)(,|\.)(\d+)/o){$if_loc_bin="$1.$3";}
if(/$InternalInterface\stxkB\/s\s(\d+)(,|\.)(\d+)/o){$if_loc_bout="$1.$3";}
#external net (if not SrvOnly)
if (defined $ExternalInterface) {
if(/$ExternalInterface\srxpck\/s\s(\d+)(,|\.)(\d+)/o){$if_ext_pin="$1.$3";}
if(/$ExternalInterface\stxpck\/s\s(\d+)(,|\.)(\d+)/o){$if_ext_pout="$1.$3";}
if(/$ExternalInterface\srxkB\/s\s(\d+)(,|\.)(\d+)/o){$if_ext_bin="$1.$3";}
if(/$ExternalInterface\stxkB\/s\s(\d+)(,|\.)(\d+)/o){$if_ext_bout="$1.$3";}
}
#memory
if(/kbmemfree\s(\d+)/) {$mem_memactualfree=$1*1024;}
if(/kbmemused\s(\d+)/) {$mem_memactualused=$1*1024;}
if(/kbbuffers\s(\d+)/) {$mem_membuffers=$1*1024;}
if(/kbcached\s(\d+)/) {$mem_memcache=$1*1024;}
if(/kbswpfree\s(\d+)/) {$mem_swapfree=$1*1024;}
if(/kbswpused\s(\d+)/) {$mem_swapused=$1*1024;}
#processus
if(/runq-sz\s(\d+)/) {$cpu_runq=$1;}
if(/plist-sz\s(\d+)/) {$cpu_plist=$1;}
if(/ldavg-1\s(\d+)(,|\.)(\d+)/) {$cpu_load1="$1.$3";}
if(/ldavg-5\s(\d+)(,|\.)(\d+)/) {$cpu_load5="$1.$3";}
if(/ldavg-15\s(\d+)(,|\.)(\d+)/) {$cpu_load15="$1.$3";}
}
$mem_memtotal = $mem_memactualused + $mem_memactualfree;
$mem_memused = $mem_memactualused - $mem_memcache - $mem_membuffers;
$mem_memfree = $mem_memactualfree + $mem_memcache + $mem_membuffers;
$mem_swaptotal = $mem_swapused + $mem_swapfree;
#uptime
my $uptime=`/bin/cat /proc/uptime`;
$uptime=~/^([0-9\.]+)/;
$cpu_uptime=$1;
}
# cette fonction calcule l'occupation cpu/mem des processus correspondants aux services http/samba/afp/squid
sub get_proc {
my %services=( "httpd" => "httpd-admin httpd",
"samba" => "nmbd smbd",
"afp" => "atalkd afpd papd cnid_metad", #ajout de cnid_metad
"squid" => "squid \\(unlinkd\\)"); #suppression de (squid)
no strict 'refs';
foreach my $svc (keys(%services)) {
${$svc.'_nbproc'}='U';
${$svc.'_mem'}='U';
${$svc.'_cpu'}='U';
my $pids=`/sbin/pidof $services{$svc}`;
#on fait le ps que si le service tourne ==> qui si pidof a renvoye qqch
if ($pids ne "\n") {
${$svc.'_nbproc'}=0;
${$svc.'_mem'}=0;
${$svc.'_cpu'}=0;
my @lines=`/bin/ps h o \%cpu,\%mem p $pids` if ($pids ne '');#sometime $pids is empty
foreach(@lines) {
my $line=$_;
$line =~ /\s([\d.]+)\s+([\d.]+)/;
${$svc.'_nbproc'}++;
${$svc.'_cpu'}+=$1;
${$svc.'_mem'}+=$2;
}
}
}
$httpd_cpu=${'httpd_cpu'}; $httpd_mem=${'httpd_mem'}; $httpd_nbproc=${'httpd_nbproc'};
$samba_cpu=${'samba_cpu'}; $samba_mem=${'samba_mem'}; $samba_nbproc=${'samba_nbproc'};
$afp_cpu=${'afp_cpu'}; $afp_mem=${'afp_mem'}; $afp_nbproc=${'afp_nbproc'};
$squid_cpu=${'squid_cpu'}; $squid_mem=${'squid_mem'}; $squid_nbproc=${'squid_nbproc'};
use strict qw(refs);
}
# cette fonction met a jour les RRDs. Elle a ete "factorisee" pour plus de lisibilite
sub update_rrd {
#DEBUG !!
debug "sensors_temp1=$sensors_temp1,sensors_temp_hd1=$sensors_temp_hd1,sensors_temp_hd2=$sensors_temp_hd2,";
debug "sensors_temp2=$sensors_temp2,sensors_fan_speed=$sensors_fan_speed,sensors_fan2_speed=$sensors_fan2_speed\n";
debug "hd_total=$hd_total,hd_used=$hd_used,hd_free=$hd_free,hd_log=$hd_log,";
debug "hd_files=$hd_files,hd_squid=$hd_squid,hd_mysql=$hd_mysql,hd_blkread=$hd_blkread,hd_blkwrite=$hd_blkwrite\n";
debug "if_loc_bin=$if_loc_bin,if_loc_bout=$if_loc_bout,if_loc_pin=$if_loc_pin,if_loc_pout=$if_loc_pout\n";
debug "if_ext_bin=$if_ext_bin,if_ext_bout=$if_ext_bout,if_ext_pin=$if_ext_pin,if_ext_pout=$if_ext_pout\n";
debug "net_samba=$net_samba,net_minlatency=$net_minlatency,net_avglatency=$net_avglatency,";
debug "net_maxlatency=$net_maxlatency,net_loss=$net_loss,net_spam=$net_spam,net_virus=$net_virus,";
debug "net_dhcp=$net_dhcp,net_mail_in=$net_mail_in,net_mail_out=$net_mail_out\n";
debug "cpu_total=$cpu_total,cpu_idle=$cpu_idle,cpu_system=$cpu_system,cpu_user=$cpu_user\n";
debug "cpu_nice=$cpu_nice,cpu_plist=$cpu_plist,cpu_runq=$cpu_runq";
debug "cpu_load1=$cpu_load1,cpu_load5=$cpu_load5,cpu_load15=$cpu_load15,cpu_uptime=$cpu_uptime\n";
debug "mem_memtotal=$mem_memtotal,mem_memused=$mem_memused,mem_memfree=$mem_memfree";
debug "mem_memactualused=$mem_memactualused,mem_memactualfree=$mem_memactualfree\n";
debug "mem_membuffers=$mem_membuffers,mem_memcache=$mem_memcache";
debug "mem_swaptotal=$mem_swaptotal,mem_swapused=$mem_swapused,mem_swapfree=$mem_swapfree\n";
debug "httpd cpu=$httpd_cpu, mem=$httpd_mem, nb=$httpd_nbproc\n";
debug "samba cpu=$samba_cpu, mem=$samba_mem, nb=$samba_nbproc\n";
debug "afp cpu=$afp_cpu, mem=$afp_mem, nb=$afp_nbproc\n";
debug "squid cpu=$squid_cpu, mem=$squid_mem, nb=$squid_nbproc\n";
debug "sessions_ftp=$sessions_ftp,sessions_ssh=$sessions_ssh,";
debug "sessions_vpn=$sessions_vpn,sessions_netbios=$sessions_netbios\n";
my $listqp=join(':', map {$_} keys %denied,@others);
foreach (keys %denied,@others){ debug "$_: $cnt{$_},";}; debug "\n";
#print join(':', map {$_,$cnt{$_}} keys %denied,@others); print "\n";
debug "qmail ";
foreach (@resultsqm){ debug "local_$_:$cntqmlocal{$_},";}; foreach (@resultsqm){ debug "$_:$cntqm{$_},";};
debug "localqueue=$localqueue,remotequeue=$remotequeue\n";
# print join(':', map {$cntqmlocal{$_}} @resultsqm) .":". join(':', map {$cntqm{$_}} @resultsqm); print ":". $localqueue .":". $remotequeue; print "\n";
if (defined $localaqueue) {
debug("altqmail ");
foreach (@resultsaqm){ debug "local_$_:$cntaqmlocal{$_},";}; foreach (@resultsaqm){ debug "$_:$cntaqm{$_},";}; debug "\n";
debug("localqueue=$localaqueue,remotequeue=$remoteaqueue\n");
# print join(':', map {$cntaqmlocal{$_}} @resultsaqm) .":". join(':', map {$cntaqm{$_}} @resultsaqm); print ":". $localaqueue .":". $remoteaqueue; print "\n";
} else {
$localaqueue=""; $remoteaqueue="";
}
my %rrds=(
"sensors"=>"$sensors_temp1:$sensors_temp2:$sensors_temp_hd1:$sensors_temp_hd2:$sensors_fan_speed:$sensors_fan2_speed:$sensors_temp_hd3:$sensors_temp_hd4:$sensors_temp_hd5:$sensors_temp_hd6",
"hd"=>"$hd_total:$hd_used:$hd_free:$hd_log:$hd_files:$hd_squid:$hd_mysql:$hd_blkread:$hd_blkwrite",
"if_loc"=>"$if_loc_bin:$if_loc_bout:$if_loc_pin:$if_loc_pout",
"if_ext"=>"$if_ext_bin:$if_ext_bout:$if_ext_pin:$if_ext_pout",
"net"=>"$net_samba:$net_dhcp:$net_mail_in:$net_mail_out:$net_spam:$net_virus:$net_minlatency:$net_avglatency:$net_maxlatency:$net_loss",
"cpu"=>"$cpu_total:$cpu_idle:$cpu_system:$cpu_user:$cpu_nice:$cpu_plist:$cpu_runq:$cpu_load1:$cpu_load5:$cpu_load15:$cpu_uptime",
"mem"=>"$mem_memtotal:$mem_memused:$mem_memfree:$mem_memactualused:$mem_memactualfree:$mem_membuffers:$mem_memcache:$mem_swaptotal:$mem_swapused:$mem_swapfree",
"httpd"=>"$httpd_cpu:$httpd_mem:$httpd_nbproc",
"samba"=>"$samba_cpu:$samba_mem:$samba_nbproc",
"afp"=>"$afp_cpu:$afp_mem:$afp_nbproc",
"squid"=>"$squid_cpu:$squid_mem:$squid_nbproc",
"sessions"=>"$sessions_ssh:$sessions_ftp:$sessions_vpn:$sessions_netbios:$sessions_afp",
"qpsmtpd" => join(':', map {$cnt{$_}} keys %denied,@others),
"qmail" => join(':', map {$cntqmlocal{$_}} @resultsqm) .":". join(':', map {$cntqm{$_}} @resultsqm) . ":". $localqueue .":". $remotequeue,
"altqmail" => join(':', map {$cntaqmlocal{$_}} @resultsaqm) .":". join(':', map {$cntaqm{$_}} @resultsaqm) . ":". $localaqueue .":". $remoteaqueue);
my $error;
foreach my $rrd (keys %rrds) {
if ( $rrd eq "qpsmtpd") {
# TODO: would be great to use template for all of them rather than assuming we are putting value in the right DS
# was needed for qpsmtpd when adding auth_failed, which could be anywhere.
RRDs::update ("$rrddir/$rrd.rrd","--template", "$listqp" ,"N:$rrds{$rrd}");
}
else {
RRDs::update ("$rrddir/$rrd.rrd","N:$rrds{$rrd}");
}
$error=RRDs::error;
print gettext("Error at RRDs::update"),"($rrd.rrd) :$error\n" if $error;
}
}
#envoi des differents mails
#mail de status avec les infos les plus pertinentes sur l'etat du serveur
sub mail_status {
my $mail = new Mail::Send;
$mail->to("$params{'StatusMailRecipient'}");
$mail->set("From","smeadmin-daemon");
$mail->subject("[STATUS] $SystemName.$DomainName");
my $body = $mail->open;
print $body localtime(time)."\n",
gettext("Server status\n"),
gettext("Number of opened connections : "),"ssh=$sessions_ssh ftp=$sessions_ftp vpn=$sessions_vpn netbios=$sessions_netbios\n",
"\n#>tail /var/log/messages :\n",
`/usr/bin/tail /var/log/messages`,
"\n#>netstat --numeric-hosts -tpu :\n", #ajoute dans smeadmin
`/bin/netstat --numeric-hosts -tpu`,
"\n#>service httpd-e-smith status\n",
`/sbin/service httpd-e-smith status`,
"\n#>service httpd-admin status\n",
`/sbin/service httpd-admin status`,
"\n#>service smb status\n",
`/sbin/service smb status`,
"\n#>service sshd status\n",
`/sbin/service sshd status`;
$body->close;
}
#envoie des mails d'alerte
sub mail_alerte {
my $pourc_hd_used = int(($hd_used/$hd_total)*100);
#ici, on utilise un tableau d'alertes. (Je trouve ca plus elegant et plus extensible). Pour chacune, on a
# - un test qui d<>clenche ou non l'alerte
# - le sujet du mail a envoyer
# - une fonction inline qui renvoie le texte du mail
my @tab_of_alerts=(
[
"($params{'MaxMailIn'} && $net_mail_in >= $params{'MaxMailIn'})",
"[ALRT] $SystemName.$DomainName : mail in = $net_mail_in (max=$params{'MaxMailIn'})",
sub { return
sprintf(gettext("During the last 5 minutes, %s incoming e-mails were detected, "),$net_mail_in),
sprintf(gettext("you had set the alert limit to %s incoming e-mails.\n"),$params{'MaxMailIn'}),
gettext("(Possible reasons : do you receive spam ? a mailbomb ? mailing-lists ?)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxMailIn",
"\n# tail /var/log/qmail/current\n",
`/usr/bin/tail /var/log/qmail/current -n500 | /usr/local/bin/tai64nlocal |/bin/grep 'starting delivery'`;
}],
[
"($params{'MaxMailOut'} && $net_mail_out >= $params{'MaxMailOut'})",
"[ALRT] $SystemName.$DomainName : mail out = $net_mail_out (max=$params{'MaxMailOut'})",
sub { return
sprintf(gettext("During the last 5 minutes, %s outgoing e-mails were detected, "),$net_mail_out),
sprintf(gettext("you had set the alert limit to %s outgoing e-mails.\n"),$params{'MaxMailOut'}),
gettext("(Possible reasons : do you send spam ? administrate a mailing-list ?)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxMailOut",
"\n# tail /var/log/qmail/current\n",
`/usr/bin/tail /var/log/qmail/current -n500 |/usr/local/bin/tai64nlocal |/bin/grep -P "(starting delivery|delivery) \\d+: (msg \\d+|success|failure|deferral).*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|CNAME_lookup_failed_temporarily|Sorry,_I_wasn't_able_to_establish_an_SMTP_connection|to remote .*)"`;
}],
[
"($params{'MaxDiskSpace'} && $pourc_hd_used >= $params{'MaxDiskSpace'})",
"[ALRT] $SystemName.$DomainName : du = $pourc_hd_used % (max=$params{'MaxDiskSpace'} %)",
sub { return
sprintf(gettext("Your hard disk is %s %% full, "),$pourc_hd_used),
sprintf(gettext("you had set the alert limit to %s %%.\n"),$params{'MaxDiskSpace'}),
gettext("(Advice : free space by deleting temp files, or upgrade your disk space)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxDiskSpace",
"\n#df\n",
`df -hTP`;
}],
[
"($params{'MaxCpu'} && $cpu_total >= $params{'MaxCpu'})",
"[ALRT] $SystemName.$DomainName : cpu = $cpu_total % (max=$params{'MaxCpu'} %)",
sub { return
sprintf(gettext("Your processor is %s %% loaded, "),$cpu_total),
sprintf(gettext("you had set the alert limit to %s %%.\n"),$params{'MaxCpu'}),
gettext("(Possible reasons : Is there a crashed process ? an intense and prolonged activity on the server ?)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxCpu",
"\n#top\n",
`/usr/bin/top -b -n1|head -n 20`;
}],
[
"($params{'MaxHwTemp'} && '$params{'SensorsTag1'}' ne '' && '$sensors_temp1' ne 'U' && $sensors_temp1 >= $params{'MaxHwTemp'})",
"[ALRT] $SystemName.$DomainName : $params{'SensorsTag1'} = $sensors_temp1 deg C (max=$params{'MaxHwTemp'} deg C)",
sub { return
sprintf(gettext("The temperature reported by sensor %s is %s degrees C, "),($params{'SensorsTag1'},$sensors_temp1)),
sprintf(gettext("you had set the alert limit to %s degrees C.\n"),$params{'MaxHwTemp'}),
gettext("(Advice : check the fans, and if the room is well ventilated or under AC.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxHwTemp";
}],
[
"($params{'MaxHwTemp'} && '$params{'SensorsTag2'}' ne '' && '$sensors_temp2' ne 'U' && $sensors_temp2 >= $params{'MaxHwTemp'})",
"[ALRT] $SystemName.$DomainName : $params{'SensorsTag2'} = $sensors_temp2 deg C (max=$params{'MaxHwTemp'} deg C)",
sub { return
sprintf(gettext("The temperature reported by sensor %s is %s degrees C, "),($params{'SensorsTag2'},$sensors_temp2)),
sprintf(gettext("you had set the alert limit to %s degrees C.\n"),$params{'MaxHwTemp'}),
gettext("(Advice : check the fans, and if the room is well ventilated or under AC.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxHwTemp";
}],
[
"($params{'MaxHdTemp'} && '$params{'hd1'}' ne '' && '$sensors_temp_hd1' ne 'U' && $sensors_temp_hd1 >= $params{'MaxHdTemp'})",
"[ALRT] $SystemName.$DomainName: temp $params{'hd1'} = $sensors_temp_hd1 deg C (max=$params{'MaxHdTemp'} deg C)",
sub { return
sprintf(gettext("The temperature of %s hard disk is %s degrees C, "),($params{'hd1'},$sensors_temp_hd1)),
sprintf(gettext("you had set the alert limit to %s degrees C.\n"),$params{'MaxHdTemp'}),
gettext("(Advice : check if the server case and the hard disks are well cooled.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxHdTemp";
}],
[
"($params{'MaxHdTemp'} && '$params{'hd2'}' ne '' && '$sensors_temp_hd2' ne 'U' && $sensors_temp_hd2 >= $params{'MaxHdTemp'})",
"[ALRT] $SystemName.$DomainName: temp $params{'hd2'} = $sensors_temp_hd2 deg C (max=$params{'MaxHdTemp'} deg C)",
sub { return
sprintf(gettext("The temperature of %s hard disk is %s degrees C, "),($params{'hd2'},$sensors_temp_hd2)),
sprintf(gettext("you had set the alert limit to %s degrees C.\n"),$params{'MaxHdTemp'}),
gettext("(Advice : check if the server case and the hard disks are well cooled.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxHdTemp";
}],
[
"($params{'MaxHdTemp'} && '$params{'hd3'}' ne '' && '$sensors_temp_hd3' ne 'U' && $sensors_temp_hd3 >= $params{'MaxHdTemp'})",
"[ALRT] $SystemName.$DomainName: temp $params{'hd3'} = $sensors_temp_hd3 deg C (max=$params{'MaxHdTemp'} deg C)",
sub { return
sprintf(gettext("The temperature of %s hard disk is %s degrees C, "),($params{'hd3'},$sensors_temp_hd3)),
sprintf(gettext("you had set the alert limit to %s degrees C.\n"),$params{'MaxHdTemp'}),
gettext("(Advice : check if the server case and the hard disks are well cooled.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxHdTemp";
}],
[
"($params{'MaxHdTemp'} && '$params{'hd4'}' ne '' && '$sensors_temp_hd4' ne 'U' && $sensors_temp_hd4 >= $params{'MaxHdTemp'})",
"[ALRT] $SystemName.$DomainName: temp $params{'hd4'} = $sensors_temp_hd4 deg C (max=$params{'MaxHdTemp'} deg C)",
sub { return
sprintf(gettext("The temperature of %s hard disk is %s degrees C, "),($params{'hd4'},$sensors_temp_hd4)),
sprintf(gettext("you had set the alert limit to %s degrees C.\n"),$params{'MaxHdTemp'}),
gettext("(Advice : check if the server case and the hard disks are well cooled.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxHdTemp";
}],
[
"($params{'MaxHdTemp'} && '$params{'hd5'}' ne '' && '$sensors_temp_hd5' ne 'U' && $sensors_temp_hd5 >= $params{'MaxHdTemp'})",
"[ALRT] $SystemName.$DomainName: temp $params{'hd5'} = $sensors_temp_hd5 deg C (max=$params{'MaxHdTemp'} deg C)",
sub { return
sprintf(gettext("The temperature of %s hard disk is %s degrees C, "),($params{'hd5'},$sensors_temp_hd5)),
sprintf(gettext("you had set the alert limit to %s degrees C.\n"),$params{'MaxHdTemp'}),
gettext("(Advice : check if the server case and the hard disks are well cooled.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxHdTemp";
}],
[
"($params{'MaxHdTemp'} && '$params{'hd6'}' ne '' && '$sensors_temp_hd6' ne 'U' && $sensors_temp_hd6 >= $params{'MaxHdTemp'})",
"[ALRT] $SystemName.$DomainName: temp $params{'hd6'} = $sensors_temp_hd6 deg C (max=$params{'MaxHdTemp'} deg C)",
sub { return
sprintf(gettext("The temperature of %s hard disk is %s degrees C, "),($params{'hd6'},$sensors_temp_hd6)),
sprintf(gettext("you had set the alert limit to %s degrees C.\n"),$params{'MaxHdTemp'}),
gettext("(Advice : check if the server case and the hard disks are well cooled.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxHdTemp";
}],
[
"($params{'MaxSamba'} && $sessions_netbios >= $params{'MaxSamba'})",
"[ALRT] $SystemName.$DomainName : cnx samba = $sessions_netbios (max=$params{'MaxSamba'})",
sub { return
sprintf(gettext("There are %s opened connections to the SAMBA service, "),$sessions_netbios),
sprintf(gettext("you had set the alert limit to %s connections.\n"),$params{'MaxSamba'}),
gettext("(Advice : if you encounter problems accessing local neighboorhood, kill some connections.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxSamba";
}],
[
"($params{'MaxSsh'} && $sessions_ssh >= $params{'MaxSsh'})",
"[ALRT] $SystemName.$DomainName : cnx ssh = $sessions_ssh (max=$params{'MaxSsh'})",
sub { return
sprintf(gettext("There are %s opened SSH sessions on the server, "),$sessions_ssh),
sprintf(gettext("you had set the alert limit to %s sessions.\n"),$params{'MaxSsh'}),
gettext("(Advice : check if it is known administrative connections, and not hackers.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxSsh",
"\n#who\n",
`who`,
"#netstat -n |grep :22\n",
`netstat -n |grep :${SshPort}`;
}],
[
"($params{'MaxFtp'} && $sessions_ftp >= $params{'MaxFtp'})",
"[ALRT] $SystemName.$DomainName : cnx ftp = $sessions_ftp (max=$params{'MaxFtp'})",
sub { return
sprintf(gettext("There are %s opened FTP sessions on the server, "),$sessions_ftp),
sprintf(gettext("you had set the alert limit to %s sessions.\n"),$params{'MaxFtp'}),
gettext("(Advice : check that it is authorized users only.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxFtp",
"\n#netstat -n |grep :21\n",
`netstat -n |grep :21`;
}],
[
"($params{'MaxVpn'} && $sessions_vpn >= $params{'MaxVpn'})",
"[ALRT] $SystemName.$DomainName : cnx vpn = $sessions_vpn (max=$params{'MaxVpn'})",
sub { return
sprintf(gettext("There are %s opened VPN sessions on the server, "),$sessions_vpn),
sprintf(gettext("you had set the alert limit to %s sessions.\n"),$params{'MaxVpn'}),
gettext("(Advice : check that it is authorized users only.)\n"),
gettext("If you have access to the server-manager, use this link to modify the limit :\n"),
"https://$SystemName.$DomainName/server-manager/cgi-bin/smeadmin?state=conf_alert&alert=MaxVpn",
"\n# netstat -n|grep -E ':(1723|1194)\n",
`netstat -n |grep -E ':(1723|1194)'`;
}]
);
#Une fois toutes ces alertes declarees, on va les tester et envoyer eventuellement
my $mail = new Mail::Send;
#destinataire
$mail->to("$params{'AlertMailRecipient'}");
#source
$mail->set("From","smeadmin-daemon");
foreach (@tab_of_alerts) {
my @line=$_;
my $test=$line[0][0]; # le test a effectuer
my $subject=$line[0][1]; # le sujet du message
my $text=$line[0][2]; # la fonction a appeler pour recuperer le texte du message
if (eval $test)
{
$mail->subject($subject);
my $body = $mail->open;
print $body "$SystemName.$DomainName :".localtime(time)."\n", &$text; # on appelle la fonction inline
$body->close; # on envoie le mail
}
}
}