Как стать автором
Обновить

«Прозрачный» HTTPS прокси для обхода блокировок Роскомнадзора

Время на прочтение 9 мин
Количество просмотров 86K
Привет, хабровчане! Я думаю, многие в последнее время столкнулись с проблемами доступа к нужным ресурсам из-за попыток Роскомпозоранадзора заблокировать Телеграм. И я думаю, комментарии тут излишни. Факт — эти ресурсы ни в чем не виноваты, но они заблокированы. Проблемы возникли с Viber, ReCaptcha, GoogleFonts, Youtube и др. (кроме самого телеграма). Это случилось и в моей организации, причем некоторые невинные сервисы нужны нам как воздух. В какое-то время решалось все использованием прокси серверов, но они были нестабильны или вовсе отключались (их также блокировал наш великий и могучий РКН).

После прочтения кучи статей, пришла идея научить Squid пускать отдельные URL через Tor. Использовать ли такой метод, решать вам. Но скажу, что после реализации пропали все проблемы, которые были до этого. Кому интересно, идем под кат.

Зачем это?
Статья написана исключительно в целях помощи тем, кто неправомерно страдает от тотального бреда, который творится у нас в стране. Также она ориентирована на тех, кому нужен именно «прозрачный» Squid с HTTPS без подмены сертификатов и возможностью отслеживания посещений как по HTTP так и по HTTPS, поскольку статья по сути является продолжением другой моей статьи, так как здесь я предлагаю исправление давнего бага, который не позволял видеть в логах доменные имена https ресурсов и не позволял использовать более новые версии Squid. Ну а также просто для тех, кому интересно использование Squid.

Какие преимущества?
  • Неограниченные возможности масштабирования
  • Относительная легкость в поддержке и администрировании
  • Если это важно, то можно предоставлять анонимный доступ на указанные в списке ресурсы (хоть это и не тема статьи, но анонимность предоставляется «искаропки»
  • Стабильность. При использовании нескольких сервисов Tor (разные конфиг файлы) их можно подключить к Squid, и получить round robin.
  • Абсолютная бесплатность. Навсегда.


Я ничего не знаю, Squid\Tor медленный, пойду и подниму VPS с VPN за бугром
Поздравляю! Вы действительно решили, что Роскомнадзор доставил вам неудобства, и вам же еще за это платить, чтобы выйти из положения? Ок. Можете смело пропускать статью, и поднимать VPN туннели. Кстати, VPN успешно блокируется. Легко. И в свете последних событий, я подскажу, что в скором времени никто не сможет использовать VPS для обхода блокировок на уровне закона. И плюс ко всему, ваш VPS может так же угодить в блокировку «просто потому что рядышком сидит телеграм». Tor не заблокируется, никак. Если его настроить с obfs, то никогда и нигде (тема, пожалуй, для отдельной статьи, так как в этой obfs не рассматривается). И сколько нужно будет поднимать таких VPS с VPN? Как это обслуживать? Здесь же решение легче в разы, надежное, и при желании, вполне скоростное, к тому же бесплатное. Так что прежде чем вводить в заблуждение других читателей, пожалуйста, еще раз обдумайте все + и — VPS с VPN, и только после этого утверждайте, что Squid+Tor — это тормознутое, ненадежное решение.

Tor заблокируют! В Китае, вон, уже заблокирован
Нет. Нет. И еще раз нет. В Китае Tor работает при настроенном obfs. Прекрасно работает. Нет в Мире способа заблокировать Tor. Даже Китаю с его мощностями, умами и финансами не удалось это сделать.

Tor медленный! А если работать через obfs, то вообще жуть!
Обратитесь к оф.документации и куче статей в Интернете, где описывается, как сделать так, чтобы скорость была на приличном уровне. И опять же, настроив таким образом несколько копий Tor с разными конфигами, их можно пристроить к Squid и получить round robin.

Итак, для начала немного теории. Как мы все знаем, Tor — это не HTTP-прокси, его нельзя сделать прямым peer для нижележащего Squid'а. Он предоставляет SOCKS-проксирование (конечно же, не только, но нам нужно именно это). Чтобы нам поженить Tor со Squid, нужно что-то, что могло бы играть роль проводника от Tor к Squid и обратно. И конечно же, дамы и господа, это Privoxy. Как раз таки он способен быть прямым peer, и отправлять все далее в Tor.

Было, как я уже говорил, прочтено куча статей, но ни одна не подходила мне. Попалась вот эта статья, но и она мне не совсем подходила, так как мне не нужен bump. Вообще, все имеющиеся статьи, практически все, подразумевают либо бамп, либо только http, а в моем случае нужно и HTTPS, и splice, и прозрачность. Также видал вот это и это, но там совсем другие подходы. Свои плюсы и минусы. Я выбрал для себя именно связку Squid + Tor.

Я уже ранее писал о том, как сделать прозрачный Squid с проксированием HTTPS без подмены сертификатов. И конечно же, я попробовал реализовать идею на нем. Но меня ждало разочарование. HTTP запросы прекрасно уходили в TOR, а вот HTTPS нет. Проблема не очень-то и известная, и я узнал у одного из разработчиков, что это недостаток старых версий Squid. Но в ходе экспериментов было найдено решение — Squid 3.5.27, в котором исправлен данный баг + красивые доменные имена в логах (https), вместо ip адресов. Но и тут меня ждали несколько разочарований, о которых речь пойдет ниже. Но всё, как говорится, допиливается напильником.

Итак, исходные данные:

  1. Debian Stretch (9) x86 (в х64 не пробовал)
  2. Сорцы Squid 3.5.23 из репозитория
  3. Свеженькие сорцы Squid с оф.сайта
  4. OpenSSL
  5. Libecap3
  6. Tor
  7. Privoxy
  8. Прямые руки и много кофе с печеньками

Собирать Squid ручками или ставить готовые пакеты (ссылки ниже), решать вам. Если вы думаете, что я впендюрил в них блекджек и ш… вирусы, то компильте сами. Также компилировать нужно, если у вас дистрибутив другой (если Убунта, то поставите). Собирать мы будем версию Squid 3.5.23, которая на момент написания статьи валяется в репозитории Stretch, повысив ее до свежих исходников 3.5.27 с оф.сайта. В отличие от моей первой статьи про HTTPS+Squid, собирать будем без Libressl.

Итак, подготовимся к сборке:

apt-get install fakeroot build-essential devscripts
apt-get build-dep squid3
apt-get install libecap3
apt-get install libecap3-dev
apt-get install libssl1.0-dev
apt-get install libgnutls28-dev

ВАЖНО!
Очень важно ставить именно libssl1.0-dev, а не другую версию, иначе Squid будет либо лагать, либо не соберется вовсе из-за непонятных ошибок


Далее получаем исходники 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

Совет
Можете, кстати, вырубить ненужные вам опции, это ускорит компиляцию

Дальше нужно пропатчить исходники вот таким патчем:

<b>client_side_request.patch</b>

--- 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
\.*google\.com
\.*viber\.*
\.amazon\.com
\.fbcdn\.net
\.slack\.*
media\.api\.viber\.com*
static\.viber\.com*
secure\.viber.*
\*.cloudfront\.net
fonts\.gstatic\.com
med-edu\.ru

Замечание
Вы можете использовать и не regex, можно использовать dstdomain, также можно «прикрутить» списки с неправомерно заблокированными подсетями (dst)

Более подробно про этот формат списка читайте в оф документации. Результат себя долго ждать не заставил — все заработало, как и было запланировано. И работает по сей день. Возможно, со статьей опоздал, но она, вероятно, пригодится в будущем).

Тему буду пополнять по возможности.

Готовые пакеты Squid (.deb x86)

UPD 04.05.18: можно добавить в torcc строчку
HTTPTunnelPort 8118

и в принципе отказаться от Privoxy. Спасибо dartraiden за замечание

Найден баг. Не рекомендуется использование HTTPTunnelPort, Privoxy нужен пока-что, пока не закроется вот это. Спасибо Юрию Воинову!

Также поправил статью по части libecap3. Не нужно компилировать ничего, а просто установить из репозитория Stretch. Спасибо AlucoST за замечание

UPD 05.05.18: товарищ dartraiden подсказывает, что в конфиг Tor можно добавить
ExcludeExitNodes {ru}, {ua}, {by}

Это исключает использование выходных узлов в указанных странах

Огромное спасибо Юрию Воинову, который помогал в решении проблем с работой данной связки!
Теги:
Хабы:
+42
Комментарии 144
Комментарии Комментарии 144

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн