Home FreeBSD FreeBSD Траффик
FreeBSD Траффик

Съём статистики по SNMP с устройств

E-mail Печать PDF

Съём статистики по SNMP с устройств

Автор: lissyara.
Оригинал: http://www.lissyara.su/articles/freebsd/traffic_count/get_switch_statistic_trough_snmp/

Немного предистории, с чего началось всё это. Провайдер мой, начал выкатывать счета за траффик, которые не лезли ни в одни ворота - по моим данным за день полторы-две сотни мегабайт траффика, по его - больше гигабайта. Особенно порадовали выходные - у меня мег с копейками, у него - полторы сотни. Звонил, пытался что-то выяснить, разобраться. В итоге, полуобкуренный товарищ из суппорта заявил мне, - "мы не считаем ваш траффик, мы построили график по предыдущим месяцам, и по нему выставляем счета...". Хорошо я сидел в этот момент.... В итоге написали письмо с требованием разобраться, а я озадачился темой - проверить - то ли я считаю. Может моя считалка где врёт... Раз, так в десять... Вначале накрутил правил в IPFW. C trafd, которым я считал, всё сошлось. Но на этом я не успокоился, вспомнил, что можно считать по SNMP, собственно, так все и делают. Тем более что у меня стоял свич AT-8326GB, шикарная машинка, с WEB-интерфейсом, телнетом, SNMP и поддержкой виртуальных свичей. Оставалось только включить в нём SNMP и найти чем считать. Конечно, для такого есть куча программ, и мильён скриптов. Но - коммунисты не ищут лёгких путей! Поэтому, как обычно, я пошёл своим.
SNMP - Simple Network Management Protocol, он работает над протоколом UDP и позволяет управляющим станциям собирать информацию о положении в сети. Для работы с SNMP устанавливаем NET-SNMP. Почему он? Просто он у меня уже стоял, поставился, когда я устанавливал cacti, когда впервые заинтересовался возможностями протокола SNMP и устройств, его поддерживающих. Если захотите что-то другое, то в портах немало программ способных работать с этипм протоколом, есть модули для PERL и PHP, их можно разыскать там же - в портах.
Ставим NET-SNMP./usr/ports/>cd /usr/ports/net-mgmt/net-snmp
/usr/ports/net-mgmt/net-snmp/>make && make install && make clean


Если Вы хотите и с этой машины снимать инфу - то надо кой-чё поднастраивать, чтоб запускался агент SNMP, в моём случае - ничё не надо делать. Я буду собирать на эту машину инфу, а не с неё.
Ставим перл и модуль ..... /usr/ports/net-mgmt/net-snmp/>cd ../../lang/perl5.8/
/usr/ports/lang/perl5.8/>make && make install && make clean


после чего даём команду rehash и use.perl port. Затем ставим модуль для работы с SNMP/usr/ports/>cd /usr/ports/net-mgmt/p5-Net-SNMP
/usr/ports/net-mgmt/p5-Net-SNMP/>make && make install && make clean


и модуль для работы с MySQL (ставить надо либо универсальный, либо той версии, которой MySQL - я пробовал ставить универсальный, но он за собой потащил MySQL4.1-server, а я пользуюсь 4.0) /usr/ports/databases/>cd p5-DBD-mysql40
/usr/ports/databases/p5-DBD-mysql40/>make && make install && make clean


Теперь, когда всё нужное ПО установлено, можно поковыряться в самом свиче по SNMP. Основные сведения по SNMP достаточно легко найти в рунете, многое интуитивно понятно само. В частности можно расширить сферу применения - мониторить не только траффик но и многое другое - размер дисков, занятое и свободное место, загрузку процессоров.....
Итак, смотрим, что мы можем поиметь, с этого свича (инфы с него лезет реально немеряно - так что пишите всё в текстовый файл, чтоб на досуге разобраться, или если знаете что ищете - разбирайтесь сами). //>snmpwalk -c my_community -v 1 192.168.20.253 .
SNMPv2-MIB::sysDescr.0 = STRING: AT-8326GB
SNMPv2-MIB::sysObjectID.0 = OID: SNMPv2-SMI::enterprises.207.1.4.72
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (138565036) 16 days, 0:54:10.36
SNMPv2-MIB::sysContact.0 = STRING: телефон 219
SNMPv2-MIB::sysName.0 = STRING: СВИЧ
SNMPv2-MIB::sysLocation.0 = STRING: Серверная, второй этаж
SNMPv2-MIB::sysServices.0 = INTEGER: 2
IF-MIB::ifNumber.0 = INTEGER: 53
IF-MIB::ifIndex.1 = INTEGER: 1
IF-MIB::ifIndex.2 = INTEGER: 2
IF-MIB::ifIndex.3 = INTEGER: 3
IF-MIB::ifIndex.4 = INTEGER: 4
IF-MIB::ifIndex.5 = INTEGER: 5
IF-MIB::ifIndex.6 = INTEGER: 6
^C


Собственно дальше смотреть нечего, у меня оно лезло минут 40... Объём всей инфы, в виде текста, составил 4 мб... Правда полезного там - доли процента (с другой стороны - там всё нужное и полезное, но не мне и не сейчас). Дальше, вытаскиваем интерфейсы, имеющиеся на свиче//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.22
IF-MIB::ifSpecific.1 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.2 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.3 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.4 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.5 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.6 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.7 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.8 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.9 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.10 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.11 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.12 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.13 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.14 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.15 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.16 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.17 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.18 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.19 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.20 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.21 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.22 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.23 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.24 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.25 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.26 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.27 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.28 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.29 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.30 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.31 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.32 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.33 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.34 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.35 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.36 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.37 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.38 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.39 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.40 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.41 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.42 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.43 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.44 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.45 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.46 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.47 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.48 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.49 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.50 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.51 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.52 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.53 = OID: SNMPv2-SMI::zeroDotZero


Оказалось 53 интерфейса... Любопытно, портов-то всего 52 (48 на 100 мегабит и 4 по 1000). По здравому размышлению, решил, что один из интерфейсов - это собственно проц приборины. Но вот какой? Логичней всего было б первый, последний, или ровно посредине диапазона. Попал с первого раза - он был последним :) //>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.2.53
IF-MIB::ifDescr.53 = STRING: AT-8326GB CPU Ethernet Network Interface
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.2.1
IF-MIB::ifDescr.1 = STRING: AT-8326GB 10/100 Mbps Ethernet Network Interface 1
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.2.25
IF-MIB::ifDescr.25 = STRING: AT-8326GB 1000 Mbps Ethernet Network Interface 25


