Для примера будем собирать трафик для подсети 172.16.5.0/24 с интерфейса bge1
Итак сам скрипт на PERL, пусть он находится в папке /scripts и называется ipacctd_ng.pl
#! /usr/bin/perl
$rul=64000; #номер начального правила в файере
$iface="bge1"; #интерфейс
$threshold=100000; #максимальное количество записей
$verbose="1"; #расширенная статистика
$savetime="1"; #метка юникс тайма в файл статистики
$nodename=sprintf("ipacct_%s",$iface); #имя ноды
$hookprefix=$iface; #крючочки (хуки) в нетграф
if($ARGV[0] ne "start" and $ARGV[0] ne "show" and $ARGV[0] ne "stop" and $ARGV[0] ne "restart"){
error();
}else{
if($ARGV[0] eq "stop"){ #stop
stop_ng_ipacctd($nodename);
}elsif($ARGV[0] eq "show"){ #дампим трафик в файл
#проверяем загружен ли ipacctd
if(check_ipacctd($iface,$rul)==0){
stop_ng_ipacctd($nodename);
`/bin/sleep 3`;
start_ng_ipacctd($nodename,$hookprefix,$rul,$iface,$verbose,$threshold,$savetime);
}else{
$cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s checkpoint",$nodename,$hookprefix);
`$cmd`;
$cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s show",$nodename,$hookprefix);
`$cmd`;
$cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s clear",$nodename,$hookprefix);
`$cmd`;
}
}elsif($ARGV[0] eq "start"){
start_ng_ipacctd($dbh,$nodename,$hookprefix,$rul,$iface,$verbose,$threshold,$savetime);
}elsif($ARGV[0] eq "restart"){
stop_ng_ipacctd($nodename);
`/bin/sleep 3`;
start_ng_ipacctd($dbh,$nodename,$hookprefix,$rul,$iface,$verbose,$threshold,$savetime);
}
}
###функция выводящая аргументы запуска==============================
sub error{
printf "\nUsage: (start|stop|restart|show)";
exit;
}
###функция start==================================================
sub start_ng_ipacctd{
$net="172.16.5.0/24";
#проверяем загруженность модулей
@modules=("ng_ipacct.ko","ng_ipfw.ko","ng_ksocket.ko");
foreach(@modules){
if(chk_mdl($_)==0){
`/sbin/kldload $_`;
}
}
#формирование ноды нетграфа
$cmd_ng=sprintf("/usr/sbin/ngctl -f- <<-SEQ
mkpeer ipacct ctl ctl
name .:ctl %s
mkpeer %s: ksocket %s_in inet/raw/divert
name %s:%s_in %s_in
msg %s_in: bind inet/0.0.0.0:3021
mkpeer %s: ksocket %s_out inet/raw/divert
name %s:%s_out %s_out
msg %s_out: bind inet/0.0.0.0:3022
rmhook .:ctl",$nodename,$nodename,$hookprefix,$nodename,$hookprefix,$nodename,$nodename,$nodename,$hookprefix,$nodename,$hookprefix,$nodename,$nodename);
`$cmd_ng`;
$cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s dlt RAW",$nodename,$hookprefix);
`$cmd`;
$cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s verbose %s",$nodename,$hookprefix,$verbose);
`$cmd`;
$cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s threshold %s",$nodename,$hookprefix,$threshold);
`$cmd`;
$cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s savetime %s",$nodename,$hookprefix,$savetime);
`$cmd`;
#формируем правила в фаирволе IPFW для перенаправления трафика в ноду нетграфа
$cmd=sprintf("/sbin/ipfw add %s divert 3021 ip from %s to any",$rul,$net);
`$cmd`;
$cmd=sprintf("/sbin/ipfw add %s divert 3022 ip from any to %s",$rul,$net);
`$cmd`;
print "ipacct has started..\n";
}
###функция stop==================================================
sub stop_ng_ipacctd{
`sh /etc/rc.firewall`;
$cmd=sprintf("/usr/sbin/ngctl shutdown %s:",$nodename);
`$cmd`;
print "ipacct has stoped..\n";
}
###функция проверки загрузки модулей================================
sub chk_mdl{
$chk=`/sbin/kldstat | /usr/bin/awk '/$_/ {print 1}'`;
if(!$chk){
return 0;
}else{
return 1;
}
}
###функция проверки ipacctd========================================
sub check_ipacctd{
$ch1=$ch2=$ch3=0;
$cmd=sprintf("/usr/sbin/ngctl list | grep %s_in",$iface); #проверяем входящий хук нетграфа
$check=`$cmd`;
if($check){
$ch1=1;
}
$cmd=sprintf("/usr/sbin/ngctl list | grep %s_out",$iface); #проверяем исходящий хук нетграфа
$check=`$cmd`;
if($check){
$ch2=1;
}
$cmd=sprintf("/sbin/ipfw show | grep divert"); #проверяем наличие правил в файерволе
$check=`$cmd`;
if($check){
$ch3=1;
}
$all_ch=$ch1+$ch2+$ch3;
if ($all_ch < 3){
return 0; #чего-то явно не хватает
}else{
return 1; #все ОК!
}
}
После старта мы можем посмотреть правила в фаирволе:
/sbin/ipfw show 64000 64000 1551459105 504714065010 divert 3021 ip from 172.16.5.0/24 to any 64000 2103320289 2367292643626 divert 3022 ip from any to 172.16.5.0/24
По команде:
/usr/sbin/ngctl list
можем посмотреть ноды и хуки нетграфа: There are 7 total nodes: Name: ngctl12701 Type: socket ID: 000c36ff Num hooks: 0 Name: ipacct_bge1_out Type: ksocket ID: 00097d52 Num hooks: 1 Name: ipacct_bge1_in Type: ksocket ID: 00097d51 Num hooks: 1 Name: ipacct_bge1 Type: ipacct ID: 00097d50 Num hooks: 2 Name: ipfw Type: ipfw ID: 0005f4a3 Num hooks: 0 Name: bge1 Type: ether ID: 00000002 Num hooks: 0 Name: bge0 Type: ether ID: 00000001 Num hooks: 0
Сделаем еще один маленький скриптик, который будет нам складывать статистику в файл.
Назовем его trafgen.pl
#!/usr/bin/perl
$tmp="/usr/local/var/trafd/tmp"; #папка для логов
opendir DIR,$tmp or mkdir $tmp;
closedir DIR;
$log=sprintf("%s/ipacctd.log",$tmp);
system("/scripts/ipacctd_ng.pl show >> $log"); #вызываем наш предыдущий скрипт с аргументом show
в /etc/crontab добавляем строчку:
*/5 * * * * root /scripts/trafgen.pl >/dev/null
Формат данны файла статистики при включенных опциях verbose=1 и savetime=1: src_IP src_Port dst_IP dst_Port Proto packets bytes unixtime