Поднимаем прозрачный прокси Squid на FreeBSD 13.0

image-loader.svg

Хочу поделиться информацией по поднятию прозрачного 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/

© Habrahabr.ru