И это действительно оказался CPU свича, а не секретный порт, нераспаянный на передней панели :) Смотрим, какие данные можно снять по интерфейсам: //>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.1.1
IF-MIB::ifIndex.1 = INTEGER: 1
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.2.1
IF-MIB::ifDescr.1 = STRING: AT-8326GB 10/100 Mbps Ethernet Network Interface 1
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.3.1
IF-MIB::ifType.1 = INTEGER: ethernetCsmacd(6)
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.4.1
IF-MIB::ifMtu.1 = INTEGER: 1514
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.5.1
IF-MIB::ifSpeed.1 = Gauge32: 100000000
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.6.1
IF-MIB::ifPhysAddress.1 = STRING: 0:c:46:9f:a9:59
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.7.1
IF-MIB::ifAdminStatus.1 = INTEGER: up(1)
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.8.1
IF-MIB::ifOperStatus.1 = INTEGER: down(2)
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.9.1
IF-MIB::ifLastChange.1 = Timeticks: (111215050) 12 days, 20:55:50.50
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.10.1
IF-MIB::ifInOctets.1 = Counter32: 1185896152
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.11.1
IF-MIB::ifInUcastPkts.1 = Counter32: 7447462
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.12.1
IF-MIB::ifInNUcastPkts.1 = Counter32: 1178
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.13.1
IF-MIB::ifInDiscards.1 = Counter32: 0
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.14.1
IF-MIB::ifInErrors.1 = Counter32: 0
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.15.1
IF-MIB::ifInUnknownProtos.1 = Counter32: 0
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.16.1
IF-MIB::ifOutOctets.1 = Counter32: 3490598015
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.17.1
IF-MIB::ifOutUcastPkts.1 = Counter32: 7962148
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.18.1
IF-MIB::ifOutNUcastPkts.1 = Counter32: 82020
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.19.1
IF-MIB::ifOutDiscards.1 = Counter32: 0
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.20.1
IF-MIB::ifOutErrors.1 = Counter32: 0
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.21.1
IF-MIB::ifOutQLen.1 = Gauge32: 192
//>snmpwalk -c my_community -v 1 192.168.20.253 .1.3.6.1.2.1.2.2.1.22.1
IF-MIB::ifSpecific.1 = OID: SNMPv2-SMI::zeroDotZero


Инфы немало. Есть и самое главное, чего ради всё это и затевалось - входящий и исходящий траффик по интерфейсам. Ну, и всякая дополнительная мишура, типа, состояние интерфейса - up или down, размер MTU, скорость, MAC-адрес, сколько было входящих-исходящих пакетов, ошибок, и много ещё чего. Для грамотного изъёма всего этого хозяйства и хранения его в БД был написан следующий скриптик на perl: #!/usr/bin/perl -w

# вводим переменные
# хост, который будем опрашивать
$snmp_host = '192.168.8.253';
# сообщество
$snmp_community = 'derzhava';
# начало МИБ`а
$snmp_part_MIB = '.1.3.6.1.2.1.2.2.1';
# максимальный номер интерфейса
$IF_max = 53;
# MySQL хост
$host = 'localhost';
# MySQL юзер
$user = 'SNMP';
# MySQL пароль
$password = 'SNMP';
# MySQL база данных
$database = 'SNMP';
# подрубаем модуль, отвечающий за SNMP
use Net::SNMP;
# подрубаем модуль для работы с MySQL
use Mysql;

# достаём время
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime time;
$year = $year + 1900;
$mon = $mon + 1;
$unix_time = time;


# Коннектимся к MySQL
$dbh = Mysql->Connect($host,$database,$password,$user);

# Создаём в БД таблицу для хранения итогов
$MySQL_query = "CREATE TABLE IF NOT EXISTS `" . $year . "_SNMP`
(`unic_id` INT(12) NOT NULL AUTO_INCREMENT ,
`SNMP_date` VARCHAR(10) NOT NULL ,
`SNMP_time` VARCHAR(8) NOT NULL ,
`SNMP_unix_time` INT(32) NOT NULL ,
`SNMP_IF` INT(2) NOT NULL ,
`SNMP_IF_speed` int(9) NOT NULL ,
`SNMP_IF_status` ENUM('1','2','3') NOT NULL ,
`SNMP_IF_traff_in` INT(255) NOT NULL ,
`SNMP_IF_traff_out` INT(255) NOT NULL ,
PRIMARY KEY (`unic_id`),
KEY `SNMP_unix_time` (`SNMP_unix_time`),
KEY `SNMP_date` (`SNMP_date`)
)TYPE = MYISAM
COMMENT='Траффик по SNMP за " . $year . " год'";
$dbh->Query("$MySQL_query") or die $Mysql::db_errstr;
# Создаём в БД таблицу для хранения временных данных
$MySQL_query = "CREATE TABLE IF NOT EXISTS `SNMP_tmp_table`
(`SNMP_unix_time` INT(255) NOT NULL,
`SNMP_IF` INT(255) NOT NULL,
`SNMP_IF_traff_in_absolute` INT(255) NOT NULL,
`SNMP_IF_traff_out_absolute` INT(255) NOT NULL
) TYPE = MYISAM
COMMENT = 'Временная таблица для данных SNMP'";
$dbh->Query("$MySQL_query") or die $Mysql::db_errstr;
# Очищаем временную таблицу, после использованием
#$MySQL_query = "TRUNCATE TABLE `SNMP_tmp_table`";
#$dbh->Query("$MySQL_query") or die $Mysql::db_errstr;

# открываем сессию SNMP
($session,$error)=Net::SNMP->session(Hostname => $snmp_host,
Community => $snmp_community);
die "session error: $error" unless($session);
# запускаем цикл по перебору всех доступных сетевых интерфейсов устройства

