Большой Воронежский Форум
» UNIX и дериваты>Учет траффика для "Домолинк" под Slackware 11
ErV 14:43 22.03.2007
Подскажите, пожалуйста, как лучше реализовать учет внешнего/внутреннего траффика в "Домолинке" под Slackware Linux 11. Желателен параллельный подсчет внешнего/внутреннего траффика (два и больше счетчиков) и разбиение его по дням/месяцам с возможностью вручную накинуть. Хотелось бы, чтобы сам "учетчик" мог работать без иксов, но давал возможность запустить реал-тайм график в иксах (по типу, как BW Meter) и получить какую-то статистику в консоли.
Уже смотрел iptraf, ipac-ng, но они делают не совсем то, что нужно - iptraf дает применить только один фильтер за раз и больше одного экземпляра на интерфейс повесить нельзя;а ipac-ng не позволяет (как я понял) исключить какой-то диапазон по маске из фильтра. Список софта для подсчета траффика (на opennet.ru) я тоже видел, но он довольно большой и больше нацелен на провайдеров...
Lampus 18:43 22.03.2007
Копай в сторону stargazer, если нужно что-то действительно мощное и куча гемороя то Netup UTM5 тебе в руки. Но если юзверей меньше 20 даже не заморачивайся.
ErV 19:41 22.03.2007

Сообщение от Lampus:
Копай в сторону stargazer, если нужно что-то действительно мощное и куча гемороя то Netup UTM5 тебе в руки. Но если юзверей меньше 20 даже не заморачивайся.

Юзверь один - это я .
Вообще мне нужно аналог учета, который позволяет делать BW Meter (по описанию с торрентов - двойной учет локального и внешнего траффика). Т.е. просто нужно следующее:
1) два счетчика - для внешнего и для внутреннего входящего траффика.
2) возможность вызвать статистику в графическом виде, которая будет в реалтайме обновляться. (т.е. чтобы я мог посмотреть скорость обмена данных в данный момент, как в виндовских DU/BW Meter)
3) нужна статистика по месяцам/неделям/дням/часам с возможностью её докинуть вручную.
4) нужна возможность поставить какой-нибудь алерт, который бы отрубал внешний интернет или отключал машину, или писал предупреждение, если дневная норма была превышена.
5) Прога должна стартовать без иксов, чтобы её можно было в момент инициализации системы запустить и больше не беспокаится.

Грубо говоря, нужен аналог BWMeter под линукс, с возможностью работать без GUI...

Геморрой не нужен, нужно просто, чтобы можно было легко настроить один раз и чтобы "оно" потом работало и считало...
dalex 20:29 22.03.2007
www.netams.com
ErV 21:48 22.03.2007
Простите, но нужно что-то проще. Сети у меня нету, толпы юзверей тоже, и комп не является роутером.... не хотелось бы опять свою программу для этого писАть..
ErV 01:35 31.03.2007
Разобрался с iptables. Остальные компоненты (график и статистику) можно на коленке собрать. Вопрос закрыт.
Mark5 12:59 03.04.2007
ErV, соберешь - дашь поюзать?
ErV 06:34 09.04.2007

Сообщение от Mark5:
ErV, соберешь - дашь поюзать?

Графика пока нет, собрал статистику (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.192.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 DROP
iptables -A total_all -j RETURN

iptables -A total_in -j total_all
iptables -A total_out -j total_all
iptables -A local_in -j local_all
iptables -A local_out -j local_all
iptables -A extern_in -j extern_all
iptables -A extern_out -j extern_all
iptables -A kill_in -j kill_all
iptables -A kill_out -j 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 -s $ROUTER -d $CARD_MASK -j ACCEPT
iptables -A OUTPUT -s $CARD_MASK -d $ROUTER -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 ([email protected])

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=`cat $1`
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 <
[email protected]>
# 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 генератор.

P.S. Блин, почем тегов [fixed],[src] и [code] тут нету? Форматирование не сохранилось...
Вверх