Qeli 0.8.1 · dual-stack и routed IPv6

IPv6 и dual-stack в Qeli

Внешний IPv4/IPv6 carrier, внутренний NetworkPlan v2, ULA/GUA, NAT66 или маршрутизация, встроенный NDP proxy для on-link префиксов, DNS, MTU и безопасная миграция.

Два уровня

Внешний carrier и внутренний TUN независимы

Начиная с 0.8.0 Qeli разделяет семейство соединения с сервером и семейства пакетов внутри туннеля. bind/listen/server могут использовать IPv4, IPv6 или hostname с A/AAAA, а tun.ip_mode, пулы и аутентифицированный NetworkPlan определяют внутренний IPv4/IPv6 data plane.

IPv4-carrier может переносить внутренний IPv6, а IPv6-carrier — внутренний IPv4. IPv6-literal в клиентском INI всегда пишется со скобками: server = [2001:db8::10]:443.
Провайдер выдал отдельный публичный on-link префикс? Перейдите к разделу «NDP proxy: настройка и проверка» — там есть схема работы, полный конфиг и диагностика через tcpdump.
Режим профиля

tun.ip_mode = ipv4 | dual | ipv6

РежимЧто получает клиентПрименение
ipv4IPv4 lease, маршруты и DNS.Совместимость или сервер без готового IPv6 uplink.
dualНезависимые IPv4 /32 и IPv6 /128 на L3 TUN, оба набора маршрутов и DNS.Рекомендуемый обычный режим.
ipv6Только IPv6 lease и план.Специализированная IPv6-only сеть; доступа к IPv4-only сервисам без отдельного NAT64 не будет.

NetworkPlan v2 отдельно передаёт assigned address, on-link prefix и gateway для каждого семейства и применяется атомарно. Полуприменённый план не считается успешным подключением.

Базовый профиль

Минимальный dual-stack пример

server.conf · [profile:main]
tun.ip_mode = dual
tun.name = vpn0
tun.address = 10.19.0.1
tun.ipv6_address = fd71:e1:8000:102::1
tun.mtu = 1400
tun.device_type = tun

pool.cidr = 10.19.0.0/24
pool.ipv6.cidr = fd71:e1:8000:102::/64

routing.nat.enabled = true
routing.ipv6.mode = nat66

dns.enabled = true
dns.listen = 10.19.0.1
dns.listen_ipv6 = fd71:e1:8000:102::1
dns.push_servers = 10.19.0.1, fd71:e1:8000:102::1

Используйте уникальный для развёртывания RFC 4193 ULA /48 и отдельный /64 на профиль. Не копируйте пример fd71:… буквально между независимыми установками и не используйте link-local fe80::/10 как пул. Quick Start генерирует случайный 40-битный Global ID.

Выход и маршруты

routing.ipv6.mode

ЗначениеЧто делаетТребования
nat66Подменяет ULA-источник на IPv6 WAN сервера.IPv6 default route, публичный GUA из 2000::/3 и рабочий ip6tables NAT. Удобно на обычном VPS, но это NAT.
routeСохраняет исходный IPv6 клиента.Для выхода в интернет — маршрутизируемый провайдером GUA-префикс и обратный маршрут. Для LAN/site-to-site достаточно маршрутов между своими сетями.
offНе выпускает IPv6 из профиля и ставит fail-closed изоляцию.Рабочий ip6tables нужен, чтобы DROP был гарантирован.
Не используйте WAN /64, уже назначенный uplink-интерфейсу, как клиентский pool. Нужен отдельный routed или отдельный on-link префикс; для второго в 0.8.1 доступен session-aware NDP proxy.

Для routed GUA задавайте reservation или static_ipv6; CLI поддерживает qeli add-client --static-ipv6 ….

Публичный IPv6 без NAT66 · 0.8.1

NDP proxy: когда нужен и как настроить

NDP (Neighbor Discovery Protocol) в IPv6 выполняет в том числе задачу, похожую на ARP в IPv4: соседний маршрутизатор отправляет Neighbor Solicitation (NS) и спрашивает, какой MAC-адрес обслуживает конкретный IPv6. Адрес VPN-клиента находится на TUN, а не на WAN-интерфейсе сервера, поэтому при on-link префиксе Qeli отвечает upstream-маршрутизатору сообщением Neighbor Advertisement (NA) с MAC-адресом сервера и затем маршрутизирует пакет в активную VPN-сессию.

Это не NAT66. Исходный публичный IPv6 клиента сохраняется. NDP proxy нужен только тогда, когда провайдер считает отдельный клиентский префикс непосредственно подключённым к своему L2-сегменту. Если провайдер создал обычный L3-маршрут префикса через WAN-адрес сервера, оставьте routing.ipv6.ndp_proxy = off.

Выберите режим по топологии провайдера

Что делает провайдерПризнакНастройка Qeli
Маршрутизирует отдельный префикс через WAN-адрес сервераДля клиентских адресов на WAN не приходят NS; в панели провайдера указан route/next hop.routing.ipv6.mode = route
routing.ipv6.ndp_proxy = off
Считает отдельный префикс on-linkНа WAN приходят NS для каждого публичного IPv6 клиента.routing.ipv6.mode = route
routing.ipv6.ndp_proxy = required
Топология пока неизвестнаНет точного описания у провайдера.Сначала проверьте трафик через tcpdump. auto допустим для диагностики, но для рабочей on-link схемы используйте required.

Как понять, нужен ли proxy

Не назначайте клиентский префикс WAN-интерфейсу. Остановите профиль или сервер, запустите захват на фактическом IPv6 uplink и с независимого внешнего IPv6-хоста обратитесь к будущему адресу клиента:

сервер Qeli и внешний IPv6-хост
# На сервере Qeli
$ sudo systemctl stop qeli-server
$ ip -6 addr show dev ens3
$ ip -6 route show table all
$ sudo tcpdump -ni ens3 'icmp6 && ip6[40] == 135'

# На внешнем IPv6-хосте
$ ping -6 2001:db8:1200:10::100

Строка Neighbor Solicitation, who has 2001:db8:1200:10::100 означает, что upstream ищет MAC для клиентского адреса и этой схеме нужен NDP proxy. Если NS нет, сначала проверьте правильность адреса, WAN-интерфейс, firewall/security group и условия провайдера: одно отсутствие пакета ещё не доказывает L3-routed схему.

Полный фрагмент профиля

Адреса 2001:db8::/32 ниже предназначены только для документации. Замените их отдельным GUA-префиксом, выданным провайдером для клиентов.

server.conf · [profile:public-v6-onlink]
[profile:public-v6-onlink]
tun.ip_mode = ipv6
tun.name = vpn-public
tun.ipv6_address = 2001:db8:1200:10::1
tun.mtu = 1280
pool.ipv6.cidr = 2001:db8:1200:10::/64

# Сохранять публичный IPv6 клиента; MASQUERADE не создаётся.
routing.ipv6.mode = route
routing.ipv6.interface = ens3
routing.ipv6.ndp_proxy = required
routing.ipv6.ndp_proxy_interface = ens3

[user:alice]
static_ipv6 = 2001:db8:1200:10::100
Не назначайте pool.ipv6.cidr интерфейсу ens3 и не создавайте для него connected route через WAN. Маршрут клиентского префикса должен вести только в TUN профиля; upstream выполняет NDP со своей стороны. Для dual-stack замените tun.ip_mode = ipv6 на dual и сохраните существующие параметры IPv4.

Параметры и требования

РежимПоведение
offResponder выключен. Значение по умолчанию и правильный выбор для обычного L3-routed префикса.
autoПытается открыть responder. При неподходящем интерфейсе, отсутствии Ethernet или CAP_NET_RAW пишет предупреждение и продолжает работу без него.
requiredНе запускает профиль, пока responder не привязан к выбранному интерфейсу. Рекомендуется для рабочей on-link схемы.

Пустой routing.ipv6.ndp_proxy_interface использует фактический uplink из routing.ipv6.interface или IPv6 default route. Нужен Ethernet-совместимый Linux-интерфейс и право CAP_NET_RAW; обычный системный сервис Qeli уже запускается с необходимыми правами. NDP proxy допустим только вместе с source-preserving режимом route, но не с nat66 или off.

Какие адреса Qeli объявляет

  • Точный IPv6 lease активной сессии из pool.ipv6.cidr, включая static_ipv6.
  • Адреса внутри non-default IPv6 client_subnet, зарегистрированного за подключённым router/site-to-site клиентом.
  • Только адреса живых сессий: disconnect, revoke или замена сессии немедленно снимают ownership.
  • /0, link-local, multicast, неверные NS и посторонние target-адреса игнорируются. Qeli не превращает responder в общий multicast relay.

