Как считать трафик на FreeBSD. Часть первая. Настройка trafd

Как считать трафик на FreeBSD. Часть первая. Настройка trafd

Автор TMeter

Один из самых элегантных способов подсчета трафика в UNIX-системах — это использование программы trafd. Наша задача, состоит в том, чтобы получить систему, которая бы автоматически считала трафик для определенного диапазона ip-адресов, и заносила результаты в MySQL таблицу формата:

Имя поля Тип поля Назначение поля
dt date Дата в формате 2002-12-31
ip char(16) IP адрес, например 192.168.3.2
sent bigint Количество посланных байт для данного IP адреса
recv bigint Количество принятых байт для данного IP адреса

Кроме того, необходимо выполнить следующие условия:

  • Не учитывать трафик с определенными признаками, например, трафик компьютеров из локальной сети к локальному веб-серверу
  • При появлении нового IP адреса в заранее известном диапазоне автоматически учитывать его трафик

Установка программ

Первое, что придется сделать — это установить MySQL и создать базу данных, в которой будут находиться таблицы, используемые в процессе биллинга. Пусть название базы данных для этих целей будет ipacc. Далее — установить пакет trafd. В FreeBSD программа trafd находится в портах, что делает установку достаточно простой:

cd /usr/ports/net/trafd
make
make install

Фактически, trafd представляет собой набор нескольких программ, но нам потребуются следующие утилиты:

  • trafd — демон сбора трафика
  • trafdump/trafsave — программы для записи собранного трафика демоном trafd в бинарный формат
  • traflog — программа для преобразования бинарных файлов трафика в тестовый формат

Шаг 1. Запуск демона trafd

Демон trafd должен запускаться после загрузки системы. Для этого создадим файл /usr/local/etc/rc.d/trafd.sh:

#!/bin/sh
/usr/local/bin/trafd -r -p -i ed0

где, -i ed0 указывает на имя сетевого адаптера, с которого будет собирать трафик; ключ -p указывает на то, что переводить сетевой адаптер в promiscuous mode не надо (по умолчанию, демон trafd переводит сетевой адаптер в promiscuous mode); ключ -r будет указывать на попытку восстановления данных из существующего бинарного файла при рестарте демона. Если техническое задание указывает на подсчет трафика с нескольких сетевых интерфейсов одновременно, то можно запустить одновременно несколько экземпляров демона trafd из файла /usr/local/etc/rc.d/trafd.sh, например:

#!/bin/sh
/usr/local/bin/trafd -r -p -i ed0
/usr/local/bin/trafd -r -p -i ed1
/usr/local/bin/trafd -r -p -i ed2

Шаг 2. Создание бинарных файлов трафика

Демон trafd хранит информацию о собранном трафике в оперативной памяти, поэтому ему необходимо периодически посылать сигнал для «сброса» накопленных данных в временный файл чтобы в случае перезагрузки компьютера восстановить накопленный трафик из временного файла (ключ -r демона trafd). Делать это будем из скрипта /usr/local/etc/traffic/save_tmp.sh.

#!/bin/sh
/usr/local/bin/trafdump ed0
/usr/local/bin/trafdump ed1
/usr/local/bin/trafdump ed2

Раз в сутки нужно записывать накопленный трафик демоном trafd в бинарные файлы /usr/local/var/trafd/trafd.ed0(1,2) при помощи программы trafsave вызывая ее из скрипта /usr/local/etc/traffic/periodic.sh:

#!/bin/sh
/usr/local/bin/trafsave ed0
/usr/local/bin/trafsave ed1
/usr/local/bin/trafsave ed2

Итак, скрипт save_tmp.sh будем вызывать раз в 15 минут, скрипт periodic.sh вызываем в конце каждых суток:

# /etc/crontab
#minute hour    mday    month   wday   who      command
*/15    *       *       *       *      root     /usr/local/etc/traffic/save_tmp.sh
59      23      *       *       *      root     /usr/local/etc/traffic/periodic.sh

Шаг 3. Копирование бинарных файлов трафика за предыдущий день

