Squid + LightSquid +Perl = ограничение(квотирование) по трафику

Очередное решение на наболевшую тему.

Задача: имея squid с настроенной авторизацией пользователей и сбором статистики сделать ограничение на используемый трафик (квоты).

лично мне от sams пришлось отказаться т.к. он прикручивается к авторизации пользователей, а для меня это неприемлемо.

решение подойдет для тех, кому не сильно критично точное лимитирование. я сильно не хотел менять устоявшуюся систему авторизаци пользователей.

итак.

1. настраиваем сквид (статей много, описывать не буду)
В squid.conf , желательно перед остальными ACL, надо будет добавить следующее

####### блокировка юзеров которые превысили лимит (файл user-deny),
####### и разрешение этим юзерам доступ только к тем IP и сайтам, которые перечислены в файле no_quota_url.txt
acl no_quota url_regex -i "/etc/squid/no_quota_url.txt"
acl banusers proxy_auth_regex -i "/etc/squid/user_deny.txt"
http_access allow no_quota banusers allowedhost
deny_info ERR_QUOTA all
http_access deny banusers allowedhost all


по порядку что к чему с файлами:
no_quota_url.txt - ведется руками.
текст:

# файл содержит сайты, который открываются, даже если превышена квота и юзер попал в users_deny.txt
очень_нужный_домен.ru
icq.com
205.188.

user_deny.txt - в дальнейшем создастся сам, но без него перечитать настройки squid не получиться

# файл содержит юзеров превысивших квоту.
# автоматически переписывается скриптом traf_limit.pl
dolzhen_bit_odin_user
user1
user2

ERR_QUOTA создадим по образу и подобию всех остальных страниц с ошибками. Я поставил что-бы получать другой текст. вот так получилось :)

<HTML><HEAD><meta http-equiv="Content-Type" content="text/html; charset=koi8-r">
<TITLE>Превышен лимит</TITLE>
</HEAD><BODY>
<H1><font color="FF0000">ПРЕВЫШЕН ЛИМИТ</font></H1>
<H2>
</H2>
<HR>
<P>

Заблокированный URL:
<A HREF="%U">%U</A>
<P>

<UL>
<LI>
<STRONG>
Вы превысили месячный лимит на интеренет.

Если Вы считаете это неправильным, свяжитесь с отделом АСУ по телефонам 1013 или 1066
<font color="FFFFFF">ИБО НЕ"УЙ СТОЛЬКО КАЧАТЬ</font>
Если этот сайт необходим для работы, то он может быть открыт по служебной записке.
</STRONG>
<P>
</UL>
<P>С Уважением отдел АСУ.


allowedhost - мое правило проверки пользователей.

2. LightSquid абсолютно штатный. вот официальный сайт http://lightsquid.sourceforge.net/
ставится и настраивается минут 5-10. собственно вся настройка у меня заключалась в том, что-бы рассортировать юзеров по группам.
Для тех у кого еще есть http сервер дополнительно будет красивая статистика. ;)

3. в /etc/squid создадим папку traf_limit

4. в /etc/squid/traf_limit создаем два файла

traf_limit.pl

#!/usr/bin/perl
#
# Довесок на LightSquid Project (c) 2004-2005 Sergey Erokhin aka ESL
#
# Скрипт создает файлик user_deny для ограничения инета по трафику

# Автор: Иван Лонин loninia@apksouz.ru  2008 год.
use File::Basename;

# коряво конечно напрямую писать путь к конфигу, но лениво было sh файлик для крона делать :)
require "/etc/squid/traf_limit/config";

#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
@dat=localtime(time);
$year =1900+$dat[5];
$month=1 + $dat[4];
if ($month<10){
	$month="0".$month
}
$filter="$year$month";

#print "$log_path/$filter*\n";
@daylist=glob("$log_path/$filter*");

foreach $daypath (sort @daylist) {
	open FF,"<$daypath/.total";

	$totaluser=<FF>;chomp $totaluser;$totaluser=~s/^user: //;
	$totalsize=<FF>;chomp $totalsize;$totalsize=~s/^size: //;

	while (<FF>) {

		($user,$size,$hit)=split;
		$h{$user}{size}+=$size;
		$h{$user}{hit}+=$hit;
	}
	close FF;
}
#
$cummulative=0;
open RES,">$res_file";
print RES "# файл содержит юзеров превысивших квоту.\n# автоматически переписывается скриптом traf_limit.pl\ndolzhen_bit_odin_user\n";
foreach $user (sort {$h{$b}{size}<=>$h{$a}{size}} keys  %h) {

	$all4user=$h{$user}{size}/1024/1024;
	if ($vip_user{$user}{size} > 0) {
		$limit=$vip_user{$user}{size};
	}else{
		$limit=$all_limit;
	}

	if ($all4user >= $limit) {
		print RES "$user\n";
		# print "$h{$user}{size}\n";
	};

}
__END__


и файлик config

#!/usr/bin/perl
# конфигурационный файл для скрипта traf_limit.pl
#
# путь к логам lightsquid
$log_path="/www/lightsquid/report";

# файл в который пушутся пользователи превысившие лимит
$res_file="/etc/squid/user_deny.txt";

# лимит инета в мегабайтах
$all_limit=150;

# привилегированные пользователи с повышенным или пониженным лимитом
# для каждого пользователя строка формата:
#$vip_user{<имя_юзера>}{size}=<лимит_в_мегабайтах>;
$vip_user{user1}{size}=5;
$vip_user{qwe}{size}=50;


назначим файликам нужного владельца и права на запуск

5. осталось в только в cron добавить запуск. Я сделал раз в сутки в 5-00. делать вечером в 20 с чем нибудь категорически не рекомендую т.к. скрипт работает на текущую дату (первого числа будут использоваться прошломесячные данные)

делаем
crontab -e
и добавляем для скрипта строчку вида
45 04 * * * /etc/squid/traf_limit/traf_limit.pl

и для сквида.
0 05 * * * /etc/init.d/squid reload

Этот момент как выяснилось нужно объяснять. Дело в том, что Squid читает файлы конфигурации и все остальные кстати тоже, только при чтении конфигурации. Поэтому после отработки скрипта или изменении файла no_quota_url.txt  обязательно надо перечитать конфиг (рестарт не желателен из-за сброса кэша). Команда как не трудно догадаться /etc/init.d/squid reload :) .

собственно все :) . естественно, что правильно оно начнет работать только с 1 числа следующего за установкой месяца, если статистика до этого не собиралась.

Удачи.

Если есть вопросы пишите на loninia”сабака”apksouz.ru

Пока статья на opennet лежала еще кусочек родился

>А по ip адресу возможно тоже самое или только по юзерам работает
>лимитирование?

да, если у тебя нет авторизации, то статистика будет собираться по ip машин.
только с привилегированными пользователями затык скорее всего будет…
попробуй их назначать либо так

$vip_user{"192.168.0.123"}{size}=5;

либо так

$user1="192.168.0.123";
$vip_user{$user1}{size}=5;

первый вариант короче, второй 100% рабочий. :)

11 Комментариев

dagМарт 3, 2009 в 16:12

шедевра :)

Сергей ВолковМарт 19, 2009 в 09:28

поставил, все супер, пасип огромное

BoarswainAMDСентябрь 24, 2009 в 10:13

Подскажите пожалуйста, а как сделать, чтобы скрипт обнулялся ни раз в месяц, а раз в сутки?
Заранее огромное спасибо.

MossonСентябрь 24, 2009 в 10:44

2 BoarswainAMD доработать traf_limit.pl там немного букв и вроде как понятно все + постоянно squid reload (несколько секунд нет инета). Плохое решение ;) .
вообще задача поставлена некорректно, если надо суточное квотирование или реалтайм квотирование, тогда скорее всего разумнее копать sams. В начале статьи я про это писал.

AnhelФевраль 15, 2010 в 13:31

Спасибо за статью! Очень нужно квотирование, пытаюсь реализовать предложенный Вами вариант.
Но есть проблема: скопировал скрипт в точности, но появилась проблема:

#sh traf_limit.pl
use: not found
require: not found
traf_limit.pl: 14: Syntax error: word unexpected (expecting “)”)

где 14 строка соответствено: “@dat=localtime(time);”

ОС: FreeBSD 8.0.

AnhelФевраль 15, 2010 в 13:46

Если 14 строчку переношу выше к 15, то выходит это:

# sh traf_limit.pl
use: not found
require: not found
=1900+[5]: not found
=1: not found
traf_limit.pl: 16: Syntax error: “{” unexpected (expecting “then”)

AnhelФевраль 15, 2010 в 18:12

Ой, простите, это же скрипт с расширением .pl
он не запускался уменя только потому, что я не выставил права на запуск для владельца скрипта.
Скрипт работает исправно, С П А С И Б О !

0pexФевраль 22, 2010 в 11:36

=)

serega3333Март 13, 2010 в 21:08

Скрипт вроде работает, но IP адреса в документ не пишет.

DimkinИюль 14, 2010 в 23:16

всё он пишет, руки кривые у вас просто!:)

AnhelОктябрь 8, 2010 в 15:07

у меня первый вариант не работает, сработал второй -

$user1=”192.168.0.123″;
$vip_user{$user1}{size}=5;

спсибо!