Проверка после запуска

конфигурация, журнал, маршрут и NDP
$ sudo qeli check-config --config /etc/qeli/server.conf
$ sudo systemctl restart qeli-server
$ sudo journalctl -u qeli-server -n 100 --no-pager | grep -F 'IPv6 NDP proxy'
$ ip -6 route show 2001:db8:1200:10::/64
$ sudo tcpdump -ni ens3 'icmp6 && (ip6[40] == 135 || ip6[40] == 136)'

При required журнал должен сообщить session-aware IPv6 NDP proxy active on 'ens3', а маршрут клиентского /64 — вести через vpn-public. Пока Alice отключена, новый NS для её адреса не получает NA. После подключения Qeli отвечает своим MAC, а внешний трафик направляется в её TUN-сессию. После отключения новые ответы прекращаются; старая запись в neighbor cache upstream может сохраняться до истечения своего таймера.

СимптомЧто проверить
required не запускает профильИмя uplink, Ethernet-тип интерфейса, root/CAP_NET_RAW и сообщение в journal.
В tcpdump нет NSПравильность адреса и WAN-интерфейса, provider route/security group; возможно, префикс уже маршрутизируется и proxy не нужен.
NS есть, но NA нет при подключённом клиентеФактически выданный static_ipv6, состояние сессии и попадание target в pool или активный client_subnet.
NA есть, но трафик не доходитМаршрут /64 в TUN, IPv6 forwarding, ip6tables/cloud firewall и firewall клиента.
auto запустился без NDPНайдите предупреждение NDP proxy auto mode is unavailable, исправьте причину и переключитесь на required.
Политика клиента

ipv6 = auto | required | off

ПолитикаРезультат
autoПринимает IPv4, dual или IPv6. Dual может безопасно понизиться до IPv4, если платформа не умеет полный IPv6-контракт.
requiredТребует внутренний IPv6 и fail-closed при старом сервере, IPv4-only профиле, MTU ниже 1280 или неполной поддержке платформы.
offПросит IPv4 у dual-профиля и отклоняет IPv6-only план.

В full-tunnel отсутствие одного семейства блокируется по умолчанию. allow_ipv6_leak=true или allow_ipv4_leak=true — явный escape hatch, разрешающий отсутствующему семейству идти физическим путём. Оба значения по умолчанию false.

DNS и MTU

Настройте оба семейства целиком

  • dns.listen и dns.listen_ipv6 должны совпадать с активными gateway-адресами профиля; dns.push_servers не должен раздавать недоступный listener.
  • IPv6 требует MTU не меньше 1280. Политика required отвергает меньший план, а PMTU probing подбирает безопасный carrier budget.
  • route, route_file, server push и ACL принимают IPv4/IPv6 CIDR, но применяются только для согласованного семейства.
  • Outer DNS для hostname endpoint может вернуть A и AAAA; roaming способен перенести сессию между семьями после аутентифицированной проверки пути.
Миграция

Старый конфиг не становится dual-stack автоматически

  1. Сделайте backup и обновите сервер до 0.8.1.
  2. Выберите уникальный ULA /64 либо получите у провайдера routed GUA-префикс.
  3. Добавьте tun.ip_mode, tun.ipv6_address, pool.ipv6.cidr, IPv6 DNS и routing.ipv6.mode.
  4. Выполните qeli check-config; для NAT66 дополнительно проверьте default route, публичный source GUA и ip6tables NAT.
  5. Оставьте клиентам ipv6=auto, проверьте IPv4 и IPv6 отдельно, затем при необходимости ужесточайте до required.
Установщик сохраняет active dual-stack только при подтверждённом IPv6 uplink и NAT; иначе создаёт безопасный активный IPv4-only профиль, а подготовленные IPv6 значения остаются для ручного включения после исправления uplink.
Границы

Чего Qeli не делает

  • Qeli не предоставляет NAT64/DNS64. IPv6-only клиент не откроет IPv4-only ресурс без отдельной NAT64-инфраструктуры.
  • Qeli не превращает случайный WAN /64 в клиентский pool: нужен отдельный routed/on-link префикс и корректный обратный путь.
  • IPv6 внутри туннеля не означает, что серверный uplink автоматически готов: проверяйте адрес, default route, firewall и обратный маршрут.
Первоисточники

Полная документация IPv6 0.8.1