Шифрование трафика в Linux

Есть много способов обхода блокировки сайтов и обеспечения приватности в сети. Такие термины, как TOR, VPN, прокси, у всех на слуху. Чтобы подключить и настроить их, не требуется специальных знаний, но существуют и более изящные решения. Сегодня я расскажу о методике обхода блокировок в Linux с маскировкой трафика и покажу несколько скриптов для автоматизации этого. Их можно без труда перенести на Raspberry Pi, чтобы сделать умный маршрутизатор.

Эта статья не является руководством. Она написана исключительно с целью ознакомить вас с некоторыми функциональными возможностями маршрутизации в системах Linux. Автор статьи и редакция сайта www.spy-soft.net не несут никакой ответственности за результат использования описанных здесь методов и приемов.

Linux предоставляет огромный набор функций для маршрутизации и инструментов ее конфигурирования. Опытные сисадмины знают об этом и используют арсенал Linux на полную катушку. Но и многие даже продвинутые пользователи не догадываются, сколько удобства могут принести все эти замечательные возможности. Сегодня мы создадим таблицы маршрутизации и опишем правила прохода по ним, а также автоматизируем администрирование этих таблиц. Итак, наши творческие планы:

  • определимся с тем, что нам требуется: установим необходимые пакеты и разберемся, зачем они нужны;
  • изучим общий принцип работы связки;
  • настроим защищенный канал VPN с использованием OpenVPN + stunnel;
  • составим списки адресов и опишем области их применения;
  • создадим скрипт для быстрого добавления домена или IP-адреса в списки IPSet с добавлением в таблицу маршрутизации и включением в правила перенаправления;
  • используем SSH для предоставления безопасного канала связи в эти ваши интернеты.

Шифрование трафика в Linux

Что нам понадобится, чтобы все работало, и желательно — комфортно? Само собой, iptables, куда же без него. Еще iproute2, он и позволит нам насоздавать кучу таблиц. IPSet потребуется для того, чтобы не городить огород из множества правил iptables.

Что есть что

  • iptables — утилита командной строки. Базовое средство управления работой файрвола для ядер Linux.
  • iproute2 — набор утилит для управления параметрами сетевых устройств в ядре Linux.
  • IPSet — инструмент для работы со списками IP-адресов и сетевых портов в сетевом фильтре. Формирует список в специальном формате для передачи файрволу.
  • stunnel — инструмент организации шифрованных соединений для клиентов или серверов, которые не поддерживают TLS или SSL. Stunnel перехватывает незашифрованные данные, которые должны были отправиться в сеть, и шифрует их. Программа работает как в Unix-системах, так и в Windows. В качестве шифрования использует OpenSSL для реализации базового протокола TLS и SSL.
  • OpenVPN — VPN-сервер с поддержкой шифрования библиотекой OpenSSL. Клиентские части доступны практически на всех платформах. Умеет работать через прокси типа Socks, HTTP, через NAT и сетевые фильтры.

Про все эти утилиты можно отыскать много информации в интернете, причем с примерами настроек в самых разных вариантах. Мы станем использовать iptables для маркировки пакетов. У нас будут два варианта настройки. Первый — когда машина, на которой выполняется обход, сама подключена к VPN. Второй вариант — когда в сети находится узел (виртуалка, Raspberry Pi или любой другой хост с Linux), играющий роль маршрутизатора. Далее мы разберем эти варианты чуть подробнее.

Коротко о двух вариантах

Клиент и сервер будут устанавливать зашифрованный канал связи по 443-му порту (stunnel) и передавать внутри OpenVPN по 995-му порту. Снаружи это должно выглядеть как обычный HTTPS

Иллюстрация работы stunnel + OpenVPN

И вот тут можно реализовать две схемы подключения.

Вариант 1. На клиентской машине iptables будет маркировать пакеты неким флагом, если адреса в пакетах и списках IPSet совпадут, и передавать их для маршрутизации.

Далее помеченные флагом пакеты будут отправлены по заранее созданной таблице маршрутизации, остальные пойдут по маршруту, заданному по умолчанию. С помощью консоли или небольшого скрипта мы поправим этот список адресов. В зависимости от ситуации списков может быть несколько.

Вариант 2. В качестве клиента выступит хост в локальной сети (виртуалка, Raspberry Pi или какое-нибудь другое устройство). Он будет указан в качестве основного шлюза на компьютерах, с которых нужен доступ к ресурсам через VPN. Получив запрос для IP-адреса из списка, шлюз включит NAT и отправит такой трафик в VPN. Остальной трафик будет маршрутизироваться до шлюза по умолчанию без NAT.

Для Linux-систем мы можем оставить шлюз по умолчанию и установить у себя IPSet и iproute2, а потом настроить их аналогично настройкам «промежуточного» хоста-маршрутизатора. В этом случае на уровне клиента будет отбираться трафик по тому же списку IPSet. То есть то, что в списке, будет отправляться на промежуточный хост-маршрутизатор и далее в VPN. Остальное будет маршрутизироваться по умолчанию.

Реализация

Предположим, что где-то далеко в облаке у нас уже есть VPS-сервер с Ubuntu или Debian. В других дистрибутивах отличия будут, скорее всего, только в установке необходимых пакетов. Этот хост в нашей конфигурации будет использоваться в качестве сервера VPN. Рекомендаций, какой VPS лучше использовать, в интернетах полным-полно — на разный бюджет, с разными конфигурациями и условиями.

Устанавливаем на сервере OpenVPN, stunnel, git:

sudo apt install openvpn stunnel4 git

Далее воспользуемся готовым скриптом для настройки сервера OpenVPN. Можно, конечно, настроить все вручную, и я советую поступить именно так. Информацию о том, как правильно сконфигурировать OpenVPN, нетрудно отыскать в Сети. Но если нужно получить результат очень быстро и вам не хочется возиться, то вот быстрое решение.

git clone https://github.com/Nyr/openvpn-install.git
cd openvpn-install
sudo ./openvpn-install.sh

Получаем скрипт установки и запускаем его. Он поможет вам создать пользовательские ключи и сертификаты, если нужно — изменить адресацию сети. Все очень доступно и понятно. На выходе для каждого пользователя мы получим один файл, внутри которого будет конфигурационный ключ и сертификаты (сервера и пользователя). Передаем этот файл на клиент.

Открываем конфигурационный файл сервера OpenVPN и правим его. Выбираем нужный порт — тот, который на сервере будет свободен для подключения. Порт лучше использовать более-менее неприметный (я выбрал 995-й, обычно почтовые порты оставляют открытыми), чтобы клиент мог гарантированно подключиться к VPN-серверу.

Вот как будет выглядеть наш конфиг:

Следующим шагом настроим stunnel:

sudo nano /etc/stunnel/stunnel.conf

Тут все просто:

  • описываем, куда будут сохраняться логи;
  • указываем название сервиса в произвольной форме;
  • выбираем, в каком режиме работает устройство: сервера или клиента. В данном случае client = no указывает на режим сервера;
  • accept = 443 указывает порт, к которому будем подключаться снаружи (443-й порт выбран не просто так — в 99% случаев он всегда открыт, проще прикинуться обычным HTTPS, и нас не заметят даже при DPI).

Генерируем ключи и сертификаты для stunnel:

sudo openssl req -nodes -new -days 365 -newkey rsa:1024 -x509 -keyout stunnelsrv.pem -out stunnel.pem

На этом этапе важно помнить, что у нас на стороне сервера работают OpenVPN на порте 995 proto tcp, dev tun0 и stunnel на порте 443. Все остальные настройки — стандартные.

Переходим к клиенту:

sudo apt install iproute2 ipset stunnel4 git openvpn

Все, что нужно, поставили, теперь настраиваем stunnel на стороне клиента:

Здесь мы указываем, куда выводить логи, режим клиента включен. С помощью директивы accept мы говорим, на какой адрес и порт передавать соединение и куда, собственно, подключаться клиенту stunnel (опция connect). Ну и какой сертификат использовать.

Передаем файл клиента OpenVPN с сервера. Проверяем настройки: используется порт 995, proto tcp, dev tun0. Очень важный момент: нам нужно объявить маршрут до нашего VPS через шлюз по умолчанию. Иначе получится, что stunnel установит соединение, потом подключится VPN и попытается все перенаправить в туннель, но stunnel уже не сможет работать, так как хост и порт будут недоступны. Также отключаем перенаправление всего трафика в VPN, проверяем адрес подключения и порт. Адрес VPN-сервера в конфиге будет 127.0.0.1 — то есть localhost. Подразумевается, что stunnel уже пробросил нужный порт клиента. Должно получиться примерно следующее:

Итак, на сервере и клиенте установлены и настроены OpenVPN и stunnel. Безопасное соединение установлено. Дальше будем рассматривать каждый вариант по очереди.

Вариант 1: клиент VPN на машине пользователя

Первым делом создадим список IP-адресов, который будем использовать далее:

sudo ipset -N vpn iphash

Добавим в него один адрес для тестов:

sudo ipset -A vpn 8.8.8.8

Теперь нам необходимо маркировать пакеты с адресами назначения, которые совпадают со списком.

sudo iptables - OUTOUT -t mangle -m set --match-set vpn dst -j MARK --set-mark (1 или 0x1)

В результате наших действий iptables при совпадении в адресе назначения и адресе из списка IPSet начнет маркировать такой трафик. Дальше создадим новую таблицу маршрутизации, для этого пропишем ее в файле /etc/iproute2/rt_tables с очередностью выше, чем default (253):

252 vpn

Теперь надо создать правило и маршрут для маркированных пакетов.

sudo ip rule add table vpn prio 1000 fwmark (1 или 0x1)
sudo ip route add table vpn dev tun0 default

Не забываем включитьrp_filter

для обеспечения асимметричной маршрутизации и разрешаем переброс пакетов между интерфейсами, на случай если кому-то нужно будет предоставить доступ к закрытым ресурсам в локальной сети.

sudo sysctl net.ipv4.tcp_fwmark_accept=1
sudo sysctl net.ipv4.conf.all.rp_filter=2
sudo net.ipv4.ip_forward=1

Теперь включим NAT для трафика, который направляется в VPN.

sudo iptables -t nat -I POSTROUTING -o tun0 -j MASQUERADE

Если нужно предоставить доступ из локальной сети через свой VPN, правило iptables нужно немного подправить, а именно перенести в другую цепочку.

sudo iptables -I PREROUTING -t mangle -m set --match-set tovpn dst -j MARK --set-mark 0x1

В итоге у нас получается, что все адреса из списка IPSet VPN идут через безопасное соединение, остальные направляются через маршрут по умолчанию.

Всем спасибо за внимание!