Skip to content

Правки в ядрах ​

В keqdroid два ядра: Xray-core 26.10.10 и mihomo 1.19.32. Оба собраны из исходников с правками: в готовых сборках нет того, на что опирается приложение, а ещё в них есть несколько ошибок, которые здесь исправлены. Сами правки лежат в tool/patches/.

Ядра собираются свежими версиями Go, в которых закрыты известные уязвимости самого Go: mihomo – на Go 1.26.10, Xray – на Go 1.27.3.

ПравкаЯдроГдеЧто даёт
версия клиента REALITYmihomoвездесерверы с минимальной версией клиента больше не отказывают в подключении
отпечаток FirefoxmihomoвездеREALITY с fp=firefox работает на обновлённых серверах
кто открыл соединениеобаAndroidработают маршруты для отдельных приложений
список пакетовmihomoAndroidTUN в mihomo вообще запускается
приложения вне VPNобаAndroidисключённое приложение не может узнать адрес сервера
UDP по адресуобавездеUDP идёт туда, куда указывают маршруты
TUN на ПКXrayWindows, Linuxраздельное туннелирование, честный пинг, аккуратная остановка
TUN на LinuxобаLinuxTUN работает при строгой проверке обратного пути, WebRTC не выдаёт адрес, серверы на компьютере отвечают тем, кто подключается снаружи
память geo-базmihomoвездеправила geosite и geoip занимают меньше памяти

REALITY на mihomo ​

Версия клиента REALITY ​

Клиент REALITY сообщает серверу свою версию, а владелец сервера может задать минимально допустимую. mihomo всегда называет одну и ту же старую версию, и поменять её нельзя. Если на сервере минимальная версия выше, сервер отказывает, причём молча, как это принято у REALITY. Клиент пишет «REALITY authentication failed», хотя ключ и адрес верные, а тот же сервер через Xray работает.

Правка называет ту же версию, что и Xray в приложении. Эта версия ни от чего не защищает, она только сообщает серверу, какую редакцию протокола понимает клиент, а mihomo её понимает.

Отпечаток Firefox ​

С сентября 2026 года новые версии Xray на сервере отклоняют подключения без постквантового ключа. В mihomo отпечаток fp=firefox снят со старого Firefox, где такого ключа ещё нет. Поэтому, как только владелец сервера обновлял Xray, все серверы REALITY с fp=firefox на mihomo переставали работать с той же ошибкой «REALITY authentication failed». Отпечатки Chrome этот ключ содержат, но там, где пользуются приложением, фильтры режут подключения с отпечатком Chrome.

Правка ставит отпечаток свежего Firefox, такой же, как у Xray. Её уберут, когда mihomo сам обновит отпечаток.

Android ​

Кто открыл соединение ​

Маршрут для отдельного приложения срабатывает, только если ядро знает, какое приложение открыло соединение. Начиная с Android 10 система не сообщает это обычным программам. Ядро ничего не находило, и ни один маршрут по приложениям не работал.

Узнать, чьё это соединение, может только приложение, которому принадлежит VPN. Поэтому ядро спрашивает об этом keqdroid, а тот – систему. Никто другой на телефоне этим каналом воспользоваться не может.

В Xray заодно исправлено, о каком соединении спрашивать. Для сайтов, которые ядро определило по имени, оно и спрашивало по имени, а система знает соединения только по адресам, поэтому ответа не было.

Список пакетов ​

При запуске TUN на Android mihomo читает список установленных приложений. Начиная с Android 11 обычным приложениям это запрещено, и TUN не запускался, хотя приложение показывало «Подключено»: прокси работал, а через туннель не проходил ни один пакет.

Этот список нужен mihomo только для его собственного раздельного туннелирования, а в keqdroid раздельным туннелированием занимается система. Правка не читает список, если он не нужен.

Приложения вне VPN ​

Приложение, которое раздельное туннелирование вывело из VPN, всё равно может само отправить данные в туннель: на Android для этого не нужно особых прав. Тогда его данные пойдут через ваш сервер, и приложение узнает адрес сервера. Так, например, банковское приложение может заметить VPN.

Система знает о таких соединениях и на вопрос о владельце отвечает «не ваше». В этом случае keqdroid называет владельца особым именем, и первое правило конфига отклоняет соединение.

