Инсталляция и настройка HTTP-Proxy Squid под FreeBSD


Задачами HTTP-Proxy (посредника HTTP-запросов) являются:
Уменьшение трафика (загрузки канала) за счет кэширования повторных обращений нескольких машин к одной Web-странице (кэшируются HTTP и FTP); это ускоряет доступ в Internet за счет отказа от повторной загрузки ранее загруженных страниц, а также позволяет снизить плату за пользование Internet, если провайдер берет оплату за количество перекачанных данных. Возможны варианты как с явным указанием Proxy-сервера на клиентах, так и прозрачное (transparent) перенаправление на Squid запросов, проходящих через маршрутизатор.
Детальный контроль над доступом пользователей в Internet с возможностью разрешать/запрещать доступ не к сервису на указанной машине, а к отдельным Web-страницам:
запрет пользователям доступа к страницам, не имеющим отношения к тем задачам, ради которых им предоставляется доступ в Internet - это чаты, порнография и т.п.
запрет загрузки баннеров, счетчиков и другой лабуды;
ограничение скорости закачки по группам страниц, клиентов и т.п.
Первые две операции позволяют экономить как трафик, так и рабочее время сотрудников (в первом случае за счет удаления отвлекающего фактора, во втором - за счет ускорения загрузки и отрисовки страниц). Ограничение скорости позволяет предотвратить узурпирование канала низкоприоритетным трафиком.
Предоставление доступа к WWW машинам с Intranet-номерами в тех случаях, когда провайдер выдал недостаточное количество IP-номеров (впрочем, с этой задачай гораздо более универсально справляется NAT/Masquerading, но остаются первые две задачи).
Ускорение доступа к WWW-серверу, установленному на нашей территории, а также распределение нагрузки на несколько WWW-серверов.

Как установить и запустить

Я не сторонник самостоятельной компиляции программ (за исключением случаев, когда требуются какие-либо отключенные в заранее скомпилированном пакете функции), поэтому беру Squid из состава packages; этот путь я рекомендую для всех начинающих администраторов. Добавление Squid в систему стандартно:
pkg_add squid-2.4_6.tgz
При этом в директорию /usr/local/etc/rc.d распакуется файл squid.sh, который при перезагрузке машины будет запускать Squid в режиме демона. Но сразу после установки Squid работать не будет - его надо "довести до ума".

Если попытаться запустить Squid сразу после инсталляции, он сообщит, что его надо запустить с ключем -z для создания структуры директорий, где он будет хранить свой кэш (ранее скачанные Web-страницы, каждая в отдельном файле), но делать это сразу не стОит - дело в том, что по умолчанию Squid хранит свой кэш в /usr/local/squid/cache, отведя под него 100 мегабайт. Если мы правильно разбили диск при инсталляции FreeBSD, у нас имеется отдельный асинхронно смонтированный раздел /cache. В этом случае закомментаренную строку
#cache_dir ufs /usr/local/squid/cache 100 16 256
надо заменить на
cache_dir ufs /cache размер 16 256
где размер должен быть порядка трех четвертей от размера раздела (переполнение этого раздела крайне нежелательно, а его можно использовать под хранение временных файлов). Числа 16 и 256 означают, что в директории /cache будет создано 16 директорий, и в каждой - еще 256 директорий (вообще-то это тоже надо настраивать в зависимости от размера кэша и среднего размера кэшированного файла, но я не готов говорить об этом). После этого можно запускать 'squid -z', но я советую сначала настроить другие параметры.

Параметр store_avg_object_size по умолчанию имеет размер 13 KB. Прежде всего, надо рассказать о том, как Squid использует этот параметр при работе с кэшем.
Кэшируемый объект идентифицируется своим URL и хранится в файле, имя которого получается из URL hash-функцией. Это такая функция, похожая на генератор псевдослучайных чисел, равномерно распределенных в заданном диапазоне. Для ведения соответствия URL хранимых Web-страниц и имен файлов в кэше заводится специальная таблица (файл /cache/swap.state), размер которой должен позволять хранить записи фиксированного размера для каждой страницы в кэше. Если таблица имеет некоторый запас (порядка 5%), то при большом количестве хранимых записей (порядка миллиона) hash-метод позволяет отыскивать нужные данные существенно быстрее других методов, но по мере заполнения таблицы поиск существенно замедляется. (© Никлаус Вирт, "Алгоритмы и структуры данных", "Мир", 1989) Число хранимых объектов расчитывается как размер кэша, деленный на средний размер хранимого объекта.
Я уже имел проблемы, связанные со слишком большим store_avg_object_size, задаваемым по умолчанию; поэтому я рекомендую
store_avg_object_size 8 KB
Позднее можно будет оценить средний размер хранимого объекта по содержимому кэша (посчитать занимаемый объем и количество файлов); лучше принять его с некоторым запасом.

При выборе размера кэша следует учесть, что наиболее часто используемые данные он должен держать в памяти. На каждый объект, хранящийся в кэше, следует отвести примерно 200 байт оперативной памяти и указать этот объем
cache_mem N MB
где N расчитать как имеющаяся память за вычетом отведеной под работу ядра и других постоянно работающих программ (рекомендую воспользоваться программами 'top' и 'ps').

Если запустить Squid с данными настройками, он откажется пропускать кого-бы то ни было. Причины те же самые, что и в SendMail для закрытия свободного ralaying (пересылки почты с другой машины на третью) - администратор обязан сам указать множество машин, которые его сервер будет обслуживать. Дело в том, что у многих провайдеров различается цена внутреннего трафика, трафика по стране и заграничного трафика, а со временем такая политика будет распространяться все шире; поэтому реально появление злоумышленников, желающих свалить разницу в цене на кого-нибудь другого (все равно кого - лишь бы меньше платить самомУ).

Изначально в Squid мы имеем:

acl all src 0.0.0.0/0.0.0.0 acl manager proto cache_object
acl localhost src 127.0.0.1/255.255.255.255 acl SSL_ports port 443 563
acl Safe_ports port 80 21 443 563 70 210 1025-65535
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT

http_access allow manager localhost
http_access deny manager
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access deny all

(подробности об устройстве acl и http_access можно посмотреть прямо в squid.conf). Чтобы Squid пускал пользователей, надо прописать их IP-адресА в какой-нибудь ACL и предоставить доступ по этому списку.

Допустим, в нашей сетИ клиенты имеют только Intranet-адреса; в этом случае нам нужно

acl all src 0.0.0.0/0.0.0.0
acl manager proto cache_object
acl localhost src 127.0.0.1/255.255.255.255
acl SSL_ports port 443 563
acl Safe_ports port 80 21 443 563 70 210 1025-65535
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT

acl intranet src 10.0.0.0/255.0.0.0
acl intranet src 172.16.0.0/255.240.0.0
acl intranet src 192.168.0.0/255.255.0.0

http_access allow manager localhost
http_access deny manager
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports

http_access allow intranet

http_access deny all

(добавленные строки выделены). В случае использования других адресов (полученных от провайдера) для списка доступа лучше придумать другое имя.

Как работают правила доступа

Управление доступа производится двумя тэгами: acl (см.подробности в файле squid.conf и у Богомолова) и http_access.

Список доступа задается в виде
acl имя тип список_значений
Действует это таким образом:
Если в списке доступа указывается несколько значений или имеется несколько определений списков доступа с одним именем, то указанные в них значения объединяются.
Если в кавычках пишется имя файла, то список значений берется из этого файла (по одному значению в каждой строке).
Если перед регулярным выражением (regexp) указывается "-i", то оно нечувствительно к регистру букв (не уверен).
Регулярные выражения - те самые, которые используются в Sed/Grep/AWK.
Доменное имя клиента определяется по его IP-адресу через ReverceDNS; доменное имя сервера - берется из URL, если оно там есть, или определяется по IP-адресу, если в URL указывается IP-адрес.

Правила доступа выглядят так:
http_access разрешить_или_запретить списки_доступа
Правило доступа может указать одно из двух действий:
allow - разрешить;
deny - запретить.
Для сравнения: у ipfw их гораздо больше; например, есть переход к правилу с указанным номером (что-то типа оператора GOTO в языках программирования).
Правила доступа применяются последовательно, поэтому их порядок, в отличие от большинства других, очень существенен: для каждого запроса правила просматриваются последовательно до тех пор, пока запрос не попадет под действие какого-нибудь из них (первого встретившегося); после этого правило применяется (выполняется действие), на чем просмотр заканчивается. Это значит, что в списке правил сначала надо записывать частный случай, а потом более общий: например, если надо запретить доступ всем, кроме избранных, то надо сначала написать "разрешить избранным", а потом "запретить всем".
Если в каком-то правиле указано несколько ACL, то правило применяется если запрос попадает сразу во все ACL. Например,
acl net1 src 192.168.1.0/255.255.255.0
acl net2 src 192.168.2.0/255.255.255.0
http_access действие net1 net2

не будет иметь никакого действия, т.к. никакой IP-номер, от которого идет запрос, не может оказаться в двух непересекающихся IP-сетях (я сам совершал такую ошибку, потому и привожу ее как пример).
Если перед списком доступа указан "!", то это означает отрицание, т.е. правило действует если запрос не попадает в список доступа.


Регулярные выражения

