Pull to refresh

Comments 42

Вы написали GUI для VPN клиента

Спасибо за комментарий! Вы правы, над GUI действительно пришлось поработать, чтобы сделать его понятным и отзывчивым. Однако, как я и старался показать в статье, самые интересные "грабли" и неожиданные сложности скрывались глубже: в интеграции нативного GoBackend, в управлении жизненным циклом VpnService и в борьбе с гонкой состояний. Именно об этих невидимых для пользователя вещах и была эта история.

Я это собственно написал потому, что обманулся заголовком т.к. подумал, что вы действительно написали впн клиент. А GUI, тем более для wireguard который конечно вне конкуренции по скорости и нагрузки на клиентское устройство (при условии нативной поддержки, а это андроид 12+ если не ошибаюсь), но в российских реалиях далеко не лучший выбор т.к. работает нестабильно ввиду того, что блокируется.

Вы правы, заголовок можно трактовать по-разному. В контексте разработки мобильных приложений "написать клиент" обычно означает создание всего приложения: от UI и архитектуры до интеграции с API и системными сервисами, вроде VpnService. Я не писал сам протокол с нуля — это была бы задача для целой команды криптографов :) Целью статьи было как раз показать всю эту "обвязку" и подводные камни, которые возникают при интеграции готового ядра. Возможно, стоило сделать заголовок более конкретным, спасибо за эту мысль.

Насчет выбора WireGuard в российских реалиях — вы абсолютно правы, и это очень важный момент. Я даже специально добавил об этом абзац во вступление. Для создания рабочего инструмента обхода блокировок "голый" WireGuard сейчас подходит слабо. Но для учебной задачи — исследования архитектуры и простоты интеграции — он, на мой взгляд, подошел идеально.

Еще раз спасибо за развернутый фидбек!

Я практически уверен что эти два ответа были написаны нейросеткой.

А я вот призадумался - ведь с наличием обратных связей очень много общающийся с нейронкой сам потихоньку в манере общения ей и уподобится?

Спасибо за комментарий. Вы правы, комментарии можно трактовать по разному, сообщения не были написаны с нуля, возможно стоило сделать больший акцент на удобстве чтения комментариев для других пользователей.

Однако автор постарался показать, что уточнение из комментария выше - это очень важный момент.

и в этом ответе тоже нейронка...

Сейчас уже в на финишной прямой новая версия протокола, поучаствовал в бете - работает хорошо

Есть незанятая (насколько я знаю) ниша в качестве идеи для развития. Проблема современного Андроида в том, что он не поддерживает цепочки сетевых фильтров и, соответственно, нельзя добавить несколько обработчиков трафика.

Сценарий такой: я пользуюсь application firewall (no-root firewall). Я хочу гибко контролировать активность приложений в системе. В том числе, не пускать всех подряд в интернет, а тех, кому надо ходить, постараться лишить отправки аналитики.

Проблема начинается тогда, когда надо работать через туннель. Приходится выбирать -- либо firewall, либо туннель. А хотелось бы и то и другое -- локально фильтровать трафик, и далее его направлять через туннель.

Посему было бы здорово сделать VPN клиент с функциональностью web application firewall.

Уже ?

Парочка Adguard + Adguard VPN умеют так в паре работать. И фильтры Adguard'а и VPN к удаленным серверам от Adguard VPN

это не будет работать с любым другим впн. если вам нужно иметь впн с маршрутами для обхода блокировок и впн скажем для доступа к рабочей инфраструктуре, а сверху ещё и фаервол который в андроиде тоже впн то увы и ах у вас ничего не получится. хотя реализовать такую связку на linux/windows/macos/etc дело пяти минут.

Тут только opensource-пара таких приложений + какой то стандарт на взаимодействие поможет. Раз гугл не хочет решать проблему.

не обязательно. теоретически возможно написать приложение которое будет само являться клиентом для *всех популярных vpn протоколов, оно будет создавать один общий tun для всех запущенных соединений и разгребать трафик внутри этого интерфейса уже своими силами. примеры такого уже существуют. но к сожалению я слишком далёк от такого колдунства.

А мне бы вот очень хотелось несколько VPN одновременно с нормальной маршрутизацией... Есть личная инфраструктура, есть две работы (на обеих всё решаю и настраиваю сам, но всё равно хотелось бы разнести), но из-за ограничения Андроида на один VPN одновременно приходится держать общую точку входа во все эти частные сети, что, мягко говоря, неправильно.

Можно было просто взять nekobox или любой другой опенсурсный клиент с поддержкой всевозможных протоколов. Ваиргард нынче почти не работает, работает даже хуже опенвпн. Ссш режут по скорости, влесс часто рвёт соединение, но вполне живёт. Прокси типа сокс5 тоже через раз работает. Тем и хорош некобокс, что там сразу пачка протоколов и переключение в 1 клик с тестированием.

это не совсем верно, wireguard прекрастно работает если сервер в пределах страны. режутся только трансграничные тоннели. у меня есть 3 wg тоннеля (один для работы, один для личной инфраструктуры, один для объединения сеток дома, у матери дома, на даче) и все прекрастно живут, а вот wg для обхода роскомпозора мне пришлось завернуть в другую штуку чтобы он работал через границу.

У меня десяток постоянно работающих WG-туннелей внутри страны (дом/квартира/офисы/сервер в ДЦ связаны в mesh-сеть), так что статистика есть. Отваливаются достаточно регулярно. Благо, настроил через OSPF автоматический fallback на Amnezia-WG, вот с ней проблем внутри РФ, три раза тьфу, не наблюдалось.

Я шиз или от самого поста и особенно ответов в комментариях воняет нейронкой?

В каких именно главах и предложениях вы это усмотрели, поделитесь пожалуйста.

p.s Что касаемо комментариев - я не вступаю в полемику если в этом нет нужды.

Шизеем вместе!

Тоже возникло такое ощущение.

В целом, текст может и авторский, но редактура GPT весьма заметна. Как и структура.

Выбор пал на WireGuard, и вот почему

Мыши плакали, кололись, но продолжали использовать Wireguard, который уж пять лет как блокируется в России по одному щелчку пальцами

Ну ведь я в самом начале описал причину, он прост и я не обхожу блокировки.

Да, я прекрасно понимаю, что на сегодняшний день "голый" WireGuard имеет проблемы с доступностью. В некоторых регионах его трафик научились определять с помощью систем глубокого анализа пакетов (DPI) и успешно блокировать.

Эта статья и сам проект — это мой личный "бортовой журнал". Я не претендую на создание самого безопасного или анонимного решения. Это скорее история о пути, граблях и открытиях, которая, надеюсь, будет полезна тем, кто тоже решит заглянуть под капот VPN-технологий на Android.

Я прочитал заголовок статьи, и возник вопрос: кто и зачем оплачивает сервера? Или используются бесплатные? Ответ не нашёл (статью не читал, поскольку интересно другое).
Правильный VPN-клиент – это комбайн, работающий с разными протоколами. Примеры: NekoBox, Hiddify, V2Box, v2rayNG (сам ими почти не пользуюсь, поскольку VPN на Android мне не особо нужен)

Привожу строки из финала статьи,

Конечно, это лишь начало пути. В планах еще много идей: от поддержки OpenVPN до внедрения push-уведомлений.

Но, возможно, самый интересный вопрос, который остался за кадром: а как все это выглядит с другой стороны? Как устроен API, который раздает конфиги? Как настроены сами VPN-серверы, чтобы работать со всем этим?

Будет ещё обзор того как устроена внутрянка самих серверов (образы докер и щепотка соли), но пока фидбек по статье сомнительный, не уверен что готов писать :)

(Получив достаточно минусов в карму и пост, ну так себе.)

Вы разрабатывали opensource решение? Для более доступного анализа лучше дать ссылку на репозиторий если такой имеется.
Как Вы решили проблему когда VpnService эксклюзивно забирает на себя слот и никакой другой VPN уже не подключить? Нужно завершать такущий VpnService чтобы запустить его для другого приложения.

По поводу проблем с нативным клиентом: падения - это баг библиотеки - не реализована валидация входящих данных. Скорее всего, код запускает panic без вызова recovery() и приложение завершается. Это, естественно, не освобождает разработчика от обработки исключений. Я бы рекомендовал вам оформить билет в их багтреккере.

Хотел, также, посмотреть на саму библиотеку GoBackend, - ссылки не нашел.

Пока в моем репозитории - полный беспорядок.
Не хочу такое показывать :) ну и токены там разного рода есть
В будущем планирую сделать все открытым, глянем как скоро я смогу это реализовать 🫡

Спасибо за статью! В нашем проекте тоже наступили на те же грабли, хотя из-за специфики у нас были и свои особенности:

  • У нас полностью самописный VPN-сервер и своя нативная библиотека на C++. Затянули ее в Android через JNI и тут началось: частые падения в местах, о которых раньше в нативном коде даже не задумывались.

  • В первой версии Android приложения использовали OkHTTP для REST-запросов, но потом ушли на свою нативную реализацию, как научили наш сервер отличает "своих" клиентов от остальных по TLS-хендшейку, а OkHTTP не позволяет работать на таком низком уровне.

  • Интеграция Conan (пакетный менеджер С++) с Android Studio была отдельным квестом.

  • Подход к выбору самого быстрого сервера у нас тоже отличается: пинг не всегда отражает реальное качество соединения (как мне кажется), поэтому мы скачиваем с каждого сервера несколько килобайт и измеряем фактическое время отклика.

Взглянул на ваш проект, выглядит вдохновляюще. Обязательно изучу ваш гитхаб репозиторий.
Касаемо подхода к выбору самого быстрого сервера, выглядит перспективней чем у меня)
Спасибо за материал - обязательно изучу.

В нынешние времена, после разработки такого приложения следующее, возможно, придётся разрабатывать уже в Нижнем Тагиле.

у меня есть давняя хотелка: либо надавать по рукам разработчикам android либо написать свой клиент который исправляет проблему которую ленятся исправить разработчики ведра, а именно использование одновременно 2+ впн тоннелей мимикрируя в один tun. в первом случае это грозит проблемами, а для второго я не програмист..
но эта проблема если честно меня сильно задолбала, невозможно одновременно иметь противороскомпозорный впн и рабочий впн, там разные маршруты и они не помешают друг другу, но ведроид считает иначе.

Если дома есть белый айпи, то зарулите трафик домой, а там уже фильтруйте и перенаправляйте как надо. Внутри страны VPN-ы вроде не фильтруют.

сейчас я так и делаю, но это неудобно и добавляет лишние правила в фаерволе нацеленные на то чтобы никто кроме меня не мог из моей домашней сети ходить в мой рабочий прод (было бы очень неловко если бы моя дочь например в поисках мультиков дропнула продовую базу (я конечно утрирую, но всё же)).

Похожее на описанное умеет андроидный Nekobox.

По крайней мере можно было делать правила маршрутизации по домену/IP/приложению и по результатам отправлять траффик в конкретный тоннель.

Единственная засада, приложение в последнее время подозрительное - с некоторого момента автор пишет, что версию а магазине Гугла он не контролирует - качать с Гитхаба.

Ну и OpenVpn он не умеет.

"ленятся исправить разработчики ведра" - вообще, это ожидаемый результат как было задумано изначально в Андроид - только одно VPN подключение может быть активировано. Ссылка на Андроид документацию на VpnService ниже.
"There can be only one VPN connection running at the same time. The existing interface is deactivated when a new one is created."
https://developer.android.com/reference/android/net/VpnService.html

Кривота остаётся кривотой вне зависимости от того специально это сделано или так просто получилось. А кривоту надо исправлять.

Я уточнил ситуацию по этой проблеме чтобы у кого то не возник ложный вывод, что это дефект и Google иправит это когда либо. Не исправит, и не стоит этого ожидать от них. Другими словами это не баг, а ожидаемое ограничение заложенное изначально. Мнение пользователей Google, в некоторых вопросах, как я убедился - мало интересует.

подметил для себя потенциальные проблемы:

  1. Нет обработки случая, когда _selectedServer или токен null

  2. Использование !! оператора (response.body()!!) может вызвать NPE

  3. Нет управления состоянием загрузки (isLoading флаг)

  4. Сообщения об ошибках напрямую передаются в UI без обработки

Хм, действительно.

Хорошо что заметили

Интересная идея для проекта! Если планируете работать над ним дальше, то вот вам несколько проблем, которые я заметил при прочтении:

1) Тост ошибки — это событие, а не состояние.

Попробуйте запустить проект с нуля без разрешения на впн, вызвать ошибку и потом переворачивать экран туда-сюда. Тост будет показываться снова и снова и снова.

Это происходит потому, что лайвдата отсылает своё последнее значение каждому новому наблюдателю, т.к. уничтожаются/регаются новые после поворота экрана.

2) При вызове suspend функций из api для ретрофита не нужно использовать Dispatchers.IO, у ретрофита свои диспатчеры, отвечающие за сетевые запросы

3) Вместо AtomicBoolean флага isRunning я бы рекомендовал посмотреть на свойство isActive у корутины, что, по идее, вам и нужно

4) Будьте аккуратны с использованием try/catch в контексте корутин, т.к. можно случайно поймать исключение, которое позволяет им отменяться (CancellationException). У вас они вручную не отменяются, но на всякий случай упомяну. Чтобы избежать такой проблемы, можно вызывать в корутине coroutineContext.ensureActive(), или просто пробрасывать дальше пойманное исключение, если это CancellationException.

В общем, это базовые проблемы, которые не особо касаются впн, но на которые стоит обратить внимание при разработке.

Спасибо за детальный разбор

Sign up to leave a comment.

Articles