====== Подсчет траффика с помощью ng_ipacct ======
Советую для начала прочитать, что такое netgraph. Например, вот [[http://www.opennet.ru/base/net/all_about_netgraph.txt.html|здесь]].
Среда окружения:
* ОС FreeBSD 8.2-Stable
* MySQL server 5.1
* обновленное дерево портов
* Пересобранное ядро с опциями:
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 () {
$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 () {
$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 () {
$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 (){
$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=) {
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: {{tag> ng_ipacct FreeBSD}}
~~DISCUSSION~~