Пишем простую систему учета трафика.
Автор : Вадим Фёдоров
У многих начинающих системных администраторов часто стоит вопрос, а как организовать систему учета трафика? С подобными вопросами вы столкнетесь на многих форумах в интернете.
В рамках данной статьи мы рассмотрим простую систему учета трафика, которая должна будет обладать следующими характеристиками:
- Учет всего трафика, проходящего через маршрутизатор работающий под ОС Linux;
- Возможность быстрого изменения конфигурации без внесения изменений в код;
- Данные о трафике должны храниться в базе данных, в нашем случае мы в качестве сервера баз данных будем использовать MySQL.
В рассматриваемом примере будем считать, что все IP адреса в нашей сети реальные. Начнем с создания конфигурационного файла, назовем его billing.conf. Пусть он имеет следующий вид:
# Формируем список IP адресов машин или сетей, для которых мы будем считать
# трафик
# Рабочее место
WS1="192.168.0.1"
# Ceть нашего клиента
NET="192.168.1.0/24"
# Объединим объединим все сети и адреса в один список.
ALLNETS="$WS1 $NET"
В принципе, формировать списки для каждого адреса или сети нет необходимости, т.к. рассматриваемая система использует только список ALLNETS, однако они могут понадобиться в случае, если вам нужно будет обрабатывать статистику о каждом пользователе. Данный конфигурационный файл является единой для всей нашей системы, состоящей как минимум из трех программ:
- Программы формирования правил учета для firewall, с использованием iptables;
- Программы снятия статистики;
- Программы отображения статистики;
Рассмотрим программу формирования правил учета для firewall, названную в нашем случае rc.firewall, которую нужно будет добавить в один из файлов, который будет выполняться при загрузке системы.
Для начала немного теории, в ядрах Linux серии 2.4.X используется firewall NetFilter, интерфейсом к которому является программа iptables. В NetFilter cущестуют несколько цепочек: INPUT - все входящие пакеты, адресованные маршрутизатору, OUTPUT - все исходящии из маршрутизатора пакеты, FORWARD - все пересланные маршрутизатором пакеты во внешнюю сеть.
#!/bin/bash
# Подключаем конфигурационный файл
. /etc/lbiling.conf
IPTABLES="/sbin/iptables" # Задаем путь к программе iptables
###################################
# Учет трафика
###################################
# Функция для создания правила учета
addrule(){
$IPTABLES -N ACCT_IN_$1 # Создаем правило для учета входяшего трафика
$IPTABLES -N ACCT_OUT_$1 # Создаем правило для учета изходяшего трафика
$IPTABLES -F ACCT_IN_$1 # Обнулим полученные цепочки
$IPTABLES -F ACCT_OUT_$1
$IPTABLES -A INPUT -j ACCT_IN_$1 # Включим учет по цепочкам
$IPTABLES -A FORWARD -j ACCT_IN_$1
$IPTABLES -A FORWARD -j ACCT_OUT_$1
$IPTABLES -A OUTPUT -j ACCT_OUT_$1
$IPTABLES -A ACCT_IN_$1 -s $2 # Считать входящим трафик у которого источник
# адрес $2
$IPTABLES -A ACCT_OUT_$1 -d $2 # Считать исходящим трафик у которого получатель
# адрес $2
}
# Создаем правила для учета трафика
for NET in $ALLNETS; do
# Для всех сетей в списке $ALLNET создать правила учета трафика
addrule $NET $NET
done
После выполнения нашей программы rc.firewall, набрав в консоли:
# iptables -L
Вы должны будете увидеть нечто подобное:
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCT_IN_192.168.0.1 all -- anywhere anywhere
ACCT_IN_192.168.1.0/24 all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCT_IN_192.168.0.1 all -- anywhere anywhere
ACCT_OUT_192.168.0.1 all -- anywhere anywhere
ACCT_IN_192.168.1.0/24 all -- anywhere anywhere
ACCT_OUT_192.168.1.0/24 all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ACCT_OUT_192.168.0.1 all -- anywhere anywhere
ACCT_OUT_192.168.1.0/24 all -- anywhere anywhere
Chain ACCT_IN_192.168.0.1 (2 references)
target prot opt source destination
all -- 192.168.0.1 anywhere
Chain ACCT_IN_192.168.1.0/24 (2 references)
target prot opt source destination
all -- 192.168.1.0/24 anywhere
Chain ACCT_OUT_192.168.0.1 (2 references)
target prot opt source destination
all -- anywhere 192.168.0.1
Chain ACCT_OUT_192.168.1.0/24 (2 references)
target prot opt source destination
all -- anywhere 192.168.1.0/24
Создадим базу данных в MySQL с названием trafficbd, для этого необходимо будет выполнить следующий SQL запрос (вопрос "как это сделать" не входит в рамки нашей статьи, обратитесь к документации MySQL):
CREATE DATABASE IF NOT EXISTS trafficbd;
use trafficbd;
#
# Структура таблицы `traffic`
#
CREATE TABLE traffic (
id int(11) NOT NULL auto_increment,
date datetime NOT NULL default '0000-00-00 00:00:00',
ip varchar(20) NOT NULL default '',
inb int(11) NOT NULL default '0',
outb int(11) NOT NULL default '0',
KEY id (id)
) TYPE=MyISAM;
Итак, подведем итоги, мы создали базу данных, написали правила учета трафика, теперь нам надо паписать программу, которая бы снимала полученную статистику, заносила её в базуданных и после этого обнуляла бы счетчики. Ниже приведен пример такой программы, её можно прописать в CRON и вызывать с некоторым периодом.
#!/usr/bin/perl
# Функция занимающаяся сбором и внесением данных в БД.
sub account{
$name=$_[0]; # Имя правила
$IP_IN=0; # Инициализация счетчиков
$IP_OUT=0;
# Командная строка MySQL для внесения данных в таблицу.
$mysqlcommand="/usr/bin/mysql -hlocalhost trafficbd -e";
# Снимем данные со счетчика входящего трафика и обнулим
$ipstuff=`/sbin/iptables -L -Z ACCT_IN_$name -v -x`;
# Выделим из вывода предыдущей команды значение счетчика
@IPTBMASS=split(/ /,$ipstuff);
chomp $IPTBMASS[2];
$string=$IPTBMASS[2];
$string=~ s/s{1,}/ /g;
@INFOMASS=split(/ /,$string);
$IP_IN=$INFOMASS[2];
# Снимем данные со счетчика исходящего трафика и обнулим
$ipstuff=`/sbin/iptables -L -Z ACCT_OUT_$name -v -x`;
# Выделим из вывода предыдущей команды значение счетчика
@IPTBMASS=split(/ /,$ipstuff);
$string=$IPTBMASS[2];
$string=~ s/s{1,}/ /g;
@INFOMASS2=split(/ /,$string);
$IP_OUT=$INFOMASS2[2];
# Получим текущее время
($min, $hours, $day, $mounth,$year) = (localtime)[1,2,3,4,5];
$time=$hours.":".$min.":00";
$mounth=$mounth+1;
$year=$year+1900;
$date=$year."-".$mounth."-".$day;
# Формируем SQL запрос
$sql="insert into traffic values('','".$date." ".$time."','".$name."','".$IP_IN."','".$IP_OUT."');";
# Выполняем его
`$mysqlcommand "$sql"`;
} # На этом функция account заканчивается:)
# Основная программа
$config=`./lconfreader.sh`; # Прочитаем конфигурационный файл.
# Ниже приводится текст скрипта lconfreader.sh:
# #!/bin/bash
# . ./lbiling.conf # Включить конфигурационный файл
# echo $ALLNETS # Вывести в stdout список всех сетей, покоторым ведется учет.
#
chomp $config;
@NETMASS=split(/ /,$config);
foreach $nets(@NETMASS)
{
# Для каждого элемента списка, выполнить функцию account
account $nets;
}
Вот собственно и вся биллинговая система :)