====== Подсчет траффика с помощью 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~~