Думаю, все сталкивались с wildchars в именах файлов:
"*" обозначает любой набор символов от пустой строки и длиннее (иногда из этого набора исключают точку - разделитель имени и расширения);
"?" обозначает любой символ в количестве одной штуки.
В Unix набор "масочных" символов гораздо шире, а кроме того, есть другие спец.символы, отвечающие за работу с переменными окружения, за запуск нескольких программ из одной командной строки и т.д.. Но в языке регулярных выражений есть свой набор спец.символов:
"." - точка обозначает любой символ в количестве одной штуки (то, что в шаблонах файлов делает "?").
"[...]" - набор символов, заключенный в квадратные скобки, обозначает любой из этих символов (только один); если два символа указаны через дефис(минус), то это обозначает любой символ из диапазона, заданного этими двумя символами. Если в число символов должен входить сам минус, его надо упомянуть первым или последним. Если первым символом внутри квадратных скобок идет "^", то это обозначает любой символ, не входящий в диапазон.
"" - бэкслеш превращает любой специальный символ в обычный, а обычный - в специальный. Чтобы указать сам бэкслеш, его пишут дважды - первый из них "экранинует" второго.
"^" - крышка в начале шаблона обозначает начало строкИ; в противном случае удовлетворяющая шаблону часть строки ищется в любом ее месте.
"$" - доллар в конце шаблона обозначает конец строкИ.
"(...)" - скобки объединяют заключенные в них символы в группу.
"(...|...)" - пайп обозначает, что требуется присутствие одного из разделяемых им слов (пайпом м.б. сколько угодно). Если все слова содержат только одну букву, лучше воспользоваться квадратными скобками.
Повторители:
"{M,N}" - обозначает, что предыдущий символ или группа символов может повторяться от M до N раз. Если M отсутствует, M=0; если N отсутствует, N=бесконечности.
"*" - звездочка обозначает, что предыдущий символ или группа символов может повторяться ноль или более раз ("{0,}").
"+" - плюс обозначает, что предыдущий символ или группа символов может повторяться один или более раз ("{1,}").
"?" - вопр.знак обозначает, что предыдущий символ или группа символов может повторяться ноль или один раз (т.е. может быть или не быть - "{0,1}").


О построении URL

Мало кто задумывался о том, какие части могут присутствовать в URL. Привожу их список (вероятно, неполный):
протокол:// - обычно http:// или ftp://.
юзер@ или юзер:пароль@ - имя юзера и пароль.
доменое_имя - как строится доменное имя, см.статью про DNS; вкратце: доменное имя может содержать буквы (нечувствительно к регистру), цифры и минус.
:порт - порт (при отсутствии определяется протоколом).
/путь_к_файлу - директории в пути разделяются слэшем; при использовании OS, отличной от Unix, Web-сервер обязан преобразовывать путь_к_файлу в стандарт серверной OS, а при доступе по FTP браузер (или другой клиент) должен сам делать команды 'cd директория'.
?аргументы - параметры запуска CGI-скрипта методом GET. параметры записываются в виде имя=значение, параметры заделяются знаком "&" (амперсенд).
#смещение - вызывает прокрутку до якоря(метки) "<A NAME="смещение">".
Запрещаем чаты и порнографию

Для простоты ограничимся IP-сетью класса C 192.168.1.*, из которой можно выходить в WWW. В этом случае в squid.conf в те же места, которые были выделены в предыдущем примере, пишем

acl intranet src 192.168.1.0/255.255.255.0
acl denylist url_regex "/etc/squid/denylist"

http_access deny denylist
http_access allow intranet

(напоминаю - порядок следования http_access существенен).


Содержимое файла denylist зависит от фантазии администратора и настойчивости юзеров. :-) Вот мой собственный список, а здесь - общие принципы:
Чаты:


^http://[^/]*chat(.[^./]+){2,}/.*
^http://[^/]*citychat.ru/.*
Многие популярные системы имеют WebChat-сайты: chat.chat.ru, chat.rambler.ruи т.д.; отличительным признаком URL является "chat" в третьем сегменте доменного имени (предполагается, что перед "chat" м.б. еще домены типа "www", а также имя юзера с паролем). Для того, чтобы накрыть имя юзера, пароль и префиксные сегменты доменного имени, я указываю "([^/]+[.@])?" - "любые символы, кроме слеша - один или более (т.к. слеш является признаком перехода к пути_к_файлу)"; затем "разделитель - собака или точка"; и все это может быть, а может и не быть (вопрос - "ноль или один раз").

Порнография:

Подавляющее большинство порносайтов содержат в доменном имени и/или в пути к файлу определенные слова - "porno", "udult", "xxx" и т.п.. Однако, такое слово может содержать и обычный сайт, в т.ч. и посвященный проблеме ограниченя порнографии. Я выбрал такой компромисс:
Сайт признается порнографическим, если он содержит порнослово как сегмент доменного имени (т.е. "www.porno.com" считается порнографическим, а "www.antiporno.com" - нет); кроме того порнографическими считаются доменные имена, в которых перед порнословом стоит "best", "cool", "free", "hot", "lady" или "top".
Порнографическими признаются картинки GIF и JPEG, содержащие в доменном имени и/или в пути к файлу порнослово. Обычные сайты будут приемлимо смотреться даже без такой картинки, а порносайт потеряет всю свою привлекательность.



Для борьбы с порнографией я побродил немного по порносайтам и нашел там достаточно много линков, чтобы составить большой список.
Баннеры:

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

Обновлено: 13.03.2015