for($i = 1; $i < $IF_max + 1; $i++){

# строим MIB для трафика
$snmp_MIB_traff_in = $snmp_part_MIB . ".10." . $i;
$snmp_MIB_traff_out = $snmp_part_MIB . ".16." . $i;
$traff_in = $session->get_request("$snmp_MIB_traff_in");
$traff_out = $session->get_request("$snmp_MIB_traff_out");
die "request error: " . $session->error unless(defined $traff_in);
# результаты по траффику
$traff_in = $traff_in->{"$snmp_MIB_traff_in"};
$traff_out = $traff_out->{"$snmp_MIB_traff_out"};

# строим MIB для примечания к интерфейсу
#$snmp_MIB_descr = $snmp_part_MIB . ".2." . $i;
#$IF_descr = $session->get_request("$snmp_MIB_descr");
#die "request error: " . $session->error unless(defined $IF_descr);
# результаты - примечание для интерфейса
#$IF_descr = $IF_descr->{"$snmp_MIB_descr"};

# строим MIB для MTU интерфейса
#$snmp_MIB_MTU = $snmp_part_MIB . ".4." . $i;
#$IF_MTU = $session->get_request("$snmp_MIB_MTU");
#die "request error: " . $session->error unless(defined $IF_MTU);
# результаты - MTU интерфейса
#$IF_MTU = $IF_MTU->{"$snmp_MIB_MTU"};

# строим MIB для скорости интерфейса
$snmp_MIB_speed = $snmp_part_MIB . ".5." . $i;
$IF_speed = $session->get_request("$snmp_MIB_speed");
die "request error: " . $session->error unless(defined $IF_speed);
# результаты - скорость интерфейса
$IF_speed = $IF_speed->{"$snmp_MIB_speed"};

# строим MIB для MAC-адреса интерфейса
#$snmp_MIB_MAC = $snmp_part_MIB . ".6." . $i;
#$IF_MAC = $session->get_request("$snmp_MIB_MAC");
#die "request error: " . $session->error unless(defined $IF_MAC);
# результаты - MAC-адрес интерфейса
#$IF_MAC = $IF_MAC->{"$snmp_MIB_MAC"};

# строим MIB для состояния интерфейса
$snmp_MIB_status = $snmp_part_MIB . ".8." . $i;
$IF_status = $session->get_request("$snmp_MIB_status");
die "request error: " . $session->error unless(defined $IF_status);
# результаты - состояние интерфейса
$IF_status = $IF_status->{"$snmp_MIB_status"};

# лезем в БД с целью достать предыдущие значения счётчиков
# для начала достаём максимальный UNIX TIME для этого интерфейса
$MySQL_query = "SELECT MAX(`SNMP_unix_time`)
FROM `SNMP_tmp_table` WHERE `SNMP_IF`='" . $i . "'";
$sth = $dbh->query("$MySQL_query") or die $Mysql::db_errstr;
@row = $sth->fetchrow;
# достаём данные от предыдущего съёма статистики
$MySQL_query = "SELECT `SNMP_IF_traff_in_absolute`,`SNMP_IF_traff_out_absolute`
FROM `SNMP_tmp_table` WHERE `SNMP_IF`='" . $i . "'
AND `SNMP_unix_time`='" . $row[0] . "'";
$sth = $dbh->query("$MySQL_query") or die $Mysql::db_errstr;
@row = $sth->fetchrow;
# Проверяем что в $row[1] и $row[0]- число или нет
# у меня из-за этого ошибки лезли частенько - два-три
# раза за сутки
if($row[1] =~ /[0-9]/){
# число. Ничего не делаем
}else{
# Там не число. Приравниваем к 0 - будет число
$row[1] = 0;
}
if($row[0] =~ /[0-9]/){
# число. Ничего не делаем
}else{
# Там не число. Приравниваем к 0 - будет число
$row[0] = 0;
}
# проверяем, больше, или меньше текущее значение, чем предыдущее,
# на случай, что счётчики сбрасывались, между измерениями
if($traff_in >= $row[0]){
# всё пучком, счётчик не сбрасывался, считаем разницу
$delta_traff_in = $traff_in - $row[0];
}else{
# счётчик сбросился - данные по этому интерфейсу
# за последнюю минуту считаем пропавшими
#$delta_traff_in = $traff_in;
}
if($traff_out >= $row[1]){
# всё пучком, счётчик не сбрасывался, считаем разницу
$delta_traff_out = $traff_out - $row[1];
}else{
# счётчик сбросился - данные по этому интерфейсу
# за последнюю минуту считаем пропавшими
#$delta_traff_out = $traff_out;
}

# Засовываем данные во временную таблицу
$MySQL_query = "INSERT INTO `SNMP_tmp_table`
(`SNMP_unix_time`,`SNMP_IF`,`SNMP_IF_traff_in_absolute`,
`SNMP_IF_traff_out_absolute`) VALUES ('" . $unix_time . "',
'" . $i . "','" . $traff_in . "','" . $traff_out ."')";
$dbh->query("$MySQL_query") or die $Mysql::db_errstr;

# засовываем даные в постоянную таблицу
$MySQL_query = "INSERT INTO `" . $year . "_SNMP`
(`SNMP_date`,`SNMP_time`,`SNMP_unix_time`,`SNMP_IF`,
`SNMP_IF_speed`,`SNMP_IF_status`,`SNMP_IF_traff_in`,
`SNMP_IF_traff_out`) VALUES
('" . $year . "-" . $mon . "-" . $mday . "',
'" . $hour . ":" . $min . ":00',
'" . $unix_time . "','" . $i ."',
'" . $IF_speed . "','" . $IF_status . "',
'" . $delta_traff_in . "','" . $delta_traff_out . "')";
$dbh->query("$MySQL_query") or die $Mysql::db_errstr;

}

# Отваливаемся от SNMP
$session->close;

# Удаляем из временной таблицы все записи,
# кроме тех, что добавили только что
$MySQL_query = "DELETE FROM `SNMP_tmp_table`
WHERE `SNMP_unix_time`!='" . $unix_time . "'";
$dbh->query("$MySQL_query") or die $Mysql::db_errstr;

1;



Ну, вот и всё. При первом запуске будет ругаться жутким образом - временная таблица пуста, но на первом же запуске он её заполнит, и при следующих должен отрабатывать без ошибок и сообщений. Также после первого запуска нужно очистить, или уничтожить таблицу с именем `ТЕКУЩИЙ_ГОД_SNMP` - он её заполняет содержимым счётчиков, а не разницей между запусками. При следующем запуске он её сделает заново и будет заполнять правильно. В crontab его, и пусть пашет с периодичностью, кому как нравится (мне, вот, раз в минуту нравится.). В вышеприведённом скрипте есть закомментированные места - я их оставил так как есть - может кому понадобиться, да и сам подумываю насчёт более подробной статистики.... Несмотря на всю специфичность скриптика, если у кого-то возникнет необходимость, он достаточно легко рихтанёт его под свои нужды.

P.S. Ненавижу перл.

 

Обновлено 28.05.2010 12:19
 

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

E-mail Печать PDF

Подсчет трафика с помощью pf
Автор: fr33man
Оригинал: http://www.lissyara.su/articles/freebsd/traffic_count/pfctl/


Решил считать трафик на внешнем интерфейсе. Сначала хотел считать с помощью trafd, но подумал, что лишняя программа в памяти не есть гуд. Второй моей мыслью был snmp, но нагружать машинку еще и snmp запросами я не решился. И тут я вспомнил, что это роутер, на котором стоит packet filter. Считать решил именно pf.

Итак, приступим. Я предполагаю, что pf у Вас уже настроен и работает. Добавляем в pf.conf следующую строку:

set loginterface ng0

Теперь проверяем работоспособность конфига:

shield@/usr/ports/net> pfctl -nf /etc/pf.conf

shield@/usr/ports/net>





И подгружаем правила:

shield@/usr/ports/net> pfctl -f /etc/pf.conf

shield@/usr/ports/net>

Вот и все. Давайте посмотрим, сколько трафика набежало:

shield@/usr/ports/net> pfctl -s info

Status: Enabled for 1 days 23:43:24 Debug: Urgent



Hostid: 0x153793d2



Interface Stats for ng0 IPv4 IPv6

Bytes In 41872728 0

Bytes Out 90656050 0

Packets In

Passed 547083 0

Blocked 29 0

Packets Out

Passed 556623 0

Blocked 2 0



State Table Total Rate

current entries 4

searches 6146672 35.8/s

inserts 3730 0.0/s

removals 3726 0.0/s

Counters

