Это старая версия документа!
Подсчет траффика с помощью ng_ipacct
Советую для начала прочитать, что такое netgraph.
Среда окружения:
- ОС 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
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, "/usr/local/script/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, "/usr/local/script/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:
Обсуждение