#!/usr/bin/perl -w ## ## Analyse.pl ## ## Made by Vincent HANQUEZ ## ## Started on Tue 09 Oct 2001 01:28:25 AM CEST tab ## Last Update jeu 07 fév 2002 08:47:59 CET Nicolas STRANSKY ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; only version 2 of the License ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ## ## ## AUTEUR: Tab ## MAINTAINERS: Tab, Nicolas STRANSKY ## ## DESCRIPTION: analyse permet de creer des resumes des fichiers de ## log cree par net-acct. Net-acct est un daemon qui permet de logguer toutes ## les connexions effectues. ## ## SYNOPSIS: analyse [-d] [-h ][-m ][-n ][-f ] ## ## VERSION: 0.35 ## ## use strict; use File::stat; use POSIX qw(strftime); use AppConfig qw(:expand :argcount); require Mail::Send; my $ip_interne = "138\.231\.1(3[6-9]|4[0-3])\."; ## Do not modify after my $VERSION = 0.35; my $AUTEUR = "Vincent HANQUEZ (aka Tab)"; my $pattern_ip = "[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}"; my ($opt_download, $opt_upload) = 0; my $opt_dnsresolve = 1; my $opt_normalize = 1; my $opt_config = 1; my $opt_file = "/var/log/net-acct/net-acct.log.0"; my $opt_configfile = "/etc/analyse.conf"; my $opt_host = ""; my $opt_mail = ""; my $opt_number = -1; my $bad_arg = 0; $opt_upload = 1; ######## ERROR GEST ######## # USAGE: affiche en cas d'erreur dans les arguments. sub usage { print "Usage:\tanalyse (-d) [-h ][-m ][-n ][-f ]\n\n"; print "\t-d, --download\tTri la base sur le download\n"; print "\t-h, --host\tResume des connexions effectues par la machine \n"; print "\t-n, --nombre\tChoisi le nombre de lignes affichees\n"; print "\t-m, --mail\tEnvoie la sortie par mail a \n"; print "\t-f, --file\tSpecifie le fichier qui sera analyse\n"; print "\t-c, --config\tSpecifie le fichier de configuration\n"; print "\t --nodns\tNe resout pas les noms DNS\n"; print "\t --nonorm\tNe transforme pas les nombres en forme plus lisible (Ko, Mo, Go)\n"; print "\t --today\tChiffres du jour, analyse de /var/log/net-acct/net-acct.log\n"; print "\t --noconfig\tNe charge pas les options du fichier de config\n"; print "\t --help\tAffiche cette aide\n"; print "\n"; print "par defaut si l'option n'est pas utilise:\n"; print "\tdownload = on tri sur l'upload\n"; print "\tnombre = tout est affiche\n"; print "\tfile = analyse de /var/log/net-acct/net-acct.log.0\n"; print "\tconfig = par defaut /etc/analyse.conf"; exit (1); } # SETOPT: gerer les options.. sub setopt { my ($opt_name, $opt_param) = @_; if ($opt_name =~ /f/) { $opt_file = $opt_param; } elsif ($opt_name =~ /h/) { $opt_host = $opt_param; } elsif ($opt_name =~ /n/) { $opt_number = $opt_param; } elsif ($opt_name =~ /c/) { $opt_configfile = $opt_param; } elsif ($opt_name =~ /m/) { $opt_mail = $opt_param; } } # Readconfig sub read_configfile { my $info = stat($opt_configfile) || die("Unable to open $opt_configfile"); my $config = AppConfig->new( 'normalize', 'dnsresolve', 'network' => { ARGCOUNT => 1 } ); $config->file($opt_configfile); $opt_normalize = $config->normalize(); $opt_dnsresolve = $config->dnsresolve(); $ip_interne = $config->network(); } ########## FCT ########### # SHOW_ALL: affiche toutes les machines sub show_all { my %db; my ($nb_to_print, $sort_by_upload) = @_; # creation de la base open (INPUT, $opt_file) || die ("Unable to open $opt_file"); while (my $line = ) { my ($src_ip, $dst_ip, $size) = (split "\t", $line)[2,4,6]; if ($src_ip =~ /$ip_interne/ ) { $db{$src_ip}->{up} += $size; } if ($dst_ip =~ /$ip_interne/ ) { $db{$dst_ip}->{down} += $size; } } close(INPUT); # Nombre d'entree a afficher if ($nb_to_print == -1) { $nb_to_print = (my @nb = (keys %db)); } my $max = (keys %db)[0]; # tris sur upload ou download my $way1 = "up"; my $way2 = "down"; if ($sort_by_upload == 0) { $way1 = "down"; $way2 = "up"; } # on affiche $nb_to_print entree, en ayant trier les machines for (my $dec = $nb_to_print; $dec > 0; $dec--) { foreach my $ip (keys %db) { if (defined($db{$ip}->{$way1}) && $db{$max}->{$way1} <= $db{$ip}->{$way1}) { $max = $ip; } } print normalize($db{$max}->{$way1})." (". normalize($db{$max}->{$way2}).")\t". ip_to_name($max)."\n" if ($db{$max}->{$way1} > 0); $db{$max}->{$way1} = 0; } } ############################# # GET_HOST_INFO: Affiche les informations sur une machine sub get_host_info { my $total_size; my %db; my ($ip_search) = @_; $total_size->{UPLOAD} = 0; $total_size->{DOWNLOAD} = 0; # Must unresolve name if (!($ip_search =~ /$pattern_ip/)) { $ip_search = name_to_ip($ip_search); if ($ip_search eq "0") { return (-1); } } # create db open (INPUT, $opt_file) || die ("Unable to open $opt_file"); while (my $line = ) { my ($src_ip, $src_port, $dst_ip, $dst_port, $size) = (split "\t", $line)[2,3,4,5,6]; if ($src_ip eq $ip_search) { $total_size->{UPLOAD} += $size; $db{$src_port}->{UPLOAD_LOCAL} += $size; $db{$dst_port}->{UPLOAD_DIST} += $size; } if ($dst_ip eq $ip_search) { $total_size->{DOWNLOAD} += $size; $db{$dst_port}->{DOWNLOAD_LOCAL} += $size; $db{$src_port}->{DOWNLOAD_DIST} += $size; } } close (INPUT); # printing info print "--- Info for $ip_search ---"; print "\n"; foreach my $type ("UPLOAD", "DOWNLOAD") { print $type.": \t".normalize($total_size->{$type})."\n"; foreach my $location ("LOCAL", "DIST") { print "PORT $location: "; my $max = (keys %db)[0]; for (my $dec=5; $dec > 0; $dec--) { foreach my $port (keys %db) { if (defined($db{$port}->{$type."_".$location}) && (! defined($db{$max}->{$type."_".$location}) || $db{$max}->{$type."_".$location} <= $db{$port}->{$type."_".$location})) { $max = $port; } } print "$max(".normalize($db{$max}->{$type."_".$location}).") " if ($db{$max}->{$type."_".$location} > 0); $db{$max} ->{$type."_".$location} = 0; } print "\n"; } print "\n"; } print "--- Calculs ---\n"; print "Upload pur:\t". normalize($total_size->{UPLOAD} - $total_size->{DOWNLOAD}/20); foreach my $type ("UPLOAD", "DOWNLOAD") { print "\nTAUX $type:\t"; print normalize($total_size->{$type}/24)."/h - "; print normalize($total_size->{$type}/1440)."/min - "; print normalize($total_size->{$type}/86400)."/s"; } print "\n"; } ########################### ######### TOOLKIT ######### # normalize: transforme un nombre, en un nombre suivi d'un prefixe # Go, Mo, Ko, Octets. sub normalize { my ($nb) = @_; if ($opt_normalize) { if (defined $nb) { if ($nb < 0) { return ("0o"); } if ($nb > (1024*1024*1024)) { return ((int($nb*100/(1024*1024*1024))/100)."Go"); } elsif ($nb > (1024*1024)) { return (int($nb/(1024*1024))."Mo"); } elsif ($nb > 1024) { return (int($nb/(1024))."Ko"); } else { return ($nb."o"); } } return ("0"); } else { if (defined $nb) { return ($nb); } else { return (0); } } } # ip_to_name: resout le nom associe a l'ip donne en argument sub ip_to_name { my ($ip) = @_; my $ret; my $host_name; my $aliases; my $addrtype; my $length; my @addrs; if (!($ip =~ /$pattern_ip/)) { return ($ip); } if ($opt_dnsresolve) { my $ipaddr = pack("C4", split(/\./, $ip)); if (($host_name, $aliases, $addrtype, $length, @addrs) = gethostbyaddr($ipaddr, 2)) { return ($host_name); } else { return ("$ip [lookup failed]"); } } return ($ip); } # name_to_ip: deresout le nom sub name_to_ip { my ($host) = @_; my $line = ""; if ($host =~ /$pattern_ip/) { return ($host); } open (COM, "host $host | awk '{print \$3}' |"); $line = ; close (COM); if (! ($line =~ /$pattern_ip/)) { print "host $host don't exist aborting\n"; return ("0");} chomp($line); return ($line); } ########################################################################## # Lit les options de la ligne de commande use Getopt::Long; Getopt::Long::config ("bundling"); Getopt::Long::GetOptions ( 'v|version' => sub { print "analyse version $VERSION\n$AUTEUR\n"; }, 'd|download' => sub { $opt_download = 1; $opt_upload = 0; }, 'u|upload' => sub { $opt_upload = 1; $opt_download = 0; }, 'c|config=s' => \&setopt, 'h|host=s' => \&setopt, 'f|file=s' => \&setopt, 'm|mail=s' => \&setopt, 'n|number=s' => \&setopt, 'help' => \&usage, 'nodns' => sub { $opt_dnsresolve = 0; }, 'nonorm' => sub { $opt_normalize = 0; }, 'noconfig' => sub { $opt_config = 0; }, 'today' => sub { $opt_file = "/var/log/net-acct/net-acct.log"; } ) or $bad_arg = 1; if ($bad_arg == 1) { usage(); } my ($mail_msg, $mail_fh); # Lit les options du fichier de config # sauf si --noconfig est utilise if ($opt_config) { read_configfile(); } # Begin Mail ? if ($opt_mail ne "") { $mail_msg = new Mail::Send; $mail_fh = $mail_msg->open(); $mail_msg->to($opt_mail); $mail_msg->subject("[ANALYSE]"); close (STDOUT); open (STDOUT, ">/tmp/analyse_mail"); } # Main Part if ($opt_host ne "") { get_host_info($opt_host); } else { show_all($opt_number, $opt_upload); } # Close Mail if ($opt_mail ne "") { close (STDOUT); open (FH, "/tmp/analyse_mail") || die ("argh not possible !\n"); while (my $line = ) { print $mail_fh $line; } close (FH); $mail_fh->close(); } exit (0);