VPN через I2P: wireguard & i2pd

от автора

Дисклеймер. Автор статьи никоим образом не призывает к чему-либо, что противоречит законодательству РФ и других благословенных государств. Юзкейс этой статьи родился в быту: был я, значит, в командировке в одной из стран ближайшего (дружественного) зарубежья, а там wireguard почему-то плохо работал, а без него связь с офисом в Москве встала — удалёнка не работает. Вот и пришлось изобретать…

О чём речь

В этой статье вы узнаете как подключиться к VPN-серверу wireguard через I2P, завернув в VPN весь нужный трафик устройства, при этом приложение I2P (i2pd) будет работать штатно через домашнего интернет-провайдера. Представленная конфигурация описана для Linux-систем, в частности для дистрибутивов, основанных на Debian (с другими принципиальных проблем тоже быть не должно).

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

Сервер

Команды приведены от рута (без sudo).

Устанавливаем wireguard:

apt install wireguard

Конфигурируем wireguard в качестве принимающего сервера. Чтобы не заниматься консольными танцами, можно воспользоваться онлайн-генератором конфигов. Обратите внимание на CIDR (адрес сети), чтобы он не конфликтовал с другими вашими сетями. В примере я использую 10.20.25.0/24. Серверную часть ложим в /etc/wireguard/wg0.conf (строки PostUp и PostDown выбрасываем, это лишнее). Также не забудьте сохранить клиентский конфиг.

В моем случае серверный конфиг рассчитан на одного клиента и выглядит примерно так (можете использовать, если сеть не конфликтует с другими вашими сетями, и не забудьте подставить ключи):

[Interface] Address = 10.20.25.1/24 ListenPort = 51820 PrivateKey = ***  [Peer] PublicKey = *** AllowedIPs = 10.20.25.2/32

Wireguard не имеет настройки для биндинга на конкретный адрес, поэтому слушает на всех сетевых интерфейсах. Если это вас не устраивает, воспользуйтесь фаерволом.

Поднимаем интерфейс wireguard и добавляем его в автозагрузку:

systemctl start wg-quick@wg0 systemctl enable wg-quick@wg0

Включаем форвардинг трафика. В файле /etc/sysctl.conf раскомментируем строку net.ipv4.ip_forward = 1 (если такой строки нет, просто добавьте ее в начало файла). Применяем изменения командой

sysctl -p

Если видите ошибку о том, что команда не найдена, воспользуйтесь whereis sysctl и вызовите утилиту по полному пути /usr/sbin/sysctl.

Чтобы система умела не только пересылать пакеты, но и делать это корректно между разными сетями, включаем маскарадинг (на Debian 12 в качестве фаервола по умолчанию используется nftables). В конец файла /etc/nftables.conf добавляем

table ip nat {     chain postrouting {         type nat hook postrouting priority 100; policy accept;         iifname "wg0" masquerade     } }

Обратите внимание, что эта конфигурация включает маскарадинг только для запросов, которые приходят через интерфейс wireguard (wg0). Чтобы включить маскарадинг во всех направлениях, оставьте в строке только слово masquerade.

На свежей системе nftables.conf примет такой вид:

#!/usr/sbin/nft -f  flush ruleset  table inet filter {         chain input {                 type filter hook input priority filter;         }         chain forward {                 type filter hook forward priority filter;         }         chain output {                 type filter hook output priority filter;         } }  table ip nat {     chain postrouting {         type nat hook postrouting priority 100; policy accept;         iifname "wg0" masquerade     } }

После изменения конфига, перезапускам nftables:

systemtl restart nftables

Базовая настройка системы в качестве VPN-сервера завершена. Теперь переходим к экзотической части.

Устанавливаем i2pd по гайду из доки:

apt-get install apt-transport-https gpg wget -q -O - https://repo.i2pd.xyz/.help/add_repo | bash -s - apt-get update apt-get install i2pd

Создаем серверный туннель для приема подключений через сеть I2P. Файл /etc/i2pd/tunnels.conf очищаем от лишнего и приводим к следующему виду:

[WG-TUNNEL] type = udpserver address = 127.0.0.1 host = 127.0.0.1 port = 51820 inport = 51820 inbound.length = 0 inbound.quantity = 1 outbound.length = 0 outbound.quantity = 1 keys = wg-tun.dat

Обратите внимание: приведена конфигурация с туннелями нулевой длины. Это значит, что любой человек или бот, который знает I2P-адрес VPN-туннеля, с легкостью определит сервер, на котором он хостится, т.к. концы входящего и исходящего туннелей будут иметь один постоянный IP-адрес.

Если по каким-то причинам вам надо скрыть сервер от вымышленного наблюдателя, установите длину туннелей в один транзитный узел и увеличьте их «ширину», используя эти значения:

inbound.length = 1 inbound.quantity = 16 outbound.length = 1 outbound.quantity = 16

Подробнее про туннели I2P можете почитать тут.

Перезапускаем i2pd и на всякий случай дублируем автозапуск сервиса, который при установке уже был добавлен туда автоматически:

systemctl restart i2pd systemctl enable i2pd

Последнее, что нам требуется на сервере — узнать I2P-адрес нашего туннеля. Самый простой способ — зайти в веб-интерфейс i2pd. Я покажу как это делается через консольный веб-браузер:

apt install lynx lynx 127.0.0.1:7070

Навигация стрелками на клавиатуре. Выбираем пункт «I2P tunnels» и оттуда копируем адрес *.b32.i2p под заголовком из конфига (WG-TUNNEL в примере выше).

Клиент

Сначала устанавливаем i2pd и wireguard аналогично тому, как это было сделано на сервере. Конфиги пока что не трогаем.

Если сейчас запустить VPN с маршрутом 0.0.0.0/0, то есть в качестве сетевого шлюза системы, i2pd вместе с другими приложениями будет ходить через туннель wireguard. Нюанс в том, что нам надо завернуть трафик wireguard в i2pd, а остальные приложения пускать через WG. Вопрос!

Если VPN маршрутизирует какую-то частную сеть, проблем не будет. Но разберем случай с VPN в качестве основного шлюза. После прочтения вы поймете как упростить эту инструкцию, опустив все танцы у костра, если ваш случай именно про маршрутизацию одной приватной подсети.

Попытки разрешить через фаервол какие-то отдельные порты или адреса для прямого выхода i2pd через домашнего провайдера упрутся в тупик: I2P-роутер общается с огромным количеством случайных адресов и по разным портам. Даже протоколы разные: полноценно используются TCP и UDP.

Решение в том, чтобы организовать изолированное сетевое пространство имен, создать там виртуальный сетевой интерфейс, который будет ходить через физический сетевой адаптер в интернет через домашнего провайдера без всяких VPN. Через специальную виртуальную сеть мы вытащим туннель i2pd в основное сетевое пространство ОС и подключим к нему клиент wireguard. Чтобы вся система была максимально секьюрна, в основном сетевом пространстве имен на сетевом интерфейсе приколотим статический локальный адрес и намеренно не зададим настройки шлюза. Матёрый killswitch получится!

Схема VPN через I2P на Linux

Схема VPN через I2P на Linux

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

Обратите внимание, что в переменной IP_ADDRESS надо указать свободный адрес вашей локальной сети — с ним будет создан изолированный сетевой интерфейс в пространстве имен i2pd, который станет равноценным участником вашей локалки помимо основного интерфейса.

#!/bin/bash # acetone, 2024  # Set your default gateway settings INTERFACE="eth0" IP_ADDRESS="192.168.0.99/24" GATEWAY="192.168.0.1"  # Nothing below this line should be changed unless you know what you are doing!  # Create i2pd network namespace ip netns add i2pd_ns ip netns exec i2pd_ns ip link set lo up  # Create macvlan interface (gateway for i2pd_ns) ip link add macvlan0 link $INTERFACE type macvlan mode bridge ip link set macvlan0 netns i2pd_ns  # Activate the macvlan interface in the i2pd namespace ip netns exec i2pd_ns ip link set macvlan0 up  # Configuring the IP address and route for i2pd_ns ip netns exec i2pd_ns ip addr add $IP_ADDRESS dev macvlan0 ip netns exec i2pd_ns ip route add default via $GATEWAY dev macvlan0  # Create virtual interfaces for i2pd to communicate with the main system ip link add bri2pd_external type veth peer name bri2pd_internal ip link set bri2pd_external up ip link set bri2pd_internal netns i2pd_ns up ip addr add 10.10.10.1/30 dev bri2pd_external ip netns exec i2pd_ns ip addr add 10.10.10.2/30 dev bri2pd_internal

Запускаем скрипт, чтобы создать в системе изолированную сеть и прочие прелести (от рута).

chmod +x ./setup_network.sh ./setup_network.sh

Я использую systemd-сервис, чтобы скрипт отрабатывал всегда при старте системы и без моего участия. Если хотите также, создайте файл /etc/systemd/system/setup-network-ns.service со следующим содержимым (исправьте строку ExecStart):

[Unit] Description=Setup Network Namespace After=network.target Wants=network.target  [Service] Type=oneshot User=root ExecStart=/path/to/your/setup_network.sh RemainAfterExit=yes  [Install] WantedBy=multi-user.target

Когда файл сервиса создан, добавляем его в автозагрузку:

systemctl enable setup-network-ns

Сетевое пространство имен создано. Чтобы мы смогли без прав суперпользователя и ввода пароля запускать в нем приложения, поставим утилиту netns-exec:

apt install git build-essential git clone --recursive https://github.com/freeacetone/netns-exec cd netns-exec make make install

Финишная прямая! Конфигурируем i2pd и wireguard.

В /etc/i2pd/tunnels.conf убираем лишнее и создаем туннель до сервера (замените значение в строке destination):

[WG-CLIENT] type = udpclient address = 10.10.10.2 host = 10.10.10.2 port = 51820 destination = ***.b32.i2p destinationport = 51820 inbound.length = 1 inbound.quantity = 16 outbound.length = 1 outbound.quantity = 16 keys = transient-vpn

Приведен конфиг с длиной туннелей в 1 транзитный узел. Это значит, что ваше устройство не будет обращаться напрямую на IP-адрес сервера. Всегда будут рандомные транзитные узлы. Если хотите подключаться напрямую, замените значения на

inbound.length = 0 inbound.quantity = 1 outbound.length = 0 outbound.quantity = 1

Теперь нужно внести небольшое изменение в файл сервиса i2pd, чтобы i2pd запускался в изолированном сетевом пространстве. В файле /lib/systemd/system/i2pd.service исправляем строку ExecStart, добавляя в ее начало /usr/local/bin/netns-exec i2pd_ns

systemctl daemon-reload systemctl restart i2pd

Если все было сделано верно, i2pd работает в отдельной сети и уже предоставляет туннель до VPN сервера. Работу в отдельной сети легко проверить через консольный браузер:

apt install lynx lynx 127.0.0.1:7070

Ошибка — это правильно! i2pd работает в изолированном пространстве имен. Если запустить браузер в том же пространстве (i2pd_ns), все будет ок:

netns-exec i2pd_ns lynx 127.0.0.1:7070

Наконец, конфигурируем туннель wireguard. Создаем файл /etc/wireguard/wg0.conf, вставляем в него клиентский конфиг (подставьте ключи и замените значение Address в зависимости от конфига на сервере):

[Interface] PrivateKey = *** Address = 10.20.25.2/24 DNS = 94.140.14.14  [Peer] PublicKey = *** Endpoint = 10.10.10.2:51820 AllowedIPs = 0.0.0.0/0, ::/0

В AllowedIPs важно вставлять IPv6 маршрут по умолчанию (::/0) даже если сервер VPN его не поддерживает — страховка от того, что IPv6 потечет мимо VPN.

Директива «DNS» не будет работать, если в системе не установлен resolvconf. Установить его просто:

apt install resolvconf 

Готово! Поднимаем туннель wireguard и добавляем его в автозагрузку:

systemctl start wg-quick@wg0 systemctl enable wg-quick@wg0

Важно: чтобы настроить киллсвитч (предотвращение утечки пакетов при отключенном VPN), после завершения всех действий, когда убедитесь, что VPN работает, задайте статические настройки вашего основного сетевого интерфейса, убрав gateway.

Экспириенс

Саспенс — это слово почему-то просится быть первым после «экспириенс» в данном контексте.

Несколько замеров на загрузку большого файла через wget на кабеле 100Мб/сек показали, что при туннелях нулевой длины скорость падает примерно в два-четыре раза с редкими возможными скачками до 80% от реальной пропускной способности канала (верю в светлое будущее, где новые релизы i2pd улучшат показатель). При туннелях с ненулевой длиной стабильный замер практически невозможен: промежуточные узлы — кот в мешке. Видео грузятся и ладно. Стабильным такое подключение назвать нельзя, но и нерабочим — тоже, и это главное. VPN через I2P, Карл!

Возможны ли случайные утечки трафика? При приведенной конфигурации — нет. Сетевое пространство имен для i2pd изолировано от основной системы на уровне ядра ОС, при этом в доступном для пользователя пространстве нет маршрутов по умолчанию кроме VPN-туннеля. Если wireguard по каким-то причинам упадет, ПК останется оффлайн даже при том, что i2pd продолжит штатную работу.

Высокотехнологичный костыль красивее родной ноги.


ссылка на оригинал статьи https://habr.com/ru/articles/869816/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *