[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: подсчет траффика



В Втр, 14/08/2007 в 12:24 +0400, Alexander GQ Gerasiov пишет:
> На Mon, 13 Aug 2007 19:12:42 +0400
> "Sapytsky Ilya" <sova00@gmail.com> записано:
> 
> > 2007/8/11, Nicholas <spam@networkgate.us>:
> > >
> > > Sapytsky Ilya wrote:
> > > > надо собирать сколько выкачали клиенты с заранее заданными ip и
> > > > общий траффик во времени.
> > >
> > > ntop ?
> > >
> > спасибо, посмотрел, интересная штука, только не понял как в ней
можно
> > посмотреть точную сумму в байтах траффика за месяц июль например....
> ты еще обрати внимание, что при перезапуске оно теряем все свои
данные.

вот для слаквари подсчёт чел навалял...

Графика пока нет, собрал статистику (bash+crond+bc+iptables): 
Ниже настроенный под домолинк вариант (внешняя сеть закрыта кроме
прокси, открыта локальная.) Комментариев нет. 

Файервол (bash скрипт): 
Скрипт нужно запускать после запуска системы (в slackware
это /etc/rc.d/rc.local) 
                                  Код:
                                    
                               #!/bin/sh 
                           #firewall script 
                                    
                     echo firewall script started 
                      CARD_MASK="192.168.1.2/32" 
                        ROUTER="192.168.1.1/32" 
                         BVF="84.17.243.19/32" 
                  RANGE1="77.45.128.0/255.255.128.0" 
                   RANGE2="80.82.32.0/255.255.224.0" 
                  RANGE3="88.83.192.0/255.255.224.0" 
                                    
                            FREE[0]=$RANGE1 
                            FREE[1]=$RANGE2 
                            FREE[2]=$RANGE3 
                              FREE[3]="" 
                                    
                       KILL[0]="80.82.32.10/32" 
                       KILL[1]="80.82.32.19/32" 
                              KILL[2]="" 
                                    
                       PAID[0]="80.82.32.27/32" 
                       PAID[1]="80.82.32.11/32" 
                              PAID[2]="" 
                                    
                         LOCAL="127.0.0.1/32" 
                                    
                           iptables --flush 
                              iptables -X 
                                    
                         iptables -N local_in 
                         iptables -N local_out 
                         iptables -N extern_in 
                        iptables -N extern_out 
                         iptables -N total_in 
                         iptables -N total_out 
                          iptables -N kill_in 
                         iptables -N kill_out 
                                    
                         iptables -N kill_all 
                        iptables -N extern_all 
                         iptables -N local_all 
                         iptables -N total_all 
                                    
                    iptables -A local_all -j ACCEPT 
                   iptables -A extern_all -j ACCEPT 
                 #следущую строчку можно закомментить 
                 #если не требуется отладить файерволл 
                      iptables -A kill_all -j LOG 
   iptables -A kill_all -j REJECT --reject-with icmp-net-prohibited 
                     iptables -A kill_all -j DROP 
                    iptables -A total_all -j RETURN 
                                    
                   iptables -A total_in -g total_all 
                  iptables -A total_out -g total_all 
                   iptables -A local_in -g local_all 
                  iptables -A local_out -g local_all 
                  iptables -A extern_in -g extern_all 
                 iptables -A extern_out -g extern_all 
                    iptables -A kill_in -g kill_all 
                   iptables -A kill_out -g kill_all 
                                    
                        iptables -P INPUT DROP 
                       iptables -P FORWARD DROP 
                        iptables -P OUTPUT DROP 
                                    
         iptables -A INPUT -s $LOCAL -d $LOCAL -i lo -j ACCEPT 
        iptables -A OUTPUT -s $LOCAL -d $LOCAL -o lo -j ACCEPT 
                                    
      iptables -A INPUT -p all -s $ROUTER -d $CARD_MASK -j ACCEPT 
    iptables -A INPUT -p all -s $CARD_MASK -d $CARD_MASK -j ACCEPT 
     iptables -A OUTPUT -p all -s $CARD_MASK -d $ROUTER -j ACCEPT 
   #iptables -A OUTPUT -p all -s $CARD_MASK -d $CARD_MASK -j ACCEPT 
                                    
                                  i=0 
                     while [ "${KILL[$i]}" != "" ] 
                                  do 
            iptables -A INPUT -p all -s ${KILL[$i]} -j kill_in 
           iptables -A OUTPUT -p all -d ${KILL[$i]} -j kill_out 
                                i=$(($i+1)) 
                                 done 
                                    
                 iptables -A INPUT -p all -j total_in 
                iptables -A OUTPUT -p all -j total_out 
                                    
      iptables -A INPUT -p tcp -s $BVF -d $CARD_MASK -j local_in 
     iptables -A OUTPUT  -p all -s $CARD_MASK -d $BVF -j local_out 
                                    
                                  i=0 
                     while [ "${PAID[$i]}" != "" ] 
                                  do 
           iptables -A INPUT -p all -s ${PAID[$i]} -j extern_in 
          iptables -A OUTPUT -p all -d ${PAID[$i]} -j extern_out 
                                i=$(($i+1)) 
                                 done 
                                    
                                  i=0 
                     while [ "${FREE[$i]}" != "" ] 
                                  do 
     iptables -A INPUT -p all -s ${FREE[$i]} -d $CARD_MASK -j local_in 
    iptables -A OUTPUT -p all -s $CARD_MASK -d ${FREE[$i]} -j local_out 
                                i=$(($i+1)) 
                                 done 
                                    
                  iptables -A INPUT -p all -j kill_in 
                 iptables -A OUTPUT -p all -j kill_out 
                                    
                 #iptables -A INPUT -p icmp -j ACCEPT 
      #iptables -A POSTROUTING -p all -s 127.0.0.1 -d 80.82.32.27 
                                    
                             CARD_MASK="" 
                               RANGE1="" 
                               RANGE2="" 
                               RANGE3="" 
                               LOCAL="" 
                                    


Учетчик траффика. 
Должен быть установлен в /usr/lib/vsi-traf 
Если устанавливался в др место, нужно изменить переменную BASE на
"правильный путь" 

файл должен называться traffic.sh 
                                  Код:
                                    
                               #!/bin/sh 
    #this script is provided "as is" with no warranty of any kind. 
 #this script can be freely distributed on the terms of GPL license;) 
                   #Made by ErV (ErV2005@rambler.ru) 
                                    
                        BASE=/usr/lib/vsi-traf 
                            DATA=$BASE/data 
                            HOUR=`date +%H` 
                            DAY=`date +%d` 
                            WEEK=`date +%W` 
                           WEEK=$(($WEEK%4)) 
                           MONTH=`date +%m` 
                            YEAR=`date +%Y` 
                        LOCK_FILE="$BASE/lock" 
                       MONTH_DIR="$YEAR/$MONTH" 
                      WEEK_DIR="$MONTH_DIR/weeks" 
                       DAY_DIR="$MONTH_DIR/$DAY" 
                BYTES_HOUR="$DAY_DIR/$HOUR:00-$HOUR:59" 
                   BYTES_DAY="$MONTH_DIR/$DAY.total" 
                  BYTES_WEEK="$WEEK_DIR/$WEEK.total" 
                   BYTES_MONTH="$YEAR/$MONTH.total" 
                       BYTES_YEAR="$YEAR.total" 
                       CURRENT_HOUR="this_hour" 
                        CURRENT_DAY="this_day" 
                       CURRENT_WEEK="this_week" 
                      CURRENT_MONTH="this_month" 
                       CURRENT_YEAR="this_year" 
                      GET_BYTES=$BASE/iptable.pl 
                                    
                         CHAINS[0]="extern_in" 
                        CHAINS[1]="extern_out" 
                         CHAINS[2]="local_in" 
                         CHAINS[3]="local_out" 
                         CHAINS[4]="total_in" 
                         CHAINS[5]="total_out" 
                             CHAINS[6]="" 
                                    
                          force_directory(){ 
                                #echo "$1" 
                          if [ ! -r "$1" ]; then 
                              mkdir "$1"; 
                                   fi; 
                                   } 
                                    
               #arg 1 - fuction that accepts chain name 
                           for_each_chain(){ 
                                   i=0; 
                   while [ "${CHAINS[$i]}" != "" ]; do 
                           $1 ${CHAINS[$i]}; 
                              i=$(($i+1)) 
                                  done; 
                                   } 
                                    
                          check_chain_dir(){ 
                        force_directory "$DATA/$1" 
                     force_directory "$DATA/$1/$YEAR" 
                  force_directory "$DATA/$1/$MONTH_DIR" 
                   force_directory "$DATA/$1/$WEEK_DIR" 
                   force_directory "$DATA/$1/$DAY_DIR" 
                                   } 
                                    
                           force_counter(){ 
                          if [ ! -r "$1" ]; then 
                           echo "0" > "$1"; 
                                    fi 
                  #    if [ `cat "$1"` == "" ]; then 
                          # echo "0" > "$1"; 
                                #    fi 
                                   } 
                                    
                        check_chain_counters(){ 
                           CHAIN_DIR="$DATA/$1" 
                  force_counter "$CHAIN_DIR/$BYTES_HOUR" 
                  force_counter "$CHAIN_DIR/$BYTES_DAY" 
                  force_counter "$CHAIN_DIR/$BYTES_WEEK" 
                 force_counter "$CHAIN_DIR/$BYTES_MONTH" 
                  force_counter "$CHAIN_DIR/$BYTES_YEAR" 
       ln -s -f "$CHAIN_DIR/$BYTES_HOUR" "$CHAIN_DIR/$CURRENT_HOUR" 
        ln -s -f "$CHAIN_DIR/$BYTES_DAY" "$CHAIN_DIR/$CURRENT_DAY" 
       ln -s -f "$CHAIN_DIR/$BYTES_WEEK" "$CHAIN_DIR/$CURRENT_WEEK" 
      ln -s -f "$CHAIN_DIR/$BYTES_MONTH" "$CHAIN_DIR/$CURRENT_MONTH" 
       ln -s -f "$CHAIN_DIR/$BYTES_YEAR" "$CHAIN_DIR/$CURRENT_YEAR" 
                                   } 
                                    
                               check(){ 
                          force_directory $DATA 
                      for_each_chain check_chain_dir 
                   for_each_chain check_chain_counters 
                                   } 
                                    
              #$1 is a counter file $2 is a value to add 
                            inc_counter(){ 
                               PREV_BYTES=0 
                            if [ -s $1 ]; then 
                             PREV_BYTES=`cat $1`; 
                                    fi 
                     echo "$PREV_BYTES + $2"|bc > $1; 
                                   } 
                                    
             #$1 is a chain name, $2 is a new added value 
                         chain_inc_counters(){ 
                                BYTES="$2" 
                           CHAIN_DIR="$DATA/$1" 
              inc_counter "$CHAIN_DIR/$BYTES_HOUR" "$BYTES" 
               inc_counter "$CHAIN_DIR/$BYTES_DAY" "$BYTES" 
              inc_counter "$CHAIN_DIR/$BYTES_WEEK" "$BYTES" 
              inc_counter "$CHAIN_DIR/$BYTES_MONTH" "$BYTES" 
              inc_counter "$CHAIN_DIR/$BYTES_YEAR" "$BYTES" 
                                   } 
                                    
                        chain_update_normal(){ 
                          BYTES=`$GET_BYTES $1` 
                     chain_inc_counters "$1" "$BYTES" 
                                   } 
                                    
                                lock(){ 
                         echo "0" > "$LOCK_FILE" 
                                   } 
                                    
                               unlock(){ 
                             rm "$LOCK_FILE" 
                                   } 
                                    
                           update_normal(){ 
                      if [ ! -r "$LOCK_FILE" ]; then 
                                 lock; 
                                    check; 
                  for_each_chain chain_update_normal; 
                                unlock; 
                                   else 
                 echo another instance already working 
                                   fi; 
                                   } 
                                    
                              case $1 in 
                             'check') check;; 
                        'update') update_normal;; 
           'unlock') unlock;;#use only after system restart!!! 
                              'lock') lock;; 
                         *) echo unknown argument 
             echo "usage traf [update|check|lock|unlock]" 
                                 esac 
                                    


Перл-скрипт, который должен находится в папке с учетчиком. (имя должное
быть iptable.pl). 
Пойдет любая другая утилита, которая берет в качестве параметров имя
цепочки iptables и возвращает число байт, попутно обнуляя счетчик.
Скрипт изначально не мой, копирайты сохранены. 
                                  Код:
                                    
                            #!/usr/bin/perl 
                                  ## 
                   ## This is a quick perl script to 
             ## pull bandwidth usage from iptables chains 
                                  ## 
        ## If you use/optimize this script, please let me know. 
           ## Brian Stanback : brian [at] stanback [dot] net 
                                   # 
           ## Example iptables rule for web bandwidth usage: 
                         ## > iptables -N WWW 
                    ## > iptables -A WWW -j ACCEPT 
        ## > iptables -A INPUT -p tcp -m tcp --dport 80 -j WWW 
        ## > iptables -A OUTPUT -p tcp -m tcp --sport 80 -j WWW 
                                  ## 
      ## Run "iptables.pl WWW" as root to test, note that you can 
        ## combine more than one protocol into a single chain. 
                                  ## 
                 ## Sudo Configuration (/etc/sudoers) 
 ## > www-data    ALL = NOPASSWD: /usr/share/cacti/scripts/iptables.pl 
                                  ## 
               ## The Input String should be set to "sudo
               <path_cacti>/scripts/iptables.pl <chain>" 
    ## and you will need to setup an input field so that the <chain>
                        argument can be passed. 
                                  ## 
            ## The data input type should be set to COUNTER 
                                  ## 
                                   # 
                                   # 
    # modified by: Paul Campbell <forums@campbell-multimedia.co.uk> 
      # Now returns a seperate entry for each rule.  Output for a 
                     # 3 rule chain might now be: 
                    # rule1:123 rule2:456 rule3:789 
                                   # 
         # Modified by ErV. Now outputs number of bytes only. 
                                    
                            if ($ARGV[0]) { 
         $chains = `/usr/sbin/iptables --line-number -xnvL $ARGV[0]`; 
                 `/usr/sbin/iptables --zero $ARGV[0]`; 
                       @chains = split(/\n/, $chains); 
                               shift(@chains); 
                               shift(@chains); 
                             foreach( @chains ) { 
                           /(\d+)\W+[0-9]+\W+([0-9]+)\W+/; 
                 #                print " rule$1:$2"; 
                               print"$2"; 
                                      } 
                                 print "\n"; 
                 #$chains[2] =~ /[\W+]?[0-9]+\W+([0-9]+)\W+/; 
                               } else { 
                          print "Usage: $0 Chain\n"; 
                                   } 
                                    


Скрипт traffic.sh должен иметь право на запись в той папке, в которой он
установлен (например, chmod g+s) 

Для работы счетчика на машине должен быть установлен bc - для подсчета
количества байт с высокой точностью (без ограничения на количество цифр
- в iptables есть лимит в 936мб). Скрипт не быстрый (из-за bc). Для моей
конфигурации (6 цепочек) он занимает где-то секунду. 

Для работы нужно запихнуть вызов скрипта при запуске системы с
параметром unlock 
(traffic.sh unlock) - на случай маловероятного сбоя из-за отключения
питания в момент работы скрипта 

Далее, нужно запихнуть в cron вызов скрипта с параметром update (то есть
traffic.sh update), например, каждые 5 минут и на 59 минуте каждого
часа. Минимум вызов нужен 1 раз в час (на 59 минуте, например), можно
сделать его чаще, чтобы статистика активнее обновляляась. 

Пример линии из crontab: 
                                  Код:
                                    
    */5,59 * * * * /usr/bin/bash /usr/lib/vsi-traf/traffic.sh update
                              > /dev/null 
                                    


Также необходим один вызов скрипта с параметром update при выключении
системы (для сохранения статистики). 

После запуска скрипт 
создаст подкаталог дата, раскидает статистику по папка. В простейшем
виде - в текстовом файле, в котором будте храниться число скачанных байт
за период, которому файл соответствует. 
Т.е. типичный вариант каталогов: 
chain_name/2007.total - число байт прошедших сквозь отслеживаемую
цепочку (chain_name) за этот год. 
chain_name/2007 - каталог с данным по месяцам для этой цепочки. 
chain_name/2007/04.total - общее число байт за апрель 
chain_name/2007/04/ - папка с данными по апрелю 
chain_name/2007/04/weeks - понедельная статистика за апрель 
chain_name/2007/04/08 - почасовая статистика за 8е апреля. 
chain_name/2007/04/08.total - общее число байт за 8е апреля (обновляется
в процессе работы) 
chain_name/2007/04/08/23:00-23:59 - число байт за час до полуночи, 8го
апреля 2007. 

Кроме этого в корне chain_name будут ярлыки на статистику за текущий
день, месяц, неделю, год и час. Ярлыки будут обновляться автоматом.
(т.е. пока cron вызывает скрипт, они будут указывать на корректные
файлы). 

Вариант не самый "красивый" внешне, но наиболее гибкий и
пуленепробиваемый для подсчета месечного/недельного/годового обьема
траффика. 
Скрипты легко модифицируются. Если кому-то нужны красивые таблички с
отчетами, то для них можно накатать Perl/Html генератор. 
------ 
Добавлено. 
Скрипт firewall'а отличается от того, что был изначально выложен на
u-antona.vrn.ru. Добавлено: 
1) "#iptables -A OUTPUT -p all -s $CARD_MASK -d $CARD_MASK -j ACCEPT" 
Может потребоваться только если нужно разрешить сетевухе отправлять
запросы самой себе. Поэтому закомментировано. 
2) "iptables -A kill_all -j LOG" Это строчка полезна, если нужно
просмотреть список "убитых" пакетов (т.е. тех, что сквозь файерволл не
прошли). Информацию о убитых пакетах можно прочитать, вызвав dmesg. Если
отсекать надо много, то лучше закомментировать эту строку, иначе
лог-файл может быстро вырасти. 

--- 
Возникавшие вопросы: 
Q: что нужно добавить к скрипту файрволла, чтобы асю разрешить? 
A.: (ответ не полный, просто "указатель направления") 
Либо тут: 
                                  Код:
                                     
                       PAID[0]="80.82.32.27/32" 
                       PAID[1]="80.82.32.11/32" 
                              PAID[2]="" 
                                    

Пробуем добавить объявление login.icq.com или его ip-адреса (лучше ip
адрес, так как иначе при запуске скрипт может обломаться из-за
невозможности разрешить DNS - если интернет выключен) 
По типу: 
                                  Код:
                                     
                       PAID[0]="80.82.32.27/32" 
                       PAID[1]="80.82.32.11/32" 
                       PAID[2]="64.12.200.89/32" 
                              PAID[3]="" 
                                    

Это разрешит все соединения с login.icq.com, на все порты. 

Либо после этого: 
                                  Код:
                                     
                                  i=0 
                     while [ "${PAID[$i]}" != "" ] 
                                  do 
         iptables -A INPUT -p all -s ${PAID[$i]} -j extern_in 
        iptables -A OUTPUT -p all -d ${PAID[$i]} -j extern_out 
                              i=$(($i+1)) 
                                 done 
                                    

Добавляем прямое объявление доступа к асе. Только нужно будет jump'ы
соответствующие добавить, чтобы траффик считался. По типу (не тестил,
проверяйте ): 
                                  Код:
                                     
                                  i=0 
                        ICQIP="64.12.200.89/32" 
                            ICQPORT="5190" 
   iptables -A INPUT -p all -s $ICQIP --sport $ICQPORT -j extern_in 
  iptables -A OUTPUT -p all -d $ICQIP --dport $ICQPORT -j extern_out 
                                    

Это разрешит соединения ТОЛЬКО с портом 5190 на login.icq.com (адрес
взял nslookup'ом). 
Если не пашет, надо порыть, к чему ещё ася коннектится (и в какую
сторону с каким портом) и открыть доступ аналогичным методом. 

Да, и чуть не забыл. Скрипт предоставляется "как есть", без гарантий, и
может быть распространен на базе GPL с соблюдением исходного авторства. 

По вопросам установки в специфический дистрибутив лезем либо в
документацию, либо в гугл





Reply to: