Подсчет траффика с помощью ng_ipacct

Советую для начала прочитать, что такое netgraph. Например, вот здесь.

Среда окружения:

options    NETGRAPH
options    NETGRAPH_ETHER
options    NETGRAPH_IFACE
options    NETGRAPH_KSOCKET
options    NETGRAPH_SOCKET

Порядок действий

1. Устанавливаем порты:

/usr/ports/databases/p5-DBI
/usr/ports/databases/p5-DBD-mysql51
/usr/ports/net-mgmt/ng_ipacct

Порт p5-DBD-mysql51 должен согласовываться с вашей установленной версией MySQL server.

2. Создаем необходимые каталоги:

mkdir -p /var/scripts/ng_stat/etc
mkdir /var/scripts/ng_stat/bin
mkdir /var/scripts/ng_stat/log

3. Создаем БД, которая будет хранить сведения по траффику, пользователя nguser с паролем pass:

# mysql -p
create database ng_stat;
grant insert,create,update,select,delete on ng_stat.* to nguser@'localhost' identified by 'pass';

4. В /var/scripts/ng_stat/etc создаем файл ng_stat.conf следующего содержания:

# Имя сервера, где находиться база данных статистики
server_db = localhost
# Имя базы данных, где будет сохраняться статистика
db_name = ng_stat
# Имя пользователи для доступа к базе
db_user = nguser
# Пароль для доступа к базе
db_pass = pass
# Таблица для авторизации пользователей через WEB.
table_auth = ipacct_auth
# Таблица со списком протоколов, эквивалент /etc/protocols
table_protocols = protocols
# Имя хоста с которого снимается статистика
listen_host = localhost
# Имена интерфейсов, которые прослушиваются на компьютере.
# Указывать через запятую
listen_interfaces = xl0,xl1
# Загружаемые модули NETGRAPH, необходимые для интерфейсов,
# которые будет обслуживать программа
# По умолчанию загружаются следующие модули: netgraph,
# ng_ether,ng_socket,ng_tee,ng_ipacct
ng_modules = netgraph,ng_ether,ng_socket,ng_tee,ng_ipacct
# Какой трешхолд необходимо установить для работы системы.
# Отнеситесь внимательно к выбору этого параметра. Он
# означает сколько записей будет храниться в буфере
# По умолчанию значение равно 5000, но если у вас меньше
# 128 Мегабайт памяти  - уменьште его.
threshold = 10000

5. В папке bin создадим свой скрипт ng_stat_start.pl:

#!/usr/bin/perl -w

use DBI;
use POSIX ":sys_wait_h";
#use strict;
#########################
# Список основных переменных
#########################
my $serverdb = "test";
my $dbname = "test";
my $dbuser = "test";
my $dbpass = "test";
my $table_auth = "test";
my $table_proto = "test";
my $listen_host = "test";
my @listen_interf;
my $iface_set = "no";
my @ng_modules;
my $ng_modules_def = "netgraph,ng_ether,ng_socket,ng_tee,ng_ipacct";
my $threshold = 5000;
#########################
# Читаем конфиг. файл.
#########################
open (CONFIG, "/var/scripts/ng_stat/etc/ng_stat.conf");

while (<CONFIG>) {
    $comment = '#';
    if(/^$comment/) {
#    print "Коментарий\n";
    }
    else {
    ($param,$arg) = split("=",$_);
    chomp $param;
    chomp $arg;
    my $razdel = "";
    $param =~ s/[\s\t]+/$razdel/g;
    $arg =~ s/[\s\t]+/$razdel/g;
    if ($param eq "server_db"){
	$serverdb = $arg;
    }
    if ($param eq "db_name"){
    	$dbname = $arg;
    }
    if ($param eq "db_user") {
    	$dbuser = $arg;
    }
    if ($param eq "db_pass") {
        $dbpass = $arg;
    }
    if ($param eq "table_auth") {
        $table_auth = $arg;
    }
    if ($param eq "table_protocols") {
        $table_proto = $arg;
    }
    if ($param eq "listen_host") {
        $listen_host = $arg;
    }
    if ($param eq "listen_interfaces") {
	my $coma = ',';
	if (defined $arg) {
		$iface_set = "ok";
		if ($arg ne ""){
			if ($arg =~ m/$coma/ ) {
				@listen_interf=split($coma,$arg);
			}
			else {
				@listen_interf = $arg;
			}
		}
	}
    }
    if ($param eq "ng_modules") {
    
	my $coma = ',';
	if ($arg =~ m/$coma/ ){
		@ng_modules = split($coma,$arg);
	} 
	else {
	
	    @ng_modules = split ($coma,$ng_modules_def);
	}
    
    }
    if ($param eq "threshold") {
	$threshold = $arg;
    }

    }
}
close (CONFIG);

if (!defined $listen_interf[0]) {
    print "Установите пожалуйста в режим прослушивания хотя бы один интерфейс.\n";
}
else {

    &check_kld_modules;
    &listening;
    
}

sub check_kld_modules {
    my @modules;
    my $pid;
    my $ng_module_cfg;
    my $chk_ng_file = "/tmp/ng_file";
    my $check_ng = 'kldstat -v | grep ng';
    $check_ng = "$check_ng";# " > $chk_ng_file";
    my $check_netgraph = 'kldstat -v | grep netgraph';
    $check_netgraph = "$check_netgraph";#" >> $chk_ng_file";
#    $pid = fork;

@modules =split ("\n", `$check_ng && $check_netgraph`);
my $mod;
$mod = "";
if (defined $modules[0]) {
	foreach my $modules (@modules) {
		$modules=~ s/\d+//g;
		if ($modules =~ s/.ko//g) {
		#
		}
		else {
			$modules =~ s/[\s\t]+//g;
			$mod = "$mod $modules ";
		}
	}
	chop $mod;
	
	foreach my $ng_modules (@ng_modules) {
		if ($mod=~m/$ng_modules/g){
		#	print "$mod содержит $ng_modules\n";
		}
		else {
			my ($pid,$kid);
			
			$pid = fork;
			if (defined $pid) {
				if ($pid == 0){
					print "Загрузка необходимого модуля ",$ng_modules,"\n";
					exec "/sbin/kldload $ng_modules > /dev/null 2>&1"  or die "Ошибка загрузки модуля $ng_modules !\n";
					exit;
				}
			}
			else {
				print "Фатальная ошибка ветвления!\n.................\n";
				die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
			}
			do {
				$kid = waitpid $pid,0;
				if ($kid == -1) {
				print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
				} elsif ($kid == 0) {
					print "Задан не блокирующий вызов и процесс еще не завершен!\n";
				}
			} until $kid=$pid;
			undef $pid;
		}
	}
}
else {
	foreach my $ng_modules (@ng_modules) {
		my ($pid,$kid);
			
		$pid = fork;
		if (defined $pid) {
			if ($pid == 0){
				print "Загрузка необходимого модуля ",$ng_modules,"\n";
				exec "/sbin/kldload $ng_modules > /dev/null 2>&1"  or die "Ошибка загрузки модуля $ng_modules !\n";
				exit;
			}
		}
		else {
			print "Фатальная ошибка ветвления!\n.................\n";
			die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
		}
		do {
			$kid = waitpid $pid,0;
			if ($kid == -1) {
			print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
			} elsif ($kid == 0) {
				print "Задан не блокирующий вызов и процесс еще не завершен!\n";
			}
		} until $kid=$pid;
		undef $pid;
		undef $pid;
	}
	
}
}

sub listening {
	my $pid;
    $ngctl = "/usr/sbin/ngctl";
	$ipacctctl = "/usr/local/sbin/ipacctctl";
    while (@listen_interf){
    
	$interface = shift @listen_interf;
#/usr/sbin/ngctl mkpeer ${IFACE}: tee lower right
        $mkpeer = "$ngctl mkpeer $interface\: tee lower right";
	$pid = fork;
	if (defined $pid) {
		if ($pid == 0){
			print "Создание и подключение нового NETGRAPH-узла к уже существующему:\n $mkpeer\n";
			exec "$mkpeer" or die "Ошибка создания нового узла NETGRAPH!\n";
			exit;
		}
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;
	
#/usr/sbin/ngctl connect ${IFACE}: lower upper left	
        $connect = "$ngctl connect $interface\: lower upper left";
	
	$pid = fork;
        if (defined $pid) {
                if ($pid == 0){
			print "Соединение двух NETGRAPH-узлов на интерфейсе:\n$connect\n";
        		exec "$connect" or die "Ошибка соединения двух NETGRAPH-узлов!\n";
			exit;
                }
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;
	
#/usr/sbin/ngctl name ${IFACE}:lower ${IFACE}_acct_tee	
        $name = "$ngctl name $interface\:lower $interface\_acct_tee ";
	
	$pid = fork;
        if (defined $pid) {
                if ($pid == 0){
			print "Присвоение имени созданному узлу:\n$name\n";
        		exec "$name" or die "Ошибка на этапе присвоения имени созданному узлу!\n";
			exit;
	        }
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;

#/usr/sbin/ngctl mkpeer ${IFACE}_acct_tee: ipacct right2left ${IFACE}_in	
        $mkpeer = "$ngctl mkpeer $interface\_acct_tee: ipacct right2left $interface\_in";
	
	$pid = fork;
        if (defined $pid) {
                if ($pid == 0){
			print "Создание и подключение нового NETGRAPH-узла к уже существующему:\n $mkpeer\n";
			exec "$mkpeer" or die "Ошибка создания нового узла NETGRAPH!\n";
			exit;
	        }
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;
	
#/usr/sbin/ngctl name ${IFACE}_acct_tee:right2left ${IFACE}_ip_acct	
        $name = "$ngctl name $interface\_acct_tee:right2left $interface\_ip_acct";
	
	$pid = fork;
        if (defined $pid) {
                if ($pid == 0){
			print "Присвоение имени созданному узлу:\n$name\n";
        		exec "$name" or die "Ошибка на этапе присвоения имени созданному узлу!\n";
			exit;
	        }
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;
	
#/usr/sbin/ngctl connect ${IFACE}_acct_tee: ${IFACE}_ip_acct: left2right ${IFACE}_out
	$connect = "$ngctl connect $interface\_acct_tee: $interface\_ip_acct: left2right $interface\_out";
	
	$pid = fork;
        if (defined $pid) {
                if ($pid == 0){
			print "Соединение двух NETGRAPH-узлов на интерфейсе:\n$connect\n";
        		exec "$connect" or die "Ошибка соединения двух NETGRAPH-узлов!\n";
			exit;
        	}
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;
	
#$IPACCTCTL ${IFACE}_ip_acct:$IFACE verbose $VERBOSE	
        $verbose = "$ipacctctl $interface\_ip_acct:$interface verbose 1";

	$pid = fork;
        if (defined $pid) {
                if ($pid == 0){
			print "Установка режима вывода информации:\n$verbose\n";
        		exec "$verbose" or die "Ошибка установки режима вывода информации\n";
			exit;
	        }
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;
	
#$IPACCTCTL ${IFACE}_ip_acct:$IFACE threshold $THRESHOLD	
        $set_threshold = "$ipacctctl $interface\_ip_acct:$interface threshold $threshold";

	$pid = fork;
        if (defined $pid) {
                if ($pid == 0){
			print "Установка THRESHOLD:\n$set_threshold\n";
        		exec "$set_threshold" or die "Ошибка установки параметра THRESHOLD\n";
			exit;
	        }
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;
    }

}

exit(0);

5.1 Даем права на запуск:

chmod a+x ng_stat_start.pl

5.2 Выполняем скрипт ng_stat_start.pl. Смотрим на ошибки, если есть. Мой вывод:

Загрузка необходимого модуля ng_ether
Создание и подключение нового NETGRAPH-узла к уже существующему:
 /usr/sbin/ngctl mkpeer bge0: tee lower right
ngctl: send msg: File exists
Соединение двух NETGRAPH-узлов на интерфейсе:
/usr/sbin/ngctl connect bge0: lower upper left
ngctl: send msg: File exists
Присвоение имени созданному узлу:
/usr/sbin/ngctl name bge0:lower bge0_acct_tee
ngctl: send msg: Address already in use
Создание и подключение нового NETGRAPH-узла к уже существующему:
 /usr/sbin/ngctl mkpeer bge0_acct_tee: ipacct right2left bge0_in
ngctl: send msg: File exists
Присвоение имени созданному узлу:
/usr/sbin/ngctl name bge0_acct_tee:right2left bge0_ip_acct
ngctl: send msg: Address already in use
Соединение двух NETGRAPH-узлов на интерфейсе:
/usr/sbin/ngctl connect bge0_acct_tee: bge0_ip_acct: left2right bge0_out
ngctl: send msg: File exists
Установка режима вывода информации:
/usr/local/sbin/ipacctctl bge0_ip_acct:bge0 verbose 1
Установка THRESHOLD:
/usr/local/sbin/ipacctctl bge0_ip_acct:bge0 threshold 10000

6. Создаем в каталоге /usr/local/etc/rc.d стартовый скрипт ng_stat.sh:

#!/bin/sh 

case "$1" in 
start) 
/var/scripts/ng_stat/bin/ng_stat_start.pl 
;; 
stop) 
/var/scripts/ng_stat/bin/ng_stat_stop.pl 
;; 
*) 
echo "" 
echo "Usage: `basename $0` { start | stop }" 
echo ""
;;
esac

7. Создаем скрипт /var/scripts/ng_stat/bin/ng_stat_stop.pl:

#!/usr/bin/perl -w

use DBI;
use POSIX ":sys_wait_h";
#########################
# Список основных переменных
#########################
my $ngctl = "/usr/sbin/ngctl";
my $serverdb = "test";
my $dbname = "test";
my $dbuser = "test";
my $dbpass = "test";
my $table_auth = "test";
my $table_proto = "test";
my $listen_host = "test";
my @listen_interf;
my $iface_set = "no";

#########################
# Читаем конфиг. файл.
#########################
open (CONFIG, "/var/scripts/ng_stat/etc/ng_stat.conf");
while (<CONFIG>) {
    $comment = '#';
    if(/^$comment/) {
#    print "Коментарий\n";
    }
    else {
    ($param,$arg) = split("=",$_);
    chomp $param;
    chomp $arg;
    my $razdel = "";
    $param =~ s/[\s\t]+/$razdel/g;
    $arg =~ s/[\s\t]+/$razdel/g;
    if ($param eq "server_db"){
	$serverdb = $arg;
    }
    if ($param eq "db_name"){
    	$dbname = $arg;
    }
    if ($param eq "db_user") {
    	$dbuser = $arg;
    }
    if ($param eq "db_pass") {
        $dbpass = $arg;
    }
    if ($param eq "table_auth") {
        $table_auth = $arg;
    }
    if ($param eq "table_protocols") {
        $table_proto = $arg;
    }
    if ($param eq "listen_host") {
        $listen_host = $arg;
    }
    if ($param eq "listen_interfaces") {
	my $coma = ',';
	if (defined $arg) {
		if ($arg ne ""){
			if ($arg =~ m/$coma/ ) {
				@listen_interf=split($coma,$arg);
			}
			else {
				@listen_interf = $arg;
			}
		}
	}
    }
    }
}
close (CONFIG);

if (!defined $listen_interf[0]) {
    print "Установите пожалуйста в режим прослушивания хотя бы один интерфейс.\n";
}
else {

   foreach my $interface (@listen_interf){
#/usr/sbin/ngctl shutdown ${IFACE}_acct_tee:
        $shutdown = "$ngctl shutdown $interface\_acct_tee:";
	my $pid;
	$pid = fork;
        if (defined $pid) {
                if ($pid == 0){
			print "Отключение созданных узлов на интерфейсе:\n$shutdown\n";
			exec "$shutdown";
			exit;
	        }
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;
#	sleep 1;
	$shutdown = "$ngctl shutdown $interface\:";
	$pid = fork;
        if (defined $pid) {
                if ($pid == 0){
			print "Отключение NETGRAPH на интерфейсе:\n$shutdown\n";
			exec "$shutdown";
				exit;
	        }
	}
	else {
		print "Фатальная ошибка ветвления!\n.................\n";
		die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
	}
	do {
		$kid = waitpid $pid,0;
		if ($kid == -1) {
		print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
		} elsif ($kid == 0) {
			print "Задан не блокирующий вызов и процесс еще не завершен!\n";
		}
	} until $kid=$pid;
	undef $pid;
    }
}

exit(0);

7.1 Даем скрипту ng_stat_stop.pl права на выполнение.

7.2 Проверяем работу скрипта.

8. Cоздаем скрипт /var/scripts/ng_stat/bin/ng_stat_in.pl:

#!/usr/bin/perl -w

use DBI;
use Time::localtime;
use POSIX ":sys_wait_h";

#########################
# Список основных переменных
#########################
my $serverdb = "test";
my $dbname = "test";
my $dbuser = "test";
my $dbpass = "test";
my $table_auth = "test";
my $table_proto = "test";
my $listen_host = "test";
my @listen_interf;
my $iface_set = "no";
my @ng_modules;
my $ng_modules_def = "netgraph,ng_ether,ng_socket,ng_tee,ng_ipacct";
my $threshold = 5000;
my $ipacct_log = '/var/scripts/ng_stat/log/ng.log';
my @ipacct_arr;
my @ipacct_arr_in;
##########################
# Читаем конфиг. файл.
#########################
open (CONFIG, "/var/scripts/ng_stat/etc/ng_stat.conf");

while (<CONFIG>) {
    $comment = '#';
    if(/^$comment/) {
#    print "Коментарий\n";
    }
    else {
    my ($param,$arg) = split("=",$_);
    chomp $param;
    chomp $arg;
    $param =~ s/[\s\t]+//g;
    $arg =~ s/[\s\t]+//g;
    if ($param eq "server_db"){
        $serverdb = $arg;
    }
    if ($param eq "db_name"){
        $dbname = $arg;
    }
    if ($param eq "db_user") {
        $dbuser = $arg;
    }
    if ($param eq "db_pass") {
        $dbpass = $arg;
    }
    if ($param eq "table_auth") {
        $table_auth = $arg;
    }
    if ($param eq "table_protocols") {
        $table_proto = $arg;
    }
    if ($param eq "stat_file") {
        $ipacct_log = $arg;
    }
    if ($param eq "listen_host") {
        $listen_host = $arg;
    }
    if ($param eq "listen_interfaces") {
        my $coma = ',';
        if ($arg =~ m/$coma/ ) {
            @listen_interf=split($coma,$arg);
            }
        else {
        @listen_interf = $arg;
        }
    }
    if ($param eq "ng_modules") {
	my $coma = ',';
        if ($arg =~ m/$coma/ ){
            @ng_modules = split($coma,$arg);
        } else {

            @ng_modules = split ($coma,$ng_modules_def);
        }

    }
    if ($param eq "threshold") {
        $threshold = $arg;
    }

    }
}
close (CONFIG);

#########################
# Проверяем время.
#########################
$gm = localtime();
$year = ($gm->year()) + 1900;
$mounth = ($gm->mon()) + 1;
$mday = $gm->mday();
$date = "$mday-$mounth-$year";
$hour = $gm->hour();
$min = $gm->min();
$sec = $gm->sec();
$hour=sprintf("%02d",$hour);
$min=sprintf("%02d",$min);
$sec=sprintf("%02d",$sec);
$time = "$hour\:$min\:$sec";
$table_date = "$year\_$mounth";

if (!defined $listen_interf[0]) {
    print "Установите пожалуйста в режим прослушивания хотя бы один интерфейс.\n";
}
else {

	while (@listen_interf){
		$interface = shift @listen_interf;
		my $pid;
		$pid = fork;
		if (defined $pid) {
			if ($pid == 0){
#$IPACCTCTL ${IFACE}_ip_acct:$IFACE checkpoint
				exec "/usr/local/sbin/ipacctctl $interface\_ip_acct:$interface checkpoint" or die "Ошибка передачи записи в checkpoint-базу!\n";
				exit;
			}
		}
		else {
			print "Фатальная ошибка ветвления!\n.................\n";
			die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
		}
		do {
			$kid = waitpid $pid,0;
			if ($kid == -1) {
			print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
			} elsif ($kid == 0) {
				print "Задан не блокирующий вызов и процесс еще не завершен!\n";
			}
		} until $kid=$pid;
		
		undef $pid;
		
		$pid = fork;
		if (defined $pid) {
			if ($pid == 0){
#$IPACCTCTL ${IFACE}_ip_acct:$IFACE show >> $DIR/$SDIR/$NAME
			exec "/usr/local/sbin/ipacctctl $interface\_ip_acct:$interface show >> $ipacct_log\.$interface" or die "Ошибка передачи записей из checkpoint-базы в файл!\n";
				exit;
			}
		}
		else {
			print "Фатальная ошибка ветвления!\n.................\n";
			die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
		}
		do {
			$kid = waitpid $pid,0;
			if ($kid == -1) {
			print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
			} elsif ($kid == 0) {
				print "Задан не блокирующий вызов и процесс еще не завершен!\n";
			}
		} until $kid=$pid;
		
		undef $pid;
		
		$pid = fork;
		if (defined $pid) {
			if ($pid == 0){
#$IPACCTCTL ${IFACE}_ip_acct:$IFACE clear
			exec "/usr/local/sbin/ipacctctl $interface\_ip_acct:$interface clear" or die "Ошибка при очистке checkpoint-базы! \nБаза не очищена. Возможно переполнение. Очистите базу в ручную\n";
				exit;
			}
		}
		else {
			print "Фатальная ошибка ветвления!\n.................\n";
			die "Разделение на процессы не возможно.\n Принудительный выход из дочернего процесса: $!\n";
		}
		do {
			$kid = waitpid $pid,0;
			if ($kid == -1) {
			print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n";
			} elsif ($kid == 0) {
				print "Задан не блокирующий вызов и процесс еще не завершен!\n";
			}
		} until $kid=$pid;
		
		undef $pid;
			
		$TMPLOG= "$ipacct_log\.$interface";
		open (TMPLOG, "$TMPLOG");
		$TMPLOG =~ s/\||`|&&|<|>//gi; #Очистка ряда символов | ` && < > из пути к файлу.
		while (<TMPLOG>){
			$tmp_log_line=$_;		
			chomp $tmp_log_line;
			$tmp_log_line = "$tmp_log_line $date $time $listen_host $interface";
			push @ipacct_arr,$tmp_log_line;
		}
		close (TMPLOG);
		truncate ($TMPLOG,0);
		
		
		undef $pid;
	}
	
	open (IPCTLOG,">>$ipacct_log");
	while (@ipacct_arr){
	
		$line_arr = shift @ipacct_arr;
		$line_arr = "$line_arr\n";
		print IPCTLOG $line_arr;	
	
	}
	close(IPCTLOG);	

	&parse_log_file;
	&check_in_mysql;
	&insert_data_db;
}

sub check_in_mysql {

my ($dbh,$sth,$count);
$dbh = DBI->connect("DBI:mysql:host=$serverdb;database=$dbname","$dbuser","$dbpass")
                or &error_connection;
$sth = $dbh->prepare("SHOW tables");
$sth->execute ();
my @row;
my $tables;
while (@row = $sth->fetchrow_array) {
	foreach $tables (@row){
		push @dbtables, $tables;
	}
}
$crt_tbl="yes";
while (@dbtables) {
	$table = shift @dbtables;
	if (defined $table) {
		if ($table eq $table_date) {
			$crt_tbl="no";
		}
	}
}

if ($crt_tbl eq "yes") {
	print "Создаем таблицу\n";
	&crt_table_log;
}

$sth->finish;
$dbh->disconnect;

}

sub error_connection {

print "Проверьте правильность имени и пароля на базу в MySQL, ее существование\n";
print "Возможной причиной так же может являться то, что сервер временно не доступен\n";
print "Будет произведено копирование всех данных в файл:\n\n$ipacct_log \n\n";
print "Накопление статистики в файл не лимитипровано, но это может повлечь за собой";
print " всплеск нагрузки на сеть и сервера. По этому обратите внимание на данное";
print " сообщение и выясните конкретную причину.\n";
foreach $line_arr(@ipacct_arr_in) {
	open (DUMPFILE, ">>$ipacct_log");
	$line_arr = "$line_arr\n";
	print DUMPFILE $line_arr;
	close (DUMPFILE);
}
die "Выход.\n";

}

sub crt_table_log {

	my ($dbh,$sth,$count);
	$dbh = DBI->connect("DBI:mysql:host=$serverdb;database=$dbname","$dbuser","$dbpass") 
		or &error_connection;
	$select = "CREATE  TABLE $table_date (ip_from varchar(255),s_port varchar(128),ip_to varchar(255),d_port   varchar(128), proto varchar(32), packets int(8), bytes int(16) default 0,date_ins varchar(32), time_ins time,host  varchar(128), interface varchar(8),index (ip_from),index (ip_to),index (proto),index (packets), index (bytes),index (host), index (time_ins), index (date_ins), index (interface))";
	$sth = $dbh->prepare("$select");
	$sth->execute ();
	$sth->finish;
	$dbh->disconnect;

}

sub insert_data_db {
my ($dbh,$sth,$count);
$dbh = DBI->connect("DBI:mysql:host=$serverdb;database=$dbname","$dbuser","$dbpass")
                or &error_connection_in;
$insert = "INSERT INTO $table_date (ip_from,s_port,ip_to,d_port,proto,packets,bytes,date_ins,time_ins,host,interface) VALUES (?,?,?,?,?,?,?,?,?,?,?)";

$sth = $dbh->prepare("$insert");
#print "$insert\n";
while (@ipacct_arr_in) {
	$line_in = shift @ipacct_arr_in;
	($ip_from,$s_port,$ip_to,$d_port,$proto,$packets,$bytes,$date_ins,$time_ins,$host,$interface)=split(/[\s\t]+/,$line_in);
	if (!defined $proto){
		$proto="0";
	}
	if (!defined $packets){
		$packets="0";
	}
	if (!defined $bytes){
		$bytes="0";
	}
	$sth->execute ($ip_from,$s_port,$ip_to,$d_port,$proto,$packets,$bytes,$date_ins,$time_ins,$host,$interface);
}

$sth->finish;
$dbh->disconnect;
}

sub parse_log_file {
open (PARSFILE, "$ipacct_log");
while ($line_parse=<PARSFILE>) {
        chomp $line_parse;
        $line_parse =~ s/[\s\t]+/\t/g;
        push @ipacct_arr_in, $line_parse;
}
close (PARSFILE);
truncate ("$ipacct_log",0);
}

exit(0);

8.1 Делаем скрипт исполняемым.

8.2 Выполняем скрипт. Смотрим на ошибки.

Итак, за каждый месяц должна автоматически создаваться табличка со столбцами:

+-----------------+--------+-----------------+--------+-------+---------+---------+----------+----------+-----------+-----------+
| ip_from         | s_port | ip_to           | d_port | proto | packets | bytes   | date_ins | time_ins | host      | interface |
+-----------------+--------+-----------------+--------+-------+---------+---------+----------+----------+-----------+-----------+

8.3 Помещаем вызов скрипта ng_stat_in.pl в крон:

*/15 * * * *	root	/var/scripts/ng_stat/bin/ng_stat_in.pl

TAG: