User Tools

Site Tools


shitbox:trafd

Устанавливаем trafd

# emerge -av trafd

базовая настройка

# cat /etc/conf.d/trafd

# what interface to run on
IFACE=eth1

автозапуск

# rc-update add trafd default

создаем каталог и базу

# mkdir /var/trafd/

# touch /var/trafd/trafd.eth1

запуск

# /etc/init.d/trafd start

автосейв

echo “*/5 * * * * root /usr/bin/trafdump eth1; sleep 2; /usr/bin/trafsave eth1” » /etc/crontab

Храним статистику в базе

создаем базу и пользователя

mysql> create database trafd;

mysql> grant all privileges on trafd.* to trafd@localhost identified by 'trafd';

скрипт, который будет писать статистику в базу

#!/bin/sh
# Вводим данные для подключения к MySQL серверу
# IP адрес MySQL сервера
IP_MySQL_servera="localhost"
# Имя пользователя для доступа к БД в которой храниться траффик
username="trafd"
# Пароль пользователя MySQL
user_passw="trafd"
# Имя базы данных
db_name="trafd"
 
# поехали
 
# Сегодяшний день
day="`date +%Y-%m-%d`"
# Текущий год
year="`date +%Y`"
# Текущий месяц
month="`date +%m`"
# Текущее время (секунды специально сделаны 00 - иногда cron запускает скрипт не
# в 00 секунд а позже (максимум что я видел - в 13), если машина очень загружена -
# как итог в логах начинает фигурировать разное число секунд.
# Мне это непонравилось :)
curr_time="`date +%H:%M:00`"
# Директория в которой будут храниться текстовые файлы с логами trafd
NewDir="/var/traffic/${year}/${month}"
# Пытаемся создать эту самую директорию на случай если это первый запуск
# или произошла смена месяца (года)
mkdir -p ${NewDir}
# Ну и топаем туда
cd ${NewDir}
 
# Местоположение исполняемого файла клиента MySQL
mysql="/usr/bin/mysql"
# Префикс для команд (лень же каждый раз набивать параметры подключения)
sql_preffix="${mysql} --host=${IP_MySQL_servera} \
--user=${username} --password=${user_passw} --database=${db_name}"
 
 
# Для всех интерфейсов выковырнутых из rc.conf (висят в ${trafd_ifaces})
# выполняем один и тот же набор действий по разбору логов и запихиванию
# их в базу данных
for iface in "eth1"
do
# Сохраняем статистику по текущему интерфейсу
/usr/bin/trafsave ${iface}
# Преобразуем логи из двоичного в текстовый формат. Сохраняются они в
# папке /tmp в виде файлов summary.* c расширением по имени интерфейса
/usr/bin/traflog -i ${iface} -a -n -s > /tmp/summary.${iface} 2>/dev/null
# Очищаем файл с логами в двоичном формате
cat /dev/null > /var/trafd/trafd.${iface}
# Дозаписываем логи в текстовый файл (пусть лежат на всякий случай...)
cat /tmp/summary.${iface} >> ${NewDir}/summary.${iface}
# Далее - загоняем траффик в БД
#
${sql_preffix} --execute="CREATE TABLE \`traffic_tmp\` \
(\`date\` DATE NOT NULL, \`time\` TIME NOT NULL, \
\`from_IP\` CHAR(16) NOT NULL, \`port_from_IP\` CHAR(8) NOT NULL, \
\`to_IP\` CHAR(16) NOT NULL, \`port_to_IP\` CHAR(8) NOT NULL, \
\`protocol\` ENUM('icmp','tcp','udp') NOT NULL, \`bytes\` int(16) NOT NULL, \
\`all_bytes\` int(16) NOT NULL) TYPE=MyISAM COMMENT='tmp_table'" 2>/dev/null
 
# Лопатим данные для интерфейса ${iface}
# Очищаем временную таблицу
${sql_preffix} --execute="DELETE FROM \`traffic_tmp\`"
# Построчно превращаем файл со статистикой в набор переменных
grep -v "^ " /tmp/summary.${iface} |
{
while read stroka
do
from_IP=`echo "${stroka}" | awk '{print $1}'`
port_from_IP=`echo "${stroka}" | awk '{print $2}'`
to_IP=`echo "${stroka}" | awk '{print $3}'`
port_to_IP=`echo "${stroka}" | awk '{print $4}'`
protocol=`echo "${stroka}" | awk '{print $5}'`
bytes=`echo "${stroka}" | awk '{print $6}'`
all_bytes=`echo "${stroka}" | awk '{print $7}'`
# Загоняем полученный набор во временную таблицу
${sql_preffix} --execute="INSERT INTO \`traffic_tmp\` (\`date\`, \
\`time\`, \`from_IP\`, \`port_from_IP\`, \`to_IP\`, \`port_to_IP\`, \
\`protocol\`, \`bytes\`, \`all_bytes\`) \
values ('${day}', '${curr_time}', '${from_IP}', \
'${port_from_IP}', '${to_IP}', '${port_to_IP}', \
'${protocol}', '${bytes}', '${all_bytes}')"
done
}
# Стираем пустые строки (а вот откуда они вылазиют я так и непонял....)
${sql_preffix} --execute="DELETE FROM \`traffic_tmp\` WHERE from_IP='' AND \
port_from_IP='' AND to_IP='' AND port_to_IP='' AND protocol=''"
# Стираем строки в которых полное число байт (вместе с технической инфой)
# равно нулю (тоже непойми откуда берутся - раз в статистику trafd попали -
# значит соединение было и байты должны были б быть...)
${sql_preffix} --execute="DELETE FROM \`traffic_tmp\` WHERE all_bytes='0'"
# Создаём таблицу для окончательного хранения траффика
# (на тот случай если она не создана - хотя конечно тоже дурацкий вариант -
# пытаться создать таблицу при каждом запуске скрипта, но другой вариант -
# проверять существование и если нету её - то создавать. А какая разница? Так
# как сделано сейчас - проще и менее ресурсоёмко)
${sql_preffix} --execute="CREATE TABLE \`${iface}_${year}\` \
(\`unic_id\` INT(16) NOT NULL AUTO_INCREMENT, \
\`date\` DATE NOT NULL, \`time\` TIME NOT NULL, \
\`from_IP\` CHAR(16) NOT NULL, \`port_from_IP\` CHAR(8) NOT NULL, \
\`to_IP\` CHAR(16) NOT NULL, \`port_to_IP\` CHAR(8) NOT NULL, \
\`protocol\` ENUM('icmp','tcp','udp') NOT NULL, \`bytes\` int(16) NOT NULL, \
\`all_bytes\` int(16) NOT NULL, \
PRIMARY KEY (\`unic_id\`), \
KEY \`date\`(\`date\`) \
) TYPE=MyISAM COMMENT='База \
данных траффика по (${iface}) интерфейсу за ${year} год'" 2>/dev/null
# Перекидываем траффик из временной таблицы в окончательную, при этом
# объединяем строки в которых совпадает ВСЁ кроме числа байт.
${sql_preffix} --execute="INSERT INTO \`${iface}_${year}\`\
(\`date\`, \`time\`, \`from_IP\`, \`port_from_IP\`, \`to_IP\`,\
\`port_to_IP\`, \`protocol\`, \`bytes\`, \`all_bytes\`) \
SELECT \`date\`, \`time\`, \`from_IP\`, \`port_from_IP\`,\
\`to_IP\`, \`port_to_IP\`, \`protocol\`, sum(\`bytes\`) as \`bytes\`,\
sum(\`all_bytes\`) as \`all_bytes\` FROM \
\`traffic_tmp\` GROUP BY \`date\`, \`time\`, \`from_IP\`, \`port_from_IP\`,\
 \`to_IP\`, \`port_to_IP\`, \`protocol\`"
 
done
 
${sql_preffix} --execute="delete from \`${iface}_${year}\` where \`from_IP\`='192.168.0.1'"
${sql_preffix} --execute="delete from \`${iface}_${year}\` where \`to_IP\`='192.168.0.1'"
 
 
# Очищаем файл c логами о том когда и по какому интерфейсу сохранялась статистика
cat /dev/null > /var/log/traffic.log

