Приветствую сообщество.
В этой заметке я хотел бы поделиться своим велосипедом по настройке ipv6 в локациях где невозможно это сделать нормальным способом (провайдер не умеет/может/хочет ipv6).
На входе у нас есть локация где есть ipv4 интернет (дача, регион, офис), oracle VM instance и роутер на базе openwrt обслуживающий сеть в нашей локации.
На выходе мы хотим получить нормально (насколько это возможно в рамках наших ограничений) работающий ipv6 там, где не удалось настроить правильным/ровным способом через провайдера.
Мы будем решать 2 задачи, а именно:
1) Все устройства в нашей локальной сети должны иметь доступ к ipv6 ресурсам в интернете
2) Из интернета мы хотим иметь возможность достучаться до устройств внутри нашей локальной сети по прямому ipv6 адресу.
Это удобно когда, например, на даче у нас есть камеры/хабы/NAS/итд и мы хотим обращаться к ним напрямую по ipv6 адресу.
Теория
Для того чтобы реализовать задачу №1 нам нужен хотя бы один роутер у которого есть ipv6 адрес и который умеет выходить в мир. Все остальные устройства мы спрячем за NAT'ом. Да-да, вы не ослышались, технология которая была придумана чтобы избавить мир от этого ужасного зла, сама будет его использовать :(
Увы, таковы ограничения oracle free tier instances.
Технически это будет выглядеть так.

У нас есть oracle compute instance (далее просто VM) на котором мы настроим global ipv6 address. На этой машине поднимем wireguard vpn, подключим к ней все наши локации и сделаем ip6tables masquerade. Таким образом все наши устройства внутри конкретной локации смогут достучаться до любых ipv6 ресурсов.
Криво ? Да ! Костыльно ? Снова, да ! Есть идеи получше ? Пишите в комментариях.
Для решения задачи №2 нам снова понадобятся костыли но уже иного рода.

