Подсчет трафика с помощью ng_netflow

Понадобилось мне как-то реализовать подсчет трафика на шлюзе, с установленной на нем ОС FreeBSD 7.3. Для подсчета трафика я решил использовать модуль ng_netflow подсистемы netgraph. Статистика будет складываться в БД и через веб морду просматриваться. В качестве СУБД буду использовать PostgreSQL, но ничто не мешает использовать другую СУБД. В качестве коллектора и анализатора статистики я использовал пакет flow-tools.

Для начала нужно создать соответствующие узлы в netgraph. Для простоты развертывания на других машинах был написан следующий скрипт:

#!/bin/sh

# PROVIDE: ngnetflow
# REQUIRE: netif
# KEYWORD: nojail shutdown

. /etc/rc.subr

name="ngnetflow"
rcvar=`set_rcvar`
start_cmd="${name}_start"
stop_cmd=":"

load_rc_config $name
eval "${rcvar}=\${${rcvar}:-'NO'}"
ngnetflow_ifaces=${ngnetflow_ifaces:-""}
ngnetflow_export=${ngnetflow_export:-""}

ngnetflow_start()
{
       if [ -z "${ngnetflow_ifaces}" ]; then
               echo "ngnetflow_ifaces is not set"
               return 1
       fi

       if [ -z "${ngnetflow_export}" ]; then
               echo "ngnetflow_export is not set"
               return 1
       fi

       count_if="0"
       for iface in ${ngnetflow_ifaces}; do
               ngctl mkpeer ${iface}: tee lower left
               ngctl name ${iface}:lower ${iface}_tee
               ngctl connect ${iface}: ${iface}_tee: upper right

               ngctl mkpeer ${iface}_tee: one2many left2right many0
               ngctl name ${iface}_tee:left2right ${iface}_tee_o2m
               ngctl connect ${iface}_tee: ${iface}_tee_o2m: right2left many1

               if [ "${count_if}" -eq "0" ]; then
                       ngctl mkpeer ${iface}_tee_o2m: netflow one iface0
                       ngctl name ${iface}_tee_o2m:one netflow
               else
                       ngctl connect ${iface}_tee_o2m: netflow: one iface${count_if}
               fi
               count_if=`echo ${count_if} | awk '{ $0++; print $0; }'`
       done

       ngctl mkpeer netflow: ksocket export inet/dgram/udp
       ngctl name netflow:export nf_ksocket
       ngctl msg nf_ksocket: connect inet/${ngnetflow_export}

       echo "Netflow system started..."

       return 0
}

run_rc_command "$1"

Скрипт прост в использовании - его нужно скопировать в /usr/local/etc/rc.d, дать права на исполнение и сделать соответствующие записи в /etc/rc.conf.

ngnetflow_enable="YES"     # разрешаем запуск скрипта при старте системы
ngnetflow_export="127.0.0.1:4444" # экспорт статистики на указанный здесь адрес
ngnetflow_ifaces="if0 if1" # интерфейсы, на которых нужно считать трафик

Далее нужно установить пакет flow-tools.

cd /usr/ports/net-mgmt/flow-tools
make install clean

После завершения установки добавляем следующие строки в /etc/rc.conf и запускаем коллектор:

flow_capture_enable="YES"
flow_capture_port="4444"
flow_capture_flags="-E 16M"
/usr/local/etc/rc.d/flow_capture start

Проверим запустился ли сервис:

sockstat -4 -l | grep flow

flowtools flow-captu 1008  1  udp4   *:4444                *:*

Если в выводе команды вы видите что-то подобное, то запуск прошел успешно.

Теперь запустим скрипт, который создаст соответствующие узлы в подсистеме netgraph.

/usr/local/etc/rc.d/ngnetflow start

Если скрипт не выдал никаких ошибок, значит запуск прошел успешно.

Для перегона статистики в БД я написал два скрипта. Первый запускается каждый день и запихивает в БД статистику за прошлый день. Второй запускается раз в месяц и создает новую таблицу в БД.
Первый скрипт (nf_daily.sh):

#!/bin/sh

# Скрипт экспортирует статистику за день в БД

REP_Y=`date -v-1d "+%Y"` # report year
REP_M=`date -v-1d "+%m"` # report month
REP_D=`date -v-1d "+%d"` # report day

