Способ учета трафика в дискретном времени, т.е. с запаздыванием. В качестве ОС выбран Linux debian. Используется встроенный firewall - iptables. PHP и MySQL установлены через apt-get.
Для удобства создан системный пользователь ipt, домашний каталог /home/ipt.
adduser ipt
Создаем цепочку COUNT, которая будет возвращать все полученные пакеты.
iptables -N COUNT
iptables -A COUNT -j RETURN
Рассматриваю вариант сервера, на котором запущены обслуживающие пользователя процессы (daemons). Например bind, nginx. Соответственно порты служб 53 и 80. Протокол UDP у DNS-сервера bind и TCP у web-сервера nginx. Выполняем команду создания дампа конфигурации iptables. Полученный файл будет использоваться при записи конфигурации iptables php-скриптом, который будет заносить данные о трафике в базу данных.
iptables-save > /home/ipt/ipt.cfg
Полученный файл необходимо дополнить собственными правилами, например отказом отвечать на DNS запросы определенным IP-адресам и правилами, которые будут перенаправлять входящий и исходящий трафик цепочке COUNT. Пример ниже.
# Generated by iptables-save v1.3.6
*mangle
:PREROUTING ACCEPT [1517138:69518344]
:INPUT ACCEPT [1517138:69518344]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [2636061:3789348870]
:POSTROUTING ACCEPT [2636061:3789348870]
COMMIT
# Generated by iptables-save v1.3.6
*filter
:INPUT ACCEPT [1517138:69518344]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [2636061:3789348870]
:COUNT - [0:0]
# Block
-A INPUT -s 91.202.63.133 -p udp --dport 53 -j DROP
-A INPUT -s 91.202.63.136 -p udp --dport 53 -j DROP
# Count
-A INPUT -p tcp -m tcp --dport 80 -j COUNT
-A INPUT -p udp -m udp --dport 53 -j COUNT
-A OUTPUT -p tcp -m tcp --sport 80 -j COUNT
-A OUTPUT -p udp -m udp --sport 53 -j COUNT
-A COUNT -j RETURN
COMMIT
*nat
:PREROUTING ACCEPT [5463:388186]
:POSTROUTING ACCEPT [4699:381379]
:OUTPUT ACCEPT [4699:381379]
COMMIT
А дальше осталось запускать скрипт, который с определенным интервалом будет считывать данные iptables и заносить их в базу данных. Вместо учета трафика по портам, можно учитывать трафик конкретного IP-адреса в частной сети. На мой взгляд, оптимальный вариант - 10 минут.
Структура таблиц Mysql.
hdr - содержит различные типы фильтров, которые отслеживаются. А именно: IP адрес, протокол, порт и направление трафика - входящий или исходящий.
CREATE TABLE IF NOT EXISTS `hdr` (
`id` int(11) NOT NULL auto_increment,
`ip` varchar(64) NOT NULL,
`proto` varchar(8) NOT NULL,
`port` int(11) NOT NULL,
`direction` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `ip` (`ip`),
KEY `proto` (`proto`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 ;
Таблица dat - данные. HDR - указатель на ID в таблице HDR. TS - время записи, информация о трафике относится к предшествующему периоду. YY,MM,DD,HH,II - это дата, разделенная по полям int, для удобства построения таблицы, понятной пользователю. PACKET - число пакетов в интервале. BYTES и KBYTES - трафик в байтах и килобайтах соответственно.
CREATE TABLE IF NOT EXISTS `dat` (
`id` int(11) NOT NULL auto_increment,
`hdr` int(11) NOT NULL,
`ts` datetime NOT NULL,
`yy` int(11) NOT NULL,
`mm` int(11) NOT NULL,
`dd` int(11) NOT NULL,
`hh` int(11) NOT NULL,
`ii` int(11) NOT NULL,
`packet` int(11) NOT NULL,
`bytes` bigint(20) NOT NULL,
`kbytes` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `hdr` (`hdr`),
KEY `tint` (`yy`,`mm`,`dd`,`hh`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
Далее добавляем запуск скрипта от имени root каждые 10 минут для пополнения базы. Например, если пользователь превысил определенный лимит трафика в текущий день скрипт может добавить правило, запрещающее доступ к внешней сети.
*/10 * * * * /usr/bin/php /home/ipt/ipt.php > /dev/null 2>&1