Сбрасываем каждый час статистику в базу

# echo “1 * * * * root /usr/local/bin/trafd.sh” » /etc/crontab

Считаем злобных нарушителей

создаем табличку

mysql> CREATE TABLE `ip_list` ( `ip_address` char(16) NOT NULL, `day_used int(16)`, `day_limit` int(16) NOT NULL, `is_blocked` tinyint(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

заполняем ее

for i in `seq 2 254`;do echo "INSERT INTO ip_list VALUES ('192.168.0.$i',0,104857600,0);";done|mysql -utrafd -ptrafd trafd

скрипт блокировки и анализа

#!/usr/bin/perl
use DBI;
use DBD::mysql
 
$platform = "mysql";
$database = "trafd";
$host = "localhost";
$port = "3306";
$user = "trafd";
$pw = "trafd";
$tablename = "eth1_".`date +%Y`;
$date=`date +%Y-%m-%d`;
chomp($date);
chomp($tablename);
# DATA SOURCE NAME
$dsn = "dbi:$platform:$database:$host:$port";
# PERL DBI CONNECT
$connect = DBI->connect($dsn, $user, $pw);
 
$queryip="select ip_address from ip_list;\n";
#print ($queryip."\n");
$queryip_handle = $connect->prepare($queryip);
$queryip_handle->execute();
$queryip_handle->bind_columns(undef, \$ip);
print (`date`);
while ($queryip_handle->fetch()) {
        print($ip."\n");
        $query="select sum(all_bytes) from ".$tablename." where date='".$date."' and (to_IP='".$ip."' or from_IP='".$ip."');\n";
#       print($query);
        $query_handle = $connect->prepare($query);
        $query_handle->execute();
        $query_handle->bind_columns(undef, \$sum);
        $query_handle->fetch();
        $query_handle->finish;
        $sum=0+$sum;
        print("sum bytes for ".$ip." is ".$sum."\n");
        $query="select * from ip_list where ip_address='".$ip."';\n";
#       print ($query);
        $query_handle = $connect->prepare($query);
        $query_handle->execute();
        $query_handle->bind_columns(undef, \$ip_address, \$day_used, \$day_limit, \$is_blocked);
        $query_handle->fetch();
        $query_handle->finish;
        print ("ip_address: ".$ip_address."\n");
        print ("day_limit: ".$day_limit."\n");
        print ("is_blocked: ".$is_blocked."\n");
        print("limit bytes for ".$ip." is ".$day_limit."\n");
        $query="update ip_list set day_used=".$sum." where ip_address='".$ip_address."';\n";
        $query_handle = $connect->prepare($query);
        $query_handle->execute();
 
        if ($sum>=$day_limit) {
                print ("traffic quota exceeded\n");
                if ($is_blocked==0) {
                        print ("ip is not blocked.. i'm blocking it...\n");
                        $runstr="sudo iptables -I FORWARD -s ".$ip_address." -j DROP";
                        print ($runstr);
                        system($runstr);
                        $query="update ip_list set is_blocked=1 where ip_address='".$ip_address."';\n";
                        $query_handle = $connect->prepare($query);
                        $query_handle->execute();
 
                }#$is_blocked==0
 
        }#if ($sum>=$day_limit)
        if ($sum<$day_limit) {
                if ($is_blocked==1) {
                        print ("ip is blocked.. i'm removing it...\n");
                        $runstr="sudo iptables -D FORWARD -s ".$ip_address." -j DROP";
                        print ($runstr);
                        system($runstr);
                        $query="update ip_list set is_blocked=0 where ip_address='".$ip_address."';\n";
                        $query_handle = $connect->prepare($query);
                        $query_handle->execute();
                }
 
        }
        print ("\n");
 
} #while
$queryip_handle->finish;
$connect->disconnect;

выполняем каждый час

echo “5 * * * * root /usr/local/bin/trafblock.pl » /var/log/trafblock.log” » /etc/crontab

shitbox/trafd.txt · Last modified: 2008/09/09 13:51 (external edit)