Для работы этого примера необходимо иметь подгруженные модули:
Убедиться в их наличии можно командой:
/sbin/kldstat
Id Refs Address Size Name1 11 0xc0400000 35e5f8 kernel...3 1 0xc4ceb000 3000 ng_ipacct.ko4 1 0xc4cee000 4000 ng_ksocket.ko5 1 0xc4d6d000 2000 ng_ipfw.ko
Если модули не загружены, то можно пересобрать ядро добавив следующее:
options NETGRAPHoptions NETGRAPH_ETHERoptions NETGRAPH_SOCKEToptions NETGRAPH_TEE
options IPFIREWALLoptions IPFIREWALL_DEFAULT_TO_ACCEPToptions IPFIREWALL_FORWARDoptions IPFIREWALL_VERBOSEoptions IPFIREWALL_VERBOSE_LIMIT=1000
либо загрузить это модулями:
/sbin/kldload /boot/kernel/ng_ipfw.ko
/sbin/kldload /boot/kernel/ng_ipacct.ko
/sbin/kldload /boot/kernel/ng_ksocket.ko
Устанавливаем порт /usr/ports/net-mgmt/ng_ipacct:
cd /usr/ports/net-mgmt/ng_ipacct
make install clean
В /etc/rc.conf добавляем:
ng_ipacct_enable="YES"ng_ipacct_modules_load="YES"Для примера будем собирать трафик для подсети 172.16.5.0/24 с интерфейса bge1
ng_ipacct_enable="YES"ng_ipacct_modules_load="YES"
Итак сам скрипт на 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 6400064000 1551459105 504714065010 divert 3021 ip from 172.16.5.0/24 to any64000 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: 0Name: ipacct_bge1_out Type: ksocket ID: 00097d52 Num hooks: 1Name: ipacct_bge1_in Type: ksocket ID: 00097d51 Num hooks: 1Name: ipacct_bge1 Type: ipacct ID: 00097d50 Num hooks: 2Name: ipfw Type: ipfw ID: 0005f4a3 Num hooks: 0Name: bge1 Type: ether ID: 00000002 Num hooks: 0Name: bge0 Type: ether ID: 00000001 Num hooks: 0
There are 7 total nodes:Name: ngctl12701 Type: socket ID: 000c36ff Num hooks: 0Name: ipacct_bge1_out Type: ksocket ID: 00097d52 Num hooks: 1Name: ipacct_bge1_in Type: ksocket ID: 00097d51 Num hooks: 1Name: ipacct_bge1 Type: ipacct ID: 00097d50 Num hooks: 2Name: ipfw Type: ipfw ID: 0005f4a3 Num hooks: 0Name: bge1 Type: ether ID: 00000002 Num hooks: 0Name: 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
src_IP src_Port dst_IP dst_Port Proto packets bytes unixtime
Пример данных в фале:
172.16.5.211 57349 95.132.7.128 19904 6 1069 822400 1239961920172.16.5.102 2208 217.118.24.17 7777 6 321 14958 1239961920172.16.5.91 64835 92.100.50.249 59039 6 426 596900 1239961920172.16.5.209 64829 77.41.95.94 43768 17 1 58 1239961923172.16.5.76 1425 195.218.181.123 80 6 4 976 1239961924172.16.5.188 61651 195.50.197.187 63375 6 1 48 1239961925172.16.5.220 28988 94.179.59.61 20473 6 5 747 1239961929....80.252.240.202 11417 172.16.5.108 60682 17 1 47 123996192278.37.156.14 1451 172.16.5.220 28988 6 6 685 123996192297.84.143.186 17834 172.16.5.209 64829 17 2 134 123996192277.234.8.71 36523 172.16.5.220 28988 17 1 95 1239961924195.189.47.2 2987 172.16.5.220 28988 17 1 131 1239961925195.230.112.239 63403 172.16.5.220 28988 6 6 801 123996193060.220.156.222 27808 172.16.5.157 34613 17 4 504 123996193293.186.239.96 80 172.16.5.101 2720 6 3 358 1239961933
Обратите внимание, что сначала идет трафик исходящий и лишь затем входящий!!!Все, дальше зависит только от полета Вашей фантазии (или извращенности )
Вы можете обрабатывать файлы и складировать их в БД (напрмер MySQL) и т.п.
Плюсы от использования ng_ipacct:
P.S. После пересборки ядра обязательно пересобрать порт /usr/ports/net-mgmt/ng_ipacct (если он был установлен до этого)
Чтиво: