#!/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 , 2006. # version 1.2 : Pascal Schirrmann , 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érieur à 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û"=>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, "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ées my ($name,$packaddr,@bytes); $ip =~ s/^\s+|\s+$//g; # on supprime des espaces éventuels en début et fin de l'IP @bytes = split (/\./, $ip); # on range dans un tableau, les 4 nombres séparés par des points de l'IP $packaddr = pack ("C4", @bytes); # on encode l'adresse IP, en un entier compacté # 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é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é 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 = ; 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é 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é/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é 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 ] #Jun 9 17:26:29 atlas pppd[5642]: sent [IPCP ConfAck id=0xf ] #Jun 9 17:26:29 atlas pppd[5642]: rcvd [IPCP ConfNak id=0x1 ] #Jun 9 17:26:29 atlas pppd[5642]: sent [IPCP ConfReq id=0x2 ] #Jun 9 17:26:29 atlas pppd[5642]: rcvd [IPCP ConfAck id=0x2 ] #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 ] #Match: date hostname pppd[pid]: rcvd [IPCP ConfAck id=0xxx? ] #if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: rcvd \[IPCP ConfAck id=0x\w+ \]/o) #if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: rcvd \[IPCP ConfAck id=0x\w+ \]/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 ] #Match: date hostname pppd[pid]: sent [IPCP ConfAck id=0xxx? ] #if($l =~ /(\w{3}\s{1,2}\d{1,2} [0-9:]{8}) $SystemName pppd\[(\d+)\]: sent \[IPCP ConfAck id=0x\w+ \]/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é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°C (limit = +60°C) sensor = thermistor #temp2: +46.0°C (limit = +60°C, hysteresis = +50°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é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°C ou °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 } } }