match 3946799 23.0/s

bad-offset 0 0.0/s

fragment 0 0.0/s

short 0 0.0/s

normalize 0 0.0/s

memory 0 0.0/s

bad-timestamp 0 0.0/s

congestion 0 0.0/s

ip-option 0 0.0/s

proto-cksum 0 0.0/s

state-mismatch 0 0.0/s

state-insert 0 0.0/s

state-limit 0 0.0/s

src-limit 0 0.0/s

synproxy 0 0.0/s

shield@/usr/ports/net>





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



Могу только добавить, чтобы очистить счетчик можно воспользоваться командой pfctl:



shield@/usr/ports/net> pfctl -F info

pf: statistics cleared

shield@/usr/ports/net>


Я не стал писать полный конфиг pf, так как я сейчас пишу статью про Policy Based Routing и pf. ))

Обновлено 28.05.2010 12:18
 

Прикручивание trafd к MySQL

E-mail Печать PDF

Автор: lissyara.
Оригинал : http://www.lissyara.su/articles/freebsd/traffic_count/trafd+mysql/


Немного истории. Когда-то у меня на сервере стоял trafd. Стоял и стоял. Считал траффик бегавший в инет и обратно. Раз в день, ночью, запускался скрипт, который подбивал траффик по хостам сети и присылал мне письмо с отчётом: кто и сколько с начала месяца успел натаскать траффика.
Короче, всё хорошо, но душа хотела чего-то большего :). Примерно в это время мне попалась на глаза статья в которой описывалось как трафик полученный от trafd запихать в БД MySQL, были приложены скрипты на perl и образцы WEB-морды на php. Ну я и загорелся.
Скрипты на perl оказались нерабочие. Может быть они и были рабочие, но в перл я ничё не понимал и до сих пор мало понимаю - мне не нравится синтаксис этого языка. Слишком свободный, слишком много можно, в том числе и в плане ошибок - поэтому было переписано на shell - ибо этот язык самый универсальный на UNIX. Также неустраивала функциональность, в нём был самый минимум - кто, куда, сколько. Обработка запускалась раз в сутки, т.е. время "во сколько" автоматически выпадало - потому, что эту статистику trafd не собирает. Также меня интересовали порты и протоколы по которым пользователи ползают - сколько на ICQ, например уходит, сколько на FTP (про HTTP отдельная песня - у меня squid, а под него считалок более чем достаточно).
Логику примерно я понял из описалова исходного скрипта - оставалась только реализация. Вот сам скрипт который получился:
#!/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/local/bin/mysql"
# Префикс для команд (лень же каждый раз набивать параметры подключения)
sql_preffix="${mysql} --host=${IP_MySQL_servera} \
--user=${username} --password=${user_passw} --database=${db_name}"

# Считываем все переменные из файла /etc/rc.conf с целью извлечь оттуда
# строчку с названиями интерфейсов по которым работает trafd
# (У меня три сетевых платы и lo0 - просто интереса ради)
. /etc/rc.conf

# Для всех интерфейсов выковырнутых из rc.conf (висят в ${trafd_ifaces})
# выполняем один и тот же набор действий по разбору логов и запихиванию
# их в базу данных
for iface in ${trafd_ifaces}
do
# Сохраняем статистику по текущему интерфейсу
/usr/local/bin/trafsave ${iface}
# Преобразуем логи из двоичного в текстовый формат. Сохраняются они в
# папке /tmp в виде файлов summary.* c расширением по имени интерфейса
/usr/local/bin/traflog -i ${iface} -a -n -s > /tmp/summary.${iface} 2>/dev/null
# Очищаем файл с логами в двоичном формате
cat /dev/null > /usr/local/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

# Очищаем файл c логами о том когда и по какому интерфейсу сохранялась статистика
cat /dev/null > /var/log/traffic.log


Теперь вкратце описалово. С той частью где ввод переменных кажется проблем быть не должно
— NewDir="/var/traffic/${year}/${month}" - директория для сохранения статистики trafd в его "родном", текстовом формате. Нужно это или нет - сами решайте. Я на всякий случай сохранял - мало ли что (БД случайно грохну, например :)).
— IP_MySQLservera="localhost" - IP адрес MySQL сервера на котором хранится БД. В данном варианте это наследие времён, когда сервер БД стоял на одной машине, а trafd крутился на другой. Если они у Вас стоят на одной машине то можно смело повыкидывать все упоминания о хосте сервера.
— username="trafd" - имя пользователя для доступа к БД
— user_passw="trafd" - парольпользователя для доступа к БД
— db_name="trafd" - имя базы данных
Далее статистика интерфейсов сохраняется в /tmp и дописывается в /var/traffic/${year}/${month}. Временный файл читается построчно, строка разбирается по полям в переменные - кто, куда, откуда, по каким портам, по каким протоколам, сколько байт, сколько байт вместе с технической информацией (не знаю, пригодится ли кому-то последнее поле, но при написании скрипта я постарался чтобы никакие из данных не пропали - пусть лежат, пригодятся). Получается куча переменных содержащих все эти данные, которые и пхаются в MySQL - во временную таблицу `traffic_first`.
После того, как весь текстовый файл переехал в БД начинается разбор того, что попало в БД - удаляются пустые строки, строки в которых число байт равно нулю (вот откуда они появляются я не вполне понимаю - если есть адреса IP, порты - то запрос был, были и данные, но данных нет....). Затем данные перелохмачиваются в таблицу `traffic_tmp` с одновременной суммацией одинаковых строк - бывает такое, что все данные одинаковые кроме числа байт. Чтоб не хранить лишние строки - такие суммируются в одну.
После попытки создать таблицу для хранения данных за текущий месяц (чтобы каждый раз не заморачиваться скрипт при каждом запуске пытается создать свои таблицы, на случай если это первый запуск, или сменился год) траффик запихивается на постоянное хранение в таблицу с именем типа `sis0_2005_06`. Затем цикл повторяется для другого интерфейса.
Запуск в "кроне" ставится на каждую минуту. Сам по себе скрипт конечно же небыстрый (это связяано с тем, что на каждый запрос соединение с MySQL устанавливается заново), но тем не менее - на моём P-166MMX он успевал отработать за 5-7 секунд даже если процессор был занят чем-то ресурсоёмким (компиляция и прочее).Если нет реальной необходимости иметь поминутную статистику то можно запускать реже - раз в 10 минут или раз в час. WEB-морду к этому хозяйству прикручивать изначально планировал - и даже приделал. Но - та, что была мне не понравилась - интерфейсом и убогостью метода подсчёта - хосты валились в кучу без разбора локальная или нет сетка, и траффик считался и входящий и исходящий без учёта того, что могут быть обращения на сам сервер (например я постоянно работаю с серваком и к концу месяца при таких методиках подсчёта лишнего траффика, неимеющего отношения к инету набирается бывает несколько гигабайт(!) информации.) Потому считать начал в командной строке запросом типа:
mysql --user=trafd --password=trafd --database=trafd --execute="SELECT \
to_IP,SUM(bytes) FROM sis0_2005 WHERE to_IP LIKE '192.168.%' \
AND from_IP NOT LIKE '192.168.8.254' GROUP BY to_IP" | mail -s traffic \
Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript


А текст из полученого письма просто в ёксель скопировать и построить графики для руководства, если вдруг выяснится, что кто-то по http налазил 50 мег и вот по ftp затащил пару порнофильмов :) Будет время, или реальная необходимость в WEB-интерфейсе, тогда и сделаю. Сложности никакой вроде не видно в этом....

Обновлено 28.05.2010 12:36
 

WEB-интерфейс для просмотра статистики интернета

E-mail Печать PDF

WEB-интерфейс для просмотра статистики интернета

Автор: lissyara.
Оригинал: http://www.lissyara.su/articles/freebsd/traffic_count/web_interface_for_trafd/

В предыдущей статье trafd & MySQL было рассмотрено, как запихнуть траффик собранный trafd в базу данных MySQL. Также был предложен "способ" подсчёта - запросами из консоли :) Нижеприведённый скрипт - это всего лишь "человеческое лицо" к тому самому запросу. И всё :)
<?php
// IP хостов, интерфейсы,
$ip_out_servera = "222.222.222.222"; // внешний IP сервака
$ip_internal_servera = "192.168.0.254"; // внутренний IP сервака
$IF_out_servera = "fxp0"; // название внешнего интерфейса сервака
$IF_internal_servera = "sis0"; // название внутреннего интерфейса сервака
$lan_mask = "192.168."; // маска по которой выбираются IP для подсчёта
//Пароли для подключения к MySQL
$db_host = "localhost";
$db_user = "trafd";
$db_passwd = "trafd";
$db_db = "trafd";
//Пытаемся приконнектится к БД
if(!mysql_connect($db_host,$db_user,$db_passwd))
{
echo "<br><br><BIG><CENTER>
Не могу прислюнявиться к MySQL-серванту!</CENTER></BIG>";
exit;
}
//Выбираем базу данных
mysql_select_db($db_db);
// определяем текущий месяц, и прошлый месяц - для вывода статистики
$curr_month = date(Y,time()) . "-" . date(m,time());
$old_month = date(Y,time()) . "-" . date('m',strtotime("-1 month"));
// строим HTML страничку:
?>
<HEAD>
<title>Страница статистики</title>
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1251">
<STYLE type="text/css">
#main_table .hilightoff {BACKGROUND: white}
#main_table .hilighton {BACKGROUND: #ccbbff}
#cheresstrochnaya_table .hilightoff {BACKGROUND: #88ff88}
#cheresstrochnaya_table .hilighton {BACKGROUND: #ccbbff}
</STYLE>
<BODY>
<BIG><CENTER>СТАТИСТИКА ИНТЕРНЕТА</CENTER></BIG><br><br>
<TABLE border="0" cellspacing="0" cellpadding="0" width="100%">
<TBODY>
<TR>
<TD width="50%" align="center" valign="top">
<TABLE border="1" cellspacing="0" cellpadding="0"
width="80%" id="main_table">
<TBODY>
<TR>
<TD height="20" align="center" colspan="3">
<BIG><CENTER>статистика за текущий месяц
<?php echo $curr_month; ?></CENTER></BIG></TD>
</TR>
<TR>
<TD height="20" width="15%" align="center">
<b>IP - адрес</b></TD>
<TD height="20" width="55%" align="center">
<b>пользователь</b></TD>
<TD height="20" width="30%" align="center">
<b>сколько скачано мегабайт</b></TD>
</TR>
<?php
// вытаскиваем статистику по пользователям из БД
$sql = mysql_query("SELECT to_IP, SUM(bytes) AS `bytes` FROM
`" . $IF_internal_servera . "_" . date(Y,time()) . "` WHERE `date`
LIKE '" . $curr_month . "-%' AND from_IP != '" . $ip_out_servera . "'
AND to_IP != '" . $ip_out_servera . "' AND
`to_IP` != '" . $ip_internal_servera . "'
AND `from_IP` != '" . $ip_internal_servera . "' AND `to_IP`
LIKE '" . $lan_mask . "%' GROUP BY `to_IP` ORDER BY `bytes` DESC");
// Строим табличку по тем кого достали
// вытаскиваем рейтинг страниц из БД
while ($d = mysql_fetch_assoc($sql)) {
// собственно тут вывод результатов.
$bytes = $d['bytes'] /1048576;
$bytes = round($bytes, 2);
if($d['to_IP'] == '192.168.0.21'){$user_name = 'Петров Ф. А.';}
if($d['to_IP'] == '192.168.0.17'){$user_name = 'Сидоров Н. А.';}
if($d['to_IP'] == '192.168.0.13'){$user_name = 'Иванов А.Л.';}
?>
<tr class=hilightoff onmouseover="className='hilighton';"
onmouseout="className='hilightoff';">
<td style="border-bottom: 1px solid #707680;"
width="" align="left"><?php echo $d['to_IP']; ?></td>
<td style="border-bottom: 1px solid #707680;"
width="" align="left"><?php echo $user_name; ?></td>
<td style="border-bottom: 1px solid #707680;"
width="" align="center"><?php echo $bytes; ?></td>
</tr>
<?php
unset ($user_name);
}
?>
</TBODY>
</TABLE>
</TD>
<TD width="50%" align="center" valign="top">
<TABLE border="1" cellspacing="0" cellpadding="0"
width="80%" id="main_table">
<TBODY>
<TR>
<TD height="20" align="center" colspan="3">
<BIG><CENTER>статистика за прошлый месяц
<?php echo $old_month; ?></CENTER></BIG></TD>
</TR>
<TR>
<TD height="20" width="25%" align="center">
<b>IP - адрес</b></TD>
<TD height="20" width="55%" align="center">
<b>пользователь</b></TD>
<TD height="20" width="30%" align="center">
<b>сколько мегабайт</b></TD>
</TR>
<?php
// вытаскиваем статистику по пользователям из БД
$sql = mysql_query("SELECT to_IP, SUM(bytes) AS `bytes` FROM
`" . $IF_internal_servera . "_" . date(Y,time()) . "` WHERE `date`
LIKE '" . $old_month . "-%' AND from_IP != '" . $ip_out_servera . "' AND
to_IP != '" . $ip_out_servera . "' AND `to_IP` != '" . $ip_internal_servera . "'
AND `from_IP` != '" . $ip_internal_servera . "' AND `to_IP` LIKE
'" . $lan_mask . "%' GROUP BY `to_IP` ORDER BY `bytes` DESC");
// Строим табличку по тем кого достали
// вытаскиваем рейтинг страниц из БД
while ($d = mysql_fetch_assoc($sql)) {
// собственно тут вывод результатов.
$bytes = $d['bytes'] /1048576;
$bytes = round($bytes, 2);
if($d['to_IP'] == '192.168.0.21'){$user_name = 'Петров Ф. А.';}
if($d['to_IP'] == '192.168.0.17'){$user_name = 'Сидоров Н. А.';}
if($d['to_IP'] == '192.168.0.13'){$user_name = 'Иванов А.Л.';}
?>
<tr class=hilightoff onmouseover="className='hilighton';"
onmouseout="className='hilightoff';">
<td style="border-bottom: 1px solid #707680;"
width="" align="left"><?php echo $d['to_IP']; ?></td>
<td style="border-bottom: 1px solid #707680;"
width="" align="left"><?php echo $user_name; ?></td>
<td style="border-bottom: 1px solid #707680;"
width="" align="center"><?php echo $bytes; ?></td>
</tr>
<?php
unset ($user_name);
}
?>

</TBODY>
</TABLE>

</TD>
</TR>
</TBODY>
</TABLE>
<br><br>

<?php
// считаем траффик этого месяца
$traffic_curr_month = mysql_fetch_array(mysql_query("SELECT SUM(bytes) AS `bytes`
FROM `" . $IF_out_servera . "_" . date(Y,time()) . "`
WHERE `to_IP` ='" . $ip_out_servera . "' AND `date`
LIKE '" . $curr_month . "-%'"));
$traffic_curr_meg = $traffic_curr_month[bytes] / 1048576;
$traffic_curr_meg = round($traffic_curr_meg, 2);

// считаем траффик прошлого месяца
$traffic_old_month = mysql_fetch_array(mysql_query("SELECT SUM(bytes) AS `bytes`
FROM `" . $IF_out_servera . "_" . date(Y,time()) . "` WHERE
`to_IP` ='" . $ip_out_servera . "' AND `date`
LIKE '" . $old_month . "-%'"));
$traffic_old_meg = $traffic_old_month[bytes] / 1048576;
$traffic_old_meg = round($traffic_old_meg, 2);
?>
Всего было траффика за&nbsp; &nbsp; этот &nbsp; &nbsp;
месяц: &nbsp; <?php echo $traffic_curr_meg; ?> мегабайт<br>
Всего было траффика за прошлый месяц:
<?php echo $traffic_old_meg; ?> мегабайт<br>
</FORM>
</BODY>
</HTML>

<?php ?>



Сложного ничего нету. Если припрёт показывать статистику пользователям, то в простейшем варианте, это будет выглядеть так:
<?php
// IP хостов, интерфейсы,
$ip_out_servera = "222.222.222.222"; // внешний IP сервака
$ip_internal_servera = "192.168.0.254"; // внутренний IP сервака
$IF_out_servera = "fxp0"; // название внешнего интерфейса сервака
$IF_internal_servera = "sis0"; // название внутреннего интерфейса сервака
$lan_mask = "192.168."; // маска по которой выбираются IP для подсчёта
//Пароли для подключения к MySQL
$db_host = "localhost";
$db_user = "trafd";
$db_passwd = "trafd";
$db_db = "trafd";
// достаём IP того кто хочет посмотреть
$ip = $_SERVER['REMOTE_ADDR'];
//Пытаемся приконнектится к БД
if(!mysql_connect($db_host,$db_user,$db_passwd))
{
echo "<br><br><BIG><CENTER>
Не могу прислюнявиться к MySQL-серванту!</CENTER></BIG>";
exit;
}
//Выбираем базу данных
mysql_select_db($db_db);
// определяем текущий месяц, и прошлый месяц - для вывода статистики
$curr_month = date(Y,time()) . "-" . date(m,time());
// строим HTML страничку:
?>
<HEAD>
<title>Страница статистики</title>
<meta http-equiv="Content-Type" content="text/html;
charset=windows-1251">
<STYLE type="text/css">
#main_table .hilightoff {BACKGROUND: white}
#main_table .hilighton {BACKGROUND: #ccbbff}
#cheresstrochnaya_table .hilightoff {BACKGROUND: #88ff88}
#cheresstrochnaya_table .hilighton {BACKGROUND: #ccbbff}
</STYLE>
<BODY>
<BIG><CENTER>СТАТИСТИКА ИНТЕРНЕТА</CENTER></BIG><br><br>
<TABLE border="1" cellspacing="0" cellpadding="0" width="100%" id="main_table">
<TBODY>
<TR>
<TD height="20" align="center" colspan="4">
<BIG><CENTER>статистика за текущий месяц
<?php echo $curr_month; ?></CENTER></BIG></TD>
</TR>
<TR>
<TD height="20" align="center" colspan="4">&nbsp;</TD>
</TR>
<TR>
<TD height="20" width="15%" align="center">
<b>IP - адрес</b></TD>
<TD height="20" width="25%" align="center">
<b>Пользователь</b></TD>
<TD height="20" width="30%" align="center">
<b>сколько скачано, мегабайт</b></TD>
<TD height="20" width="30%" align="center">
<b>сколько осталось мегабайт</b></TD>
</TR>
<TR>
<TD height="20" width="15%" align="center">&nbsp;</TD>
<TD height="20" width="25%" align="center">&nbsp;</TD>
<TD height="20" width="30%" align="center">&nbsp;</TD>
<TD height="20" width="30%" align="center">&nbsp;</TD>
</TR>
<?php
// вытаскиваем статистику по пользователям из БД
$sql = mysql_query("SELECT to_IP, SUM(bytes) AS `bytes` FROM `"
. $IF_internal_servera . "_2005` WHERE `date` LIKE '"
. $curr_month . "-%' AND to_IP != '" . $ip_out_servera .
"' AND `to_IP` != '" . $ip_internal_servera .
"' AND `to_IP` = '" . $ip . "' AND `from_IP` != '"
. $ip_internal_servera . "' GROUP BY `to_IP` ORDER BY
`bytes` DESC");
// Строим табличку по тем кого достали
// вытаскиваем рейтинг страниц из БД
while ($d = mysql_fetch_assoc($sql)) {
// собственно тут вывод результатов.
$bytes = $d['bytes'] /1048576;
$bytes = round($bytes, 2);
// определяем пользователя
if($d['to_IP'] == '192.168.0.21'){$user_name = 'Петров Ф. А.';}
if($d['to_IP'] == '192.168.0.17'){$user_name = 'Сидоров Н. А.';}
if($d['to_IP'] == '192.168.0.13'){$user_name = 'Иванов А.Л.';}
// считаем скока осталось траффику
$bytes_ostalos = 200 - $bytes;
?>
<tr class=hilightoff onmouseover="className='hilighton';"
onmouseout="className='hilightoff';">
<td style="border-bottom: 1px solid #707680;"
width="" align="left"><?php echo $d['to_IP']; ?></td>
<td style="border-bottom: 1px solid #707680;"
width="" align="left"><?php echo $user_name; ?></td>
<td style="border-bottom: 1px solid #707680;"
width="" align="center"><?php echo $bytes; ?></td>
<td style="border-bottom: 1px solid #707680;"
width="" align="center"><?php echo $bytes_ostalos; ?></td>
</tr>
<?php
unset ($user_name);
unset ($bytes);
unset ($bytes_ostalos);
}
?>
</TBODY>
</TABLE>
</BODY>
</HTML>
<?php ?>



То есть, просто определяется IP адрес компьютера с которого был сделан http запрос, и выводится статистика только для этого адреса. Если за одним компьютером работает больше одного пользователя - то надо придумывать что-то дополнительно :(

Обновлено 28.05.2010 12:33
 

Установка NTOP на FreeBSD 6.2

E-mail Печать PDF

Установка NTOP на FreeBSD 6.2

Автор: roygbiv.
Оригинал: http://www.lissyara.su/articles/freebsd/traffic_count/ntop/


Задача: собрать мощный сервер для анализа трафика в сети. Иметь возможность периодически вылавливать и анализировать netflow-статистику с Cisco.
Необходимость возникла из-за незнания "предпочтений" пользователей, и невозможности регулировать аппетиты "топперов" без диаграмм загрузки сети определёнными хостами.
До этого была настроена flow-tools+flowscan+cflowd статистика, которая ловила mirror с главного мартшрутизатора и превращала всё в NetFlow анализируемые пакеты, но захотелось опробовать другие инструменты.

Ожидаемый результат: с помощью данного решения есть возможность без особых трудностей и напряжения серого вещества, да ещё и доступными средствами,
собирать и анализировать статистику сети на простейшем оборудовании (любой свитч с mirroring'ом всех портов на один), и строить наглядные графики и таблички
"кто-откуда, когда и сколько", но, это решение не позволит вам без доп.знаний СОХРАНЯТЬ статистику. Если вам нужно импортировать данные,
либо нужно будет написать скрипты (поддерживается импорт в perl,php и прочее), либо использовать другое решение.
Данная система отображает текущее состояние нагрузки сети, а история в графиках будет жить только до первого перезапуска.
Мне больше от неё и не надо было, т.к. остальное делает вышеуказанная связка flow-tools+flowscan (где посмотреть:1 и 2).

Решение не абсолютное, и использованию подлежит лишь в тех случаях, когда сетевой отдел либо единица управления сетью (в виде ленивого админа)
не располагает средствами для покупки как дорогих программных, так и аппаратных решений для анализа трафика и ему нужны графические отчёты для шефа.
Структура реализации: единый центр обмена данными, в котором есть главный маршрутизатор, посылающий зеркалом весь трафик сети на один свой порт, далее, с этого порта принимает и анализирует данные сервер.

Выбор пал на ntop. О нём и его модулях далее пойдёт речь.
Данная статья не рассчитана на профи, прошу не тыкать мне умными замечаниями, кроме конструктивов и замеченными ошибками. Описания настройки Ntop под FreeBSD в сети я не нашёл.
То, что здесь описано, у меня работает.

Оф. сайт программы - http://www.ntop.org/
Ntop - это мощный и довольно тонкоконфигурируемый инструмент для мониторинга сетей и выявления неполадок.
Распространяется свободно по лицензии GPL, v2 (и поздние).
Возможно управление из командной строки, а так же использование встроенного веб-сервера (умеет ssl).
ntop использует libcap (т.е. сильно грузит CPU для обработки трафика), так что заранее выбирайте сервер помощнее (мой был P4 D 3GHz, 3200MB RAM).

Описание возможностей 3.2 версии ( http://www.ntop.org/overview.html ):

* Сортировка трафика по большому кол-ву протоколов
* Возможность сортировки данных о трафике по многим критериям
* Отображение сетевой активности (данные о трафике)
* Хранение данных в формате RRD (Round Robin Tool)
* Распознавание особенностей (напр. почтовые адреса) пользователей (детализированное сканирование)
* Пассивное (т.е. без посылки пакетов-запросов) распознавание типов ОС компьютеров
* Отображение распределения IP трафика по протоколам
* Анализ IP трафика и сортировка по источнику/месту назначения
* Отображение структуры и направления IP трафика в виде схем (кто с кем обменивается?)
* Вывод сведений об использовании IP трафика сортировкой по типу протоколов
* Возможность работы в режиме NetFlow/sFlow коллектора для приёма потоков, генерируемых роутерами (Cisco, Juniper) или коммутаторами (Foundry Networks)
* Генерация статистики обмена сетевым трафиком в RMON-подобном формате.

Установку будем производить из портов, как все лентяи.
Символ \ по ходу лирики - переход на следующую строку (для самых внимательных).
Если не обновляли давно порты: portsnap fetch; portsnap extract


далее, после муторного ожидания ищём пакет ntop: whereis ntop
ntop: /usr/ports/net/ntop


У меня была версия 3.2 (с октября 2005го года не обновлялась), но сейчас вышла 3.3, возможны изменения.
Идём в директорию и собираем пакет, но не делайте make clean! Нам кое-что понадобится из исходников. cd /usr/ports/net/ntop && make install
[X] LOCALE Enable locale (i18n) support. (поддержка интернациализации)
[X] PCAP_PORT Use libpcap from ports. (используем libcap из портов,а не системный)
[ ] XMLDUMP Enable XML Dump support. (не собирается :( )
[X] ASDATA Install AS data. (show traffic by Autonomous System Number,
# жрёт доп. память для обработки AS, в большинстве случаев не нужна)
[X] TCPWRAPPER Enable TCP wrapper support


После установки, идём в /usr/ports/net/ntop/work/ntop-3.2/packages/FreeBSD-ports/net/ntop/files и достаём оттуда sample-config (ntop.conf.sample): cp /usr/ports/net/ntop/work/ntop-3.2/packages/\
FreeBSD-ports/net/ntop/files/ntop.conf.sample \
usr/local/etc/ntop/ntop.conf


И меняем права на файл, а то он какой-то исполняемый, что не есть правильно: chmod -x /usr/local/etc/ntop/ntop.conf


Теперь необходимо проделать операцию создания каталогов для хранения данных ntop.
Для этого необходимо создать пользователя (используйте интерактивный # adduser) с ограниченными правами и доступом к выбранной вами папки.
У меня он такой: cat /etc/passwd | grep ntop
ntop:*:2001:2001:ntop manager:/data/netflow/ntop_db:/usr/sbin/nologin


Изменим владельца каталога: chown -R ntop:ntop /data/netflow/ntop_db


Правим конфигурационный файл ntop на своё усмотрение, приведу свой конфиг: cat /usr/local/etc/ntop/ntop.conf
--user ntop # под кем запускать демон
--db-file-path /data/netflow/ntop_db # путь к БД

# на каком сетевом интерфейсе слушать (сюда приходит весь mirror-трафик)
--interface rl0

# отключить "доверие" MAC-адресам, в случае >
# когда у нас данные идут с mirror интерфейса активного оборудования
--no-mac

# логи идут не на экран терминала (stdout, по умолчанию), а в syslog
--use-syslog=local3
# на каком порту слушает встроенный веб-сервер >
# (можно ещё --https-3001 вместе с http,
# сертификат здесь - /usr/local/etc/ntop/ntop-cert.pem )
--http-server 3000

# помогаем программе определить что считать локальным
# трафиком (внутренняя сеть будет обособлена для удобства)
--local-subnets 192.168.0.0/16,172.16.192.0/24

# можно указать домен для сети, либо программа определит >
# его самостоятельно
--domain vasya.ru
--daemon # запускать в виде демона, что под freebsd всегда верно


Полный список команд и вариантов можно посмотреть так: /usr/local/bin/ntop -h


Чтобы логи шли в определённый файл, как мы указали в конфиге, необходимо добавить в syslog.conf следующее: echo '!ntop' >> /etc/syslog.conf \
echo 'local3.* /var/log/ntop.log' >> /etc/syslog.conf


и создать этот файл с минимальными правами (чтобы вражище не подсмотрел): touch /var/log/ntop.log && chmod 600 /var/log/ntop.log


Перед запуском всей системы необходимо создать базу и задать пароль администратора: /usr/local/bin/ntop -P /data/netflow/ntop_db -u 2001 -A


где указана папка, которой владеет ntop пользователь с порядковым номером 2001 (мы его таким создали).
Вывод будет примерно таким:Thu May 3 23:31:52 2007 NOTE: Interface merge enabled by default
Thu May 3 23:31:53 2007 Initializing gdbm databases

ntop startup - waiting for user response!

Please enter the password for the admin user:
Please enter the password again:
Thu May 3 23:32:06 2007 Admin user password has been set


Готово, всё настроено и ждёт запуска - для начала сбора статистики и зарисовки диаграмм с графиками для начальника, чтобы учёл старания.
Если у Вас есть сетевой фильтр (firewall), откройте 3000ый tcp порт наружу, а если захотите snmp статистики, то и 161ый udp тоже в режиме keep-state (+163 udp на всякий случай).
Для IPFW это выглядит примерно так (вместе с другими правилами в скрипте): ipfw add allow tcp from me 3000 to 192.168.1.1 via em0


где 192.168.1.1 - IP вашего админского компа, чтобы другим неповадно было, а em0 - сетевая на текущем сервере, где стоит ntop и которая смотрит в ту же сеть, что и админский комп.
Если будете использовать родной скрипт - /usr/local/etc/rc.d/ntop, то не забудьте: echo 'ntop_enable="YES"' >> /etc/rc.conf
echo 'ntop_flags="@/usr/local/etc/ntop/ntop.conf"' >> /etc/rc.conf


И если у вас папка БД программы отличается (как и у меня) от /var/db/, то исправьте проверку на наличие ntop_pw.db файла
в /usr/local/etc/rc.d/ntop скрипте с указанием вашей папки (сами найдёте).
После этого запускаем демона: /usr/local/etc/rc.d/ntop start


и идём в любимый браузер по ссылке http://адресвашегосервераntop:3000
Смотрим и любуемся на потёкшую статистику, а модули в админке подключаем через логин admin и пароль тот, который вводили при создании БД.
Если есть netflow-генерирующий мартшутизаторо-коммутатор или на машине установлен ucd-snmp (net-snmp вроде тоже подойдёт), идём в секцию plugins и включаем там необходимые модули, немножко их настроив:
add netflow device - появляется таблица, где необходимо указать параметры поступающего потока. Здесь всё просто, нужно только иметь доп.сетевую (разумнее), которая ловит netflow, и указать её в конфигурации с дополнительными параметрами.
Так же в админке можно имзенять кучу настроек, тюнинговать существующие и добавлять новые правила фильтрации, дополнять параметрами опции сервера и создавать пользователей для доступа к своей статистике с разными привилегиями.

Если нужно сделать так, чтобы сервер был доступен из-под apache (http://vasya.ru/ntop к примеру), необходимо сделать следующее:
запустить ntop на 3000ом порту (значение можно поменять, конечно же), с параметрами:
-w127.0.0.1:3000 -W0 #слушать на http//localhost:3000 и не слушать на https вообще.
Apache должен быть собран с модулями (не все могут быть необходимы, но всё-таки) mod_cgid mod_headers mod_security mod_proxy mod_proxy-http mod_proxy-html proxy_connect.load
proxy_html.load mod_rewrite mod_ssl mod_userdir и поддерживать работу на 443ем порту (ssl).
Секция вирт.хоста в конфиге апача (либо,если версия 2.x,то файла путьдоapache/extra/httpd-vhosts.conf)
NameVirtualHost *:443
<VirtualHost *:443>

###### Весь трафик на 443ем порту ( HTTPS )

# поменяйте на свою почту
ServerAdmin webmaster@localhost
SSLEngine On
# поменяйте на путь к вашему сертификату
SSLCertificateFile /etc/apache2/ssl/apache.pem

# измените пути к логам
ErrorLog /var/log/apache2/error.log
# выберите уровень логирования из предложенных:
# debug, info, notice, warn, error, crit, alert, emerg.
LogLevel warn
CustomLog /var/log/apache2/access.log combined
ServerSignature On
### PATCH SUGGESTED BY NESSUS ABOUT TRACE ATTACKS
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]

#### NTOP (PROXY проброс) ########
ProxyHTMLLogVerbose On
LogLevel warn
ProxyHTMLExtended On
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass /ntop/ http://localhost:3000/
ProxyPassReverse /ntop/ http://localhost:3000/
<Location /ntop/>
SetOutputFilter proxy-html
ProxyHTMLURLMap / /ntop/
ProxyHTMLURLMap /ntop/plugins/ntop/ /ntop/plugins/
RequestHeader unset Accept-Encoding
</Location>

</VirtualHost>


И перезапустите apache (в моём случае поставлен из портов, версия 2.2.4): /usr/local/etc/rc.d/apache22 restart


и зайти по адресу https://vasya.ru/ntop/ .

Либо, как другой вариант (редирект с помощью apache-модуля proxy), вкратце:ProxyPass /ntop/ http://localhost:3000/


а в вирт.хостах:RewriteEngine On
RewriteCond %{HTTP_REFERER} vasya.ru/ntop
RewriteCond %{REQUEST_URI} !^/ntop
RewriteRule ^/(.*)$ http://vasya.ru/ntop/$1 [L,P]


По идее, всё должно работать, секцию с апачем я пока честно своровал и не пробовал.

На заметку: Ntop 2.1.3 was the last version with the mySQL stuff and is completely unsupported.

При установке руководствовался и откровенно тырил мысли с сайта ntop.org.
Все вопросы к разработчикам, я не при чём, у меня всё работает :)


Обновлено 28.05.2010 12:35
 


Страница 1 из 2.

  • Вопросы по поводу написанных статей можно обсудить в нашем сообществе в Вконтакте / Questions about written articles can be discussed in our community in Vkontakte Вопросы по поводу написанных статей можно обсудить в нашем сообществе в  Вконтакте / Questions about written articles can be discussed in our community in Vkontakte
Яндекс.Метрика