Система учета трафика во FreeBSD

У многих начинающих системных администраторов часто стоит вопрос, а какорганизовать систему учета трафика? С подобными вопросами вы сталкнетесь на многих форумах в интернете.

В рамках данной статьи мы рассмотрим простую систему учета трафика, которая должна будет обладать следующими характеристика:

* Учет всего трафика проходящего через маршрутизатор работающий под ОС Linux;

* Возможностью быстрого изменения конфигурации без внесения изменений в код;

* Данные о трафике должны храниться в базе данных, в нашем случае мы в качестве сервера баз данных будем использовать MySQL.

В рассматриваемом примере будем считать, что все IP адреса в нашей сети реальные.

Начнем с создания конфигурационного файла, назовем его billing.conf. Пусть он имеет следующий вид:

<******* 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 - все пересланные маршрутизатором пакеты во внешнюю сеть.

<******* rc.firewall **************>

#!/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):

<********* База данных trafficbd.sql *****>

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;

}

<**********************************>

Обновлено: 12.03.2015