Login Form  

   

Если считать пакет 5 версии протокола NetFlow, то получим данные следующего вида

:

00000000 00 05 00 1E │ 64 DB 5B 60 │ 51 23 3F B6 │ 38 E5 5D 5A │ 67 33 DF D6 │ 00 00 00 00
00000018 0A 4F E2 0A │ 0A 01 FF 01 │ C0 A8 22 02 │ 00 14 00 02 │ 00 00 00 02 │ 00 00 01 96
00000030 64 DA F4 3C │ 64 DB 11 88 │ E9 96 01 85 │ 00 10 11 00 │ 00 00 00 00 │ 14 10 00 08
00000048 0A 5C 03 04 │ 0A 4F E2 32 │ C0 A8 22 56 │ 00 02 00 14 │ 00 00 00 02 │ 00 00 00 D9
00000060 64 DA F4 40 │ 64 DB 1B 68 │ 00 35 C0 19 │ 00 10 11 24 │ 00 00 00 00 │ 10 14 00 00
00000078 0A 49 D0 08 │ 0A 4F E2 0A │ C0 A8 22 56 │ 00 02 00 14 │ 00 00 00 02 │ 00 00 02 8E
00000090 64 DA F4 C0 │ 64 DB 14 2C │ 00 8A 00 8A │ 00 10 11 24 │ 00 00 00 00 │ 10 14 00 00
000000A8 0A 4F A5 0A │ 0A 02 1A 8C │ C0 A8 22 02 │ 00 08 00 02 │ 00 00 00 03 │ 00 00 00 90
000000C0 64 DA F5 08 │ 64 DB 17 E4 │ 0E 8B 16 13 │ 00 02 06 00 │ 00 00 00 00 │ 14 10 00 08
******************************************************************************************
000003D8 0A 4F A1 46 │ 0A 48 38 1B │ C0 A8 22 02 │ 00 08 00 02 │ 00 00 00 0A │ 00 00 04 F2
000003F0 64 DB 3E 50 │ 64 DB 48 18 │ 11 9A 01 BB │ 00 1B 06 00 │

В соответствии со спецификацией протокола 5 версии, каждый такой пакет - таблица

Первые 24 байта (0-23) — это шапка:

00 05 - версия протокола 5
00 1E - в таблице будет 30 записей
64 DB 5B 60 - System uptime в милисекундах (переводить надо?)
51 23 3F B6 - Текущее время в секундах (с начала эпохи)
38 E5 5D 5A - Остаточная часть в наносекундах
67 33 DF D6 - Номер последовательности.
00 - тип движка
00 - идентификатор движка
00 00 - sampling_interval - интервал между передачей данных. В нашем случае 0, значит данные будут направляться с сенсора сразу

Остальные данные — записи, которые разбиты по 48 байт. Ниже приведена таблица соответствия.

Bytes Contents Description
0-3 srcaddr Source IP address
4-7 dstaddr Destination IP address
8-11 nexthop IP address of next hop router
12-13 input SNMP index of input interface
14-15 output SNMP index of output interface
16-19 dPkts Packets in the flow
20-23 dOctets Total number of Layer 3 bytes in the packets of the flow
24-27 First SysUptime at start of flow
28-31 Last SysUptime at the time the last packet of the flow was received
32-33 srcport TCP/UDP source port number or equivalent
34-35 dstport TCP/UDP destination port number or equivalent
36 pad1 Unused (zero) bytes
37 tcp_flags Cumulative OR of TCP flags
38 prot IP protocol type (for example, TCP = 6; UDP = 17)
39 tos IP type of service (ToS)
40-41 src_as Autonomous system number of the source, either origin or peer
42-43 dst_as Autonomous system number of the destination, either origin or peer
44 src_mask Source address prefix mask bits
45 dst_mask Destination address prefix mask bits
46-47 pad2 Unused (zero) bytes

Наличие такой жесткой структуры дает нам возможность применения шаблонов при распаковке и регулярных выражений. Модифицируем наш код:

#!/usr/bin/perl
use strict;
use IO::Socket::INET;
use DBI;
use POSIX;
use feature qw { switch };
$| = 1;
my ($socket,$received_data,$peer_address,$peer_port, $version);
$socket = new IO::Socket::INET (
 LocalPort => '9999',
 Proto => 'udp',
) or die "ERROR in Socket Creation : $!\n";
my ($dbname) = 'flow';
my ($dbhost) = '127.0.0.1';
my ($dbusr) = 'netflow';
my ($dbpass) = 'netflow';
my ($db) = DBI->connect("DBI:mysql:$dbname;host=$dbhost", "$dbusr", "$dbpass") || die "Could not connect to database: $DBI::errstr";
while(1) {
my ($recieved_data);
while(!$recieved_data) {
 $socket->recv($recieved_data,4096);
 $peer_address = unpack("N", $socket->peeraddr());
}
 $version = unpack("n", substr($recieved_data,0,2));
 given ( $version ) {
  when ( 5 ) { fv5($recieved_data,$peer_address); }
  }
}
$socket->close();
$db->disconnect();
sub fv5 {
 my $sth = $db->prepare("SELECT COUNT(*) FROM devices WHERE `device_header`=$_[1]");
 $sth->execute;
 if ($sth->fetchrow == 0) {
  $db->do("INSERT INTO devices (`device_header`) VALUES($_[1])");
 }
 my $sth = $db->prepare("SELECT `device_id` FROM `devices` WHERE `device_header`=$_[1]");
 $sth->execute;
 my $result = $sth->fetchrow_hashref;
 my $dev_id = $result->{device_id};
 my (@header) = unpack("nnN4NNNHHH2", substr($_[0],0,24));
 my @records = ();
 my ($i, $fmt, @substr);
 my $data = "INSERT INTO `v5` VALUES\n";
 for ($i=0; substr($_[0], 24+48*$i, 48); $i++) {
  @substr = unpack("N3n2N4n2C4n2C2n", substr($_[0], 24+48*$i, 48));
  $records[$i] = "('$dev_id','$header[3]','$header[2]','" . join("','", @substr) . "')";
 }
 $data .= join(",\n", @records);
 $db->do("$data");
}

Для нормальной работоспособности нам понадобится инициализировать базу данных NetFlow на нашем сервере. Сделать это можно с помощью SQL скрипта:

-- Delete old base and user
DROP DATABASE `flow`;
DROP USER 'netflow'@'localhost';

-- Create new database and use it
CREATE DATABASE IF NOT EXISTS `flow` CHARACTER SET utf16;
USE `flow`;
-- Create user and grant privileges
CREATE USER 'netflow'@'localhost' IDENTIFIED BY PASSWORD
'*993AA45E0B64915AFBD1A5BE5713FD509A8E6C2C';
GRANT ALL PRIVILEGES ON `flow` . * TO 'netflow'@'localhost' WITH GRANT OPTION;
-- Create table for templates
CREATE TABLE IF NOT EXISTS `devices` (
`device_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`device_header` VARCHAR(100),
`device_description` VARCHAR(100),
`device_data` VARCHAR(100)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `v5` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`device_id` INT UNSIGNED NOT NULL,
`datetime` INT UNSIGNED,
`sysuptime` INT UNSIGNED,
`srcaddr` INT UNSIGNED,
`dstaddr` INT UNSIGNED,
`nexthop` INT UNSIGNED,
`input` SMALLINT UNSIGNED,
`output` SMALLINT UNSIGNED,
`dpkts` INT UNSIGNED,
`doctets` INT UNSIGNED,
`first` INT UNSIGNED,
`last` INT UNSIGNED,
`srcport` SMALLINT UNSIGNED,
`dstport` SMALLINT UNSIGNED,
`pad1` TINYINT UNSIGNED,
`tcp_flags` TINYINT UNSIGNED,
`prot` TINYINT UNSIGNED,
`tos` TINYINT UNSIGNED,
`src_as` SMALLINT UNSIGNED,
`dst_as` SMALLINT UNSIGNED,
`src_mask` TINYINT UNSIGNED,
`dst_mask` TINYINT UNSIGNED,
`pad2` SMALLINT UNSIGNED
) ENGINE=InnoDB;

После инициализации БД и запуска скрипта мы получим некоторые данные в таблице v5 (если сенсор такженастроен корректно)

Что бы их просмотреть, можно воспользоваться примером SQL скрипта:

SELECT
FROM_UNIXTIME(`datetime`-CEIL((`sysuptime`-`first`)/1000)) AS first,
1000 - MOD(`sysuptime`-`first`, 1000) AS firstms,
FROM_UNIXTIME(`datetime`-CEIL((`sysuptime`-`last`)/1000)) AS last,
1000 - MOD(`sysuptime`-`last`, 1000) AS lastms,
INET_NTOA(`srcaddr`) as `srcaddr`,
INET_NTOA(`dstaddr`) as `dstaddr`,
INET_NTOA(`nexthop`) as `nexthop`,
`input`,
`output`,
`dpkts`,
`doctets`,
`srcport`,
`dstport`,
`tcp_flags`,
`prot`,
`tos`,
`src_as`,
`dst_as`,
`src_mask`,
`dst_mask`
FROM `v5` WHERE `device_id`=1
LIMIT 0, 30

Примерной такой же вывод дает flow-print из пакета flow-tools. Различие заключается в механизме представления. Здесь вам необходимо обладать навыками в SQL что бы получать необходимые данные.

   
© it-answer.ru