Биллинг ipcad во FreeBSD

Автор: Dark

Настройка биллинга Freebsd + ipcad + web-интерфейс на php

Есть тысячи способов реализации, и готовых, обкатанных и тех, над которыми придется поломать мозг. Мы остановимся на чем-то среднем, в виду случайно сложившихся обстоятельств. Данная система не напрягаясь работает на Pentium-III 533 Mhz с 96 Mb RAM и справляется с примерно 20 сотрудниками, выкачивающими около 20 гб в месяц.

Что нам потребуется, чтобы биллить:

1. ОС FreeBSD

2. Коллектор - это зверёк, умеющий собирать, выдавать и даже иногда считать трафик. Для нас важно, что он умеет скидывать трафик в stdout, а там мы с ним уже сделаем все что захотим.

3. Получение лога трафика и его обработка. У нас этим будет заниматься самописный perl-скрипт.

4. Представление визуальных отчетов будем реализовывать на apache+php.

Почему именно так?

1. Потому что FreeBSD лучшая серверная ОСь из мне известных.

2. Можно обойтись и без netflaw, тот же ipfw или pf умеют вести логи, можно взять другой коллектор, но в силу неопределенных причин был взят именно ipcad. Нормальный коллектор, систему не грузит, ну и ладно.

3. Собственно почему самописный? Да потому что как иначе сделать - непонятно. Серьезным программистом можно и не быть, зато чуток потренироваться можно. Главное, он будет разбирать пакеты и записывать их в логи таким способом, который нам будет максимально удобен. Можно, конечно, запихивать логи в SQL базу, но большого смысла в этом как-то не вижу.<

4. Ну представить себе шлюз с сервером Apache как-то не проблема, но если это только шлюз, то ставить туда еще и MYSQL для хранения трафика, имхо, бессмысленно. А вот связка Apache + PHP весьма стандартна. Вообще, я больше склоняюсь в последнее время к постороению веб-морды на CGI (perl), но пока не до этого.

От теории к практике. Все вводимые команды должны быть выполнены из под root-а.

IPCAD.

Ставим ipcad. Самый простой и быстрый способ:

root@localhost# pkg_add -vr ipcad

Чуть медленнее и сложнее из портов (говорят, так круче) :)

root@localhost# cd /usr/ports/net-mgmt/ipcad

root@localhost# make install

Теперь, ipcad у нас установлен. не забываем в rc.conf добавить строчку автозапуска, можно так:

root@localhost# echo 'ipcad_enable="YES"' >> /etc/rc.conf

Что ж, самое время подправить конфиг коллектора. Во-первых, создадим его:

root@localhost# cd /usr/local/etc

root@localhost# cp ipcad.conf.simple ipcad.conf

Редактируем ipcad.conf. Вообще, можно сильно намудрить, но мы удовлетворимся следующим конфигом:

interface rl0;

interface rl1;

rsh enable at 127.0.0.1;

rsh root@127.0.0.1 admin;

rsh 127.0.0.1 view-only;

chroot = /tmp;

pidfile = ipcad.pid;

dumpfile = ipcad.dump;

Вот этих 7 строчек вполне достаточно чтобы взлететь. Ну что ж взлетаем:

root@localhost# /usr/local/etc/rc.d/ipcad.sh start

root@localhost# ps ax | grep ipcad

530 ?? Ss 0:00.10 /usr/local/bin/ipcad -rds -c /usr/local/etc/ipcad.conf

Летим... это хорошо. Сейчас наш коллектор набирает трафик из интерфейсов. Получить таблицу дампа можно так:

root@localhost# rsh localhost dump

root@localhost# rsh localhost show ip accounting

В ответ получаем так необходимую нам таблицу, примерно такого вида:

Source Destination Packets Bytes SrcPt DstPt Proto IF

192.168.0.200 224.0.0.1 1 36 - - 2 rl0

192.168.0.11 64.12.25.146 1 40 1381 443 6 rl0

64.12.25.146 192.168.0.11 1 40 443 1381 6 rl0

88.212.196.89 192.168.0.89 5 612 80 4749 6 rl0

192.168.0.89 88.212.196.89 5 762 4749 80 6 rl0

194.67.35.195 192.168.0.89 6 1614 80 4748 6 rl0

62.105.38.43 62.105.32.2 1 73 49409 53 17 rl1

62.105.38.43 62.105.32.2 1 72 55928 53 17 rl1

62.105.38.42 201.240.63.112 1 48 25 16032 6 rl1

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Accounting data age is 1

Accounting data age exact 60

Accounting data saved 1181910720

Interface rl0: received 44026, 5 m average 10431 bytes/sec, 18 pkts/sec, dropped 0

Interface rl1: received 176894, 5 m average 40646 bytes/sec, 80 pkts/sec, dropped 9

Flow entries made: 823

Memory usage: 109 kbytes.

Free slots for rsh clients: 9

IPCAD uptime is 5 minutes

Итак, коллектор у нас работает. Самое простое позади и мы переходим к следующей части нашего творчества.

Собираем и сортируем трафик.

Здесь надо сделать отступление. Каким же образом нам оптимально распоряжаться дампами ipcad-а?

Пожалуй, для нас будет оптимально скидывать дамп каждую минуту, чтобы мы знали время с точностью до минуты когда и куда какой пакет ходил. Время мы подпишем - это не проблема. Дальше, скидывать дамп будем в файл, там уж решим куда девать отсортированные данные. Сортировку предоставим perl скрипту (хотя можно и в шелл-скриптинге потренироваться). Тогда вперед! Создаем директорию, где будем держать скрипты и логи.

root@localhost# mkdir /var/log/traf

root@localhost# mkdir /usr/local/etc/traf

root@localhost# touch /usr/local/etc/traf/dump.sh

root@localhost# touch /usr/local/etc/traf/sort.pl

root@localhost# cd /usr/local/etc/traf

root@localhost# chmod u+x *

Кстати, рекомендую проверить достаточно ли место в разделе /var, если нет, то кладите логи куда-нибудь в другое место. Итак, у нас теперь есть все нужные нам директории и файлы. Правда, пока пустые, но это ненадолго. Как мы будем обрабатывать наши логи?

1. Будем создавать в /var/log/traf/ директорию типа YYYY-MM-DD для упрощения дальнейшей обработки по дням. Можно складывать и в поддиректории типа /var/log/traf/YYYY/MM/DD - это, пожалуй, более удобный и гибкий вариант с точки зрения дальнейшей ротации, но пока остановимся на первом варианте. Кто понял принцип - переделает сам.

2. В директории будем складывать файлики типа 192.168.0.1_in.log или 192.168.0.2_out.log для упрощения обработки трафика по юзерам. Можно организовать хранение без разделения входящего и исходящего трафика на файлы. Но так, пожалуй, удобнее.

Действуем. В файл /usr/local/etc/traf/dump.sh вбиваем следующее содержимое:

#!/bin/sh

# name of script: dump.sh

HOST=localhost

rsh $HOST dump

rsh $HOST show ip accounting > /var/log/traf/acc.txt

/usr/local/etc/traf/sort.pl && rm /var/log/traf/acc.txt

В /etc/crontab помещаем строчку:

* * * * * root /usr/local/etc/traf/dump.sh

Второй наш файл сортировщик будет написан на перле. Прошу сразу не бить за корявый код, поскольку я не программист. Зато код читабельный и понять его даже без комментариев сможет и первоклассник:

#!/usr/bin/perl

# file sort.pl :)

$ext_if="rl1";

$int_if="rl0";

$serverip = "63.64.65.66";

$lan="192.168.";

$dir = "/var/log/traf/";

my $time = `date -v-1M +%H:%M`;

my $day = `date +%d`;

my $month = `date +%m`;

my $year = `date +%Y`;

chomp $year; chomp $month; chomp $time; chomp $day;

#opening file