Закрыты и обходные пути:

  • соединение отклоняется до того, как успело открыться, иначе сам факт открытия уже показывал бы, что туннель работает;
  • через DNS туннеля такое приложение могло спросить, с какого адреса пришёл запрос, и получить адрес сервера. Теперь на запросы без известного владельца ядро отвечает только адресами сайтов;
  • системный DNS в режиме «Только выбранные» тоже приходит без владельца, но приложение его узнаёт и пропускает, иначе выбранные приложения остались бы без DNS.

Если keqdroid не ответил ядру, соединение проходит: отклоняется только то, что система прямо назвала чужим.

UDP по адресу назначения ​

Оба ядра выбирали путь для UDP один раз, по первому пакету. Если игра сначала обращалась к адресу, которого нет в ваших маршрутах, её голосовой чат так и шёл по этому пути, куда бы его ни отправлял маршрут. А если первый пакет попадал под «Напрямую», мимо туннеля уходило и всё остальное.

С настройкой «UDP по маршрутам для каждого адреса» путь выбирается по маршрутам отдельно для каждого адреса. По умолчанию она выключена: звонки, игры и торренты, которые соединяются друг с другом напрямую, могут перестать это делать, если маршруты разведут их по разным путям.

TUN на ПК ​

Раньше TUN на Windows и Linux работал на sing-box, теперь это собственный TUN Xray. То, что умел sing-box, пришлось добавить в Xray:

  • Раздельное туннелирование. «Только выбранные» отправляет все остальные программы мимо туннеля, а у Xray не было способа сказать «любая программа, кроме этих». На Windows имена программ теперь сравниваются без учёта регистра, иначе winword не совпадал с WINWORD.EXE. На экране «Соединения» видно, какая программа открыла соединение.
  • Пинг. При включённом TUN любой адрес, даже несуществующий, отвечал на ping примерно за 1 мс, потому что отвечал сам туннель. Теперь ping и tracert показывают настоящую сеть.
  • UDP-таймаут. Настройка «UDP-таймаут» в TUN закрывает UDP-сессии, которые простаивают. В Xray такого не было.
  • Остановка. На Windows ядро останавливалось так резко, что не успевало за собой убрать: в настройках сети и в кэше DNS оставались следы туннеля. Теперь ядро останавливается так же, как по Ctrl+C.
  • Счётчики трафика. Приложение читает их у ядра по локальному адресу, к которому может обратиться любая программа на компьютере. Раньше Xray отдавал там ещё и лишние сведения о себе, теперь только счётчики.

TUN на Linux ​

Здесь три правки. Первая есть только в Xray, две другие – в обоих ядрах.

  • Строгая проверка обратного пути. Xray записывал маршрут в туннель в основную таблицу маршрутов Linux. Если в системе включена строгая проверка обратного пути (rp_filter=1, её часто включают для защиты), Linux выбрасывал каждый ответ от сервера. По основной таблице ответ на этот адрес ушёл бы в туннель, а пришёл он через сетевую карту, поэтому Linux считал пакет поддельным. Ядро запускалось, но трафик не шёл. Теперь маршрут лежит в отдельной таблице, к которой ведут правила, как у sing-box и mihomo. Заодно в туннель попадает DNS-запрос к любому адресу, а не только к адресам из /etc/resolv.conf.
  • WebRTC. Браузер отправляет запросы WebRTC в том числе с адреса каждой сетевой карты. В mihomo такой запрос проходил мимо туннеля, и сайт видел ваш настоящий адрес. Теперь в обоих ядрах всё, что отправляют программы обычного пользователя, идёт в туннель.
  • Ответы на подключения снаружи. Если на компьютере работает сервер, к которому подключаются из интернета, например Sunshine для стриминга игр, то в Xray его ответы уходили в туннель и до того, кто подключился, не доходили. Теперь оба ядра помечают ответы на соединения, начатые снаружи, и такие ответы уходят тем же путём, каким пришёл запрос. Так же делает sing-box. Для этого нужен nftables. Если его нет, ядро пишет предупреждение в журнал, и ответы по-прежнему уходят в туннель. Исключение – UDP-сервер, который не указывает, с какого адреса отвечать: его ответы тоже уходят в туннель. Sunshine адрес указывает.

Память geo-баз ​

mihomo при первом же правиле geosite или geoip навсегда оставлял в памяти список, которым не пользуется ни одно правило, а каждый загруженный список доменов хранил в двух копиях. Правка убирает и то, и другое. С российскими сайтами, рекламой и geoip:ru ядро занимает примерно на 2,5 МБ меньше памяти, с большими списками – около 5 МБ. На маршрутизацию это не влияет.