posts projects about

Фиксация TTL на Android для обхода ограничений на раздачу интернета

25 февраля 2019 г. android

Столкнулся с проблемой раздачи интернета с Android-телефона на другие устройства через мобильную точку доступа у некоторых операторов. Оператор или вообще запрещает раздавать интернет, или берет за это деньги. Однако есть способы обойти этот запрет. Здесь расскажу что у меня получилось.

Как оператор узнает, что интернет раздается

Оператор на своей стороне смотрит на значение TTL в заголовках IP-пакетов, приходящих от клиента. Схематично выглядит так: TTL схема

Если на телефоне открывать в браузере какую-нибудь страничку, то провайдеру от телефона будут приходить пакеты с 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-
Переменная CROSS_COMPILE именно такая, заканчивается на -. Здесь нет ошибки.

Теперь надо создать конфиг для будущей сборки. Возможные варианты конфигов в моем случае лежат в папке с исходниками ядра в arch/arm64/configs (вместо arm64 может быть ваша архитектура). Вспоминая версию ядра, которая установлена в телефоне, выбираю конфиг msm-perf_defconfig:

$cd ~/android_kernel_oneplus_msm8996/
$make msm-perf_defconfig

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

$make menuconfig

Появится интерактиваная утилита, в которой нужно найти нужный модуль. TTL Target support

Переходя по дереву внутрь, и, найдя TTL Target support, нажать M, чтобы указать, что нужно скомпилировать этот модуль. TTL Target support

Сохраняем конфиг, выходим, и собираем ядро с модулями:

$make
$make modules
Если эти команды завершились ошибкой, значит, скорее всего неправильно выбран конфиг, toolchain или сами исходники ядра. Определенные исходники можно собрать только подходящим тулчейном и с подходящим конфигом.

Если ошибок не было, то в папке с исходниками должен появится файл 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
Если insmod возвращает ошибку 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, добавил в автозагрузку.

ScriptManager

Всё! Теперь с этого телефона можно раздавать интернет!

Спасибо вот этой статье - https://habr.com/post/238625/ . Во многом, делал по этому мануалу.