open (TRAF, '@lines = ;

close (TRAF);

#looking for TODAY's directory exists

$today = $dir.$year."-".$month."-".$day;

if (chdir $today)

{

}

else

{

mkdir $today;

}

# Looking for server log file exists

$router_in = $today."/router_in.log";

$router_out = $today."/router_out.log";

if (-s $router_in)

{

}

else

{

`touch $router_in`;

}

if (-s $router_out)

{

}

else

{

`touch $router_out`;

}

$in=0;

$out=0;

$free=0;

$summa=0;

$i = 0;

while ($i <= $#lines)

{

# put every word in string to massive

@word = split (" ", $lines[$i]);

# looking that external interface is in string

if ($word[7] eq $ext_if)

{

# So, counting incoming and outcoming traffic total

if ($word[0] eq $serverip)

{

open (ROUTER_OUT, ">>$router_out") ;

print ROUTER_OUT "$time $word[1] $word[3] $word[6] ";

close(ROUTER_OUT);

}

elsif ($word[1] eq $serverip)

{

open (ROUTER_IN, ">>$router_in") ;

print ROUTER_IN "$time $word[0] $word[3] $word[6] ";

close(ROUTER_IN);

}

# If there is no server IP, possible that this packets are broadcast and there is no need to count them

# but we'll try :)

else

}

# Now looking for internal interface

elsif ($word[7] eq $int_if)

{

# looking for first 8 simbols in IP.

# If both IP looks like 192.168. - there's no need to count

$a1 = substr ($word[0],0,8);

$b1 = substr ($word[1],0,8);

if ($a1 ne $b1)

{

# if traffic is outgoing putting it to file like 192.168.0.1_out.log

if ($a1 eq $lan)

{

$filename = $dir."/".$year."-".$month."-".$day."/".$word[0]."_out.log";

if (-s $filename)

open (OTCHET1, ">>$filename") ;

if ($rl0in =~ /d/)

if ($rl0out =~ /d/)

print OTCHET1 "$time $word[1] $word[3] $word[6] ";

close(OTCHET1);

}

# if traffic is incoming putting it to file like 192.168.0.1_in.log

elsif ($b1 eq $lan)

{

$filename = $dir."/".$year."-".$month."-".$day."/".$word[1]."_in.log";

if (-s $filename)

open (OTCHET1, ">>$filename") ;

if ($rl0in =~ /d/)

if ($rl0out =~ /d/)

print OTCHET1 "$time $word[0] $word[3] $word[6] ";

close(OTCHET1);

}

#enf if not equal IPs

}

#

# This is local traffic if someone need

else

{

$localrl0=$localrl0 + $word[3];

}

}

$i++;

}

Вот и все. Логи у нас выглядят так, как нам это нужно. Теперь нам необходимо средство просмотра этих самых логов. Если логи не надо показывать начальству, можно написать на том же perl скрипт который нам покажет статистику по нашему пользователю:

#!/usr/bin/perl

# file user_stats :)

$path = "/var/log/traf/";

if (@ARGV[0] ne "")

{

$user=@ARGV[0];

}

else

{

$user="192.168.0.1";

}

my $time = `date +%H:%M`;

my $day = `date +%d`;

my $month = `date +%m`;

my $year = `date +%Y`;

chomp $year; chomp $month; chomp $time; chomp $day;

$grep_dirs=$year."-".$month."-";

@dirs=`ls $path | grep $grep_dirs`;

print "Total user $user traffic statistic for $month-$year ";

print " DATE INCOMING OUTCOMING ";

$i=0;

while ($i <= $#dirs)

{

chomp @dirs[$i];

#accounting incoming traffic

$file_in=$path.@dirs[$i]."/".$user."_in.log";

open (IN, "$file_in"); @incoming = ; close (IN);

$j=0; $traf_in=0;

while ($j <= $#incoming)

{

$string = @incoming[$j]; @strings = split (" ", $string);

$traf_in=$traf_in+@strings[2];

$j++;

}

$file_out=$path.@dirs[$i]."/".$user."_out.log";

open (OUT, "$file_out"); @outcoming = ; close (OUT);

$k=0; $traf_out=0;

while ($k <= $#outcoming)

{

$string = @outcoming[$k]; @strings = split (" ", $string);

$traf_out=$traf_out+@strings[2];

$k++;

}

$day_in=sprintf ("%.1f",($traf_in/(1024*1024)));

$day_out=sprintf ("%.1f",($traf_out/(1024*1024)));

print @dirs[$i]." ".$day_in." ".$day_out." ";

$total_in=$total_in+$traf_in;

$total_out=$total_out+$traf_out;

$i++;

}

$total_in=sprintf ("%.2f",($total_in/(1024*1024)));

$total_out=sprintf ("%.2f",($total_out/(1024*1024)));

print " Total incoming traffic $total_in mb ";

print "Total outcoming traffic $total_out mb ";

print " ";

Сохраняем код в файле user_stats.pl, делаем его исполняемым. А работает он так:

root@localhost# ./user_stats.pl 192.168.0.2

DATE INCOMING OUTCOMING

2007-06-04 15.5 2.3

2007-06-05 15.9 2.0

2007-06-06 15.6 2.3

2007-06-07 17.7 2.8

2007-06-08 20.1 2.0

2007-06-09 24.9 8.9

2007-06-10 0.0 0.0

2007-06-11 0.0 0.0

2007-06-12 0.0 0.0

2007-06-13 13.1 1.9

2007-06-14 13.4 3.6

2007-06-15 57.6 21.

Total incoming traffic 193.80 mb

Total outcoming traffic 47.73 mb

На основе этого скрипта можно создать другие, которые будут обрабатывать статистику за день, неделю, посещаемые ресурсы и так далее. Но это, пожалуй, больше подойдет для web-интерфейса. Именно об этом и пойдет разговор в следующий раз.

Обнаружилось, что движок сайта обрезает символы в коде. Так что, возможно, скопировать с сайта и вставить в файл не получится. Зато, готовые скрипты можно скачать тут.

Нароботки веб-морды, которая будет показывать трафик, можно качнуть здесь. Конечно, там многого нету, и кое-что не дописано, но я постараюсь почаще обновлять код и выкладывать его.

P.S.: Всё-таки приятно, когда на разных серверах, можно использовать одно и то же решение практически без изменений.

Последнее изменение: пятница, 29 августа 2008 г. 18:21:36

http://www.ounix.ru/index.php?page=article&id=8

Обновлено: 12.03.2015