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

Маршрутизация IPv6 через WireGuard с поддержкой SLAAC

Время на прочтение6 мин
Количество просмотров20K

Вдохновившись аргументами из статьи «IPv6 — прекрасный мир, стоящий скорого перехода на него», мне стало катастрофически не хватать IPv6. Конечная цель: обеспечить каждое из своих устройств уникальным публичным псевдостатическим IPv6.

Для дома решение довольно простое: при наличии статического IPv4, можно получить подсеть IPv6 от туннельного брокера и на этом вопрос можно считать закрытым.

А вот с мобильными устройствами так не получится: услуга статического IPv4 тут скорее редкость; да и при наличии бесплатного WiFi я выберу подключение к нему, а не к мобильной сети.

Остаётся единственный вариант — использовать VPN. Существующие на GitHub решения типа “wireguard-install” или “openvpn-install” имеют фатальный недостаток: они отдают клиенту единственный IPv6/128 адрес, а чтобы у клиентов появилась возможность автоконфигурации, нужна целая /64 подсеть.

Предлагается решение на основе WireGuard.


Вам понадобятся

  1. Особый виртуальный сервер. Для реализации задуманного, нужно купить VDS, которому хостер согласится отдать хотя бы /60 подсеть. Как оказалось, найти такое — достаточно сложная задача: в худшем случае, хостеры почему-то продают IPv6 поштучно; в лучшем — только /64 подсети. В результате долгих поисков и благоприятного стечения обстоятельств, был найдена компания Melbicom, которая способна выделить /56 подсеть на VDS.

  2. Linux + wireguard + udppd + nftables. На моём сервере установлен ArchLinux, но описанное решение может быть воспроизведено и на других дистрибутивах.

Условные обозначения

ens3 – имя сетевого интерфейса.

Далее в тексте используются следующие «IP» адреса:

  • 2a06:X:X:a::2/128 и 213.x.x.2/24 – IPv6 и IPv4 адреса VDS. Назначаются хостером автоматически и бесплатно к каждому приобретаемому VDS.

  • 2a06:X:X:100::/56 – Маршрутизируемая до VDS подсеть /56 IPv6. Заказывается отдельно.

  • 2a06:X:X:111::/64 – подсеть для клиента (мобильного устройства), которая выделяется из заказанной выше /56 подсети.

  • 2a06:X:X:111:a:b:c:d/64 – пример IPv6 клиента (мобильного устройства), где a:b:c:d (interface id) выбирается клиентом самостоятельно.

Где заглавная буква X означают одну группу шестнадцатеричных цифр IPv6 адреса, а строчная x - одну группу десятичных цифр IPv4 адреса.

Тестирование наличия выделенной /56 подсети

Изначально, на сервере, сеть не должна быть настроена, но должна маршрутизироваться до него. Содержимое /etc/systemd/network/ens3.network выглядит примерно так:

[Match]
Name = ens3

[Network]
Address = 213.x.x.2/24
Gateway = 213.x.x.1

Address = 2a06:X:X:a::2/128
Gateway = 2a06:X:X:a::1

Для проверки, выполним команду: tcpdump ip6 -nq -i ens3

Далее, пингуем любой IPv6 из выделенной подсети, например 2a06:X:X:111:a:b:c:d. Если всё хорошо, то в дампе появятся строки типа:

19:14:39.689842 IP6 fe80::XX > ff02::XX ICMP6, neighbor solicitation, who has 2a06:X:X:111:a:b:c:d, length 32

Установка ndppd

Ndppd — это демон, задача которого слушать интерфейс: ожидать «neighbor solicitation» и отвечать «router advertisement» Таким образом, вышестоящий роутер узнает, куда адресовать трафик выделенной подсети. Далее этот трафик через wireguard будет передан клиенту.

К сожалению, в ArchLinux ndppd пока доступен только из AUR. Если в вашем дистрибутиве он доступен из репозиториев, переходите к следующем разделу.

Для начала ставим все необходимые компоненты:
pacman -Suy git base-devel

Далее создаём пользователя, под которым будем все это собирать:
useradd -m router

Переходим в пользователя:
su router

cd /home/router

Теперь из-под пользователя выполняем команды:
git clone https://aur.archlinux.org/ndppd.git

cd ndppd

makepkg

Возвращаемся в root:
exit

Переходим в каталог ndppd:
cd /home/router/ndppd

Находим в каталоге ndppd-*.zst файл и устанавливаем его:
pacman -U ndppd-0.2.5-1-x86_64.pkg.tar.zst

Настройка ndppd

Создаём файл /etc/ndppd.conf с содержимым:

proxy ens3 {
	rule 2a06:X:X:100::/56 {
		static
	}
}

Где:

  • ens3 – имя интерфейса

  • static - опция, которая сообщает ndppd, что он должен немедленно отвечать на Neighbor Solicitation, без дополнительных проверок.

Подробное описание параметров изложено в документации.

Далее активируем сервис:
systemctl enable ndppd

и запускам:
systemctl start ndppd

Установка системных переменных

Чтобы заработала пересылка IPv6 пакетов между интерфейсами, необходимо в каталоге /etc/sysctl.d/ создать файл wireguard.conf с содержимым:

net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

Первая строка включает пересылку IPv4, вторая — IPv6. Подробное описание каждого из параметров можно узнать из документации.

Применяем настройки:
sysctl --system

Настройка WireGuard на сервере

Создаём публичный и приватный ключи сервера:
wg genkey | tee server-private.key | wg pubkey > server-public.key

Создаём публичный и приватный ключи клиента:
wg genkey | tee client1-private.key | wg pubkey > client1-public.key

Создаём pre-shared key:
wg genpsk > pre-shared.key

Создаём файл /etc/wireguard/wg0.conf:

[Interface]
SaveConfig = false
ListenPort = 52525 #Может быть любым
PrivateKey = #содержимое server-private.key#
Address = 10.20.30.1/24, 2a06:X:X:100::/56

[Peer]
PublicKey = #содержимое client1-public.key#
PresharedKey = #содержимое pre-shared.key#
AllowedIPs = 10.20.30.17/32, 2a06:X:X:111::/64

Активируем и запускаем демона wireguard:
systemctl enable wg-quick@wg0 && systemctl start wg-quick@wg0

В случае изменения конфигурации, перезапуск удобно выполнять командой:
wg-quick down wg0 && wg-quick up wg0

Настройка nftables

Поскольку iptables постепенно выходит из употребления, я предпочитаю nftables.

Установка командой:
pacman -S nftables

Для конфигурации нужно создать или отредактировать файл /etc/nftables.conf :

#!/usr/sbin/nft -f

# Start by flushing all the rules.
flush ruleset

# Документация https://man.archlinux.org/man/nft.8

# Определение переменных: интерфейсы и виртуальная локальная IPv4 подсеть
define wan = ens3
define vpn = wg0
define vpn_net4 = 10.20.30.0/24

# Общие настройки для IPv6 и IPv4
table inet wg-common {
	# Все пересылаемые пакеты по умолчанию дропаем, за исключением тех, которые идут между vpn и wan
	chain forward {
		type filter hook forward priority 0; policy drop;
		iifname $wan oifname $vpn accept;
		oifname $wan iifname $vpn accept;
	}

	chain input {
		type filter hook input priority 0;

		# allow established/related connections
		ct state {established, related} accept

		# early drop of invalid connections
		ct state invalid drop

		# allow from loopback
		iifname lo accept

		# allow icmp
		ip protocol icmp accept
		meta l4proto ipv6-icmp accept

		# allow ssh
		tcp dport ssh accept
		
		# Разрешаем вкходящие соединения с WireGuard
		udp dport 52525 accept;

		# everything else
		reject with icmpx type port-unreachable
	}
}

# Настройка NAT для IPv4
table ip wg-nat {
	# Все исходяющие пакеты IPv4 c подсети vpn на интерфейс wan подвергаются маскараду
	chain pre {
		type nat hook postrouting priority 0;
		oifname $wan ip saddr $vpn_net4 masquerade persistent;
	}
}

Настройка WireGuard на клиенте

Конфигурация клиента выглядит так:

[Interface]
PrivateKey = #содержимое client1-private.key#
Address = 10.20.30.17/32, 2a06:X:X:111:a:b:c:d/64
DNS = 9.9.9.9, 149.112.112.112, 2620:fe::fe, 2620:fe::9

[Peer]
PublicKey = #содержимое server-public.key#
PresharedKey = #содержимое pre-shared.key#
AllowedIPs = 2000::/3
Endpoint = #Публичный IP сервера, или домен#:52525
PersistentKeepalive = 25

На этом конфигурация завершена. Всё, что осталось это установить на телефон WireGuard, импортировать полученный конфиг, включить и пользоваться IPv6. Важной особенностью тут является то, что в IPv6 адресе клиента вместо a:b:c:d можно указать абсолютно любой interface id. Такой себе ручной SLAAC. А если хочется пустить через wireguard ещё и весь IPv4 трафик, в поле AllowedIPs добавьте подсеть 0.0.0.0/0 .

Бонус: обход блокировок

Если из-за политики государства, часть Интернета заблокирована, при помощи клиента WireGuard на роутере с OpenWRT можно обойти блокировку.

Для этого переносим конфиг клиента на роутер с OpenWRT, указав в параметре AllowedIPs заблокированные подсети. Например, чтобы разблокировать Яндекс из Украины, нужно указать:

AllowedIPs=5.45.192.0/18,5.45.196.0/24,5.45.202.0/24,5.45.205.0/24,5.45.213.0/24,5.45.229.0/24,5.45.240.0/24,5.255.192.0/18,5.255.195.0/24,5.255.196.0/24,5.255.197.0/24,5.255.255.0/24,37.9.64.0/18,37.9.64.0/24,37.9.73.0/24,37.9.112.0/24,37.140.128.0/18,77.88.0.0/18,77.88.8.0/24,77.88.35.0/24,77.88.44.0/24,77.88.54.0/24,77.88.55.0/24,87.250.224.0/19,87.250.247.0/24,93.158.128.0/18,95.108.128.0/17,100.43.64.0/19,141.8.128.0/18,141.8.174.0/24,178.154.128.0/19,178.154.131.0/24,178.154.160.0/19,185.32.187.0/24,199.21.96.0/22,199.36.240.0/22,213.180.192.0/19,213.180.199.0/24,2a02:6b8::/29,2620:10f:d000::/44

Список подсетей Яндекса взят отсюда https://ipinfo.io/AS13238

IPv4 заработает сразу. А чтобы заработал IPv6, нужно при помощи nat6 подменить префикс клиента. В разделе Firewall :: Custom Rules допишем следующие пользовательские правила:

ip6tables -t nat -A POSTROUTING -d 2a02:6b8::/29 -j NETMAP --to 2a06:X:X:111::/64
ip6tables -t nat -A POSTROUTING -d 2620:10f:d000::/44 -j NETMAP --to 2a06:X:X:111::/64

После этого можно перейти на https://yandex.ru/internet/ и убедиться, что всё работает.

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 10: ↑10 и ↓0+10
Комментарии22

Публикации

Истории

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

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань