Шлюз на Ubuntu: автоматический обход блокировок сайтов

Представим ситуацию, в которой сотрудникам компании необходимо получить доступ к заблокированным провайдерами РФ ресурсам. Статья не призывает нарушать закон (хотя, ничего противозаконного в этом нет), а лишь показывает возможность обхода блокировок. Итак, у нас есть шлюз на базе Ubuntu 18.04, сервис бесплатного VPN доступа protonvpn.com и сервис со списком заблокированных IP адресов antifilter.download. С сервиса мы будем брать список недоступных подсетей и создавать маршруты к ним через наш VPN. В итоге пользователи получат доступ к заблокированным ресурсам автоматически без использования дополнительных программ на своей стороне.

Регистрируемся на сайте protonvpn.com, в личном кабинете выбираем слева Download, справа  Select platform - Linux, Select protocol - UDP. В поле Select connection and download выбираем Server configs и скачиваем конфиг для Netherlands - NL-FREE#2 (в моём случае на бесплатном тарифе доступны страны USA и Netherlands).

Ставим openvpn и копируем полученный конфиг в файл /etc/openvpn/openvpn.conf. Помимо ключей в файле для доступа необходимы имя и пароль из личного кабинета (пункт меню Account). Чтобы не вводить их постоянно при поднятии канала - внесем изменения в конфиг:
nano /etc/openvpn/openvpn.conf
находим строчку auth-user-pass и дописываем через пробел путь к файлу, где у нас будут имя и пароль, получается так:
auth-user-pass /etc/openvpn/auth.conf
Пишем в файл /etc/openvpn/auth.conf в первой строчке имя, во второй пароль.
Вторым шагом мне нужно запретить получать маршруты от openvpn сервера т.к. по умолчанию он пускает весь Интернет трафик через себя. Для этого добавим (или раскомментируем) в клиентском конфиге строчку:
route-nopull
Я также добавил в конфиг логирование (и создал файлы) для контроля подключения:
log /var/log/openvpn/openvpn.log 
status /etc/openvpn/openvpn-status.log
Теперь пробуем запустить наш конфиг:
sudo systemctl restart openvpn
Ждем минуту и проверяем интерфейс и подключение:
ifconfig tun0
curl -s ipinfo.io
Переходим ко второй части. В ней использовались конфиги из этой отличной статьи.
Устанавливаем bird (IPv6 отключим) и настраиваем связь по BGP протоколу с antifilter.download (BGP - Активировать управление BGP) для получения списка заблокированных подсетей и создания соответствующих им маршрутов через openvpn.
sudo add-apt-repository ppa:cz.nic-labs/bird
sudo apt-get update
sudo apt-get install bird
Настраиваем bird:
nano /etc/bird/bird.conf

log syslog all;
# указываем логин авторизации, обычно внешний IP адрес
router id 83.222.161.126;  
# список подсетей для которых не применять правила
function martians() {
 return net ~ [ 100.64.0.0/10+,
                     169.254.0.0/16+,
                     172.16.0.0/12+,
                     192.168.0.0/16+,
                     10.0.0.0/8+,
                     127.0.0.0/8+,
                     224.0.0.0/4+,
                     240.0.0.0/4+,
                     0.0.0.0/32-,
                     0.0.0.0/0{0,7} ];
}
protocol device {
 scan time 15;
}
# таблица для наших адресов
protocol kernel kernel_routes {
 scan time 60;
import none;
export all;
kernel table 1000; # kernel routing table number
}
 # импортируем весь список адресов
protocol static static_routes {
 import all;     #route 192.168.X.Y/24 via 192.168.A.B;
}
# настраиваем BGP пиринг и направляем трафик через шлюз соединения openvpn
protocol bgp antifilter {
 import filter {
    if martians() then reject;
    gw = 10.8.3.1; # адрес шлюза
    accept;
    };
export none;
local as 64999; # local default as-number
neighbor 163.172.210.8 as 65432;
multihop;
hold time 240;
}
Проверяем:
birdc show route
Проблема protonvpn.com в том, что при перезапуске соединения часто меняется подсеть и соответственно IP адрес шлюза. Этот адрес прописан у нас в конфиге bird. Значит нужно сделать так, чтобы при поднятии соединения openvpn менялось значение gw в 38 строке конфига bird и происходил перезапуск сервиса для применения настроек. Для этого пишем скрипт на bash и инициируем его запуск в конфиге openvpn при поднятии соединения и маршрутов.
nano /etc/openvpn/up.sh
#!/usr/bin/env bash
#
# Скрипт меняет адрес шлюза VPN подключения в конфиге bird
# получаем IP адрес openvpn подключения
IP=$(/sbin/ip route | awk '/tun0/ { print $9 }')
# меняем последний октет адреса на 1 для получения адреса шлюза
GATE=$(echo -n $IP | sed 's:[^.]*$:1:')
# меняем IP шлюза в конфиге bird в 38 строке конфига
sudo -u bird sed -i '38s/.*/        gw = '$GATE'; # адрес шлюза /' '/etc/bird/bird.conf'
# перезапускаем bird
systemctl restart bird
# или birdc configure
# добавляем таблицу маршрутизации 1000, если она не используется
if [$(ip rule list | grep 'lookup 1000')]; then
exit 0
else
ip rule add table 1000
fi
exit 0
Делаем скрипт исполняемым
chmod +x  /etc/openvpn/up.sh
Добавляем в конфиг openvpn /etc/openvpn/openvpn.conf запуск скрипта:
# Запуск скрипта при установке соединения и поднятии маршрутов
script-security 2
route-up /etc/openvpn/up.sh
Перезапускаем openvpn и ждем пару минут для проверки работы:
systemctl restart openvpn
Проверить что наша таблица маршрутизации используется политиками маршрутизации, можно командой
ip rule list
Вывод должен быть таким:
0: from all lookup local
32765: from all lookup 1000
32766: from all lookup main
32767: from all lookup default
Вторая строка с номером 32765 - это наша политика, по которой для любых источников пакета нужно смотреть в таблицу 1000. Стоит она перед политиками для main и default, соответственно применяется ранее.
Проверить заполняемость таблицы 1000 можно командой:
ip route list table 1000
или
birdc show route
Вывод должен показать список маршрутов для заблокированных подсетей.
Чтобы удалить политику можно воспользоваться командой:
ip rule del prio 32765
Осталось на нашем шлюзе включить форвардинг пакетов и настроить NAT. Создаем и делаем исполняемым файл /etc/firewall.sh:
touch /etc/firewall.sh
chmod +x /etc/firewall.sh
nano /etc/firewall.sh

#!/bin/sh
#########################
# Настройки интерфейсов #
########################
#Интернет
IF_INET="ens192"
#Локальная сеть
IF_INTERNAL="ens160"
# OpenVPN интерфейс
IF_VPN="tun0"

IPT="/sbin/iptables"

# Удаляем старые правила
$IPT -F
$IPT -X
$IPT -t nat -F
$IPT -t nat -X
$IPT -t mangle -F
$IPT -t mangle -X

# Настраиваем политики по умолчанию
$IPT -P OUTPUT ACCEPT
$IPT -P INPUT ACCEPT
$IPT -P FORWARD ACCEPT

# Разрешаем все операции с loopback интерфейса
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A FORWARD -o lo -j ACCEPT

# Поддерживаем уже установленные соединения
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

#Даем доступ в Интернет для локальной подсети
$IPT -A FORWARD  -s 0.0.0.0/0 -d 192.168.0.0/24 -j ACCEPT
$IPT -A FORWARD  -s 192.168.0.0/24 -d 0.0.0.0/0 -j ACCEPT

# Включаем NAT
$IPT -A FORWARD -i $IF_INET -o $IF_INTERNAL -s 192.168.0.0/24 -m conntrack --ctstate NEW -j ACCEPT
$IPT -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
$IPT -A POSTROUTING -t nat -j MASQUERADE

#Включаем форвардинг
echo 1 > /proc/sys/net/ipv4/ip_forward
Далее добавляем этот скрипт в автозагрузку, например таким способом.

В моем случае провайдер перехватывал запросы к DNS серверу гугла и менял IP заблокированных ресурсов на свой адрес со страницей оповещающей о запрете доступа.
nslookup linkedin.com 8.8.8.8
Server:  8.8.8.8
Address: 8.8.8.8#53

Non-authoritative answer:
linkedin.com canonical name = fz139.ttk.ru.
Name: fz139.ttk.ru
Address: 188.43.20.6
Избежать такого поведения можно двумя способами. Первый способ - пустить трафик до DNS сервера тоже через VPN (создать отдельное правило).

Второй способ - подобрать DNS, запросы до которого еще не подделываются провайдером, например, 1.1.1.1 и использовать его в качестве основного (раздавать по умолчанию клиентам через DHCP).
nslookup linkedin.com 1.1.1.1
Server:  1.1.1.1
Address: 1.1.1.1#53

Non-authoritative answer:
Name: linkedin.com
Address: 108.174.10.10
Name: linkedin.com
Address: 2620:109:c002::6cae:a0a
В моём случае система используется в качестве только Интернет-роутера, соответственно DHCP и DNS сервера подняты на других машинах под Windows Server. Если вам необходимы эти службы в одном месте можете использовать bind9 и isc-dhcp-server.

Комментариев нет:

Отправить комментарий