#!/usr/bin/perl 
$|=1;

use DBI;
use Switch;
use FindBin qw($Bin);
use POSIX qw/strftime/;

our $messaggi = 0;
while( $_ = shift @ARGV ) {
	$messaggi	= 1	if /^\-v$/;
}

open CONFFILE, "< $Bin/traffico.conf" or die ("Manca file di configurazione\n");
while (<CONFFILE>) {
        if(/^\$fw_name = "(\S+)"/ ) {
                $fw_name = $1;
        }
        if(/^\$db_host = "(\S+)"/ ) {
                $db_host = $1;
        }
        if(/^\$db_user = "(\S+)"/ ) {
                $db_user = $1;
        }
        if(/^\$db_name = "(\S+)"/ ) {
                $db_name = $1;
        }
        if(/^\$db_pass = "(\S+)"/ ) {
                $db_pass = $1;
        }
}
close CONFFILE;

my $sys_error = 0;

if (!lockpid ("lock")) {
	print "Prg in esecuzione";
	exit 0;
}

printf  "Inizio attivita' %s\n",strftime('%d-%m-%Y %H:%M:%S',localtime) if ($messaggi);
my $dbmysql = DBI->connect("DBI:mysql:;host=$db_host", "$db_user", "$db_pass") or die ($DBI::errstr);
$sts = $dbmysql->prepare("use $db_name");
$sts->execute ();

my $fw_query = "SELECT id, attivo, aggiornamenti, path, errore FROM firewall WHERE nome = '$fw_name'";
my $fw_sts = $dbmysql->prepare($fw_query);
$fw_sts->execute ();
my $fw_dato = $fw_sts->fetchrow_hashref;
my $fw_id = $$fw_dato{'id'};
my $fw_aggiornamenti = $$fw_dato{'aggiornamenti'};
my $fw_attivo = $$fw_dato{'attivo'};
my $fw_path = $$fw_dato{'path'};
my $fw_errore = $$fw_dato{'errore'};

if ($fw_errore == 2) {
	fw_update ($fw_id, 0, -1, 0, NULL);
	log_server($fw_id, 0, 0, 'Connessione ripristinata');
}

@path_stat = stat ($fw_path);
$permessi = sprintf "%04o", $path_stat[2] & 00700;
if (!defined ($path_stat[2])) {
	$sys_error = 1;
	fw_update ($fw_id, 0, -1, 1, 'Path configurazioni non disponibile');
	log_server($fw_id, 0, 2, 'Path configurazioni non disponibile');
}
if (($permessi ne '0700') && (!$sys_error)) {
	$sys_error = 1;
	fw_update ($fw_id, 0, -1, 1, 'Path configurazioni non scrivibile');
	log_server($fw_id, 0, 2, 'Path configurazioni non scrivibile');
}

if (!$sys_error) {
	fw_update ($fw_id, 0, -1, 0, NULL);
}

if (($fw_aggiornamenti == 1) && $fw_attivo && !$sys_error) {
	printf  "Inizio gestione aggiornamenti %s\n",strftime('%d-%m-%Y %H:%M:%S',localtime) if ($messaggi);
	fw_update ($fw_id, 0, 2, 0, NULL);
	log_server($fw_id, 0, 0, 'Rilevati aggiornamenti');

	$azioni_query = "SELECT id, tabella, idtabella, stato FROM azioni WHERE fw = $fw_id AND dataexec IS NULL and ignora = 0 AND stato != 5 ORDER BY id";
	my $azioni_sts = $dbmysql->prepare($azioni_query);
	$azioni_sts->execute ();

	my $file_ok = 1;
	while ((my $azioni_dato = $azioni_sts->fetchrow_hashref) && $file_ok) {
		my $azioni_id = $$azioni_dato{'id'};
		my $azioni_tabella = $$azioni_dato{'tabella'};
		my $azioni_idtabella = $$azioni_dato{'idtabella'};
		my $azioni_stato = $$azioni_dato{'stato'};

		switch ($azioni_tabella) {
			case "interfacce"	{
				if ($azioni_stato == 1 || $azioni_stato == 2) {
					my $interfacce_query = "SELECT device, descrizione, rate, ceil FROM interfacce WHERE id = $azioni_idtabella";
					my $interfacce_sts = $dbmysql->prepare($interfacce_query);
					$interfacce_sts->execute ();
					my $interfacce_dato = $interfacce_sts->fetchrow_hashref;
					my $nome_interfaccia = $$interfacce_dato{'device'};
					my $nomefile1 = "$fw_path/".$$interfacce_dato{'device'};
					my $nomefile2 = "$fw_path/".$$interfacce_dato{'device'}."-2.root";
					open (OUTFILE1, ">", $nomefile1);
					open (OUTFILE2, ">", $nomefile2);
					print OUTFILE1 "#".$$interfacce_dato{'descrizione'}."\n";
					print OUTFILE1 "DEFAULT=1000\n";
					print OUTFILE1 "R2Q=10\n";
					print OUTFILE2 "#".$$interfacce_dato{'descrizione'}."\n";
					print OUTFILE2 "RATE=".$$interfacce_dato{'rate'}."Mbit\n";
					print OUTFILE2 "CEIL=".$$interfacce_dato{'ceil'}."Mbit\n";
					print OUTFILE2 "BURST=15k\n";
					close OUTFILE1;
					close OUTFILE2;
					azione_conf ($azioni_id);
					log_server($fw_id, $azioni_id, 0, "Inserita interfaccia $nome_interfaccia") if ($azioni_stato == 1);
					log_server($fw_id, $azioni_id, 0, "Modificata interfaccia $nome_interfaccia") if ($azioni_stato == 2);
				} elsif ($azioni_stato == 3) {
					my $interfacce_query = "SELECT device FROM interfacce WHERE id = $azioni_idtabella";
					my $interfacce_sts = $dbmysql->prepare($interfacce_query);
					$interfacce_sts->execute ();
					my $interfacce_dato = $interfacce_sts->fetchrow_hashref;
					my $nomefile1 = "$fw_path/".$$interfacce_dato{'device'};
					my $nomefile2 = "$fw_path/".$$interfacce_dato{'device'}."-2.root";
					unlink ($nomefile1); 
					unlink ($nomefile2); 
					azione_conf ($azioni_id);
					log_server($fw_id, $azioni_id, 0, "Eliminata interfaccia $nome_interfaccia");
				} else {
					fw_update ($fw_id, 0, 0, 1, 'Richiesta azione non prevista');
					azione_conf ($azioni_id);
					log_server($fw_id, $azioni_id, 2, "Richiesta operazione $azioni_stato non esistente su device $nome_interfaccia");
				}
			}
			case "defrule"	{
				if ($azioni_stato == 1 || $azioni_stato == 2) {
					my $defrule_query = "SELECT descrizione, priorita, rate, ceil FROM defrule WHERE id = $azioni_idtabella";
					my $defrule_sts = $dbmysql->prepare($defrule_query);
					$defrule_sts->execute ();
					my $defrule_dato = $defrule_sts->fetchrow_hashref;
					my $nomeregola = creanome ($azioni_idtabella);
					my $nomefile = "$fw_path/$nomeregola";
					open (OUTFILE, ">", $nomefile);
					print OUTFILE "#".$$defrule_dato{'descrizione'}."\n";
					print OUTFILE "RATE=".$$defrule_dato{'rate'}."Mbit\n";
					print OUTFILE "CEIL=".$$defrule_dato{'ceil'}."Mbit\n";
					print OUTFILE "BURST=15k\n";
					print OUTFILE "LEAF=sfq\n";
					my $rule_query = "SELECT ipin, portin, ipout, portout FROM rule WHERE iddefrule = $azioni_idtabella";
					my $rule_sts = $dbmysql->prepare($rule_query);
					$rule_sts->execute ();
					while (my $rule_dato = $rule_sts->fetchrow_hashref) {
						my $ipin = $$rule_dato{'ipin'};
						my $portin = $$rule_dato{'portin'};
						if ($portin == 0) {
							$portin = "";
						} else {
							$portin = ":$portin";
						}
						my $ipout = $$rule_dato{'ipout'};
						my $portout = $$rule_dato{'portout'};
						if ($portout == 0) {
							$portout = "";
						} else {
							$portout = ":$portout";
						}
						print OUTFILE "RULE=$ipin$portin,$ipout$portout\n";
					}
					print OUTFILE "PRIO=".$$defrule_dato{'priorita'}."\n";
					close OUTFILE;
					azione_conf ($azioni_id);
					log_server($fw_id, $azioni_id, 0, "Inserita regola $nomeregola") if ($azioni_stato == 1);
					log_server($fw_id, $azioni_id, 0, "Modificata regola $nomeregola") if ($azioni_stato == 2);
				} elsif ($azioni_stato == 3) {
					my $nomeregola = creanome ($azioni_idtabella);
					my $nomefile = "$fw_path/$nomeregola";
					unlink ($nomefile); 
					azione_conf ($azioni_id);
					log_server($fw_id, $azioni_id, 0, "Eliminata regola $nomeregola");
				} else {
					my $nomeregola = creanome ($azioni_idtabella);
					fw_update ($fw_id, 0, 0, 1, 'Richiesta azione non prevista');
					azione_conf ($azioni_id);
					log_server($fw_id, $azioni_id, 2, "Richiesta operazione $azioni_stato non esistente su regola $nome_regola");
				}
			}
			case "RESET" {
				reset_file ($fw_path);
				azione_conf ($azioni_id);
				log_server($fw_id, $azioni_id, 0, "Richiesta operazione di RESET");
			}
			case "FINE APPLICA" {
				$file_ok = 0;
				azione_conf ($azioni_id);
			}
			else {
			}
		}
	}
	`/etc/init.d/htbinit restart`;
	fw_update ($fw_id, 1, 0, 0, NULL);
	printf  "Termine gestione aggiornamenti %s\n",strftime('%d-%m-%Y %H:%M:%S',localtime) if ($messaggi);
} elsif (($fw_aggiornamenti == 1) && $fw_attivo && $sys_error) {
	$azioni_query = "SELECT id, tabella FROM azioni WHERE fw = $fw_id AND dataexec IS NULL and ignora = 0 AND stato = 5";
	my $azioni_sts = $dbmysql->prepare($azioni_query);
	$azioni_sts->execute ();

	my $azioni_ok = 1;
	while ((my $azioni_dato = $azioni_sts->fetchrow_hashref) && ($azioni_ok)) {
		my $azioni_id = $$azioni_dato{'id'};
		my $azioni_tabella = $$azioni_dato{'tabella'};

		my $azioni_risop = 0;
		switch ($azioni_tabella) {
			case "CREADIR" {
				if (mkdir $fw_path, 0755) {
					fw_update ($fw_id, 1, 0, 0, NULL);
					azione_conf ($azioni_id);
					log_server($fw_id, $azioni_id, 0, "Creato path dati $fw_path");
				} else {
					fw_update ($fw_id, 1, 0, 1, $!);
					azione_conf ($azioni_id);
					$azioni_ok = 0;
					log_server($fw_id, $azioni_id, 2, "Non e' stato possibile creare il path dati $fw_path");
				}
			}
		}		
	}
}

