Профили маршрутизации¶
Профиль маршрутизации — это полный набор правил: что идёт напрямую, что через туннель и что блокируется, плюс опциональный split-DNS. Это ответ на «у меня подписка — одна ссылка vless://, внутри неё нет маршрутизации»: профиль несёт маршрутизацию отдельно от серверов.
★ Совместимость формата. Формат профиля тот же, что использует Happ, включая имена полей. Это сделано намеренно: профили ходят между приложениями ссылками и файлами, и совместимость важнее своих названий.
Профиль¶
{
"Name": "Bypass RU",
"GlobalProxy": true,
"DirectSites": ["geosite:category-ru", "domain:gosuslugi.ru"],
"DirectIp": ["geoip:ru", "192.168.0.0/16"],
"ProxySites": ["geosite:youtube"],
"BlockSites": ["geosite:category-ads-all"],
"RemoteDNSType": "DoH", "RemoteDNSDomain": "https://dnsforge.de/dns-query",
"DomesticDNSType": "DoU", "DomesticDNSIP": "77.88.8.8",
"DnsHosts": { "example.com": "1.2.3.4" },
"DomainStrategy": "IPIfNonMatch",
"UpdateUrl": "https://example.com/routing.json",
"UpdateInterval": 24,
"LastUpdated": 1756600000
}
| Поле | Значение |
|---|---|
Name |
Имя профиля. Оно же — ключ обновления: импорт профиля с тем же именем заменяет старый, а не создаёт дубликат. |
GlobalProxy |
Куда идёт трафик, не попавший ни в одно правило: true — через туннель, false — напрямую. |
DirectSites / ProxySites / BlockSites |
Домены и категории: geosite:ru, domain:example.com, regexp:… |
DirectIp / ProxyIp / BlockIp |
IP-адреса, подсети и geoip:ru. |
RemoteDNS* / DomesticDNS* |
Split-DNS: удалённый резолвер отвечает за проксируемые имена, локальный — за прямые. Шесть полей — см. «Поля split-DNS» ниже. |
DnsHosts |
Статические соответствия домен → IP. |
DomainStrategy |
Порядок сопоставления правил: AsIs (по умолчанию), IPIfNonMatch, IPOnDemand. |
FakeDNS |
Принимается для совместимости (true/false, булево или строкой, как у Happ); ядро SMProxy FakeDNS не использует, значение игнорируется. |
UpdateUrl |
Откуда брать свежую копию профиля. С ним профиль самодостаточен: раздавайте его как base64 или файл, и он всё равно будет обновляться. |
UpdateInterval |
Как часто обновлять, в часах. 12…168 (неделя); по умолчанию 24. |
LastUpdated |
Необязательное. Unix-время последнего изменения профиля — число или строка с числом, как в Happ. Показывается в карточке профиля и работает как защита от отката версии — см. ниже. |
Правила применяются в порядке block → direct → proxy и ставятся перед правилами, пришедшими с конфигурацией сервера.
GlobalProxy и FakeDNS принимаются и как JSON-булево, и как строки "true" / "false", которые шлют Happ и INCY. Поля, которые другие клиенты добавляют для своего интерфейса — RouteOrder, UseChunkFiles — игнорируются: SMProxy всегда применяет правила в порядке block → direct → proxy.
Поля split-DNS¶
| Поле | Значение |
|---|---|
RemoteDNSType |
Протокол удалённого резолвера: DoH, DoT, DoQ или DoU (обычный UDP). |
RemoteDNSDomain |
Адрес резолвера — URL DoH/DoT, например https://dnsforge.de/dns-query. Пусто для обычного UDP. |
RemoteDNSIP |
IP резолвера. Вместе с RemoteDNSDomain это bootstrap-адрес домена — та же роль, что у ;ip=… в заголовке s-resolve; без домена — обычный UDP-резолвер. |
DomesticDNSType / DomesticDNSDomain / DomesticDNSIP |
Те же три поля для локального резолвера (прямые имена). |
RemoteDns / DomesticDns |
Устаревшее написание из старых профилей Happ/INCY — синоним RemoteDNSIP / DomesticDNSIP. Читается только если новое поле отсутствует или пустое. В новых профилях не использовать. |
Как используются резолверы:
-
Кто за что отвечает. Remote — имена, идущие через туннель, Domestic — имена, идущие напрямую (
DirectSites). Удалённый резолвер опрашивается через туннель, локальный — через физическую сеть. -
RemoteDNSDomain— ещё и собственный резолвер клиента для служебных запросов (обновление подписки, загрузка профиля), когда подписка не присылаетs-resolve. Профиль маршрутизации, таким образом, задаёт DNS для всего, а не только для трафика внутри туннеля. -
Bootstrap. Суффикс
;ip=…изs-resolveне работает внутриRemoteDNSDomain— там нет разбора, адрес уйдёт с мусором на конце. Bootstrap-адрес кладите вRemoteDNSIP. -
Цепочка запасных. Сначала резолверы профиля, затем DNS-серверы из самого конфига подключения (их разбиения
domains/skipFallbackсохраняются). Если все резолверы профиля недоступны, разрешение имён уходит на серверы конфига. -
Поддержка массивов клиентами: SMProxy начиная с Android 411 / iOS, macOS, tvOS 305 / Windows, Linux 193. Happ, INCY и старые сборки SMProxy читают только строку — присылайте строку, если не уверены, что пользователи обновились.
Строка или массив — расширение SMProxy. RemoteDNSDomain, RemoteDNSIP, DomesticDNSDomain и DomesticDNSIP принимают либо одну строку (классический формат, совместимый с Happ/INCY), либо массив строк:
"RemoteDNSDomain": ["https://dns1.example/dns-query", "https://dns2.example/dns-query"],
"RemoteDNSIP": ["1.2.3.4", "5.6.7.8"]
Порядок = приоритет: ядро опрашивает резолверы сверху вниз, вторая запись — запасная для первой. *DNSIP[i] — bootstrap-адрес для *DNSDomain[i]; IP без парного домена работает как обычный резолвер.
Защита от отката — LastUpdated¶
Когда профиль с тем же Name приходит автоматически (заголовки подписки, обновление по UpdateUrl, ссылка), он заменяет сохранённый только если его LastUpdated больше. Если метки нет с одной из сторон, профиль заменяется безусловно. Увеличивайте значение при каждом изменении профиля. Ручной импорт из интерфейса приложения применяется всегда.
🧩 — Не пишите JSON руками — Конструктор соберёт профиль из обычных полей и сразу даст JSON, ссылку smproxy://routing/onadd/… и QR-код. Всё считается в браузере. — Конструктор профиля →
Как передать профиль пользователю¶
Ссылкой — самый естественный способ: из браузера, из сообщения или по QR-коду.
| Ссылка | Что делает |
|---|---|
smproxy://routing/add/<base64\|url> |
Импортировать профиль, не переключаясь на него |
smproxy://routing/onadd/<base64\|url> |
Импортировать и включить |
smproxy://autorouting/add/<url> · …/onadd/<url> |
То же плюс обновление с этого URL |
smproxy://routing/off |
Выключить маршрутизацию |
Полезную нагрузку можно передать и как ?data=<base64>. URL может вернуть JSON профиля, его base64 или другую ссылку smproxy:// — принимаются все три варианта.
Заголовком подписки — профиль приходит вместе с самой подпиской.
| Заголовок | Назначение |
|---|---|
routing |
Профиль: base64, обычный JSON или URL, откуда его забрать. Обновляется вместе с подпиской. |
autorouting |
URL, откуда забрать профиль и обновлять его по собственному расписанию. |
routing-update-url |
Откуда обновлять профиль — если не хочется класть UpdateUrl внутрь самого профиля. |
routing-update-interval |
Интервал обновления в часах (12…168). Значения вне диапазона подрезаются. |
routing-profile |
Какой профиль должна использовать эта подписка — по имени. |
Профиль, пришедший с подпиской, добавляется в список, но не включается — выбор остаётся за пользователем. Эти ключи работают и без Provider ID.
Заголовки принимают и deep-link-команды. Значением routing / autorouting может быть deep-link-команда — в тех же формах, что кликабельные ссылки, с любым словом схемы (smproxy://, happ://, yourapp://): внутри заголовка слово перед :// не важно.
| Значение заголовка | Действие |
|---|---|
*://routing/add/<base64\|url> |
Импортировать профиль в список, не назначать его |
*://routing/onadd/<base64\|url> |
Импортировать и назначить этой подписке |
*://autorouting/add/<url> · …/onadd/<url> |
То же плюс поддерживать профиль в актуальном состоянии по этому URL |
*://routing/off |
Отвязать профиль от этой подписки — провайдер выключает её маршрутизацию |
Полезная нагрузка может быть зашифрована как crypt1/<base64> — как и любое другое значение заголовка.
Те же команды принимаются и отдельной строкой в теле подписки, прямо среди ссылок на серверы (совместимо с INCY):
vless://uuid@server1:443?security=tls#Server1
vmess://eyJhZGQiOiAic2VydmVyMi...
incy://routing/onadd/ewogICJOYW1lIjogIl...
Настоящий HTTP-заголовок или явный заголовок в теле #routing: важнее строки без префикса.
Глобально и по подписке¶
Пользователь выбирает один активный профиль в настройках — это глобальный выбор. Подписка может его переопределить: если в ней указан профиль (в её настройках или заголовком routing-profile), при подключении к её серверам применяется он. И то, и другое можно выключить: глобально в настройках (или ссылкой routing/off), а для подписки — вариантом «Не применять».
Какой профиль победит¶
При обновлении подписки несколько заголовков выше могут прийти одновременно. Они разбираются в таком порядке:
1
routing / autorouting — профиль, присланный целиком, важнее скачанного по routing-update-url. Присылайте сам профиль, если хотите быть уверены, какая именно версия окажется у клиента.
2
только routing-update-url — если профиль не пришёл целиком, клиент скачает его по этому адресу и импортирует. Заголовок работает сам по себе — routing рядом не нужен.
3
routing-profile (имя) — определяет, каким профилем подписка пользуется, и перебивает всё, что пришло в этом обновлении. Если указать Corporate и одновременно прислать профиль Default, подписка возьмёт Corporate, а Default всё равно попадёт в список.
Имя, которому ничего не соответствует, ничего не меняет. Если пришёл routing-profile: Corporate, а профиля с таким именем на устройстве нет, подписка сохранит прежние настройки маршрутизации. Клиент не подставит другой профиль и не сбросит настройку — опечатка в заголовке не может незаметно перенаправить трафик ваших пользователей.
Глобальный выбор не трогается никогда. Всё описанное выше задаёт профиль для этой подписки. Профиль, выбранный пользователем в настройках, остаётся как есть и продолжает действовать для всех остальных подписок. Чтобы сменить профиль подписки, используйте routing-profile; заголовка, меняющего глобальный выбор пользователя, нет.
Изменения применяются при следующем подключении. Профили читаются при сборке конфигурации туннеля, поэтому профиль, пришедший на активном соединении, начнёт действовать после переподключения — обновление подписки на ходу не перенаправляет живой трафик.
Какой резолвер используется, по порядку
заголовок s-resolve → поле RemoteDNSDomain активного профиля маршрутизации → настройка пользователя → встроенный список (если пользователь его включил) → системный резолвер.
s-resolve: off отключает предразрешение целиком — профиль в этом случае не подхватится.