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 месяца.