estraidati ();

lockpid ("unlock");
printf  "Termine attivita' %s\n",strftime('%d-%m-%Y %H:%M:%S',localtime) if ($messaggi);
exit 0;

sub azione_conf {
	my $id = shift;
	my $azioniup_query = "UPDATE azioni SET dataexec= NOW() WHERE id = $id";
	my $azioniup_sts = $dbmysql->prepare($azioniup_query);
	$azioniup_sts->execute ();
}

sub fw_update {
	my $id  = shift;
	my $syn = shift;
	my $agg = shift;
	my $err = shift;
	my $msg = shift;

	if ($syn) {
		$syn = ", ultimosync = NOW()";
	} else {
		$syn = "";
	}
	
	if ($agg == -1) {
		$agg = "";
	} else {
		$agg = ", aggiornamenti = $agg";
	}

	my $fwup_query = "UPDATE firewall SET ultimoconn = NOW(), errore = $err, msg_err = '$msg' $syn $agg WHERE id = $id";
	my $fwup_sts = $dbmysql->prepare($fwup_query);
	$fwup_sts->execute ();
}

sub reset_file {
	my $dir = shift;

	opendir (DIR, $dir); 
	my @files = grep { /^[^\.]/ } readdir(DIR);
	closedir DIR; 

	foreach $file (@files) { 
		unlink ("$dir/$file"); 
	} 
}

sub creanome {
	my $idparent = shift;

	my $query = "SELECT interfacce.device, defrule.idparent, defrule.priorita FROM defrule JOIN interfacce ON defrule.idinterfacce = interfacce.id WHERE defrule.id = '$idparent'";
	my $sts = $dbmysql->prepare($query);
	$sts->execute ();
	my $dato = $sts->fetchrow_hashref;

	if ($$dato{'idparent'} == 0) {
		$ritorno = $$dato{'device'}."-2:".$$dato{'priorita'};
		return $ritorno;
	} else {
		$ritorno = creanome($$dato{'idparent'}).":".$$dato{'priorita'};
		return $ritorno;
	}
}

sub log_server {
	my $fw = shift;
	my $idazione = shift;
	my $stato = shift;
	my $testo = shift;

	my $query = "INSERT log_server SET fw = $fw, idazione = $idazione, data= NOW(), stato = $stato, testo = '$testo'";
	my $sts = $dbmysql->prepare($query);
	$sts->execute ();
}

sub lockpid {
	my $op = shift;
	
	my $pidfile = "/tmp/traffico.pid";
	if ($op eq "lock") {
		if (open PIDFILE, "< $pidfile") {
			read PIDFILE, $oldpid, 256;
			my $exists = kill 0, $oldpid;
			if ( $exists ) {
				return 0;
			} else {
				close PIDFILE;
			}
		} else {
			close PIDFILE;
		}
		open PIDFILE, "> $pidfile" || return 0;
		print PIDFILE $$;
		close PIDFILE;
	} elsif ($op eq "unlock") {
		unlink $pidfile;
	}
	return 1;
}

sub estraidati {
	my $class;
	my $classid;
	my $parent;
	my $rate;
	my $ceil;
	my $crate;
	my $sent;
	my $range;

	$campi = "INSERT INTO dati_traffico (idfirewall, idinterfacce, iddefrule, sent, rate, data, calc, diff) VALUES ";
	$campi_tmp = "INSERT INTO dati_traffico_tmp (idfirewall, idinterfacce, iddefrule, sent, rate, data, calc, diff, dataunix) VALUES ";

	printf  "Inizio estrazione dati %s\n",strftime('%d-%m-%Y %H:%M:%S',localtime) if ($messaggi);
	my $query = "SELECT id, device FROM interfacce WHERE attivo = 1 AND stato != 3";
	my $sts = $dbmysql->prepare($query);
	$sts->execute ();
	while (my $dato = $sts->fetchrow_hashref) {
		my $device_id = $$dato{'id'};
		my $device = $$dato{'device'};
		my $outcompleto;
		my @outriga;

		my $contarighe = 0;
		my @righequery;

		$outcompleto = qx/\/usr\/sbin\/tc -s class show dev $device/;
		@outriga = split /\n/, $outcompleto;

		for ($i=0;$i< scalar(@outriga);$i++) {
			my $rigaatt = $outriga[$i];
			if($rigaatt =~ /^ lended: / ) {
				$range="$rate $ceil";
				$crate=sprintf "%8.1lf",$crate;
				$sent=sprintf "%10.0lf",$sent/1024;
				$$device{$classid}[0]=$crate if (($conta eq 0) || ($crate > $$device{$classid}[0]));
				if ($conta eq 0) {
					$$device{$classid}[4]=$crate;
					$$device{$classid}[5]=$sent;
				} else {
					$$device{$classid}[4] += $crate;
				}
				$$device{$classid}[6]=$sent;
				$$device{$classid}[1]=$crate;
				$$device{$classid}[2]=$ceil;

				my @pezzi = split ':', $classid;
				my $classe = $pezzi[1];
				my $defrule_id;
				if ($classe == 2) {
					$defrule_id = 0;
				} else {
					my $pri_query = "SELECT id FROM defrule WHERE idinterfacce = $device_id AND priorita = $classe AND attivo = 1 AND stato != 3 ";
					my $pri_sts = $dbmysql->prepare($pri_query);
					$pri_sts->execute ();
					my $pri_dato = $pri_sts->fetchrow_hashref;
					$defrule_id = $$pri_dato{'id'};
				}
				printf  "Inizio SELECT iddefrule $defrule_id %s\n",strftime('%d-%m-%Y %H:%M:%S',localtime) if ($messaggi);
				my $prec_query = "SELECT ($sent-sent) AS inviati, (UNIX_TIMESTAMP(NOW()) - dataunix) AS tempo FROM dati_traffico_tmp WHERE id = (SELECT MAX(id) FROM dati_traffico_tmp WHERE idfirewall = $fw_id AND idinterfacce = $device_id AND iddefrule = $defrule_id)";
				my $prec_sts = $dbmysql->prepare($prec_query);
				$prec_sts->execute ();
				printf  "Fine SELECT iddefrule $defrule_id %s\n",strftime('%d-%m-%Y %H:%M:%S',localtime) if ($messaggi);
				my $media;
				my $tempo;
				my $inviati;
				if (my $prec_dato = $prec_sts->fetchrow_hashref) {
					$tempo = $$prec_dato{'tempo'};
					$inviati = $$prec_dato{'inviati'};
					$inviati = $sent if ($inviati < 0);
					if ($tempo > 0) {
						$media = $inviati/$tempo;
					} else {
						$media = 0;
					}
				} else {
					$media = 0;
					$inviati = 0;
				}
				$righequery[$contarighe++] = "($fw_id, $device_id, $defrule_id, $sent, $crate, NOW(), $media, $inviati";
				next;
			}
			if($rigaatt =~ /^ Sent (\d+) bytes /) {
				$sent=$1;
				next;
			}
			if($rigaatt =~ /^ rate (\S+)(bit|bps) /) {
				# print "BPS rate!\n" if $2 eq "bps";
				($crate=$1);
				$crate=~s/K/*1024/;
				$crate=~s/M/*1024*1024/;
				$crate=eval $crate;
				next;
			}
			if($rigaatt =~ /^class (\S+) (\S+:\S+) (root|parent (\S+:\S+)) .*rate (\S+)bit ceil (\S+)bit/) {
				$class=$1;
				$classid=$2;
				$rate=$5;
				$ceil=$6;
				($parent=$3)=~s/parent //;
				printf  "Inizio elaborazione classe $classid %s\n",strftime('%d-%m-%Y %H:%M:%S',localtime) if ($messaggi);

				$rate=~s/K/*1024/;
				$rate=~s/M/*1024*1024/;
				$rate=eval $rate;
				$rate/=1024;

				$ceil=~s/K/*1024/;
				$ceil=~s/M/*1024*1024/;
				$ceil=eval $ceil;
				$ceil/=1024;
				next;
			}

		}
	
	my $querycrt = "$campi ".$righequery[0].")";
	my $querytmp = "$campi_tmp ".$righequery[0].", UNIX_TIMESTAMP(NOW()))";
	for (my $i=1;$i<scalar(@righequery);$i++) {
		$querycrt .= ", ".$righequery[$i].")";
		$querytmp .= ", ".$righequery[$i].", UNIX_TIMESTAMP(NOW()))";
	}
#	print "$querycrt\n";
#	print "$querytmp\n";
	my $ins_sts = $dbmysql->prepare($querycrt);
	$ins_sts->execute ();
	$ins_sts = $dbmysql->prepare($querytmp);
	$ins_sts->execute ();

	printf  "Termine estrazione dati %s\n",strftime('%d-%m-%Y %H:%M:%S',localtime) if ($messaggi);
	}
my $querydel = "DELETE FROM dati_traffico_tmp WHERE data < DATE_SUB(now(), INTERVAL 60 MINUTE)";
my $ins_sts = $dbmysql->prepare($querydel);
$ins_sts->execute ();

}

