>Сказав "А" скажи и "Бэ" :) Раз уж начал выкладывай тему целиком,
>в принципе интересный вариант, есть вероятность что комуто пригодится, так как
>вопросов на эту тему среди админов достаточно.
угумс, говорю "Б" ->
Еще раз скажу что ЭТОТ вариант не очень хорош тем что он не в реалтайме работает, т.е. если юзверь в течении дня превысит свой лимит, то залочится он на следующий день, но это не страшно - можно просто излтшек перенсьти на следующий месяц(неделю или год... как пожелаете). У меня есть и реалтамовская наработка когда SQUID пайпится на прогу, которая уже смотрит лимит и в случае превышения или по внешней команде блокирует IP используя файрвол, но это я в следующей теме опишу.
ну следуем далее...
Упростим задачу а заодно и сделаем более гибко. Таблицу GROUPS нафиг удаляем а в табличку USERZ добавим поле LIMIT - у каждого IP свой лимит будет.
для того, шобы обновить данные в нашей базе - необхдимо перелопатить squid.log а заодно и запаковать его. Я написал скрипт на перле, который стартует в 00:05 каждые сутки.
алгоритм скриптика следующий:
1. стопаем squid;
2. упаковываем и удаляем access.log;
3. читаем в массив либо напрямую из файла построчно, лучше в массив - больше возможностей над данными поиздеваться;
4. подсчитываем на каждый IP набежавший за день траффик;
5. обновляем данные в таблицах базы;
6. на основе данных таблицы USERZ формируем файл со списком непревысивших свой лимит;
7. запускаем squid;
а вот и сам скрипт:
#!/usr/bin/perl -w
#squidloger.pl
use Mysql;
my $prev_date=`date -v-1d '+%Y%m%d'`;#День вчерашний
chomp($prev_date);
`/usr/local/squid/logs/squidlog_rotate.sh`;
#у меня шеловский скрипт внешний, который bzip-ует файл и дает ему имя #вчерашняя_датаaccess.log.bz2
my $database_name="squid_stat2";
my $log_path='/usr/local/squid/logs/';
my $fn1=$log_path.$yt_d.'access.log.bz2';
my $dbh=Mysql->Connect("",$database_name) || die "Cannot connect to Mysql:$database_name : $!\n";
my @DAT=`bzcat '$fn1'`;#Читаем из запакованного файла access.log в массив
my %userz=();#hash - в него будем считать
foreach (@DAT){
chomp;
if (/(\d{10})\.\d{3}\s+\d+\s\d+\.\d+\.\d+\.(\d+)\s.+\/\d+\s(\d+)\s\w+\s(.+)\s-.+/)
{
$userz{$2}+=$3;
#В $2 - IPшник в $3 кол-во байт
#пробегаемся по массиву и суммируем в HASHе %userz чего кто накачал
};
};
$prev_mon=`date -v-1d '+%m'`;#Вчерашний месяц
chomp($prev_mon);
#Вот здесь начинаем бежать по хешу %userz
#и обновлять данные в табличке permon;
foreach (keys %userz) {
print ("$_\t$userz{$_}\n");
#Так просто вывожу на STDOUT чего кто за день накачал
#крон в почте мне пришлет
my $upd_query=sprintf("update permon,userz set permon.traff=permon.traff+%d where permon.clientip=%d and permon.mon=%d and userz.clientip=permon.clientip and userz.state;",$userz{$_},$_,$prev_mon);
#Перевожу на русский этот мутный запрос:
#инкрементируем в теблице PERMON значение поля TRAFF на кол-во закачанных за день байт
#только в тех записях, где PERMON.CLIETNIP=нужный нам IP, PERMON.MON=вчерашний
#месяц, USERZ.STATE=1
#Проверку USERZ.STATE я добавил потому что
#если USERZ.STATE=0 - значит это уже заблокированный IP и траффик на него
#можно не считать
$dbh->Query($upd_query);
};
$curmon=`date '+%m'`;#Текущий месяц
chomp($curmon);
if ($curmon>$yt_d) {
#Если $curmon>$prev_mon - значит новый месяц наступил и необходимо
#создать новые записи в PERMON для всех существующих в USERZ IP-шников
#на новый месяц и с нулевыми значениями TRAFF.
my $ins_query=sprintf("insert into permon select clientip,%d,0 from userz;",$curmon);
$dbh->Query($ins_query);
};
$upd_query=sprintf("update permon,userz set userz.state=(userz.tlimit>=permon.traff) where permon.clientip=userz.clientip and permon.mon=%d;",$curmon);
#обновляем таблицу USERZ
#если PERMON.TRAFF>USERZ.LIMIT и PERMON.MON=текущий_месяц - значит USERZ.STATE=0;
$dbh->Query($upd_query);
open (F, ">/usr/local/etc/squid/shtraff.txt");
#Формируем файл shtraff.txt
my $qr=$dbh->Query("select clientip from userz where state=1;");
#Выбираем из таблицы USERZ только тех, у кого STATE=1 - короче
#всех кто не заблокирован
while (@qline=$qr->FetchRow) {
print F "192.168.0.$qline[0]\n";
#... ну и пишем в файл
};
close F;