Авг 29 2009

ipfw и ipacctd. Считаем трафик.

Существует достаточно готовых систем подсчета трафика, но большая часть из них черезчур навороченная для небольшого оффиса и часто не стоят того времени, которое нужно на их внедрение. Маленький биллинг легко создать самому. В принципе нам нужны 2 составляющие для учета трафика. 1-я это система сбора данных по трафику и вторая — система которая посчитает трафик.
Для сбора трафика воспользуемся файерволом, ipacctd и небольшим перловым скриптом, который будет импортировать данные по трафику в базу MySQL.

В первую очередь создадим правила файерволла. Мы воспользуемся tee для копирования всех пакетов проходящих через внутренний интерфейс. Выглядит это так:

ipfw="/sbin/ipfw -q"
${ipfw} flush
${ipfw} add 1 tee 500 ip from any to any via em0

Это правило говорит копировать весь проходящий трафик через интерфейс em0 в divert порт 500.
Теперь нужно установить ipacctd и настроить его на этот порт. Ставим ipacctd из портов:

cd /usr/ports/net-mgmt/ipacctd/
make install clean

Установка проходит быстро без всяких там дополнительных диалогов настройкт. А настройка ipacctd производится непосредственно в стартовом скрипте, через флаги командной строки. Открываем /usr/local/etc/rc.d/ipacctd и добавляем такие строки:

ipacctd_rules="em0"
ipacctd_rule_em0_flags="-p 500 -t -s -w -v"
ipacctd_rule_em0_pid="/var/run/ipacctd_em0.pid"

А в /etc/rc.conf добавим:

echo 'ipacctd_enable="YES"' >> /etc/rc.conf

и запустим его:

/usr/local/etc/rc.d/ipacctd start

Проверяем наличие запущенного ipacctd:

ps afx|grep ipacctd

Если увидим примерно такое:

96053  ??  Ss     0:00,00 /usr/local/sbin/ipacctd -p 500 -t -s -w -v -r /var/run/ipacctd_em0.pid

то все запустилось нормально.
И проверим как у нас обстоит дело с открытыми сокетами ipacctd:

sockstat -l|grep ipacctd

Должно появится:

root     ipacctd    96053 5  div4   *:500                 *:*
root     ipacctd    96053 6  stream /tmp/ipacct/ipacct.500

Первая строка это открытый диверт сокет, через который ipacctd получает копию всех проходящих через файерволл пакетов и вторая строка — unix сокет через который ipacctd будет отдавать накопленную информацию.
Проверяем — есть ли накопленная информация:

cat -f /tmp/ipacct/ipacct.500

должны увидеть информацию о прошедших пакетах.
Можно переходить к созданию базы MySQL в которую будем скриптом импортировать данные по пакетам.

mysql -uroot -p
create database ipacctd;
grant all on ipacctd.* to 'ipacctd'@'localhost' identified by 'ipacctd-777';

И создадим таблицу такого вида:

use ipacctd;
CREATE TABLE `traff` (
  `timestamp` int(11) NOT NULL default '0',
  `src` varchar(15) NOT NULL default '0.0.0.0',
  `src_p` int(5) NOT NULL default '1',
  `dst` varchar(15) NOT NULL default '0.0.0.0',
  `dst_p` int(5) NOT NULL default '1',
  `proto` varchar(4) NOT NULL default '',
  `bytes` bigint(20) NOT NULL default '0',
  `num` bigint(20) NOT NULL default '0',
  KEY `traff_src` (`src`),
  KEY `traff_dst` (`dst`),
  KEY `traff_timestamp` (`timestamp`));

Теперь можно переходить к разработке скрипта, который будет импортировать прошедший трафик в базу.
Скрипт напишем на перле, поэтому нужно установить библиотеку для работы с MySQL:

cd /usr/ports/databases/p5-DBD-mysql50/
make install clean

Наш скрипт не будет расчитан на обсчет большого трафика, если нужно пересчитывать террабайты траффика, к построению биллинга нужно подходить более основательно. Поэтому скрипт напишем по простому, без излишних наворотов.

#!/usr/bin/perl -w
use DBI;
$dbh=DBI->connect("dbi:mysql:ipacctd","ipacctd","ipacctd-777") or die "can't connect MySQL $!";
@traff=`/bin/cat /tmp/ipacct/ipacct.500`;
foreach(@traff)
{
  @tmp=split(" ",$_);
  $query="insert into traff set src='$tmp[0]', src_p='$tmp[1]', dst='$tmp[2]', dst_p='$tmp[3]', proto='$tmp[4]', bytes='$tmp[5]', num='$tmp
  $dbh->do($query);
}

И поставим его(этот скрипт) на cron:

crontab -e

и в нем вносим строку:

*/5     *       *       *       *       /root/bin/import.pl

И теперь скрипт подсчета статистики. У меня он выглядит так:

#!/usr/bin/perl -w
use DBI;
if(!$ARGV[0] or !$ARGV[1] or !$ARGV[2])
{
  print "Usage stat.pl ip.add.re.ss 01-01-2009 01-02-2009\n";
  exit;
}
$dbh=DBI->connect("dbi:mysql:ipacctd","ipacctd","ipacctd-777") or die "can't connect MySQL $!";
$date_b_t=$ARGV[1];
chomp $date_b_t;
$date_e_t=$ARGV[2];
@date_b=split('-', $date_b_t);
@date_e=split("-",$date_e_t);
$timestamp_begin=`/bin/date -v$date_b[0]d -v$date_b[1]m -v$date_b[2]y -v0H -v0M -v0S +%s`;
$timestamp_end=`/bin/date -v$date_e[0]d -v$date_e[1]m -v$date_e[2]y -v0H -v0M -v0S +%s`;
chomp $timestamp_begin;
chomp $timestamp_end;
$ip=$ARGV[0];
chomp $ip;
$query="select sum(bytes)/1024/1024 from traff where timestamp>='$timestamp_begin' and timestamp<'$timestamp_end' and (src='$ip' or dst='$i
$sth=$dbh->prepare($query);
$sth->execute();
($traff)=$sth->fetchrow_array();
if(!$traff)
{
  print "Traffic ip $ip с $date_b_t по $date_e_t не найден\n";
}
else
{
  print "Traffic ip $ip с $date_b_t по $date_e_t $traff Mb\n";
}

Вызывается он так:

./stat.pl 192.168.1.1 01-01-2009 01-05-2009

В нашем примере, мы пытаемся посчитать трафик абонента 192.168.1.1 с 1 января 2009 года по 1-е мая 2009 года.
То есть за 4 месяца.

Добавить в закладки:

google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru

Украинская Баннерная Сеть