«Прозрачный» HTTPS прокси для обхода блокировок Роскомнадзора
Привет, хабровчане! Я думаю, многие в последнее время столкнулись с проблемами доступа к нужным ресурсам из-за попыток Роскомпозоранадзора заблокировать Телеграм. И я думаю, комментарии тут излишни. Факт — эти ресурсы ни в чем не виноваты, но они заблокированы. Проблемы возникли с Viber, ReCaptcha, GoogleFonts, Youtube и др. кроме самого телеграма. Это случилось и в моей организации, причем все эти невинные сервисы нужны нам как воздух. В какое-то время решалось все использованием прокси серверов, но они были нестабильны или вовсе отключались (их также блокировал наш великий и могучий (нет) РКН.
После прочтения кучи статей, пришла идея научить Squid пускать отдельные URL через Tor. Какие здесь плюсы и минусы, решать вам. Но скажу, что после реализации пропали все проблемы, которые были до этого. Кому интересно, идем под кат.
Статья написана исключительно в целях помощи тем, кто неправомерно страдает от тотального бреда, который творится у нас в стране.
Итак, для начала немного теории. Как мы все знаем, Tor — это не HTTP-прокси, его нельзя сделать прямым peer для нижележащего Squid’а. Он предоставляет SOCKS-проксирование (конечно же, не только, но нам нужно именно это). Чтобы нам поженить Tor со Squid, нужно что-то, что могло бы играть роль проводника от Tor к Squid и обратно. И конечно же, дамы и господа, это Privoxy. Как раз таки он способен быть прямым peer, и отправлять все далее в Tor.
Было, как я уже говорил, прочтено куча статей, но ни одна не подходила мне. Попалась вот эта статья, но и она мне не совсем подходила, так как мне не нужен bump. Вообще, все имеющиеся статьи, практически все, подразумевают либо бамп, либо только http, а в моем случае нужно и HTTPS, и splice, и прозрачность.
Я уже ранее писал о том, как сделать прозрачный Squid с проксированием HTTPS без подмены сертификатов. И конечно же, я попробовал реализовать идею на нем. Но меня ждало разочарование. HTTP запросы прекрасно уходили в TOR, а вот HTTPS нет. Проблема не очень-то и известная, и я узнал у одного из разработчиков, что это недостаток старых версий Squid. Но в ходе экспериментов было найдено решение — Squid 3.5.27, в котором исправлен данный баг + красивые доменные имена в логах (https), вместо ip адресов. Но и тут меня ждали несколько разочарований, о которых речь пойдет ниже. Но всё, как говорится, допиливается напильником.
Итак, исходные данные:
- Debian Stretch (9) x86 (в х64 не пробовал)
- Сорцы Squid 3.5.23 из репозитория
- Свеженькие сорцы Squid с оф.сайта
- OpenSSL
- Libecap3
- Tor
- Privoxy
- Прямые руки и много кофе с печеньками
Собирать Squid ручками или ставить готовые пакеты (ссылки ниже), решать вам. Если вы думаете, что я впендюрил в них блекджек и ш… вирусы, то компильте сами. Также компилировать нужно, если у вас дистрибутив другой (если Убунта, то поставите). Собирать мы будем версию Squid 3.5.23, которая на момент написания статьи валяется в репозитории Stretch, повысив ее до свежих исходников 3.5.27 с оф.сайта. Также нам понадобится для этих дел libecap, его мы тоже соберем. В отличие от моей первой статьи про HTTPS+Squid, собирать будем без Libressl.
Итак, подготовимся к сборке:
apt-get install fakeroot build-essential devscripts
apt-get build-dep squid3
apt-get build-dep libecap2
apt-get install libssl1.0-dev
apt-get install libgnutls28-dev
Очень важно ставить именно libssl1.0-dev, а не другую версию, иначе Squid будет либо лагать, либо не соберется вовсе из-за непонятных ошибок
Далее на время добавим в sources.list дистрибутив Buster:
deb-src http://ftp.de.debian.org/debian/ buster main contrib non-free
и обновим кеш пакетов
apt-get update
Скачаем из Buster нужные исходники для сборки libecap3:
apt-get source libecap3/buster
Далее соберем libecap:
cd libecap-1.0.1/
dpkg-buildpackage -us -uc -nc -d
Удалим старье (если оно вдруг есть), и установим новье:
apt-get purge libecap2
dpkg -i libecap_1.0.1-3.2_i386.deb
libecap3-dev_1.0.1-3.2_i386.deb
Можно убрать из sources.list репозиторий Buster и приступать к самому интересному — красноглазию и костыльству!
Далее получаем исходники Squid 3.5.23
apt-get source squid3
Качаем именно этот архив с исходниками Squid:
wget -O squid-3.5.27-2018.tar.gz http://www.squid-cache.org/Versions/v3/3.5/squid-3.5.27-20180318-r1330042.tar.gz
Переходим в каталог исходников Squid и обновляем исходники до новоскаченных сорцов:
cd squid3-3.5.23/
uupdate -v 3.5.27-2018 ../squid-3.5.27-2018.tar.gz
Переходим в новоиспеченный каталог с обновленными исходниками:
cd ../squid3-3.5.27-2018
Добавляем в debian/rules опции для компиляции:
--enable-ssl \
--enable-ssl-crtd \
--with-openssl
Можете, кстати, вырубить ненужные вам опции, это ускорит компиляцию
Дальше нужно пропатчить исходники вот таким патчем:
client_side_request.patch
--- src/client_side_request.cc Thu Aug 18 00:36:42 2016
+++ src/client_side_request.cc Mon Sep 19 04:41:45 2016
@@ -519,20 +519,10 @@
// note the DNS details for the transaction stats.
http->request->recordLookup(dns);
- if (ia != NULL && ia->count > 0) {
- // Is the NAT destination IP in DNS?
- for (int i = 0; i < ia->count; ++i) {
- if (clientConn->local.matchIPAddr(ia->in_addrs[i]) == 0) {
- debugs(85, 3, HERE << "validate IP " << clientConn->local << " possible from Host:");
- http->request->flags.hostVerified = true;
- http->doCallouts();
- return;
- }
- debugs(85, 3, HERE << "validate IP " << clientConn->local << " non-match from Host: IP " << ia->in_addrs[i]);
- }
- }
- debugs(85, 3, HERE << "FAIL: validate IP " << clientConn->local << " possible from Host:");
- hostHeaderVerifyFailed("local IP", "any domain IP");
+ debugs(85, 3, HERE << "validate IP " << clientConn->local << " possible from Host:");
+ http->request->flags.hostVerified = true;
+ http->doCallouts();
+ return;
}
void
Для чего он нужен? Я объясню. Когда я писал первую статью про peek and splice, я говорил что более новые версии не работают, и это было так, и вот как раз таки этот патч исправляет ту самую проблему, которая заключалась в том, что Squid выборочно рвет HTTPS соединения, с интересным сообщением в cache.log:
SECURITY ALERT: Host header forgery detected on ... (local IP does not match any domain IP)
Дело в том, что на одном хосте что-то резолвится в один IP, на соседнем иногда в другой, на самом Squid в третий, т.к. существует кеш DNS и обновляется он не синхронно. Squid не находит соответствия ip-домен в своём кеше (потому что обновил свой кеш немного раньше или позже) и прерывает соединение. Вроде как, защита, но в наше время это считается нормальным (round-robin DNS). Разработчики перестраховались. И нам это не нужно совершенно! Тем, кто скажет, что данный патч, возможно, несет в себе угрозу безопасности, я отвечу, что по поводу этого патча я консультировался с Юрием Войновым, который имеет непосредственное отношение к команде разработчиков Squid. Никакой угрозы здесь нет!
Итак, файлик для патча создали, код кинули, надо пропатчить:
patch -p0 -i client_side_request.patch
Далее необходимо отменить применение одного патча при компиляции (иначе получите ошибку, что этот патч применить невозможно, так как он уже применен). Идем в debian/patches/series и закомментим там 0003-SQUID-2018_1.patch, поставив перед ним знак #:
#0003-SQUID-2018_1.patch
Ну, а дальше — компиляция и сборка пакетов!
dpkg-buildpackage -us -uc -nc
Установим squid-langpack
apt-get install squid-langpack
и установим свеженькие пакеты
dpkg -i squid-common_3.5.27-2018-1_all.deb
dpkg -i squid_3.5.27-2018-1_i386.deb
dpkg -i squid3_3.5.27-2018-1_all.deb
Если apt матерится на зависимости, сделайте
apt-get -f install
Далее нужно выключить Squid из автозагрузки (по умолчанию используется init файл, Squid жалуется на недоступность PID файла)
systemctl disable squid
и создать systemd сервис в директории /etc/systemd/system (файл сервиса есть в исходниках, и полностью скопирован сюда)
cat /etc/systemd/system/squid3.service
## Copyright (C) 1996-2018 The Squid Software Foundation and contributors
##
## Squid software is distributed under GPLv2+ license and includes
## contributions from numerous individuals and organizations.
## Please see the COPYING and CONTRIBUTORS files for details.
##
[Unit]
Description=Squid Web Proxy Server
After=network.target
[Service]
Type=simple
ExecStart=/usr/sbin/squid -sYC -N
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
[Install]
WantedBy=multi-user.target
Включим его
systemctl enable squid3.service
Установим tor, privoxy
apt-get install tor privoxy
Конфиг Tor я лично вообще не трогал, а вот конфиг Privoxy можно привести к такому виду:
listen-address 127.0.0.1:8118
toggle 0
enable-remote-toggle 0
enable-remote-http-toggle 0
enable-edit-actions 0
forward-socks5t / 127.0.0.1:9050 .
max-client-connections 500
Почти готово. Перейдем в каталог /etc/squid, кое-что там изменим. Создадим pem файлик, необходимый для splice:
openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -keyout squidCA.pem -out squidCA.pem
И приведем squid.conf к следующему виду:
acl localnet src 192.168.0.0/24 # Ваша локалка
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # 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
acl SSL method CONNECT
#Укажем DNS для Squid. Крайне рекомендую использовать одинаковые DNS тут и у клиентов
dns_nameservers 77.88.8.8
# Список доменов, которые нужно пустить через Tor
acl rkn url_regex "/etc/squid/tor_url"
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager
http_access allow localnet
http_access allow localhost
http_access deny all
icp_access deny all
htcp_access deny all
#прозрачный порт указывается опцией intercept
http_port 192.168.0.1:3128 intercept options=NO_SSLv3:NO_SSLv2
#также нужно указать непрозрачный порт, ибо если захотите вручную указать адрес
#прокси в браузере, указав прозрачный порт, вы получите ошибку доступа, поэтому нужно
#указывать непрозрачный порт в браузере, если конечно такое желание будет, к тому же в логах #сыпятся ошибки о том, что непрохрачный порт не указан=)
http_port 192.168.0.1:3130 options=NO_SSLv3:NO_SSLv2
#и наконец, указываем HTTPS порт с нужными опциями
https_port 192.168.0.1:3129 intercept ssl-bump options=ALL:NO_SSLv3:NO_SSLv2 connection-auth=off cert=/etc/squid/squidCA.pem
sslproxy_cert_error allow all
sslproxy_flags DONT_VERIFY_PEER
#укажем правило со списком блокируемых ресурсов (в файле домены вида .domain.com)
acl blocked ssl::server_name "/etc/squid/blocked_https.txt"
acl step1 at_step SslBump1
ssl_bump peek step1
#терминируем соединение, если клиент заходит на запрещенный ресурс
ssl_bump terminate blocked
ssl_bump splice all
# Никогда не пускать напрямую домены, указанные в списке РКН
never_direct allow rkn
# Указываем прокси, куда отправлять домены из списка, в нашем случае - Privoxy
cache_peer 127.0.0.1 parent 8118 0 no-query no-digest default
cache_peer_access 127.0.0.1 allow rkn
cache_peer_access 127.0.0.1 deny all
sslcrtd_program /usr/lib/squid/ssl_crtd -s /var/lib/ssl_db -M 4MB
coredump_dir /var/spool/squid
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
logfile_rotate 4
pid_filename /var/run/squid.pid
Список url_regex имеет примерно такой вид:
zenway\.ru
lukomore\.org
\.*google\.com
\.*viber\.*
\.amazon\.com
telegram.*
tdesktop.*
thegeekdiary\.com.*
\.fbcdn\.net
telegra\.ph
\.slack\.*
media\.api.\viber\.com*
static\.viber\.com*
secure\.viber.*
media-share.*
\*.cloudfront\.net
t\.me
cdn4\.telesco\.pe
fonts\.gstatic\.com
med-edu\.ru
Более подробно про этот формат списка читайте в оф документации. Результат себя долго ждать не заставил — все заработало, как и было запланировано. И работает по сей день. Возможно, со статьей опоздал, но она, вероятно, пригодится в будущем)
Тему буду пополнять по возможности.
Готовые пакеты Squid и Libecap (.deb x86)
Огромное спасибо Юрию Войнову, который помогал в решении проблем с работой данной связки!