Введение
Есть первая версия этой заметки, в которой я больше душу изливал, чем делился подробностями реализации. Эту заметку я писал, пока делал автоматизацию, т.к. уже 3 месяца я перезапускаю это вручную, отчего я устал ещё в первый день. То есть, я опять же для себя стараюсь, чтобы потом легче было это поддерживать.
Автоматизация запуска
Юнит systemd
[Unit]
Description=Privoxy/Squid transparent proxy
After=network.target
[Service]
ExecStart=/root/startup_proxy.sh # <--запуск
ExecStop=/root/stopdown_proxy.sh # <--очистка
RemainAfterExit=yes
Type=simple
[Install]
WantedBy=multi-user.target
Он элементарен, на нём останавливаться не буду.
Скрипт запуска
Далее скрипт запуска:
- Для работы Proxy нужен отдельный
netns
, т.к. перехват трафика реализован через подмену DNS. Таким образом, для моих устройств ресурсы, требующие обхода, будут разрешать в IP, принадлежащий этому отдельномуnetns
:
NETNS_NAME="proxy"
NETNS_EXEC="ip netns exec $NETNS_NAME"
ip netns add $NETNS_NAME || exit 10
- Ну и настройка
veth
для связи междуnetns
и доступом в Интернет изproxy
. Отмечу также, что я решил повесить шейпер на исходящий изproxy
интерфейс. Важно не забыть:- Добавить маршрут из
proxy
в Интернет, т.к. маршрута по умолчанию там не создаётся; - Поднять петлю
lo
, т.к. в новомnetns
он создастся, но не поднимется; - Настроить SNAT из
proxy
в Интернет.
- Добавить маршрут из
ip link add to_proxy type veth peer name to_global || exit 20
ip addr add ${GLOBAL_NETNS_IP}/24 dev to_proxy || exit 21
ip link set to_proxy up || exit 22
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source ${OUTER_IP} || exit 23
ip link set to_global netns $NETNS_NAME || exit 30
$NETNS_EXEC ip addr add ${PROXY_NETNS_IP}/24 dev to_global || exit 31
$NETNS_EXEC tc qdisc add dev to_global root tbf rate 15mbit latency 50ms burst 512k || exit 32
$NETNS_EXEC ip link set to_global up || exit 33
$NETNS_EXEC ip ro add default via ${GLOBAL_NETNS_IP} || exit 34
$NETNS_EXEC ip link set lo up || exit 35
- Запуск всех процессов. В данном списке нет Tor и ещё одного экземпляра Bind9. Они упущены потому, что они уже настроены и ими я пользуюсь и отдельно, и начал пользоваться задолго до поднятия прозрачного прокси.
named
— Bind9. Этот экземпляр настроен на пропуск всех запросов стороннему DNS, таким образом он будет разрешать DNS-имена в реальные IP, по которым будут ходить прокси;privoxy
— Прокси-сервер. Он умеет в прозрачность, но не умеет в подмену сертификатов. Используется на 80 порту как прозрачный, и им же пользуется Squid как непрозрачным для MITM атаки на HTTPS на своём 443 порту;squid
— Прокси сервер, который умеет в подмену сертификатов. Запускается он весьма экстравагантно, да. В моём репозитории довольно старая версия, возможно с этим связано. С тонной отладочных сообщений в консоли он — субъективное ощущение — работает стабильней, чем без.
$NETNS_EXEC /usr/sbin/named -4 -d 9 -u bind -c /etc/bind/named.conf.proxy || exit 40
$NETNS_EXEC /usr/sbin/privoxy /etc/privoxy/privoxy.config || exit 41
nohup $NETNS_EXEC /usr/sbin/squid -YCNX -d 5 -f /etc/squid/squid_privoxy.conf > /dev/null 2>&1 &
disown
На этом скрипт запуска пока заканчивается.
Скрипт остановки
Со скриптом остановки всё проще, т.к. не надо расстраивать интерфейсы — достаточно их удалить.
- Убиваем все запущенные процессы в
proxy
. Squid иногда не хочет останавливаться, поэтому ему мы можем послатьSIGKILL
.
NETNS_NAME="proxy"
ip netns pids $NETNS_NAME | xargs -r kill
sleep 3
ip netns pids $NETNS_NAME | xargs -r kill -SIGKILL
- Подчищаем сеть, удалив один из
veth
(по идее, удалится вместо с братом при удаленииnetns
, но на всякий случай я продублировал) иnetns
целиком:
ip link delete to_proxy
ip netns delete $NETNS_NAME
- Подчищаем правила
iptables
. По идее, дубликаты правила для SNAT погоды не сделают, т.к., судя по счётчикам, дубликаты не отрабатывают, но для красоты я их всё-таки подчищаю:
while iptables -t nat -D POSTROUTING -o eth0 -j SNAT --to-source ${OUTER_IP}; do : ; done
Конфигурационные файлы
Bind9 основной
В нём мне необходимо подменять ответы DNS-сервера на мой IP. Для этого я подключил файл, в котором перечислены зоны, которые я хочу подменять. Все они достаточно высокого уровня, то есть каждая охватывает конкретный домен, по сути.
Сам файл нет смысла приводить полностью, опишу пару записей для примера:
zone "xvideos.com" IN {
type master;
file "/etc/bind/db.myip.ru";
};
zone "xvideos-cdn.com" IN {
type master;
file "/etc/bind/db.myip.ru";
};
Как видно, эти настройки говорят обращаться к файлу db.myip.ru
. А это уже стандартный файл БД для DNS-сервера:
;
; BIND data file for t-proxy
;
$TTL 604800
@ IN SOA . root. (
2 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
@ IN NS ${OUTER_IP}
@ IN A ${PROXY_NETNS_IP}
* IN A ${PROXY_NETNS_IP}
Перед тем, как публиковать заметку, я максимально обобщил базу данных таким образом, чтобы на любой запрос она отправляла ${PROXY_NETNS_IP}
. Работоспособность при этом не пострадала.
Bind9 для прокси
Здесь DNS-сервер уже должен разрешать домены в настоящие адреса, по которым будет ходить прокси. По большому счёту, из-за этого и заводился отдельный netns
: чтобы разделить два DNS-сервера на уровне системы. Его конфиг, по сути, является стандартным конфигом Bind9
, но с пробросом всех запросов на сторонний DNS.
options {
directory "/var/cache/bind";
forwarders {
8.8.8.8;
};
dnssec-validation no;
auth-nxdomain no; # conform to RFC1035
listen-on {
127.0.0.1;
};
allow-query {
127.0.0.1;
10.48.0.0/24;
};
};
include "/etc/bind/named.conf.default-zones";
Также прямо в этот же конфиг я добавил проброс некоторых запросов в Tor. Теоретически, есть ресурсы, доступ к которым можно производить внутри сети Tor, не выходя из её выходного узла.
zone "xvideos.com" IN {
type forward;
forwarders {
${OUTER_IP} port 9053; //TOR
};
};
zone "xvideos-cdn.com" IN {
type forward;
forwarders {
${OUTER_IP} port 9053; //TOR
};
};
Privoxy
Для Privoxy у меня почти стандартная конфигурация. Выглядит так, если отсеять комментарии:
user-manual /usr/share/doc/privoxy/user-manual
confdir /etc/privoxy
logdir /var/log/privoxy
actionsfile match-all.action # Actions that are applied to all sites and maybe overruled later on.
actionsfile default.action # Main actions file
actionsfile user.action # User customizations
filterfile default.filter
filterfile user.filter # User customizations
logfile logfile
debug 8192 # Log the destination for each request Privoxy let through. See also debug 1024.
listen-address ${PROXY_NETNS_IP}:80
toggle 0
enable-remote-toggle 0
enable-remote-http-toggle 0
enable-edit-actions 0
enforce-blocks 0
buffer-limit 4096
enable-proxy-authentication-forwarding 0
forward-socks5t / ${OUTER_IP}:9050 .
forwarded-connect-retries 0
accept-intercepted-requests 1
allow-cgi-request-crunching 0
split-large-forms 0
keep-alive-timeout 300
tolerate-pipelining 1
socket-timeout 300
max-client-connections 512
log-messages 1
По факту, наибольшую пользу наносят следующие две строчки:
listen-address ${PROXY_NETNS_IP}:80 # <-- откуда слушать
forward-socks5t / ${OUTER_IP}:9050 . # <-- куда проксировать
Squid
По традиции, конфигурация Squid тоже близка к стандартной:
http_access allow all
icp_access allow all
htcp_access allow all
dns_nameservers 127.0.0.1
https_port ${PROXY_NETNS_IP}:443 intercept ssl-bump options=ALL:NO_SSLv3:NO_SSLv2 connection-auth=off dynamic_cert_mem_cache_size=4MB cert=/etc/squid/ssl/squid.pem key=/etc/squid/ssl/squid.key
sslproxy_cert_error allow all
sslproxy_flags DONT_VERIFY_PEER
acl step1 at_step SslBump1
ssl_bump peek step1 all
ssl_bump splice all
ssl_bump server-first all
ssl_bump none all
never_direct allow all
cache_peer ${PROXY_NETNS_IP} parent 80 0 no-query proxy-only no-digest default
cache_peer_access ${PROXY_NETNS_IP} allow all
sslproxy_cert_error allow all
sslproxy_flags DONT_VERIFY_PEER
sslcrtd_program /usr/lib/squid/ssl_crtd -s /var/lib/ssl_db -M 16MB
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
Из особенностей здесь, как раз, настройка прозрачности HTTPS(Peek and splice):
acl step1 at_step SslBump1
ssl_bump peek step1 all
ssl_bump splice all
ssl_bump server-first all
ssl_bump none all
never_direct allow all
Ещё, по идее, для Squid нужно ключей сгенерировать. Приведу сюда листинг команд для генерации из старой заметки.
openssl genrsa -out /etc/squid/ssl/squid.key
openssl req -new -key /etc/squid/ssl/squid.key -out /etc/squid/ssl/squid.csr
openssl x509 -req -days 3650 -in /etc/squid/ssl/squid.csr -signkey /etc/squid/ssl/squid.key -out /etc/squid/ssl/squid.pem
openssl x509 -in /etc/squid/ssl/squid.pem -outform DER -out squid.der