Qeli 0.8.1 · сеть меняется, сессия остаётся

Session roaming: как Qeli переносит сессию

Смена физического пути без новой lease: TCP/UDP handover, ожидание пригодной Wi‑Fi/LTE сети, fail-closed TUN, stable multipath slots и диагностика.

Суть функции

Сессия отделена от физического соединения

Начиная с Qeli 0.8.0, session roaming сохраняет одну логическую VPN-сессию, когда у устройства меняется физический путь: Wi‑Fi сменяется мобильной сетью, меняется внешний адрес, происходит NAT rebinding или доступным становится другой A/AAAA endpoint. Новый carrier проверяется внутри уже аутентифицированного контракта, поэтому сервер не выдаёт второй lease и не создаёт вторую пользовательскую сессию.

Что сохраняется: TUN, внутренние IPv4/IPv6-адреса, маршруты, DNS-план, квоты и учёт текущей сессии. Меняется только внешний carrier-путь. Это уменьшает окно разрыва, но не обещает абсолютную потерю ноль пакетов на любой сети.
Не путайте с failover профилей. Roaming не переводит профиль reality-tls на udp-quic и не выбирает другой сервер. Он переносит ту же сессию того же профиля между доступными физическими путями.
Последовательность

Prepare → проверка → commit

  1. Платформенный адаптер замечает изменение сети и готовит точный candidate path: временный host route, правила kill-switch и отдельный socket, привязанный к нужному интерфейсу.
  2. Общее ядро связывает candidate с текущей generation/epoch и проверяет его аутентифицированным обменом. Неверный CID, token, направление или stale epoch отклоняются.
  3. До подтверждения старый путь остаётся активным. После успешного commit новый carrier становится единственным текущим путём, а временное candidate-состояние передаётся обычному владельцу сессии.
  4. Ошибка до commit откатывает только candidate. Если результат после точки commit неоднозначен, Qeli завершает generation и выполняет чистый reconnect, не оставляя «живой», но чёрный туннель.
CarrierКак переносится путьЗащита
TCPMake-before-break: новый socket проходит JOIN/проверку до закрытия старого. Commit переносит весь bonded carrier set, а не только один stream.Двухфазный commit и reconnect при неоднозначной post-commit ошибке.
UDPНовый peer/CID считается candidate. Аутентифицированные данные нового пути удерживаются в bounded-очереди до commit.128-битный challenge, anti-amplification, отклонение stale epoch и ограничение candidate.

Тот же механизм покрывает смену внешнего IPv4 на IPv6 и обратно, если endpoint, listener и платформа поддерживают обе семьи. Внутреннее семейство TUN при этом не обязано совпадать с внешним carrier.

Клиент

roaming = off | auto | required

ЗначениеПоведениеКогда выбирать
offCapability скрывается; при смене пути выполняется обычный reconnect.Диагностика или намеренное отключение функции.
autoИспользует согласованный TCP/UDP roaming; при старом сервере, core или неподдерживаемой платформе безопасно возвращается к reconnect.Рекомендуемый режим и дефолт поставляемых клиентских шаблонов.
requiredЗавершает подключение до передачи credentials/полного AUTH, если весь transport-specific контракт недоступен.Только полностью обновлённый и проверенный парк.
Явный local или ненулевой lport закрепляет carrier socket. В auto Qeli использует reconnect fallback, а required отклоняется проверкой конфигурации.
Сервер

Включение и ресурсные пределы

server.conf · [profile:main]
roaming.enabled = true
roaming.grace_secs = 30
roaming.max_orphaned = 256
roaming.max_orphan_bytes = 67108864

# client.conf · [qeli]
roaming = auto
КлючДефолт нового шаблонаДиапазонНазначение
roaming.enabledtrueboolFeature gate профиля. Если ключ отсутствует в старом sparse-конфиге, фактический результат — false.
roaming.grace_secs301…3600Сколько неожиданно отсоединённая TCP-сессия ждёт аутентифицированного resume.
roaming.max_orphaned2561…65536Предел отсоединённых TCP-сессий профиля, сохранённых для resume.
roaming.max_orphan_bytes671088644194304…1073741824Общий предел памяти orphaned-сессий профиля.

Новые профили установщика включают bounded roaming. Обновление бинаря не меняет существующий server.conf: добавьте ключи явно, проверьте qeli check-config и только затем перезапустите профиль.

Совместимость

Транспорты, платформы и маршруты

  • Обычный TCP: plain, fake-tls, obfs, reality и reality-tls.
  • UDP camouflage: udp-fake-tls, udp-quic, udp-obfs и obfs-awg через единую state machine.
  • Android и iOS передают ядру физические network changes; Windows, macOS и Linux используют тот же fail-closed результат candidate/commit. Старый native core в режиме auto означает reconnect.
  • Явные exclude и carrier host routes имеют приоритет: roaming не должен случайно направить endpoint внутрь самого туннеля.
  • Startup и live PMTU проверяются аутентифицированным 128-битным challenge; новая сеть может получить другой безопасный размер пакета.
Новое в 0.8.1

Мобильное восстановление учитывает реальную доступность сети

  • Android и iOS не расходуют reconnect backoff, пока нет пригодного Wi‑Fi или мобильного carrier. После появления связи попытка продолжается сразу.
  • Android сохраняет fail-closed TUN между перезапусками native core, если NetworkPlan не изменился. Ручное Disconnect остаётся окончательным.
  • iOS не применяет повторно идентичные NetworkExtension settings и передаёт новому поколению ядра только bounded-очередь uplink-пакетов, ещё не принятых старым.
  • TCP multipath использует стабильные logical slot ID: исчезновение или возврат одного bonded carrier не переназначает здоровые потоки.
  • Android сохраняет до 1000 последних событий, но не более 512 КиБ, в приватном no-backup журнале. Кнопка Clear удаляет историю; секреты и полный профиль туда не записываются.
Что проверить после обновления: свойства соединения должны показывать фактически согласованные roaming, Recordizer, семейство туннеля и resolved carrier endpoint, а transport ABI 1.15 — отдельно от compatibility floor.
Проверка

Как понять, что roaming действительно сработал

server
$ sudo qeli check-config --config /etc/qeli/server.conf
$ sudo journalctl -u qeli -f
  1. Подключитесь с roaming=auto, запустите непрерывный ping и длинную загрузку.
  2. Переключите Wi‑Fi на мобильную сеть либо измените доступный uplink, не отключая профиль.
  3. Проверьте, что внутренняя lease/TUN не были пересозданы. В панели и статистике должны увеличиться attempts/commits, а candidate после завершения вернуться к нулю.
  4. Если растут failures или reconnect fallbacks, проверьте server feature gate, версию native core, явные local/lport, firewall обоих carrier-путей и PMTU.
Первоисточники

Контракт и реализация 0.8.1