Как позвонить всем вокруг
Мы в Postuf большие поклонники франшизы Watch Dogs — приключенческой видеоигры, в которой главный герой в лице Эйдена Пирса, имея доступ к вымышленной системе ctOS, способен проворачивать со своего смартфона разные хакерские трюки. Однажды нам стало интересно, возможно ли в реальной жизни повторить трюк звонка на телефоны находящихся рядом людей.
Оказалось, возможно:
Чтобы заставить все телефоны вокруг звенеть, необходимо всего лишь всем им (желательно, одновременно) отправить команду на звонок. Делов-то! Супер простая цель, которая не так легко достижима на практике. Отправить такую абстрактную команду можно либо непосредственно на каждый телефон, если он вас каким-либо образом «слушает», либо через посредника — сотового оператора, которого каждый девайс «слушает» по умолчанию (в зависимости от своей SIM).
Минусы первого способа — придется разбираться в том как устроен «протокол» сотового звонка, чтобы суметь отправить заветную команду на звонок, а также думать над тем, как в принципе заставить телефоны вокруг «слушать» команды.
Минусы второго способа — слишком большое число операторов и совершенно непонятно, как найти телефоны «вокруг» себя. Здесь можно было бы схитрить, воспользовавшись услугой из даркнета по получению номеров абонентов в конкретном регионе (в соте) — т.н «Зонтик», но на практике оказалось, что в реальном времени такую услугу никто не предоставляет — нужно ждать несколько дней, что делает этот способ сомнительным.
Становимся мобильным оператором
Чтобы можно было звонить мобильным устройствам напрямую, необходимо, чтобы они относились к нам как к полноценному оператору сотовой связи. Неотъемлемая составляющая любой современной сотовой сети — базовая станция (BTS), к которой подключаются мобильные устройства для дальнейшего взаимодействия с сетью. За базовой станцией может и не быть никакой реальной «сети», однако об этом абоненты никогда не узнают.
О поднятии собственных базовых станций уже писали не один десяток раз, в том числе и на Хабре, поэтому лишний раз углубляться в подробности не будем. Отметим лишь, что наиболее удобной будет станция поколения 2G, т.к в этом поколении можно напрочь прибить все механизмы безопасности на уровне самой BTS, на которые полагаются современные устройства.
Существует целый ряд уже готовых реализаций 2G BTS, среди них особенно выделяются Osmocom и YateBTS. Для поднятия своей BTS также понадобится SDR-оборудование. Мы решили остановиться на наиболее доступной связке Osmocom+LimeSDR. Небольшой ресерч с использованием лишь одного гугла позволил в достаточно короткие сроки разобраться с основными концепциями GSM (2G) сети и поднять собственную «коробочную» версию сети.
Собственная мобильная сеть
На этом этапе мы уже могли подключать абонентов к себе вручную через выбор сети в настройках смартфона. Но на ручном подключении далеко не уедешь…
Вышибаем абонентов из родной сети к себе
Как заставить чужие мобильные телефоны подключаться к какой-то левой сотовой сети вместо «родной», да еще и к сети более старого (небезопасного) поколения 2G? Для ответа на этот вопрос понадобилось разобраться с тем, как мобильные устройства вообще сканируют эфир в поисках базовых станций. Кратко алгоритм выглядит так:
«текущее_поколение» = МАКСИМАЛЬНО_ПОДДЕРЖИВАЕМОЕ (5G, 4G, 3G, 2G)
«найденные_станции» = просканируй_эфир («текущее поколение»)
если «найденные_станции» != пусто
подключиться (лучшая_базовая_станция («найденные_станции»))
иначе, если «текущее_поколение» > 2G
«текущее_поколение» -= 1
goto 2
И говорит нам этот алгоритм о том, что для получения абонента в свою сеть, необходимо, чтобы вокруг не было базовых станций поколений выше 2G, да еще и наша BTS должна быть самой «лучшей» из всех 2G. Проще говоря, мы должны быть единственными в округе, чтобы мобильным устройствам даже не пришлось выбирать (алгоритм выбора «лучшего» не тривиален и зависит от реализации радиомодуля).
Чтобы стать «единственной» BTS, можно заглушить сигнал от всех базовых станций вокруг. Проблема тут в том, что точечно этого сделать не получится — доступные для покупки средства глушения связи накрывают диапазоны целиком. Где тогда оставить нашу BTS?
Посмотрим, какие вообще диапазоны частот входят в стандарт GSM:
Uplink (передача данных) | Downlink (прием данных) | |
Европа, Азия | 880 — 915 МГц (E-GSM-900) | 925 — 960 МГц (E-GSM-900) |
США, Канада, Латинская Америка и Африка | 824 — 849 МГц (GSM-850) | 869 — 894 МГц (GSM-850) |
Что если притвориться для телефонов вокруг, будто бы они из привычной Европейской среды попали в Американскую? Ведь это вполне реальный кейс — их владельцы вполне себе могли отправиться в путешествие на другую сторону Земного шара.
Большинство доступных в продаже глушилок поддерживают селективное глушение полос мобильной связи. Вот фрагмент ТТХ одной из таких:
Характеристики мультичастотного подавителя
Приобретаем любой подавитель, способный заглушить связь в радиусе 10–20 метров, включаем диапазоны глушения E-GSM-900, DCS-1800, все диапазоны 4G и 3G, которые в сумме накроют всю мобильную связь в радиусе действия глушилки, за исключением американского GSM-850. А на американской полосе GSM-850 поднимаем нашу BTS:
Одинокая BTS на американской частоте
После этой операции все телефоны магическим образом разделились на 2 категории:
те, кто беспрепятственно подключаются к BTS в течение нескольких минут после глушения (в основном Android-девайсы);
те, кто долго висят без сети и подключаются спустя 30+ минут после глушения (в основном iOS-девайсы).
Ждать 30 минут, пока телефон перестроится в новый режим, — слишком долго — за это время все вокруг просто разойдутся. Здесь мы пошли на вторую уловку — перенесли BTS в самое начало стандартной европейской полосы E-GSM-900 — на частоту 925.2МГц, подкрутили глушилку так, чтобы она накрывала все базовые станции в диапазоне E-GSM-900 выше BTS:
BTS в самом начале E-GSM-900, дальше все закрыто глушилкой
В этом случае мы смогли собрать 100% мобильных устройств в радиусе подавления на своей BTS!
Массовый звонок
На текущий момент у нас есть 1 базовая станция стандарта GSM, поднятая в самом начале европейской полосы E-GSM-900, выше которой все закрыто глушилкой. Абоненты подключаются, и с ними уже можно взаимодействовать посредством VTY-интерфейса Osmocom. Для удобства мы написали скрипт на Python, который все красиво отображает в терминале:
Список подключенных абонентов после нескольких минут работы BTS совместно с глушилкой
Чтобы звонить со стороны BTS на выбранные номера телефонов (msisdn) необходима SIP-телефония, интегрированная со стеком Osmocom. Самое быстрое решение — провести интеграцию с SIP-стеком Asterisk по официальному мануалу от Osmocom.
После этого мы можем совершать звонки абонентам на их локальные номера (msisdn) уже по мануалу Asterisk. Попробуем позвонить 1–2 абонентам с произвольного номера — звонки успешно доходят. Запускаем звонок всем подключившимся абонентам…и натыкаемся на серьезное ограничение GSM по числу параллельных звонков. Так как GSM — крайне древний и простой протокол, в основе разделения абонентов лежат принципы временнОго разделения (TDMA) в сочетании с частотным разделением (FDMA), а конфигурация Osmocom по этой части выглядит следующим образом:
trx 0 # FDMA
rf_locked 0
arfcn 975 # номер GSM-частоты в ARFCN-нотации (925.2МГц)
nominal power 23
timeslot 0 # TDMA
phys_chan_config CCCH # Common Control Channel
timeslot 1 # TDMA
phys_chan_config SDCCH8 # Stand-alone Dedicated Control Channel
timeslot 2 # TDMA
phys_chan_config TCH/F # Traffic Channel Full Rate
timeslot 3 # TDMA
phys_chan_config TCH/F # Traffic Channel Full Rate
timeslot 4 # TDMA
phys_chan_config TCH/F # Traffic Channel Full Rate
timeslot 5 # TDMA
phys_chan_config TCH/F # Traffic Channel Full Rate
timeslot 6 # TDMA
phys_chan_config TCH/F # Traffic Channel Full Rate
timeslot 7 # TDMA
phys_chan_config TCH/F # Traffic Channel Full Rate
Каждый TRX (приемо-передатчик) имеет собственную несущую частоту (ARFCN) и содержит 8 тайм-слотов, каждый из которых может иметь свою конфигурацию каналов. Например:
CCCH — канал для непосредственного «вещания» информации о BTS и первичного обнаружения BTS мобильными устройствами;
SDCCH — сигнальный канал, необходим для установки звонка и рассылки SMS;
TCH — передача речевого трафика.
Подробно о конфигурациях каналов в GSM можно почитать здесь, а узнать их маппинг в более низкоуровневые каналы (channel combinations) в стеке Osmocom — из кода Osmocom.
В текущей конфигурации мы сможем совершать не более 6 параллельных звонков :(Даже не 8, потому что основному каналу CCCH нужен целый тайм-слот, а также еще 1 слот для минимум одного SDCCH, который нужен для установки звонка.
Увеличить число тайм-слотов возможности нет на уровне протокола GSM, попробуем тогда расшириться в плоскости FDMA — увеличить количество TRX. Благо, Osmocom дает возможность довести число TRX при использовании LimeSDR до 6 (6×8 = 48 тайм-слотов), правда после активации четырех и более TRX начинались проблемы с перегрузкой LimeSDR. Стабильная работа BTS на одном LimeSDR сохранялась при использовании трех TRX, что в сумме давало 6+8+8=22 параллельных звонка (на каждом TRX не нужно иметь служебные каналы, поэтому TRX №2 и №3 можно забить чисто речевыми каналами — TCH). Это уже было лучше, но все же недостаточно для полноценного массового звонка.
Попутно всплыла еще одна проблема, сокращающая число потенциальных звонков и связанная с глушением чужих базовых станций на полосе E-GSM-900. Дело в том, что начало границы глушения на полосе E-GSM-900 должно быть максимально выше нашей BTS и минимально ниже первой чужой станции. А согласно распределению частот мобильных операторов в России, первая «чужая» базовая станция присутствует спустя буквально пару МГц — на частоте 927.5Мгц — 3G станция UMTS, принадлежащая Мегафону.
Первая «чужая» базовая станция на полосе E-GSM-900
Таким образом в начале полосы E-GSM-900 остается всего 927.5–925 = 2.5МГц «свободного места», а с тремя активными TRX будет занято 1.8МГц из них (каждый занимает 0.4МГц полосы и требует 0.2МГц свободного пространства после себя) — почти впритык. Однако из-за того, что границы глушилки могут «плавать» на ±1–2МГц из-за температуры окружающей среды, необходимо сместить начало границы глушения немного ниже частоты 927.5МГц — на частоту ~926МГц, чтобы обеспечить надежное закрытие базовой станции Мегафона. В этом случае последний TRX может попадать в зону глушения, и звонки будут либо обрываться, либо вообще не будут даже начинаться:
BTS с тремя TRX без глушилкиBTS с тремя TRX с глушилкой (глушилка их задевает)
Здесь стало ясно, что для увеличения числа параллельных звонков придется уходить с полосы E-GSM-900. Но куда в этот раз? С полосы GSM-850 мы уже ушли из-за того, что не все мобильные устройства её сканируют. А что если совместить эти два способа?
Вытягиваем абонентов с помощью станции-«приманки»
В ходе многочисленных экспериментов и наблюдений за чужими базовыми станциями выяснилось, что станции могут сообщать подключенным абонентам своих «соседей» (в рамках одной мобильной сети), а абоненты в свою очередь принимают эту информацию и кэшируют у себя.
BTS сообщает о своём соседе с ARFCN=128 (869.2МГц)
Если, например, абонент подключился к GSM-станции на частоте 955МГц, и она сообщила, что рядом с ней есть еще одна GSM-станция на частоте 957МГц, то при внезапном исчезновении активной станции (на частоте 955МГц) абонент в первую очередь сходит в свой кэш и попробует переключиться на станции оттуда, вместо полного сканирования радиоэфира. Для абонента это банально менее энергозатратно!
Если мы поднимем одну BTS в начале европейской полосы E-GSM-900, а вторую — в любом месте американской полосы GSM-850 и заставим «европейскую» BTS сообщать о своем соседе на «американской» полосе, у нас получится провернуть трюк с «отравлением» кэша, чтобы ускорить перевод медлительных абонентов на полосу GSM-850, которую они так долго не хотят начинать сканировать. Потребуется еще один LimeSDR для запуска второй BTS.
Провернуть этот трюк мы решили следующим образом:
Поднимем первую BTS с 3 TRX на частоте 869.2МГц (американская полоса), которая сообщает пока что несуществующего соседа на частоте 871.2МГц;
Поднимем вторую BTS с 1 TRX на частоте 925.2МГц (европейская полоса), которая сообщает единственного соседа на частоте 869.2МГц;
Собираем глушилкой абонентов вокруг — какие-то из абонентов «осядут» на первой BTS, какие-то на второй;
Выключаем вторую BTS (925.2МГц) и тут же поднимаем её, но уже с 3 TRX на американской частоте 871.2МГц — теперь сосед существует у первой BTS, а перезапущенная BTS сообщает соседа на 869.2МГц;
Все абоненты успешно «спустились» с 925.2МГц на 869.2МГц/871.2МГц.
Такой трюк позволил нам собрать 100% мобильных устройств в радиусе подавления на своих BTS, и вдобавок в нашем распоряжении оказалось 2*(6+8+8) = 44 таймслота под параллельные звонки. Неплохо, но можно лучше.
Звоним много и быстро
На этом этапе мы поняли, что выжали максимум из «железного уровня», а потому далее нам предстояла долгая и кропотливая работа по оптимизации софтварного уровня с целью еще большего увеличения числа звонков и ускорения их установки.
Начали мы с банального устранения хардкода, которым грешат ребята из Osmocom. После парочки оформленных issue стало ясно, что у ребят и без нас дел по горло, поэтому мы просто форкнули репозиторий и исправляли все находимые баги/фичи/затыки самостоятельно у себя с учетом наших потребностей (а они у нас достаточно агрессивные с точки зрения эксплуатации сетей GSM).
Оптимизация стека Osmocom под массовый звонок в сумме заняла у нас несколько месяцев — при каждом выявляемом затыке приходилось разбираться, какие механизмы GSM лежат в его основе, изучать эти механизмы и придумывать такой способ исправления, который бы не выходил за рамки протокола GSM. Ключевые milestone получились следующие:
Исправление бага, из-за которого выставлялся низкий уровень усиления для BTS и базовая станция была крайне слабой, спустя пару месяцев этот баг поправили официально.
Устранение дополнительного хардкода.
Хардкод портов в сервисе osmo-bts, который не позволял в пределах одной системы запускать более одной BTS [git].
Хардкод при выборе номера физического канала LimeSDR в сервисе osmo-trx [git].
Подготовка сбалансированной конфигурации каналов для обеих BTS — такой, чтобы при массовом звонке активных звонков было не просто много (TCH), но еще и не было затыка при их массовой установке (SDCCH) [git].
Добавлено равномерное распределение абонентов по двум BTS — если будет перевес на какой-то одной из них, потенциал звонка не будет реализован полностью на менее загруженной (там останутся свободные речевые каналы в то время как на соседней BTS будет их недостаток) [git].
Уменьшен таймаут paging-request (своеобразный ping перед стартом звонка) с 10 до 3 секунд — в процессе сбора абонентов некоторые из них могут «отвалиться». Такие отвалившиеся абоненты занимают каналы (т.к для них тоже запускается paging-request), в результате чего не получается достучаться до всех живых абонентов [git].
Реализован звонок в 2 «эшелона»: сначала пускаем команду звонка тем, у кого наименьший last_seen (отклик на последний пинг), а затем всем остальным [git].
Исправление бага в libosmocore, который из-за захардкоженного размера буфера не позволял единоразово отправлять команду более чем на 75 звонков. Позже выяснилось, что в проекте libosmocore на репорт также отреагировали и этот баг исправили спустя некоторое время [git].
Изменен алгоритм распределения абонентов на более «умный». распределение происходит в реальном времени на основе свободных каналов у BTS, а перед звонком сначала все они пингуются с помощью механизма silent-call, чтобы понять, кто жив, а кто уже отвалился [git].
Произведен «тюнинг» GSM-таймеров [git].
Добавлена фильтрация двух-симочных телефонов [git].
Увеличение числа звонков с 44 до 72 за счет снижения битрейта речевого канала в 2 раза — перешли с
TCH/F(full-rate)
наTCH/H(half-rate)
[git].Произведен «тюнинг» сетевой подсистемы Linux (sysctl), активно используемой стеком Osmocom для обмена данными между сервисами (IPC) [git].
Для всех входящих звонков от абонентов вешаем трубку — чтобы они не занимали ресурсы BTS [git].
Внедрен pool для более оптимальной отправки paging-request (GSM-пинг) с учетом отвалившихся абонентов перед совершением звонка [git].
Добавлена фильтрация технических GSM-устройств по IMEI (модемы, PoS-терминалы, IoT-устройства и т.д) перед звонком [git].
После всех этих оптимизаций мы смогли звонить всем вокруг одновременно в количестве 72 штук. В качестве бонуса, мы также внедрили рассылку SMS всем вокруг в количестве 384 штук.
По SMS самый интересный затык был в обращениях к SQLite-базе, используемой Osmocom для хранения данных об SMS — они вычитывались из базы по одному. Для нормальной GSM-сети это в общем-то приемлемо до тех пор, пока абоненты не начнут отправлять SMS чаще, чем несколько раз в секунду. Мы перетрясли все запущенные сервисы Osmocom путем отслеживания их сетевого взаимодействия с целью выяснить причину промедления. Очень «приятно» было в итоге обнаружить, как базовые принципы, применяемые при разработке веб-приложений нарушаются в чуть более хардкорных проектах — ну оно и простительно, наверное, — там разработчики все же сосредоточены немного на других вещах — например, как освоить несколько сотен страниц спецификации GSM и не оступиться в реализации.
Итоговая сборка нашего варианта BTS на базе 2 LimeSDR выглядит так и умещается в 24-литровый рюкзак:
Весь исходный код доступен в публичном репозитории Postuf на GitHub, так что при наличии желания, двух LimeSDR, глушилки подходящей мощности и чистой Ubuntu 20.04 на 8-ядерном железе вы сможете повторить описанное у себя. А для удобства мы подготовили CLI-скрипт, который предоставляет простой интерфейс ко всем подкапотным операциям.
❝ We has given you the truth. Do what you will.❞ ©