Чтобы какое-то устройство было видно из интернета ему нужен global ipv6 address.
А где ж его взять когда его нет ? Ответ: ip6tables DNAT.
Мы настроим на нашей VM еще пачку global ipv6 адресов и будем пробрасывать их на устройства внутри локаций через ip6tables DNAT.
Криво ? Да ! Костыльно ? Снова, да ! Есть идеи получше ? Пишите в комментариях.
Внимательный читатель спросит: а почему бы просто не нарезать и зароутить ipv6 /64 подсеть через wireguard vpn в нужную локацию ?
Увы, oracle free tier не маршрутизирует выделенную подсеть /64 на нашу VM.
Адреса из подсети /64 нужно назначать ручками (ohh, shit) и поштучно (ohh, shit !) c лимитом не более 32 адресов (ohhh, shit ?!) на одну VM :(
Вот такие пироги... С практической точки зрения это означает что мы сможем достучаться не более чем до 32 устройств во всех наших локациях.
Практика
В практической части настройку мы будем делать в трех местах:
роутер на базе прошивки openwrt
oracle cloud interface
внутри oracle VM
В этой заметке предполагается что читатель уже обзавелся oracle cloud free tier account ом (как его получить можно почитать например тут) и уже поднял/настроил wireguard vpn на oracle VM.
Пошаговая инструкция
Шаг 1: Настройка ipv6 на oracle VM
Сначала включаем/настраиваем ipv6 на VM, подробный гайд на эту тему можно почитать тут.
Теперь добавим нашей VM global unique ipv6 адрес.
Это нужно для того чтобы решить задачу №1, именно под этим адресом все устройства из наших локаций будут ходить на ipv6 ресурсы в интернете.
Для этого в интерфейсе oracle cloud:
Идем в Compute → Instances → <выбираем нашу VM> → Attached VNICs → <выбираем Primary VNIC> → IPv6 Addresses → Assign IPv6 Address
В открывшемся блоке Subnet IPv6 Prefix выбираем ранее созданный subnet → Manually assign IPv6 addresses from prefix → <задаем ipv6 адрес> → Assign.
Во всех примерах далее будет использоваться адрес 2603:a:b:c::100Теперь заходим на нашу VM по ssh и добавляем этот адрес на внешний интерфейс
ip a a 2603:a:b:c::100 dev enp0s3 |
Проверяем
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9000 |
Видим что все в порядке, теперь попробуем попинговать его из интернета (не забываем включить соответствующее правило в файерволе если вы его не отключили в oracle cloud interface). Сделать это можно например так.
Если пинг прошел успешно можно вас поздравить и переходить к следующему шагу ?
Шаг 2: Настройка ipv6 в локальной сети нужной локации
Для нормально функционирующего ipv6 на роутере нам необходимо поднять /64 подсеть. Учитывая то, что link-local адреса не маршрутизируются, а global адресов у нас нету мы поднимем ULA подсеть. Эти адреса не глобальные но они маршрутизируются, и этого достаточно для решений обеих задач.
ULA адреса берутся из специально выделенного диапазона fc00::/7.
Мы для удобства будет использовать fd01::/16 для первой локации, fd02::/16 для второй, fd03::/16 для третьей, итд.
На роутере с openwrt это делается очень просто
Идем в Network → Interfaces → Global network options и задаем там желаемую подсеть

Идем в Network → Interfaces и в интерфейсе который обслуживает наш LAN, проверяем что Delegate IPv6 prefixes (checked) и IPv6 assignment length 64 (вкладка Advanced Settings)

После вышеописанных манипуляций убеждаемся что подсеть поднялась на интерфейсе обслуживающем локальную сеть.
Настраиваем DHCPv6 на роутере так, чтобы устройства в нашей сети начали получать адреса вида fd01::/64 (нам понадобятся дальше статические ipv6 адреса когда мы будем настраивать доступ к конкретным устройствам из интернета).
Для этого идем в Network → Interfaces и в интерфейсе который обслуживает наш LAN


Проверяем что устройства внутри нашей локальной сети начали получать адреса вида fd01::a:b:c:d/128
Шаг 3: Настройка wireguard server/client
Тут нет никаких особых премудростей, подойдет любая инструкция.
Ниже я опишу только самые важные моменты.
На сервере (oracle VM) в конфиге wireguard не забываем добавить подсети вида fd01::/64, fd02::/64 итд в AllowedIPs соответствующих секций и перезапустить server
[Peer] |
На клиенте (openwrt router) не забываем в настройки peer в AllowedIPs добавить подсеть → ::/0 и перезапустить интерфейс
На клиенте заворачиваем весь ipv6 трафик на wireguard интерфейс
ip -6 r a default dev wgoracle |
Проверяем пингуется ли ipv6 global адрес из шага 1 с любого устройства из локальной сети.
ping -c 4 2603:a:b:c::100 |
Ну что ж отлично, полпути уже проделано.
На сервере включаем ipv6 forwarding
sysctl -w net.ipv6.conf.all.forwarding=1 |
Ну а теперь самый важный шаг: на сервере настраиваем ipv6 маскарад
ip6tables -t nat -A POSTROUTING -o enp0s3 -s fd01::1/64 -j MASQUERADE |
Это правило говорит о том, что весь трафик из локальной сети fd01::1/64 будет NAT ится в oracle VM global ip из шага 1 (в нашем примере это 2603:a:b:c::100)
С любого устройства из локальной сети пробуем пингануть какой-нибудь внешний ipv6 ресурс
ping6 -c 4 ipv6.ya.ru |
Ура ! Работает ! :) На этом шаге задача №1 успешно решена.
Любые ipv6 ресурсы нам теперь доступны через самопальный ipv6-in-ipv4 туннель :)
Шаг 4: Настраиваем доступ к конкретным устройства внутри LAN из интернета.
Предположим что у нас внутри LAN есть устройства к которым мы хотим достучаться (камера, smart home hub, NAS). И у этих устройств уже есть статические ULA ipv6 адреса которые они получают через dhcpv6 которые мы настроили на шаге 2.
Ниже мы настроим прямой доступ из интернета к устройству fd01::10.
Для всех остальных устройств шаги аналогичные. Приступаем:
На сервере (oracle VM) убеждаемся что устройство доступно по ULA адресу
Далее заходим в oracle cloud interface (как мы делали это на шаге 1) и добавляем адрес 2603:a:b:c::1:10.

Тут хочу замечу что такая нотация удобна лично мне, вы можете выбрать любую другую.
Внешний адрес 2603:a:b:c::1:10 будет мапиться на внутренний fd01::10.
Другой внешний адрес, например, 2603:a:b:c::2:15 будет мапиться в fd02::15.
И так далее.
Самый важный шаг: на сервере настраиваем IPv6 DNAT (по сути маппинг внешнего адреса во внутренний)
ip6tables -t nat -A PREROUTING -d 2603:a:b:c::1:10 -j DNAT --to-destination fd01::10 |
Проверяем через пинг (не забываем настроить правило в файерволе локальной сети) с какого-нибудь внешнего ресурса.
ping -c 4 2603:a:b:c::1:10 |
Ура ! Заработало ! Трафик действительно дошел до нашего устройства :)
Заключение
Ну что ж, обе задачи нами успешно решены через набор подпорок и костылей.
Автор полностью осознает ущербность, неправильность и костыльность предложенных решений и посыпает голову пеплом.
Но, увы, других (более “ровных”) вариантов пока отыскать не удалось.
В комментариях предлагаю забросать автора помидорами и указать правильные способы решения вышеупомянутых задач :)
Успехов !