Есть приложения критичные к разрывам связи, переподключение происходит мучительно и вообще не всегда. Поставил перед собой цель, сделать прыжки маршрутов и физических подключений прозрачными, что бы связь была постоянной и TCP коннект не рвался.
И поможет в этом старый, добрый и ламповый «openvpn». Но установка и настройка — тема давно избитая, трогать её, здесь не планируется.
Что нам нужно:
- Сервер Linux с постоянным IP (vps, vds, dedic или просто домашний)
- Openvpn на сервере и клиенте, настроенные на работу по UDP.
- iproute2 — собственно для фокуса нужна работающая утилита ip на Android.
- Так же потребуется внести изменения в исходный код openvpn-settings c последующий сборкой apk.
Приступим
Начнем с правки «openvpn-settings». Суть в том, что при любом изменении в сетевой конфигурации нативному демону openvpn посылается команда SIGUSR1, что заставляет его отключаться и подключаться по новой. Для наших целей это вред, но нам все равно желательно иметь возможность выполнять некоторые действия при изменении сетевой конфигурации.
Кто-то скажет, но ведь есть persist-tun. Отвечаю, работает не так, как хочется, openvpn дергает скрипты «лежать-вставать» каждый раз, когда приходит SIGUSR1. И в принципе отличить по имеющимся переменным перезапуск от старта, без выкрутасов почти не возможно. Это подрывает всю затею, а хочется просто и надежно.
Поэтому мы заменим отправку SIGUSR1 на вызов shell скрипта.
Скачиваем исходники командой
hg clone https://code.google.com/p/android-openvpn-settings/
Открываем файл
\src\de\schaeuffelhut\android\openvpn\service\ManagementThread.java
Находим функцию public void sendSignal(int s) её мы и будем редактировать.
Комментируем отправку SIGUSR1 и вставляем вызов нашего скрипта с правами рут.
Файл скрипта у нас будет называться точно так же как и файл подключения, но дополненный расширением sh.
Должно получится так:
case SIGUSR1: //sendCommand( new SimpleCommand( "signal SIGUSR1" ) ); new Shell( "OpenVPN-Settings-ip-route", String.format( "/system/bin/sh %s.sh", Util.shellEscape(mDaemonMonitor.mConfigFile.getAbsolutePath()) ), Shell.SU ).run(); break;
Всё, можно собирать, подписывать, устанавливать. Перед установкой обязательно деинсталлируйте старый «openvpn-setting» из системы, так как просто замена может оставить в кеше прежнюю версию байткода.
Далее проверим конфигурации подключения openvpn.
Сервер
На сервере требуется внести директиву float, поскольку мы будем менять физическое соединение, а с ним и IP.
Так же сервер должен транслировать внутренний адрес нашего клиента во внешнюю сеть. Для настройки этого мне удобней использовать директивы up и down.
up "/bin/sh /etc/openvpn/androidupdown"
down "/bin/sh /etc/openvpn/androidupdown"
Скрипт должен быть примерно таким:
NATGW="1.2.3.4" # ip с которого будет натится клиент NATDEV="eth0" # интерфейс с которого клиент получает доступ в общую сеть NATNET="10.9.8.0/24" # vpn подсеть, которую надо транслировать во внешний мир sysctl -w net.ipv4.ip_forward=1 ACT="A" [ "down" = "$script_type" ] && ACT="D" iptables -t nat -$ACT POSTROUTING -s $NATNET -o $NATDEV -j SNAT --to-source $NATGW
Клиент
На клиенте также необходимо задать директиву up и down с указанием скрипта, который выполнит настройку маршрутов.
Если вы помните, мы условились, что имя файла будет повторять имя конфигурации с добавление sh. Да, мы будем вызывать один и тот же скрипт и из демона, и из монитора.
Если конфигурация называется «testconfig.ovpn», то пусть будет так:
up "/system/bin/sh /sdcard/openvpn/testconfig.ovpn.sh"
down "/system/bin/sh /sdcard/openvpn/testconfig.ovpn.sh"
Cкрипт
# Общая часть export ANDROID_PROPERTY_WORKSPACE=12,66560 # Может зависеть от устройства export PATH=/system/bin:/system/xbin:$PATH setprop net.dns1 8.8.8.8 # всем известный DNS setprop net.dns2 8.8.4.4 # Сработает только при вызове демоном openvpn. if [ "init" = "$script_context" ]; then ACT="add" [ "down" = "$script_type" ] && ACT="del" ip route $ACT throw $remote_1 table 100 ip route $ACT default dev $dev table 100 ip rule $ACT table 100 pref 1000 fi
Здесь стоит немного пояснить.
Мы создаем альтернативную таблицу маршрутизации под номером 100 в которой указываем шлюзом по умолчанию vpn туннель. И добавляем правило маршрутизации, которое заворачивает весь трафик в нашу таблицу под номером 100, раньше чем он попадет в основную таблицу под именем main.
В альтернативной таблице есть маршрут, который выталкивает пакеты предназначенные для сервера, обратно в цепочку правил. Далее они попадут в основную таблицу маршрутизации. Там они смогут найти основной маршрут физического соединения. Но, а если не найдут, такое случатся во время реконнектов, то это не страшно. Openvpn может потерпеть некоторое время, но разумеется не вечно. Только сообщения в логах, напомнят об отсутствии связи непродолжительное время.
Не забывайте скрипты должны заканчиваться переводом строки.
Для разрешения запуска скриптов на Android, необходимо установить «Built-in + script» в «Preferences» которые вызываются по долгому тапу на подключении. Теперь можно пробовать.
В результате тестирования оказалось, что некоторые программы сами проверяют состояние сети и пытаются переподключаться во время любых изменений. Тут либо просить авторов исправить ситуацию. Либо самостоятельно де компилировать и исправлять. В любом случае закрытие TCP сессии происходит, не по таймауту, а так как положено.
Буду рад любой критике и замечаниям. Желаю стабильного коннекта!
ссылка на оригинал статьи http://habrahabr.ru/post/157687/
Добавить комментарий