Фиксация TTL на Android для обхода ограничений на раздачу интернета
25 февраля 2019 г. android
Столкнулся с проблемой раздачи интернета с Android-телефона на другие устройства через мобильную точку доступа у некоторых операторов. Оператор или вообще запрещает раздавать интернет, или берет за это деньги. Однако есть способы обойти этот запрет. Здесь расскажу что у меня получилось.
Как оператор узнает, что интернет раздается
Оператор на своей стороне смотрит на значение TTL в заголовках IP-пакетов, приходящих от клиента. Схематично выглядит так:
Если на телефоне открывать в браузере какую-нибудь страничку, то провайдеру от телефона будут приходить пакеты с TTL 64. Такие пакеты он пропускает.
Но если включить мобильную точку доступа, подключиться к ней, например, с планшета, и на планшете открыть страницу, то, проходя через мобильную точку доступа на телефоне TTL будет уменьшаться на 1, и провайдеру будут уходить пакеты с TTL 63, которые он будет отбрасывать. Уменьшение TTL при прохождении через роутер — это стандартизированное поведение роутера, такое поведение предусмотрено стандартом RFC791.
В этой ситуации выхода два — либо на планшете выставлять TTL 65, чтобы, проходя через телефон, провайдеру приходили пакеты с TTL 64, либо на самом телефоне делать так, чтобы он не уменьшал TTL.
Если wi-fi клиент — дектоп-машина с Windows или MacOS, то выставить TTL 65 можно одной командой.
Windows
Создать в реестре ключ
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DefaultTTL
типа REG_DWORD со значением 65 (в десятичной системе)
MacOS
Команда в консоле:
$ sudo sysctl -w net.inet.ip.ttl=65
Но если клиент планшет на iOS или другое устройство, где нельзя просто так выставить TTL, то придется воспользоваться вторым способом — заставить телефон не уменьшать TTL для проходящих через него пакетов. Это может быть не совсем просто.
Учим телефон не уменьшать TTL
Этот способ потребует root-права (инструкция) на android-телефоне или jailbreak на iOS. Т.к. я делал это на Android, то опишу как делать для него. Про iOS здесь инструкции не будет.
Для разных устройств, процедура будет отличаться, я постараюсь рассказать в чем будут заключаться эти отличия. В данном примере я использую OnePlus 3 и Android 8.0 Oreo
Итак, у нас есть Android телефон с root-правами. Узнаем умеет ли ядро системы работать с TTL. Для этого смотрим содержимое двух файлов на телефоне (например с помощью приложения ES Проводник, оно умеет смотреть системные файлы):
/proc/net/ip_tables_matches
/proc/net/ip_tables_targets
В обоих должно быть упоминание TTL. В моем случае в ip_tables_targets
упоминания ttl не было. Это значит, что ядро не умеет изменять TTL. Чтобы его научить этому, нам понадобится из исходников собрать модуль ядра и загрузить его в телефон.
Как собрать модуль ядра
Нам понадобятся:
- ОС — Linux или MacOS (можно собрать и на Windows - см.ниже)
- исходники ядра для конкретного устройства
- toolchain определенной версии и опредленной архитектуры
Я собирал модуль на Windows, но используя, Ubuntu-подсистему в Windows 10. Как ее включить я писал здесь. Если у вас не Win10, то придется ставить Ubuntu на VirtualBox-машину.
Для своего OnePlus 3 я брал исходники ядра здесь - https://github.com/OnePlusOSS/android_kernel_oneplus_msm8996 (msm8996 - это модель процессора Qualcomm Snapdragon 820 MSM8996). Исходники для Android 8.0 Oreo в ветке QC8996_O_8.0.0
Для других Oneplus-ов можно взять их рядом - https://github.com/OnePlusOSS. Для других моделей телефонов надо искать исходики где-то в интернете или на сайте производителя.
Toolchain — это утилиты для сборки кода под опредленную платформу. Узнать какая именно нужна для вашего телефона можно так:
C:\Users\fote>adb shell
OnePlus3:/ $ uname -a
Linux localhost 3.18.66-perf+ #1 SMP PREEMPT Thu Dec 6 00:54:59 CST 2018 aarch64
OnePlus3:/ $ cat /proc/version
Linux version 3.18.66-perf+ (OnePlus@ubuntu-117) (gcc version 4.9.x 20150123 (prerelease) (GCC) ) #1 SMP PREEMPT Thu Dec 6 00:54:59 CST 2018
В моем случае это aarch64
. Из этого вывода также понадобится версия gcc: 4.9
и версия ядра: 3.18.66-perf+
Далее идем сюда — https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/,
и скачиваем нужный тулчейн. Версии для MacOS можно найти также по этой ссылке.
В моем случае я скачал aarch64-linux-android-4.9
, здесь aarch64 и 4.9 совпадает с теми версиями которые мы узнали выше.
Теперь идем в консоль и готовимся к компиляции. Установим необходимые тулзы и склонируем репы с тулчейном и исходниками ядра в домашнюю папку:
$sudo apt install build-essential python-minimal libncurses5-dev libncursesw5-dev
$cd ~
$git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/
$git clone --branch=QC8996_O_8.0.0 https://github.com/OnePlusOSS/android_kernel_oneplus_msm8996
В исходниках ядра смотрим в папку arch
и подбираем нужную архитектуру. В моем случае в этой папке, нет aarch64
, но есть arm64
. Это то же самое, просто называется по другому. Буду использовать эту архитектуру. Указываем ее и путь до бинарей тулчейна в переменных окружения:
$export ARCH=arm64
$export CROSS_COMPILE=/home/fote/aarch64-linux-android-4.9/bin/aarch64-linux-android-
-
. Здесь нет ошибки.
Теперь надо создать конфиг для будущей сборки. Возможные варианты конфигов в моем случае лежат в папке с исходниками ядра в arch/arm64/configs
(вместо arm64 может быть ваша архитектура). Вспоминая версию ядра, которая установлена в телефоне, выбираю конфиг msm-perf_defconfig
:
$cd ~/android_kernel_oneplus_msm8996/
$make msm-perf_defconfig
После того как конфиг создан, нам надо внести в него изменения, чтобы нужный нам модуль для фиксации TTL скомпилировался. Для этого выполняем:
$make menuconfig
Появится интерактиваная утилита, в которой нужно найти нужный модуль.
Переходя по дереву внутрь, и, найдя TTL Target support
, нажать M, чтобы указать, что нужно скомпилировать этот модуль.
Сохраняем конфиг, выходим, и собираем ядро с модулями:
$make
$make modules
Если ошибок не было, то в папке с исходниками должен появится файл net/netfilter/xt_HL.ko
Вот мой скомпилированный файл для OnePlus 3, Android 8.0.0 - xt_HL.ko. Можно сразу взять его, если совпадает модель телефона и версия системы.
Копируем его на телефон, и через adb shell пытаемся включить его (чтобы в adb shell работал su, надо в /system/build.prop
добавить строку ro.debuggable=1
, например с помощью ES Проводника):
C:\Users\fote>adb shell
OnePlus3:/ $ su
OnePlus3:/ # insmod /sdcard/xt_HL.ko
exec format error
, значит, скорее всего, неправильно была выбрана версия исходников ядра или архитектура. В dmesg
можно узнать подробности ошибки совместимости, и пересобрать под правильную версию.
Если модуль загрузился, можно пробовать зафиксировать TTL:
#iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set 64
И наконец, добавляем в автозагрузку телефона скрипт, который будет включать фиксацию TTL:
#!/system/bin/sh
insmod /sdcard/xt_HL.ko
iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set 64
Такой скрипт я положил в /sdcard/fixttl.sh
, и с помощью приложения ScriptManager, добавил в автозагрузку.
Всё! Теперь с этого телефона можно раздавать интернет!
Спасибо вот этой статье - https://habr.com/post/238625/ . Во многом, делал по этому мануалу.