FreeBSD+ipfw+Squid+SquidGuard+… часть 6

И вот наконец мы добрались до того, ради чего, собственно говоря, всё и затевалось. Для начала устанавливаем из портов прокси сервер Squid. У меня использована стабильная версия 2.6 и именно ей посвящено дальнейшее описание...

Squid + SquidGuard +…

И вот наконец мы добрались до того, ради чего, собственно говоря, всё и затевалось.

Идея системы фильтрации и значительная часть ее реализации позаимствована из статьи Андрея Бешкова «Система фильтрации интернет траффика на основе squidGuard + Apache + Squid + Berkeley DB». К ней я и отсылаю интересующихся обоснованиями выбора именно такой системы. Здесь же рассмотрим только ее практическую реализацию.

Squid

Для начала устанавливаем из портов прокси сервер Squid. У меня использована стабильная версия 2.6 и именно ей посвящено дальнейшее описание. Версию 2.5 (также имеющуюся в портах) не рекомендую, т.к. там несколько более запутанная настройка. С новой 3.0 не экспериментировал, потому не могу гарантировать, что вся система будет работать без изменений в настройках. Итак…

# cd /usr/ports/www/squid26

# make install

По окончании установки редактируем конфигурационный файл:

# ee /usr/local/etc/squid/squid.conf

У меня он выглядит вот так (естественно, здесь отсутствует множество строк комментариев — этот файл, как это обычно и бывает в мире *nix, содержит внутри себя подробную документацию):

# Минимальные рекомендуемые права:
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 to_localhost dst 127.0.0.0/8
acl SSL_ports port 443 563      # ssl
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443 563     # https
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
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
# Разрешаем управление только с localhost
http_access allow manager localhost
http_access deny manager
# Запрещаем запросы к неизвестным портам
http_access deny !Safe_ports
# Запрещаем запрос CONNECT к чему-либо кроме портов SSL
http_access deny CONNECT !SSL_ports
# Открываем доступ к Squid всем, поскольку управлять
# доступом у нас уже будет SquidGuard. Так что двойная
# проверка ни к чему
http_access allow all
#
# Дальше идет очень важная строка. Именно тут отличие от
# предыдущих версий Squid. «прозрачный» прокси
# теперь включается гораздо проще — указанием
# параметра transparent
# Обрабатываем запросы на порт 3128 localhost
http_port 127.0.0.1:3128 transparent
#
# Что не должно кэшироваться. Просто рекомендованный
# разработчиками вариант:
hierarchy_stoplist cgi-bin ?
acl QUERY urlpath_regex cgi-bin \?
cache deny QUERY
# Размер оперативной памяти, отводимой под кэш
cache_mem 64 MB
# Каталог, где будет находиться кэш
# Число 4000 - размер кэша в мегабайтах, должен
# быть, как минимум, на 20% меньше свободного пространства
# в разделе диска
cache_dir ufs /usr/local/squid/cache 4000 16 256
# Количество старых лог-файлов, которые нужно хранить
# (по умолчанию 10, по-моему, даже 5 — много)
logfile_rotate 5
# То, что будет подставляться в качестве пароля при
# анонимном доступе к FTP-серверам
ftp_user vasja@pupkin.ru
# Если пользователь прервал загрузку, когда скачано
# не менее 70% файла, завершить его загрузку в кэш
quick_abort_pct 70
# Время жизни запросов, завершившихся ошибкой (напр., 404)
negative_ttl 1 minutes
# локальное имя или e-mail оператора, которому придет
# сообщение в случае аварии прокси (в нашем примере, admin)
cache_mgr admin
# Чтобы видеть сообщения об ошибках по-русски:
error_directory /usr/local/etc/squid/errors/Russian-koi8-r
# Не включать IP адрес клиента в заголовок запроса:
forwarded_for off
# Разрешаем управлять кэшем с помощью cachemgr.cgi
# В качестве пароля установим слово «secret»
cachemgr_passwd secret all
# Squid будет запускаться от имени пользователя squid
# и группы squid (это нам еще понадобится)
cache_effective_user squid
cache_effective_group squid
# Для поддержки клиентов, нестандартно закрывающих соединение
half_closed_clients on

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

Далее мы должны создать каталоги для кэша и лог-файлов, а затем сделать так, чтобы их «владельцем» стал именно тот пользователь, от имени которого будет выполняться Squid (в нашем примере его зовут squid — см. конфигурационный файл выше):

# mkdir /usr/local/squid/cache

# mkdir /usr/local/squid/logs

# chown -R squid:squid /usr/local/squid/cache /usr/local/squid/logs

Впоследствие могут пригодится и некоторые другие ключи для запуска Squid

  • -d выводить на устройство stderr отладочную информацию
  • -f <имя_файла> запуск с другим файлом конфигурации
  • -h вывод справки
  • -k reconfigure отправка сигнала HUP (чтобы файл конфигурации был повторно прочитан; обычно используется после его изменений)
  • -k shutdown «вежливое» выключение
  • -k interrupt выключение, сразу разрывающее текущие соединения
  • -k kill принудительное прерывание работы
  • -v вывод информации о версии и ключах компиляции Squid
  • -X отладочный режим для разборки конфигурационного файла
  • -F ускоренное перестроение кэша после сбоя (но на время перестроения запросы не обслуживаются)

Далее необходимо создать в каталоге cache иерархию каталогов кэша (в соответствии с записью в конфигурационном файле там должно быть 16 каталогов, в каждом из которых — по 16 подкаталогов). Конечно, мы не будем делать это вручную. Воспользуемся самим Squid’ом:

# /usr/local/sbin/squid -z

Готово. Теперь можем запустить прокси-сервер в работу.

# /usr/local/sbin/squid -D

Ключ -D обозначает, что нам пока не нужно, чтобы Squid при запуске проверял работоспособность DNS-серверов (сейчас важно убедиться в работоспособности самого прокси).

Во время запуска на другой консоли (если мы работаем за компьютером непосредственно, консоли переключаются клавишами Alt+Fn, где n — номер консоли) или в другом терминальном окне (если работаем через SSH) наблюдаем за сообщениями, появляющимися в файле протокола:

# tail -f /var/log/messages

Вообще команда tail предназначена для вывода нескольких (по умолчанию, десяти) последних строк файла. Но добавление ключа -f <имя_файла> превращает ее в средство отслеживания добавляющихся в файл строк. Чтобы прервать ее работу в этом случае используют сочетание клавиш Ctrl+C.

Если всё сделано правильно, ошибок там не появится. А когда мы увидим что-то похожее на

Jul 9 11:22:49 sch415 squid[3792]: Squid Parent: child process 3794 started,

значит, Squid заработал. Можем попробовать позаходить на разные сайты с компьютеров локальной сети, а затем посмотреть файлы протоколов (они у нас, напомню, в /usr/local/squid/logs).

Apache

Вообще-то, Apache — очень совершенный http-сервер (на таких «живет» большая часть Интернет). Но у нас он будет подменять те сервера, которые мы, по той или иной причине, решили от пользователей закрыть. Как мы уже поступали со многими программами, установим сервер из портов:

# cd /usr/ports/www/apache13

# make install

Заметьте, мы устанавливаем версию 1.3, хотя в портах есть и 2.*. Эти версии существенно отличаются.

Запускаем Apache:

# /usr/local/apache/bin/apachectl start

Создаем каталог, в котором будут лежать файлы-подменки:

# mkdir /usr/local/apache/htdocs/replace

Помещаем туда (любым возможным способом: загрузкой с помощью links, копированием и т.п.) файлы 1x1.gif (он будет передаваться клиентам вместо баннеров), my.mp3 (маленький огрызок мелодии, который получит каждый желающий загрузить музыку), возможно, еще какие-либо картинки и т.п.

В каталог /usr/local/apache/cgi-bin помещаем специальный сценарий на perl — block.cgi. Он будет выводить сообщение при попытке посетить запрещенную страницу. Можно использовать либо оригинальный squidGuard.cgi.in из пакета SquidGuard, но лучше взять переведенный Андреем Бешковым. Чтобы скрипт смог работать, ему нужно выставить соответствующие права:

# chown nobody:wheel /usr/local/apache/cgi-bin/block.cgi

# chmod 500 /usr/local/apache/cgi-bin/block.cgi

Berkeley DB

Для работы SquidGuard необходима база данных, где будут храниться запреты. В этом качестве используется Berkeley DB. А она, в свою очередь, использует библиотеку libtool. На момент написания статьи ее актуальная версия — 1.5.26. Установка обычным способом из портов у меня не сработала (да, ошибки встречаются везде), потому пришлось загрузить архив с сайта (нужно воспользоваться ссылкой «Download this directory in tarball»), распаковать его и полностью выполнить процедуру сборки и инсталляции.

# tar zxvf libtool15.tar.gz

# cd libtool15

# make

(после этой команды будет выполнена загрузка исходников, которая может занять достаточное время при медленном канале, а затем компиляция)

# make install

При выполнении дух последних команд смотрим внимательно на появляющиеся сообщения, если что-то происходит не так, наиболее важная информация для понимания причин неприятности будет в последних строчках.

После установки libtool займемся Berkeley DB. Тут процесс будет заметно более сложным. Для начала нам нужно загрузить исходный код и два патча. Внимание! Нужна версия 3.2.9. Я не перепроверял, но по данным Андрея Бешкова только она может быть успешно собрана под FreeBSD. Распаковываем архив исходников, копируем в него оба патча и применяем их по очереди:

# tar zxvf db-3.2.9.tar.gz

# cp patch.3.2.9.1 patch.3.2.9.2 ./db-3.2.9

# cd db-3.2.9

# patch -p0 < patch.3.2.9.1

# patch -p0 < patch.3.2.9.2

А дальше — компилируем и устанавливаем:

# cd build_unix

# ../dist/configure

# make

# make install

SquidGuard

Ну, вот дело дошло и до последнего компонента нашей системы — редиректора SquidGuard. Его мы, как и предыдущие программы, соберем из исходников. Начнем с их загрузки с www.squidguard.org. Затем распакуем, скомпилируем и установим:

# tar zxvf squidGuard-1.3.tar.gz

# cd squidGuard-1.3

# ./configure --prefix=/usr/local/squidGuard \

--with-db=/usr/local/BerkeleyDB.3.2 \

—with-sg-config=/usr/local/squidGuard/squidGuard.conf \

—with-sg-logdir=/usr/local/squidGuard/log \

--with-sg-dbhome=/usr/local/squidGuard/db

# make

# make test

# make install

Обратите внимание на «страшную» команду configure (эти несколько строк именно одна команда). В ней мы указали: 1) куда будет установлен SquidGuard; 2) где находится библиотека BercleyDB; 3) где будет лежать файл конфигурации программы; 4) куда будут записываться файлы протоколов и 5) где будет база данных блокируемых сайтов. Естественно, ошибиться при вводе этой команды крайне нежелательно.

Создаем каталог для протоколов:

# mkdir /usr/local/squidGuard/log

Теперь нам нужен список «нехороших» сайтов. В сети есть несколько источников таких списков. Я воспользовался помощью наших американских коллег. Загружаем список. Распакуем его и перенесем в каталог, заданный при конфигурации:

# tar zxvf blacklists.tgz -C /usr/local/squidGuard

# mv /usr/local/squidGuard/blacklists /usr/local/squidGuard/db

В появившихся подкаталогах будут находиться файлы domains (домены, блокируемые целиком), urls (если нужно блокировать страницу, а не весь домен) и expression (регулярные выражения, определяющие, какие подстроки запрещены в url).

Категории блокируемых сайтов
База Комментарии
ads реклама
adult сайты для взрослых
aggressive агрессия
audio-video музыка и видео
forums форумы
drugs наркотики
gambling азартные игры
hacking хакерство
local-block сайты заблокированные местным админом
local-ok сайты разрешенные местным админом
mail бесплатные почтовые сервера
porn порнография
proxy общедоступные прокси сервера
publicite опять реклама
redirector анонимные прокси сервера
violence насилие
warez пиратское програмное обеспечение

К этой базе добавим еще базу баннеров (banners).

Теперь нам необходимо настроить SquidGuard. Создаем файл squidGuard.conf

# ee /usr/local/squidGuard/squidGuard.conf

Выглядеть он может примерно так:

# куда записывать протоколы:
logdir /usr/local/squidGuard/log
# где находится база данных:
dbhome /usr/local/squidGuard/db
#
# Дальше описываем диапазоны адресов для разных групп пользователей
# === ИТ инфраструктура
src it-computers {
ip 10.0.1.1, 10.0.1.100, 10.0.1.210
}
# === Компьютерные классы
src nachalka {
ip 10.0.1.50-10.0.1.56
}
src r33 {
ip 10.0.1.211-10.0.1.222
}
src books {
ip 10.0.1.101-10.0.1.113
}
# === Библиотека
src library {
ip 10.0.1.238
}
# === Работники школы
src staff {
10.0.1.231-10.0.1.254
}
# =============

# При попытке загрузить запрещенные типы файлов подменяем их:
rewrite media {
s@.*\.mp3$@http://10.0.1.1/replace/my.mp3@r
s@.*\.swf$@http://10.0.1.1/replace/noflash.jpg@r
s@.*\.flv$@http://10.0.1.1/replace/noflash.jpg@r
s@.*\.wmv$@http://10.0.1.1/replace/stop300.gif@r
s@.*\.mov$@http://10.0.1.1/replace/stop300.gif@r
s@.*\.exe$@http://10.0.1.1/replace/stop300.gif@r
log rewr
}

# Теперь отметим, какие базы и как будут использоваться
# Порнографию просто отрубаем с записью в протокол
dest porn {
domainlist porn/domains
urllist porn/urls
log porn
}
# рекламные картинки и баннеры заменяем на 1-пиксельный GIF
dest ads {
domainlist ads/domains
urllist ads/urls
log ads
redirect http://10.0.1.1/replace/1x1.gif
}
dest banners {
domainlist banners/domains
urllist banners/urls
# expressionlist banners/expressions
log banners
redirect http://10.0.1.1/replace/1x1.gif
}
# Сайты и страницы, не требующие проверки
dest local-ok {
domainlist local-ok/domains
urllist local-ok/urls
}
# Сайты, добавленные к базе (из Америки видно не всё ;-))
dest local-block {
domainlist local-block/domains
urllist local-block/urls
log local-block
redirect http://10.0.1.1/cgi-bin/block.cgi?clientaddr=%a&clientname=%n
&clientident=%i&clientgroup=%s&targetgroup=%t&url=%u
}

# Теперь распределяем, каким группам пользователей что можно
acl {
	# пропускать все, кроме рекламы:
	it-computers {
	pass local-ok !banners !ads all
	}
	# в компьютерных классах ограничений больше всего:
	nachalka {
	pass local-ok !porn !banners !ads !local-block all
	rewrite media
	}
	r33 {
	pass local-ok !porn !banners !ads !local-block all
	rewrite media
	}
	# а здесь разрешим загружать музыку и т.п.
	books {
	pass local-ok !porn !banners !ads !local-block all
	}
	library {
	pass local-ok !porn !banners !ads !local-block all
	}
	staff {
	pass local-ok !porn !banners !ads !local-block all
	}
	# с компьютеров, не входящих в группы, доступ к Интернет закрыт:
	default {
	pass none
	redirect http://10.0.1.1/cgi-bin/block.cgi?clientaddr=%a
	&clientname=%n&clientident=%i&clientgroup=%s&targetgroup=%t&url=%u
	log default
	}
}
# === end of acl

Установим права на служебные файлы и каталоги (сделаем их владельцем пользователя, от имени которого будет работать SquidGuard):

# chown -R nobody /usr/local/squidGuard/log /usr/local/squidGuard/db

# chown nobody /usr/local/squidGuard/squidGuard.conf

Чтобы SquidGuard не строил при каждом запуске базы данных в оперативной памяти, напишем сценарий, который построит их (сохранив на диске) и перезапустит Squid (и с ним SquidGuard):

# ee /usr/local/squidGuard/bin/rebuild_base.sh

#!/bin/sh
/usr/local/squidGuard/bin/squidGuard -C all
chown -R squid /usr/local/squidGuard/db
/usr/bin/killall -HUP squid

Установим необходимые права (этот сценарий должен иметь право запускать только root, а остальным с ним вообще ничего делать нельзя), а затем запустим его:

# chmod 100 /usr/local/squidGuard/bin/rebuild_base.sh

# /usr/local/squidGuard/bin/rebuild_base.sh

Теперь ждем, когда задача будет завершена. Процесс не слишком быстрый. Затем протестируем работу SquidGuard. Воспользуемся написанной опять же Андреем Бешковым маленькой тестовой программкой на Перле. Загружаем архив, распаковываем его и помещаем полученный файл test.pl в каталог /usr/local/squidGuard/bin. Устанавливаем ему разрешение на исполнение, запускаем и вводим тестируемый IP-адрес. В файле result.txt смотрим результат. (Там, где результат — пустая строка, сайт будет доступен, во всех остальных случаях показана строка, на которую произойдет перенаправление Squid’а) Набор сайтов можно поменять, отредактировав сценарий. Если результаты теста нас удовлетворили, подключим SquidGuard к Squid. Для этого в файл /usr/local/etc/squid/squid.conf добавим следующие строки:

# если не отвечает ни один экземпляр SquidGuard, работать напрямую
redirector_bypass on
# где находится SquidGuard
redirect_program /usr/local/squidGuard/bin/squidGuard
# сколько экземпляров SquidGuard запускать
redirect_children 10
#

Перезапускаем Squid (а редиректоры он уже [пере]запустит сам):

# killall -HUP squid

Если после этого в конце файла протокола /usr/local/squidGuard/log/squidGuard.log появились строки, подобные:

2008-07-10 14:57:54 [1285] squidGuard 1.2.0 started (1215687474.577)

2008-07-10 14:57:54 [1285] squidGuard ready for requests (1215687474.645)

…значит все запустилось нормально. Теперь сделаем, чтобы наша система запускалась автоматически при загрузке компьютера. Для этого внесем два сценария в «стартовый каталог» FreeBSD rc.d:

# ee /usr/local/etc/rc.d/apache.sh

#!/bin/sh
/usr/local/apache/bin/apachectl start

# ee /usr/local/etc/rc.d/squid.sh

#!/bin/sh
/usr/local/sbin/squid -D

# chmod 100 /usr/local/etc/rc.d/apache.sh /usr/local/etc/rc.d/squid.sh

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

Для полного счастья админа школьной сети недостает только автоматического обновления баз блокируемых сайтов. Что делать?— естественно, писать сценарий. Базу надо скачать, распаковать, перенести в каталог баз данных SquidGuard, после чего запустить уже имеющийся сценарий перегенерации БД:

# ee /usr/local/squidGuard/bin/update_blacklist.sh

#!/bin/sh
/usr/local/bin/wget -q --cache=off \
'http://squidguard.mesd.k12.or.us/blacklists.tgz' \
-O /usr/local/squidGuard/update/blacklist.tgz
tar zxvf /usr/local/squidGuard/update/blacklist.tgz -C \
/usr/local/squidGuard/update/
cp -R -f /usr/local/squidGuard/update/blacklists/* /usr/local/squidGuard/db
rm -R /usr/local/squidGuard/update/blacklists
/usr/local/squidGuard/rebuid_base.sh

Устанавливаем права:

# chmod 100 /usr/local/squidGuard/bin/update_blacklist.sh

Создаем временный каталог для распаковки:

# mkdir /usr/local/squidGuard/update

И настраиваем планировщик cron на периодическое выполнение сценария обновления:

# crontab -e -u root

Запускаем редактирование (-e) таблицы периодических заданий пользователя (-u) root. Для просмотра таблицы нужно было бы использовать ключ -l.

Запустится указанный в настройках ОС текстовый редактор (по умолчанию это vi). С его помощью дополним файл примерно такой строкой:

1  15  *  *  5  /usr/local/squidGuard/bin/update_blacklist.sh

Она означает, что файл update_blacklist.sh должен запускаться каждую пятницу (5 день недели) в 15 часов 1 минуту. Правильнее было бы назначать обновление на ночное время (например, на 2 часа и сколько-то-там минут), но мы по правилам не можем оставлять компьютеры включенными на ночь.

vi — редактор с непривычным для людей не из мира *nix интерфейсом. Для выхода из него нужно сделать следующее:

— нажимаем Esc — редактор переходит в командный режим

— нажимаем : (двоеточие, оно появится в нижней строке экрана) — редактор переходит в расширенный режим

— набираем wq<Enter> — файл сохраняется и завершается работа с редактором.

Вот, собственно говоря, и всё. Два учебных года — полёт нормальный. Помимо добавления нескольких адресов в список запрета, никаких дополнительных телодвижений. Утром щелкнул выключателем, вечером — shutdown -h now. Бывало, в нарушение правил, машинка (P-II/333MHz/256M) работала по несколько суток не выключаясь.


PS Заметка была написана почти два года назад. С тех пор система умудрилась проработать полтора года практически без участия человека (и почти без выключения). Единственная поломка — выход из строя… одной из сетевых карт.