Для операторов
Это контракт, который iOS-приложение держит с панелью. Если вы ведёте серверную сторону и даёте людям адрес или ссылку — ниже, что приложение запросит, что примет и что отвергнет. Это не список провайдеров. Откуда обычно берётся конфигурация — на странице откуда берутся серверы.
Как конфигурация попадает внутрь
iOS регистрирует один тип URL. Нажатие на зарегистрированную схему открывает приложение, и импортируется весь URL. Роутера по пути или хосту нет. Схемы, точные строки:
tunelly,
vless,
vmess,
trojan,
ss,
hysteria2,
hy2,
tuic,
wireguard.
vless, hysteria2, hy2,
wireguard и tunelly — так приходит
рабочая конфигурация.
vmess, trojan, ss и
tuic открывают приложение только затем, чтобы его
можно было отвергнуть явно — они не поддерживаются.
socks, socks5, http и
https парсер понимает, но они не зарегистрированы,
поэтому нажатие на такую ссылку приложение не открывает.
Тот же текст может прийти с экрана приветствия одной вставкой из буфера, с экрана «Добавить сервер» или набором в поле. Как это выглядит для подписчика — на странице как добавить конфигурацию.
Классификация по порядку: сначала проверяется запечатанный
конверт. Затем целый файл wg-quick. Затем остальной
текст. Голый panel.example.com/sub/abc
переписывается в https:// и забирается.
https://host:port#name и
http://user:pass@host считаются share-прокси, их
не забирают — иначе сервер потеряется.
Запрос подписки
Это то, что панели нужно соблюсти. Приложение делает
GET только по http или
https. Сессия эфемерная. Таймаут запроса —
двадцать секунд, ресурса — сорок. Кэш не используется.
Заголовки запроса
- User-Agent
- Одно из имён ниже, в этом порядке.
- Accept
*/*- x-hwid
- Идентификатор вендора iOS, если он есть. Это не аппаратный идентификатор. Он стабилен для этого приложения на этом устройстве и сбрасывается, когда приложение удаляют.
- x-device-os
ios, уходит вместе сx-hwid.
Порядок имён
Панели уже ветвятся по нескольким известным именам и отдают разные документы. Мы спрашиваем на этих диалектах, чтобы панель вернула список, который можно прочитать. Имена — это контракт. Номера версий меняются с релизами; строки ниже — у текущей сборки.
- 1. Tunelly — эта сборка шлёт
Tunelly/0.1 - 2. Happ — эта сборка шлёт
Happ/1.64.0 - 3. v2rayNG — эта сборка шлёт
v2rayNG/1.9.0 - 4. ClashMeta — эта сборка шлёт
ClashMeta/1.18.0 - 5. SFA — эта сборка шлёт
SFA/1.10.0
HTTP 401, 403 и 404 останавливают этот порядок: эти ответы про адрес, а не про имя. Другой HTTP-статус или тело, которое это имя не читает, переходит к следующему.
Тело
Тело определяется по содержимому.
Content-Type не используется — панели достаточно
часто отдают base64 как text/html и JSON как
text/plain, чтобы заголовку верить было нельзя.
Принимается:
- файл
wg-quick - JSON-массив конфигураций Xray
- JSON-объект с
outbounds -
JSON-обёртки с ключами
links,servers,configs,dataилиsubscription - простой список ссылок
- base64, в том числе двойной
Отвергается по имени:
- HTML-страница
- Clash YAML
- Clash JSON
Эти документы разбираются здесь. Трафик несёт свой движок, а не передаётся в чужое ядро.
Метаданные ответа
Читаются из заголовков или из строк
#name: value в теле. Если говорят оба, побеждает
тело. Имя файла в Content-Disposition не читается.
- profile-title
-
Отображаемое имя. Префикс
base64:снимается. Ограничения по длине нет. - subscription-userinfo
-
upload,download,total,expire. Каждое поле необязательно. - profile-update-interval
- Часы. Панель, которая имеет в виду сутки, пишет
24. - profile-web-page-url
- Страница, которую оператор хочет показать.
- support-url
- Куда подписчик пишет вам, не нам.
- announce
- Свободный текст. Префикс
base64:снимается. - announce-url
- Ссылка к этому тексту.
- new-url
- Новый адрес целиком. Показывается человеку. Молча не применяется.
- new-domain
-
Новый хост; путь — учётные данные — остаётся. То же
подтверждение, что у
new-url. - fallback-url
- Куда идти, если сохранённый адрес перестал отвечать.
- update-always
-
trueили1считает подписку устаревшей при каждом открытии приложения. Свой переключатель обновления у человека всё равно главный.
Какие протоколы несёт движок
VLESS, Hysteria2, WireGuard (включая AmneziaWG) — и ничего больше. Конфигурация на любой другой протокол отвергается при импорте, чтобы не существовало строки, которая не несёт трафик. Таблицы параметров — на страницах протоколов.
Два исправления, в которых операторы ошибаются. Пароль
Hysteria2 — userinfo в URI; параметр запроса auth
не читается. spx / SpiderX разбирается, но движок
его не соблюдает — не стоит выдавать это за работающее.
Как спрятать адрес
Запечатанный носитель прячет адрес панели от подписчика,
который пользуется приложением. Форма URI —
tunelly://e/<ver>/<kid>/<payload>.
Файловая форма —
tunelly-seal/1 <kid> <payload>.
Три вида: адрес подписки, одна ссылка или снимок тела.
Запечатанный конверт проверяется раньше любой другой ветки
импорта.
Это прячет адрес от подписчика, который пользуется приложением. Это не секрет от того, кто смотрит бинарник, и не секрет от того, кто смотрит трафик устройства — устройству всё равно нужно отправлять пакеты на сервер. Это удерживает от случайного копирования, а не замена контролю доступа на панели. Ключи не являются «надёжно встроенными» в каком-то более сильном смысле.
Браузерный инструмент — на странице запечатать подписку. Чужие зашифрованные форматы ссылок мы не открываем.
Что не сработает
Конфигурацию, которую движок не может соблюсти, импорт отвергает с причиной:
- нереализованные протоколы — VMess, Trojan, Shadowsocks, TUIC, SOCKS, HTTP
- тела Clash, YAML или JSON
- HTML-ответы
- обфускация и смена портов Hysteria2
- reserved-байты WARP
- gRPC multi-mode
- KCP
- типы TCP-заголовков кроме none и http
- XHTTP и HTTP/2 без TLS снизу
- пустые учётные данные
Оператор, который пришёл из другого клиента, будет искать и то, чего здесь нет. Чтобы никто не строил на выдуманном поведении:
- импорт по QR
- универсальные ссылки
- share extension
- типы документов
- ручной редактор по полям
- лимит установок
- ссылки, привязанные к устройству
- учётная запись провайдера
- принудительные настройки приложения
- глубокие ссылки маршрутизации
- загрузка geo-файлов
- JSON, который передаётся в чужое ядро
- режимы пинга
- TV API
Откуда берётся сервер
Мы не держим серверы и доступ не продаём. Откуда берутся серверы — как конфигурация обычно доходит до приложения такого рода, без имён тех, у кого покупают.