20 мар. 2010 г.

Подсчет трафика на FreeBSD с использованием ng_ipacct


У нас на шлюзе (FeeBSD) в качестве фаирвола используется PF, когда возникла необходимость учета и анализа трафика в качестве инструмента был выбран ng_ipacct.


Конфигурация ng_ipacct

Установка из портов стандартная, и конфиг с небольшими изменениями

# $FreeBSD: ports/net-mgmt/ng_ipacct/files/ng_ipacct.conf,v 1.6 2008/06/03 10:40:16 skv Exp $
#
# Please read and meditate on netgraph(4), ipacctctl(8) and ngctl(8).

# Enable ng_ipacct (i.e. enable run startup script "ng_ipacct.sh")
ng_ipacct_enable="YES"

# Enable kernel modules loading.
# On "ng_ipacct.sh start" all kernel modules specified
# in ${ng_ipacct_modules_list} will be loaded.
# Note: on "ng_ipacct.sh stop" only "ng_ipacct" will be unloaded.
ng_ipacct_modules_load="YES"

# Netgraph can load required ng_* modules automatically on the hook creation
# - except for "ng_ether". Generally, modules preloading is recommended.
# Do not add to this list modules which are statically compiled into kernel.
#ng_ipacct_modules_list="netgraph ng_ether ng_cisco ng_socket ng_tee ng_ipacct"
ng_ipacct_modules_list="ng_ipacct"

# List of monitored interfaces. For each interface additional vars must be
# specified in corresponding variables 'ng_ipacct_IFACE_*'.
# See examples below.
ng_ipacct_interfaces="rl1 rl0"

# Default start/stop scripts.
#
# Single quotes are required to preserve newlines.
# '%%iface%%' will be automatically expanded with a relevant interface.
# This feature should be applied to use indentical rules
# for similar interfaces.
ng_ipacct_default_ether_start='
    mkpeer %%iface%%: tee lower right
    name %%iface%%:lower %%iface%%_tee
    connect %%iface%%: lower upper left

    mkpeer %%iface%%_tee: ipacct right2left %%iface%%_in
    name %%iface%%_tee:right2left %%iface%%_ip_acct
    connect %%iface%%_tee: %%iface%%_ip_acct: left2right %%iface%%_out
'

ng_ipacct_default_ether_stop='
    shutdown %%iface%%_ip_acct:
    shutdown %%iface%%_tee:
    shutdown %%iface%%:
'

ng_ipacct_bpf_ether_start='
    mkpeer %%iface%%: tee lower right
    name %%iface%%:lower %%iface%%_tee
    connect %%iface%%: lower upper left

    mkpeer %%iface%%_tee: bpf right2left %%iface%%_in
    name %%iface%%_tee:right2left %%iface%%_bpf
    connect %%iface%%_tee: right2left left2right %%iface%%_out
   
    mkpeer %%iface%%_bpf: ipacct %%iface%%_match_in %%iface%%_in
    name %%iface%%_bpf:%%iface%%_match_in %%iface%%_ip_acct
    connect %%iface%%_bpf: %%iface%%_ip_acct: %%iface%%_match_out %%iface%%_out
'

ng_ipacct_bpf_ether_stop='
    shutdown %%iface%%_ip_acct:
    shutdown %%iface%%_bpf:
    shutdown %%iface%%_tee:
    shutdown %%iface%%:
'

# Configuration for 'rl1_ip_acct' node:

ng_ipacct_rl1_dlt="EN10MB"    # required line; see ipacctctl(8)
ng_ipacct_rl1_threshold="15000"    # '5000' by default
ng_ipacct_rl1_verbose="yes"    # 'yes' by default
ng_ipacct_rl1_start=${ng_ipacct_default_ether_start}
ng_ipacct_rl1_stop=${ng_ipacct_default_ether_stop}
ng_ipacct_rl1_checkpoint_script="/usr/bin/ipacct.sh rl1"

ng_ipacct_rl0_dlt="EN10MB"    # required line; see ipacctctl(8)
ng_ipacct_rl0_threshold="15000"    # '5000' by default
ng_ipacct_rl0_verbose="yes"    # 'yes' by default
ng_ipacct_rl0_start=${ng_ipacct_default_ether_start}
ng_ipacct_rl0_stop=${ng_ipacct_default_ether_stop}
ng_ipacct_rl0_checkpoint_script="/usr/bin/ipacct.sh rl0"


Настройка cron

В crontab добавляем запуск скидывания статистики каждые 10 мин.:
*/10    *    *    *    *    root    /usr/local/etc/rc.d/ng_ipacct checkpoint

Скрипт, который обрабатывает статистику, задается сдесь:
ng_ipacct_rl1_checkpoint_script="/usr/bin/ipacct.sh rl1"
ng_ipacct_rl0_checkpoint_script="/usr/bin/ipacct.sh rl0"

Вывод статистики

Код скрипта, основной задачей которого является скидывание файлов статистики на ftp сервер:
#!/bin/sh
IPACCTCTL="/usr/local/sbin/ipacctctl"
WPUT="/usr/local/bin/wput"
FTPHOST="hostname"
FTPUSER="username"
FTPPASS="password"
IFACE=$1
DIR="/var/log/ipacct"
TMP=$DIR
PREFIX=$(date +%Y%m%d%H%M)
NAME="ng_ipacct_$1.log"
$IPACCTCTL ${IFACE}_ip_acct:$IFACE checkpoint
$IPACCTCTL -n ${IFACE}_ip_acct:$IFACE show >> $DIR/$NAME
$IPACCTCTL ${IFACE}_ip_acct:$IFACE clear
sleep 3
/usr/bin/tail -1 $DIR/$NAME | /usr/bin/fgrep exceed
NEW_FILE=$TMP/$PREFIX-$NAME
mv $DIR/$NAME $NEW_FILE
if [ -f $NEW_FILE ]; then
  $WPUT --tries=5 --basename=$TMP  $NEW_FILE ftp://$FTPUSER:$FTPPASS@$FTPHOST
  if [ $? = 0 ]; then
    rm $NEW_FILE
  fi
fi


Сохранение статистики трафика интерфейса в MySQL

Обработка проводится на дрогом хосте скриптом на php (запускается в консоли), при этом данные сохраняются в mysql:
#!/usr/bin/php
<?php
ini_set('memory_limit', '128M');

require_once 'settings.php';
require_once 'functions.php';
require_once 'Ftp.php';

start_timer('main');

abs_mysql_connect($cfg['db_host'], $cfg['db_user'], $cfg['db_pass'], $cfg['db_name']);

$ftp=new Abs_Ftp($cfg['ftp_user'], $cfg['ftp_pass'], $cfg['ftp_host']);

$ftp_files=$ftp->nlist();

foreach ($ftp_files as $ftp_file)
{

    if ($ftp_file==="." or $ftp_file==="..") {
        continue;
    }

    $tmp_file=$cfg['tmp'].'/'.$ftp_file;

    try {
        //читаем файл с сервера
        $ftp->get($tmp_file, $ftp_file);
        debug_print("Process $ftp_file \n");

        $i=0;
        $info=fname_to_info($ftp_file);
        $time=$info["time"];
        $if=$info["if"];       
        if (is_null($if)) {
            continue;
        }
               
        $file=fopen($tmp_file, "r");

        abs_mysql_query("START TRANSACTION");
        $sql="INSERT INTO `if_$if` (`time`, `from_ip`, `from_port`, `to_ip`, `to_port`, `proto`, `byte`) VALUES ";
        $i=0;
        $count=0;
        $fill_sql=false;
        while (!feof ($file)) {
            $i=$i+1;
            $count=$count+1;
            $line=parse_raw_str(fgets($file));

            $from_ip=$line['from_ip'];
            $from_port=$line['from_port'];
            $to_ip=$line['to_ip'];
            $to_port=$line['to_port'];
            $proto=$line['proto'];
            $byte=$line['byte'];
            if (!is_null($byte) and $byte!==0) {
                $sql.=" ('$time', '$from_ip', '$from_port', '$to_ip', '$to_port', '$proto', '$byte' ), ";
                $fill_sql=true;
            }
            if ($i % 50===0 and $fill_sql){
                $i=0;
                $sql=substr($sql, 0, -2);
                $sql.=" ON DUPLICATE KEY UPDATE `byte`=`byte`+VALUES(`byte`);";
                abs_mysql_query($sql);
                print_progress($count);
                $sql="INSERT INTO `if_$if` (`time`, $if_name `from_ip`, `from_port`, `to_ip`, `to_port`, `proto`, `byte`) VALUES ";
                $fill_sql=false;
            }
        }
        if ($i!==0 and $fill_sql) {
            $sql=substr($sql, 0, -2);
            $sql.=" ON DUPLICATE KEY UPDATE `byte`=`byte`+VALUES(`byte`);";
            abs_mysql_query($sql);
            print_progress($count);
        }
        abs_mysql_query('COMMIT');

        fclose($file);
        //удаляем файл
        $ftp->delete($ftp_file);
        unlink($tmp_file);
        debug_print("\nSaved $time : $if ($count) \n");
    } catch (Exception $e) {
        debug_print("Error in file $ftp_file \n");
    }
}


Скачать:

Комментариев нет:

Отправить комментарий