Поднимаем прозрачный прокси Squid на FreeBSD 13.0
Хочу поделиться информацией по поднятию прозрачного HTTP и HTTPS прокси сервера Squid с фильтрацией сайтов и без подмены сертификатов на FreeBSD 13.0 RELEASE. На Хабре уже есть похожая статья по настройке прозрачного прокси сервера Squid с фильтрацией ресурсов и без подмены сертификатов на Linux. Решил актуализировать информацию на свежо установленной ОС FreeBSD 13.0 и поделиться с вами.
При использовании действий «peek-and-splice», сквид выдергивает имя ресурса с помощью SNI и клиент дальше работает с ресурсом. Т.е. не происходит подмена сертификата. Этот режим подходит для нашего прозрачного прокси.
Ставить Squid мы будем из портов, так как необходимо включить некоторые параметры в сборку, также для заворачивания трафика на порт прокси мы будем использовать пакетный фильтр PF.
Для начала скачиваем порты:
portsnap fetch extract
Если порты уже установлены в системе (/usr/ports), то выполняем обновление:
portsnap fetch update
Ставим пакет libressl — форк openssl:
pkg install -y libressl
rehash
После установки выполняем подмену OpenSSL на LibreSSL:
mv /usr/bin/openssl /usr/bin/openssl.old
ln -s /usr/local/bin/openssl /usr/bin/openssl
openssl version
В файле /etc/make.conf определим параметры для сборки нашего сквида:
DEFAULT_VERSIONS+=ssl=libressl
OPTIONS_FILE_SET+=ECAP
OPTIONS_FILE_SET+=GSSAPI_NONE
OPTIONS_FILE_UNSET+=GSSAPI_BASE
OPTIONS_FILE_UNSET+=TP_IPFW
OPTIONS_FILE_SET+=TP_PF
Переходим в директорию порта:
cd /usr/ports/www/squid
Выполняем установку порта:
make install clean BATCH=yes
Создадим сертификат для SSL-bump’инга:
cd /usr/local/etc/squid
/usr/local/bin/openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -keyout squidCA.pem -out squidCA.pem
Инициализируем файл базы SSL:
/usr/local/libexec/squid/security_file_certgen -c -s /var/log/squid/ssl_db -M 4MB
Приводим squid.conf к следующему виду:
#
# Squid configuration:
#
# Set a hostname
visible_hostname proxy.local
# Set nameservers (optional)
dns_nameservers 1.1.1.1
# Local area network
acl localnet src 192.168.0.0/16
# Blocked domains
acl blocked_urls url_regex -i "/usr/local/etc/squid/blocked_urls.acl"
# Squid ports listening
http_port 0.0.0.0:3128
http_port 0.0.0.0:3129 intercept
https_port 0.0.0.0:3130 intercept ssl-bump connection-auth=off cert=/usr/local/etc/squid/squidCA.pem
always_direct allow all
sslproxy_cert_error allow all
acl blocked_https ssl::server_name "/usr/local/etc/squid/blocked_urls.acl"
acl step1 at_step SslBump1
ssl_bump peek step1
ssl_bump terminate blocked_https
ssl_bump splice all
sslcrtd_program /usr/local/libexec/squid/security_file_certgen -s /var/log/squid/ssl_db -M 4MB
# Allowed ports
acl open_ports port 80 # http
acl open_ports port 443 # https
acl ssl_ports port 443
acl CONNECT method CONNECT
#
# Access Permission configuration:
#
# Deny requests to certain unsafe ports
http_access deny !open_ports
# Deny CONNECT to other than secure ssl ports
http_access deny CONNECT !ssl_ports
# Only allow cachemgr access from localhost
http_access allow localhost manager
http_access deny manager
# Deny access to localhost
http_access deny to_localhost
# Deny access to domains
http_access deny blocked_urls
# Allow access from local networks
http_access allow localnet
http_access allow localhost
# And finally deny all other access to this proxy
http_access deny all
# Disk cache directory
cache_dir ufs /var/squid/cache 100 16 256
# Leave coredumps in the first cache dir
coredump_dir /var/squid/cache
#
# Add any of your own refresh_pattern entries above these.
#
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
# Errors pages
error_directory /usr/local/etc/squid/errors/ru
error_default_language ru
Далее создадим файл со списком запрещенных сайтов:
vi /usr/local/etc/squid/blocked_urls.acl
.youtube.com
.instagram.com
Проверяем конфиг на наличие ошибок:
squid -k parse
Инициализируем кэш:
squid -z
Пробуем запустить прокси сервер:
/usr/local/etc/rc.d/squid onestart
Проверяем статус запущенной службы:
/usr/local/etc/rc.d/squid onestatus
sockstat -l | grep squid
Подгружаем пакетный фильтр PF как модуль ядра:
kldload pf
kldstat | grep pf.ko
Включаем пакетный фильтр PF:
pfctl -e
Добавляем правила в PF для заворачивания трафика на порт прокси:
vi /etc/pf.conf
rdr pass inet proto tcp from any to any port http -> 127.0.0.1 port 3129
rdr pass inet proto tcp from any to any port https -> 127.0.0.1 port 3130
Проверяем и применяем правила:
pfctl -nvf /etc/pf.conf
pfctl -f /etc/pf.conf
Так как мы используем пакетный фильтр PF для заворачивания трафика на порт сквида, необходимо предоставить пользователю squid доступ на чтение /dev/pf, иначе получите ошибку в логе:
PfInterception PF open failed: (13) Permission denied.
Открываем /etc/devfs.conf и добавляем в конец следующее:
own pf root:squid
perm pf 0640
Перезапускаем devfs:
/etc/rc.d/devfs restart
Не забываем включить пересылку пакетов между интерфейсами:
sysctl net.inet.ip.forwarding=1
Настраиваем автозапуск в файле /etc/rc.conf:
gateway_enable="YES" # параметр sysctl net.inet.ip.forwarding=1
squid_enable="YES" # запускать прокси сервер Squid
pf_enable="YES" # запускать пакетный фильтр PF
pflog_enable="YES" # возможность логирования трафика через интерфейс pflog
Дополнения:
Иногда сквид может прерывать HTTPS соединения на некоторых ресурсах и в логах могут сыпаться ошибки вида:
SECURITY ALERT: Host header forgery detected on ... (local IP does not match any domain) IP)
Как решение можно использовать локальный кэширующий DNS резолвер, который будут использовать клиенты и сам сквид в том числе.
Источники:
https://habr.com/ru/post/267851/
https://habr.com/ru/post/354708/
https://www.ew8bak.ru/2017/02/14/freebsd-%D0%BF%D1%80%D0%BE%D0%B7%D1%80%D0%B0%D1%87%D0%BD%D1%8B%D0%B9-%D0%BF%D1%80%D0%BE%D0%BA%D1%81%D0%B8-squid-http-https/