#!/usr/bin/perl -w use Gtk; set_locale Gtk; init Gtk; #Primeiro criamos a janela principal, definimos seus atributos #e conectamos as callbacks apropriadas. $window = new Gtk::Window("toplevel"); $window->signal_connect("delete_event",sub{ Gtk->exit(0); }); $window->set_title("Mentus Software - Log Analyser"); $window->border_width(15); #Vamos definir a FileSelection box: $file_dialog = new Gtk::FileSelection( "Escolha o arquivo de LOG:" ); $file_dialog->signal_connect( "destroy", sub { Gtk->exit( 0 ); } ); $file_dialog->ok_button->signal_connect( "clicked",\&FileSel); $file_dialog->cancel_button->signal_connect( "clicked",sub { $file_dialog->hide(); } ); #Agora vamos definir a box principal, que vai conter o resto dos #widgets: $mainbox = new Gtk::VBox(0,10); $label = new Gtk::Label("Input file"); $label->set_alignment(0,0); $label->show(); $mainbox->pack_start($label,0,0,0); #Definimos aqui a inputbox e que vai dentro dela $inputbox = new Gtk::HBox(0,10); #Entry text $entry = new Gtk::Entry(255); $entry->signal_connect("changed",\&EntryChanged); $entry->set_text("syslog"); $inputbox->pack_start($entry,1,1,0); $entry->show(); #Botao para Browse $browse = new_with_label Gtk::Button("Browse"); $browse->signal_connect("clicked",sub{ $file_dialog->show(); }); $inputbox->pack_start($browse,0,0,0); $browse->show(); $mainbox->pack_start($inputbox,0,0,0); $inputbox->show(); #Definimos agora a optbox $optbox = new Gtk::HBox(0,15); #Dentro dela colocamos as duas boxes verticais #Primeira $agruparbox = new Gtk::VBox(0,10); $agruparlbl = new Gtk::Label("Agrupar por:"); $agruparlbl->set_alignment(0,0); $agruparbox->pack_start($agruparlbl,0,0,0); $agruparlbl->show(); $rdorigem = new Gtk::RadioButton("origem"); $agruparbox->pack_start($rdorigem,0,0,0); $rdorigem->show(); $rddestino = new Gtk::RadioButton("destino",$rdorigem); $agruparbox->pack_start($rddestino,0,0,0); $rddestino->show(); $rddata = new Gtk::RadioButton("data",$rdorigem); $agruparbox->pack_start($rddata,0,0,0); $rddata->show(); $rddp = new Gtk::RadioButton("porta destino",$rdorigem); $agruparbox->pack_start($rddp,0,0,0); $rddp->show(); $optbox->pack_start($agruparbox,0,0,0); $agruparbox->show(); #Segunda $pacotebox = new Gtk::VBox(0,10); $pacotelbl = new Gtk::Label("Tipo de Pacote"); $pacotebox->pack_start($pacotelbl,0,0,0); $pacotelbl->show(); $rdpacketdied = new Gtk::RadioButton("packet died"); $rdpacketdied->signal_connect("toggled",\&RadioToggled); $pacotebox->pack_start($rdpacketdied,0,0,0); $rdpacketdied->show(); $rdnewnotsyn = new Gtk::RadioButton("New not syn",$rdpacketdied); $rdnewnotsyn->signal_connect("toggled",\&RadioToggled); $pacotebox->pack_start($rdnewnotsyn,0,0,0); $rdnewnotsyn->show(); #sub-segunda $subpacotebox = new Gtk::HBox(0,1); $rdoutro = new Gtk::RadioButton("outro",$rdpacketdied); $rdoutro->signal_connect("toggled",\&RadioToggled); $subpacotebox->pack_start($rdoutro,0,0,0); $rdoutro->show(); $rdentry = new Gtk::Entry(50); $rdentry->set_text("http dropped"); $subpacotebox->pack_start($rdentry,0,0,0); $rdentry->set_editable(0); $rdentry->show(); $pacotebox->pack_start($subpacotebox,0,0,0); $subpacotebox->show(); $optbox->pack_start($pacotebox,0,0,0); $pacotebox->show(); $mainbox->pack_start($optbox,0,0,0); $optbox->show(); #Definimos agora acoesbox $acoesbox = new Gtk::HBox(0,0); $run = new_with_label Gtk::Button(" Run "); $run->signal_connect("clicked",\&Run_Analysis); $acoesbox->pack_start($run,1,0,0); $run->show(); $quit = new_with_label Gtk::Button(" Quit "); $quit->signal_connect("clicked",sub{ Gtk->exit(0);} ); $acoesbox->pack_start($quit,1,0,0); $quit->show(); $mainbox->pack_start($acoesbox,0,0,0); $acoesbox->show(); $mainbox->show(); $window->add($mainbox); $window->show(); #Definimos agora a janela que vai conter os resultados: @titulos = ("Data","Fonte","PF","Destino","PD","Proto","Tam"); $rwindow = new Gtk::Window("toplevel"); $rwindow->set_usize(630,350); $rwindow->signal_connect("destroy",sub{ $rwindow->hide(); }); #Todo o conteúdo da nossa janela vai ficar dentro dessa VBox $vbox = new Gtk::VBox(0,5); $rwindow->add($vbox); $vbox->border_width(5); $scrolled_window = new Gtk::ScrolledWindow(undef,undef); $vbox->pack_start($scrolled_window,1,1,0); $scrolled_window->set_policy("automatic","automatic"); $scrolled_window->show(); # Aqui vem o que vai dentro da scrolled window $clist = new_with_titles Gtk::CList(@titulos); $clist->set_shadow_type("out"); $clist->set_column_width(0,130); $clist->set_column_width(1,100); $clist->set_column_width(2,50); $clist->set_column_width(3,100); $clist->set_column_width(4,50); $clist->set_column_width(5,50); $clist->set_column_width(6,60); $clist->signal_connect("select_row",\&SelecionaLinha); $scrolled_window->add($clist); $clist->show(); #Vamos criar agora uma hbox, para colocar os botoes de acao $hbox = new Gtk::HBox(0,0); $rquit = new Gtk::Button("Quit"); $rquit->signal_connect("clicked",sub{ $rwindow->hide();}); $hbox->pack_start($rquit,1,0,0); $rquit->show(); $vbox->pack_start($hbox,0,0,0); $hbox->show(); $vbox->show(); #$rwindow->show(); main Gtk; #Essa funcao e chamada cada vez que clicamos OK na filedialog sub FileSel { $entry->set_text($file_dialog->get_filename()); $file_dialog->hide(); } #Essa funcao e uma callback associada a mudança da entrybox #que recebe o nome do arquivo de entrada. Cada vez que o usuario #digita alguma coisa la, atualizamos a filedialog para ter #aquele caminho como padrao. Dessa forma, se o usuario digita #/var/log, quando ele clicar em 'Browse', a filedialog vai estar #nesse caminho. sub EntryChanged { $file_dialog->set_filename($entry->get_text()); } #Essa funcao e chamada cada vez que as radioboxes sao ativadas #para escolher o tipo de pacote que queremos analisar #Se a radio 'outro' está escolhida, a entrybox fica editavel #caso contrario, ela perde a editabilidade. sub RadioToggled { $rdentry->set_editable($rdoutro->active); } #Essa funcao quando executada, le as opcoes que o usuario indicou #na interfaca grafica e roda a analise de acordo. sub Run_Analysis { my $agrupar_por; my $tipo_de_pacote; my $nome_do_arquivo; if ($rdpacketdied->active) { $tipo_de_pacote = "packet died"; } elsif ($rdnewnotsyn->active) { $tipo_de_pacote = "New not syn"; } else { $tipo_de_pacote = $rdentry->get_text(); } if ($rddestino->active) { $agrupar_por = "destino"; } elsif ($rdorigem->active) { $agrupar_por = "origem"; } elsif ($rddp->active) { $agrupar_por = "dp"; } else { $agrupar_por = "data"; } $entrada = $entry->get_text(); analisa($entrada,$agrupar_por,$tipo_de_pacote); } # Essa funcao e' um callback para o evento selecao de linha. # Dada a selecao de uma coluna que contenha um endereco IP # Ela chama o comando 'host IP' para tentar achar o endereço sub SelecionaLinha() { (undef,$row,$column,undef,undef) = @_; if ($column == 1 || $column == 3 || $column == 0) { $text = $clist->get_text($row,$column); if ($text =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) { $addr = $1 . "." . $2 . "." . $3 . "." . $4; print("Looking up $addr:\n "); system("host $addr"); } } return(); } # Essa funcao recebe como parametros # o nome do arquivo de log a ser analisado # o tipo de analise a ser feita e o tipo de pacote # que estamos procurando. Por exemplo: # analisa("syslog","origem","packet died") sub analisa($$$) { ($log_file,$sumario,$type) = @_; $wlogs = "/tmp/mentusla"; #Vamos verificar agora se o diretorio de logs existe. Se existe, apagamos o que tem nele, se nao existe, criamos ele. if ( -e $wlogs) { `rm -rf $wlogs`; } mkdir($wlogs,0700); # my $main_regex = '(.*\d+:\d+:\d+)\s.*\skernel:\s.*IN=.*\sOUT=.*?\s.*SRC=(\d+\.\d+\.\d+\.\d+)\sDST=(\d+\.\d+\.\d+\.\d+)\s.*\sID=\d+\s.*PROTO=(TCP|UDP)\sSPT=(\d+)\sDPT=(\d+).*'; my $main_regex = '(.*\d+:\d+:\d+)\s.*kernel.*IN=.*\sOUT=.*?\s.*SRC=(\d+\.\d+\.\d+\.\d+)\sDST=(\d+\.\d+\.\d+\.\d+)\s.*\sID=\d+\s.*PROTO=(TCP|UDP)\sSPT=(\d+)\sDPT=(\d+).*'; my $basica = 'LEN=(\d+)\s*$'; my $extendida = 'LEN=(\d+).*'; # As expressoes regulares acima fazem o parsing de cada linha do # arquivo de log e extraem as informações necessárias para nossa análise, # a dizer: a data, a fonte, o destino, a porta de destino e a fonte, o # protocolo e o tamanho do pacote. # Precisamos de duas expressoes regulares para o tamanho porque no caso de # new not syn só temos o primeiro LEN, enquanto no caso de packet died # queremos o último. my %acum_data; my %acum_origem; my %acum_destino; my %acum_dp; # Os hashes acima armazenam e contam o número de ocorrencias de cada # tipo de entrada de acordo com os fatores data, origem e destino. # Usaremos eles para a geração dos relatórios. open(LOG_FILE,"$log_file") || die("Unable to open file $log_file : $!\n"); while($input = ) { if ($input !~ /$type/) { next; } if ($input !~ /$main_regex/) { next; } ($data,$src,$dst,$proto,$spt,$dpt) = ($1,$2,$3,$4,$5,$6); if ($input =~ /$basica/) { $len = $1; } elsif ($input =~ /$extendida/) { $len = $1; } else { die("Error parsing expression.\n"); } # Temos agora os dados que precisamos da linha armazenados nas variáveis # apropriadas. Basta então fazermos algumas arrumações: ($null,$null,$null,$null,$null,$year,$null,$null,$null) = localtime(time); $year += 1900; $data =~ s/(\w+)\s+(\d+)\s(\d+:\d+:\d+)/$year-$1-$2 $3/; $dia = $data; $dia =~ s/(.*)\s.+/$1/; my %entry = ( date => $dia, SRC => $src, DST => "DST" . $dst, PROTO => $proto, SPT => $spt, DPT => $dpt, LEN => $len ); # No hash acima colocamos as informações dessa entraca em específico. $acum_data{$dia} += 1; $acum_origem{$src} += 1; $acum_destino{"DST" . $dst} += 1; $acum_dp{$dpt} += 1; # Por fim atualizamos as informações dos acumuladores. $our_log = $data . "|" . $src . "|" . $spt . "|" . $dst . "|" . $dpt . "|" . $proto . "|" . $len . "\n"; # Montamos acima a linha que descreve essa entrada do log que iremos jogar para os # sublogs foreach (sort keys %entry) { open(DLOG,">>$wlogs/$entry{$_}"); print DLOG $our_log; } close(DLOG); } close(LOG_FILE); #Geramos agora o output, na saída grafica (na CList que criamos la em cima) #Antes de tudo entretanto vamos limpar a CList e depois mostrar a janela: $clist->clear(); if ($sumario eq "origem") { foreach (sort keys %acum_origem) { $rwindow->set_title("Tipo de pacote: $type - Organizar por: origem"); $contador = $acum_origem{$_}; $clist->append(" "); $clist->append("$_ $contador"); open(SUBLOG,"$wlogs/$_"); while () { chomp; @vec=split(/\|/); $clist->append(@vec); } } } if ($sumario eq "destino") { foreach (sort keys %acum_destino) { $rwindow->set_title("Tipo de pacote: $type - Organizar por: destino"); $contador = $acum_destino{$_}; $y = $_; $y =~ s/DST(\d)/$1/; $clist->append(" "); $clist->append("$y $contador"); open(SUBLOG,"$wlogs/$_"); while () { chomp; @vec=split(/\|/); $clist->append(@vec); } } } if ($sumario eq "data") { foreach (sort keys %acum_data) { $rwindow->set_title("Tipo de pacote: $type - Organizar por: data"); $contador = $acum_data{$_}; $clist->append(" "); $clist->append("$_ $contador"); open(SUBLOG,"$wlogs/$_"); while () { chomp; @vec=split(/\|/); $clist->append(@vec); } } } if ($sumario eq "dp") { foreach (sort keys %acum_dp) { $rwindow->set_title("Tipo de pacote: $type - Organizar por: porta destino"); $contador = $acum_dp{$_}; $clist->append(" "); $clist->append("$_ $contador"); open(SUBLOG,"$wlogs/$_"); while () { chomp; @vec=split(/\|/); $clist->append(@vec); } } } #Depois fazermos as alterações, podemos mostrar a janela: $rwindow->show(); }