Сразу после наступления новых суток, бинарные файлы трафика /usr/local/var/trafd/trafd.ed0(1,2) необходимо сохранить в надежное место. Таким местом для нас будет являться директория /usr/local/var/traffic. Для копирования бинарных файлов трафика за прошедшие сутки напишем следующий скрипт, и сохраним его под именем /usr/local/etc/traffic/daily.sh:

#!/bin/sh

date=`date -v-1d '+%Y%m%d'`
fp=/usr/local/var/traffic/$date
cp /usr/local/var/trafd/trafd.ed0 $fp.ed0
rm /usr/local/var/trafd/trafd.ed0
cp /usr/local/var/trafd/trafd.ed1 $fp.ed1
rm /usr/local/var/trafd/trafd.ed1
cp /usr/local/var/trafd/trafd.ed2 $fp.ed2
rm /usr/local/var/trafd/trafd.ed2

В результате чего, в директории /usr/local/var/traffic будут появляться бинарные файлы трафика с именами, обозначающими дату и название интерфейса, например, 20021231.ed0 и т.д. Естественно, что запуск этого скрипта необходимо выполнять через крон:

# /etc/crontab
#minute hour    mday    month   wday   who      command
5       0       *       *       *      root     /usr/local/etc/traffic/daily.sh

Шаг 4. Преобразование бинарных файлов трафика в текстовый вид

Итак, после 3-его шага, мы имеем бинарные файлы трафика за прошедшие сутки, которые необходимо начинать обрабатывать. Для начала их нужно преобразовать из бинарного формата в текстовый вид. Для этих целей существует программа traflog, которую будем вызывать из скрипта /usr/local/etc/traffic/expandplain.sh:

#!/bin/sh

date=`date -v-1d '+%Y%m%d'`
fp=/usr/local/var/traffic/$date
fn=/usr/local/var/traffic_plain/$date

/usr/local/bin/traflog -a -n -i $fp.ed0 >> $fn.ed0
/usr/local/bin/traflog -a -n -i $fp.ed1 >> $fn.ed1
/usr/local/bin/traflog -a -n -i $fp.ed2 >> $fn.ed2

Как вы уже наверно догадались, текстовые файлы трафика будут складывать в директорию /usr/local/var/traffic_plain. Вызов скрипта expandplain.sh также будет происходить по расписанию.

# /etc/crontab
#minute hour    mday    month   wday   who      command
10      0       *       *       *      root     /usr/local/etc/traffic/expandplain.sh

Текстовый формат файла трафика достаточно прост для восприятия его человеком:

 (/usr/local/var/traffic/20021106.ed2) xeon.tmeter.ru at Nov 6 21:59:08
 Summary: 48191 data bytes, 53659 all bytes, 5 records
     From           Port         To            Port  Proto     Data       All
12.129.206.119     80      192.168.100.2      client  tcp      24624      25672
216.26.160.8       110     192.168.100.2      client  tcp      10217      11673
192.168.100.2      client  216.34.191.52      25      tcp       6307       6991
192.168.100.2      client  66.185.95.98       25      tcp       6295       6795
192.168.100.2      client  12.129.206.119     80      tcp        748       2528

Шаг 5. Помещаем вчерашний трафик в MySQL базу данных

Трафик за прошедшие сутки необходимо загнать с таблицу MySQL базы данных для того, чтобы с ним было легче работать. Вчерашний трафик поместим в таблицу под названием yesterday следующего формата:

create table yesterday (src_ip char(16), src_port int, 
   dst_ip char(16), dst_port int, proto int, bytes bigint);

Для обработки текстовых файлов трафика будем использовать следующий скрипт (назовем его /usr/local/etc/traffic/db_step1.pl):

#!/usr/bin/perl
use Mysql;

$plain_path='/usr/local/var/traffic_plain/';
$yesterday=`date -v-1d '+%Y%m%d'`;
chomp($yesterday); $full_path=$plain_path.$yesterday.".ed0";

$dbh = Mysql->Connect("","ipacc");
$del_query="delete from yesterday;";
$dbh->Query($del_query);

open(F,$full_path) || die "Can't open traffic plain file";
while ($str=)
{
  chomp($str);
  $fi=substr($str,0,1);

  if (($fi>='1') && ($fi< ='9'))
  {
      @a=split('\s+',$str);
      # @a[0] - src_ip, @a[1] - src_port, @a[2] - dst_ip, @a[3] - dst_port
      # @a[4] - proto, @a[6] - size of packets

      if (@a[1] eq 'client') { 
          $src_port=65535;
      } else {
          if (@a[1] eq 'none') {
	        $src_port=0;
	     } else {
	        $src_port=@a[1];
	     }
      }
      if (@a[3] eq 'client') {
          $dst_port=65535;
      } else {
          if (@a[3] eq 'none') {
	        $dst_port=0;
	     } else {
	        $dst_port=@a[3];
	     }
      }
      $proto=0;
      if (@a[4] eq 'icmp') {
         $proto=1; }
      if (@a[4] eq 'tcp') {
         $proto=6; }
      if (@a[4] eq 'udp') { 
         $proto=17; }

      $ins_query="insert into yesterday (src_ip, src_port, dst_ip,\
         dst_port, proto, bytes) values ('".@a[0]."',".$src_port.\
         ",'".@a[2]."',".$dst_port.",".$proto.\",".$a[6].");";
      $dbh->Query($ins_query);
  };
};

close(F);

Совершенно естественно, что и этот скрипт будет вызываться по крону:

# /etc/crontab
#minute hour    mday    month   wday   who      command
15      0       *       *       *      root     /usr/local/etc/traffic/db_step1.pl

Шаг 6 (последний). Обработка и суммирование вчерашнего трафика

Итак, мы имеем таблицу yesterday. В ней собраны адреса сетевых пакетов, которые демон trafd «поймал» вчера. Из этой таблицы нам необходимо исключить из подсчета определенные пакеты, вычислить итоговое значение трафика в байтах для определенной части ip-адресов и записать результат в таблицу traffic. Делать это мы будет через промежуточную таблицу traffic_tmp:

create table traffic_tmp (ip char(16), 
   sent bigint default 0, recv bigint default 0);

create table traffic (dt date, ip char(16), 
   sent bigint default 0, recv bigint default 0);

Ниже приведенный скрипт /usr/local/etc/traffic/db_step2.pl производит калькуляцию итога за прошедшие сутки:

#!/usr/bin/perl
use Mysql;

$dbh = Mysql->Connect("","ipacc");
$del_query="delete from traffic_tmp;";
$dbh->Query($del_query);

#
#  exclude NetBIOS packets
#
$q="delete from yesterday where ((src_port>=137) AND (src_port< =139))";
$dbh->Query($q);
$q="delete from yesterday where ((dst_port>=137) AND (dst_port< =139))";
$dbh->Query($q);
#
#  Here you can put another rules to exclude an accounting of useless traffic
#

#
# Calculate amount of traffic for each host in 192.168.3.x subnet
#
$query_sent="insert into traffic_tmp (ip,sent) \
      select src_ip as ip, sum(bytes) as sent \
      from yesterday where src_ip like '192.168.3.%' group by src_ip;";
$dbh->Query($query_sent);
$query_recv="insert into traffic_tmp (ip,recv) \
      select dst_ip as ip, sum(bytes) as recv \
      from yesterday where dst_ip like '192.168.3.%' group by dst_ip;";
$dbh->Query($query_recv);
#
# Here you can put operators to count the traffic of another subnet
#

#
#  itogo. Insert itogo in the main "traffic" table
#
$yesterday=`date -v-1d '+%Y-%m-%d'`; chomp($yesterday);
$qi="insert into traffic (dt,ip,sent,recv) \
      select '".$yesterday."',ip, sum(sent) as sent, sum(recv) as recv \
      from traffic_tmp group by ip;";
      $dbh->Query($qi);

Куда вставить запуск этого скрипта, я, надеюсь, вы уже догадались 😉

Загрузить набор скриптов из этой статьи ipacc_trafd.tgz (1,5кбайт)

tmeter.ru

Запись опубликована в рубрике *Unix,*Linux, FreeBSD. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Я не спамер This plugin created by Alexei91