WORKDIR="/root/netflow"
TMPDIR="/tmp"
FLOWS_DIR="/var/db/flows"
EXP_FORMAT="DPKTS,DOCTETS,SRCADDR,DSTADDR,NEXTHOP,INPUT,OUTPUT,SRCPORT,DSTPORT,PROT,TOS,TCP_FLAGS,SRC_MASK,DST_MASK"

DB_HOST="192.168.7.253"
DB_PORT="5432"
DB_USER="netflow"
DB_PASS="1234"
DB_NAME="netflow"
DB_TABLE="${REP_Y}-${REP_M}"
DB_COLUMNS="\
\"dpkts\",\
\"doctets\",\
\"srcaddr\",\
\"dstaddr\",\
\"nexthop\",\
\"input\",\
\"output\",\
\"srcport\",\
\"dstport\",\
\"proto\",\
\"tos\",\
\"tcp_flags\""


EXP_FILE="${TMPDIR}/netflow.csv"
SQL_FILE="${TMPDIR}/netflow.sql"
LOG_FILE="${WORKDIR}/nf_daily.log"

flow-cat "${FLOWS_DIR}/${REP_Y}/${REP_Y}-${REP_M}/${REP_Y}-${REP_M}-${REP_D}" | \
flow-export -f2 -m ${EXP_FORMAT} 2> /dev/null | \
egrep -v "^#" > ${EXP_FILE}

if [ ! -f ${EXP_FILE} ]; then
 echo "Export file not found"
 exit 1
fi

if [ -f ${SQL_FILE} ]; then
 rm -f ${SQL_FILE}
fi

for line in `cat ${EXP_FILE}`; do
 data=`echo ${line} | awk '{ split($0, str, ",");
                           printf("%u, %u, $$%s$$, $$%s$$, $$%s$$, %d, %d, %d, %d, %d, %d, %d",
                                   str[1], str[2], str[3], str[4],
                                   str[5], str[6], str[7], str[8],
                                   str[9], str[10], str[11], str[12]);
                           }'`
 echo "INSERT INTO \"${DB_TABLE}\"(${DB_COLUMNS}) VALUES (${data});" >> $SQL_FILE
done

psql -q -d ${DB_NAME} -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER}  -f $SQL_FILE

rm -f ${EXP_FILE}
rm -f ${SQL_FILE}

exit 0

Второй скрипт (nf_month.sh):

#!/bin/sh

DB_HOST="192.168.7.253"
DB_PORT="5432"
DB_USER="netflow"
DB_PASS="1234"
DB_NAME="netflow"
DB_TABLE=`date "+%Y-%m"`

SQL_QUERY="CREATE TABLE \"${DB_TABLE}\" (\
 \"id\" bigserial NOT NULL UNIQUE PRIMARY KEY,\
 \"dpkts\" bigint,\
 \"doctets\" bigint,\
 \"srcaddr\" cidr,\
 \"dstaddr\" cidr,\
 \"nexthop\" cidr,\
 \"input\" smallint,\
 \"output\" smallint,\
 \"srcport\" int,\
 \"dstport\" int,\
 \"proto\" smallint,\
 \"tos\" smallint,\
 \"tcp_flags\" smallint\
);"

psql -q -d ${DB_NAME} -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER} -c "${SQL_QUERY}" > /dev/null 2>&1

exit 0


Поправьте параметры подключения к БД на свои и не забудте дать права на запуск скриптам. Теперь добавим их в крон:

0       1       1       *       *       /root/netflow/nf_month.sh
30      0       *       *       *       /root/netflow/nf_daily.sh

Осталось только создать таблицу за текущий месяц, чтобы скрипту nf_daily.sh было куда складывать статистику, для этого можно просто запустить скрипт nf_month.sh.

Вот еще веб морда, написанная на перле, для просмотра собранной статистики.

#!/usr/bin/perl

use strict;
use warnings;

my $DB_HOST = 'localhost';
my $DB_PORT = '5432';
my $DB_NAME = 'netflow';
my $DB_USER = 'netflow';
my $DB_PASS = '1234';

my $stat_month = '';
my $query_menu = '
SELECT
    "tablename"
FROM "pg_tables"
WHERE "tableowner" = $$#owner#$$;';
my $query_content = '
SELECT
    SUM("dpkts") AS "packets",
    (SUM("doctets")/1048576)::bigint AS "size",
    host("dstaddr") FROM "#tbl_name#"
WHERE "dstaddr" << $$192.168.7.0/24$$
GROUP BY "dstaddr"
ORDER BY "dstaddr";';

if ($ENV{'REQUEST_METHOD'} && ($ENV{'REQUEST_METHOD'} eq 'GET')){
    my $param = $ENV{'QUERY_STRING'};
    foreach    (split(/&/, $param)){
        my @str = split(/=/);
        if ($str[0] eq 'month'){
            $stat_month = $str[1];
            $stat_month =~ s/'|"|\$|\(|\)//;
            last;
        }
    }
}

print("Content-type: text/html\n\n");

$query_menu =~ s/#owner#/$DB_USER/;
system("psql -h $DB_HOST -p $DB_PORT -d $DB_NAME -U $DB_USER -t -c '$query_menu' -o /tmp/db_menu.txt");
if (length($stat_month) > 0){
    $query_content =~ s/#tbl_name#/$stat_month/;
    system("psql -h $DB_HOST -p $DB_PORT -d $DB_NAME -U $DB_USER -t -c '$query_content' -o /tmp/db_table.txt");
}


print('<html>',
            '<head>',
            '<title>Statistics</title>',
            '<style type="text/css">',
            'table { border-collapse: collapse; }',
            '.header { background-color: lightblue; }',
            '.content { background-color: orange; }',
            '</style>',
            '</head>',
            '<body>'
);

sub get_menu(){
    my $text = '';

    if (!open(FIN, "< /tmp/db_menu.txt")){
        return '<h3>Empty!!!</h3>'
    }

    $text .= join('', '<table align="center" border="1" width="100%">',
                '<tr><td align="center" class="header">Menu</td></tr>'
    );
    while (<FIN>){
        chomp;
        next if length == 0;
        s/\s|\t//g;
        $text .= join('', '<tr><td align="center" class="content"><a href="?month=',
                    $_,
                    '">',
                    $_,
                    '</a></td></tr>'
        );
    }
    $text .= '</table>';

    close(FIN);

    return $text;
}

sub get_content(){
    my $text = '';

    if (!open(FIN, "< /tmp/db_table.txt")){
        return '<h3>Empty!!!</h3>';
    }

    $text .= join('', '<table border="1">',
                '<tr><td class="header">packets</td>',
                '<td class="header">megabytes</td>',
                '<td class="header">IP</td></tr>'
    );
    while (<FIN>){
        chomp;
        next if length == 0;
        $text .= '<tr>';
        foreach (split(/\|/)){
            chomp;
            s/\s|\t//g;
            $text .= join('', '<td class="content">', $_, '</td>');
        }
        $text .= '</tr>';
    }
    $text .= '</table>';

    close(FIN);

    return $text;
}

print('<table width="100%">',
            '<tr><td align="center" valign="top" width="15%">',
            get_menu(),
            '</td>'
);

print('<td align="left" valign="top" width="85%">',
            get_content(),
            '</td></tr></table>',
            '</body></html>'
);

system("rm -f /tmp/db_menu.txt /tmp/db_table.txt");

Ну на этом все, можно пользоваться.

Прикрепленные файлы
Гость (не проверено)

Can't get enough of good vintage wine. Doesn’t matter iff it’s ddry or


sweet, it’s the perfect way to relax.


Are there anyy wine lovers around? #RedWine





my webpage; ขายไวน์ยกลัง - https://Www.Fairviewumc.church/bbs/board.php?bo_table=free&wr_id=961130

Гость (не проверено)

Can't get enough of good glass off wine.


From a local vineyard or imported,it’s thhe perfect way tto relax.


Who else enjoys wine tasting? #WhiteWine





Also visit my web page: ขาย ไวน์ - https://Docs.Brdocsdigitais.com/index.php/User:LeifFoland52

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

CAPTCHA
Этот вопрос задается для того, чтобы выяснить, являетесь ли Вы человеком или представляете из себя автоматическую спам-рассылку.

Последние комментарии

Яндекс.Метрика