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: