Частые звонки рекламщиков и шпионаж, это одна из причин, почему я очень редко использую дисконтные карты, а когда использую – выношу мозг, чтобы мне не названивали и не рассылали спам. Но тем не менее, телефоны так или иначе просачиваются к рекламщикам. Девочек в кол-центрах тоже можно пожалеть, очень часто на них орут, требуют исключить из обзвона и так далее. Когда от одного такого звонка в не очень удобный момент у меня очень бомбануло, и я высказал все, что я думаю о звонящих, я понял что так дальше жить нельзя, и надо что-то делать. И таки сделал. Демонстрация на видео ниже, а в блоге куча деталей реализации.
Теория и планирование
Для успешной контр-атаки на телефонных рекламщиков необходимо было сделать следующее:
- Брать трубку и держать звонящего на линии. Входящие звонки бесплатны, исходящие нет. Бюджет любой рекламы конечен.
- Делать это автоматически, чтобы не отвлекаться и не вникать в происходящее
- Сохранить возможность дозвониться до тебя для дальних знакомых, которым не очень хочется давать “основной” номер.
- ОПЦИОНАЛЬНО: сделать бесполезными данные геопозиционирования со стороны оператора. Вообще не понятно как и кому эти данные продаются, как хранятся и обрабатываются
Как это все провернуть? Элементарно, Уатсон! Нам надо поднять свою цифровую АТС! Развернем Asterisk, воткнем в сервер голосовой USB модем. Так как по городу он двигаться не будет, геопозиционирование бесполезно. А для выхода на город придумаем костыль, либо прикупим дешманский FXO шлюз. Ну, за работу, красноглазые!
Железо
Для реализации задумки из хлама было извлечено несколько старых 3g/4g модемов, которые валялись без дела с давних времен.
Один из них отлично поддерживал голосовую связь и поддерживался chan_dongle.
Когда уже вариант с сотовой сетью заработал, и стало ясно что затея осуществима, я заказал дешевый FXO шлюз с aliexpress. Стоит удовольствие 27$ с доставкой. Эта штука быстро и решительно переведет домашнюю телефонную “лапшу” в VoIP. Есть еще более дешевый вариант с dial-up модемом, некоторые из них умели в голосовую связь и поддерживались плагином DAHDI, но я их давно утилизировал за ненадобностью на ближайшую свалку, а заказывать с aliexpress за 10 баксов dial-up модем и гадать взлетит/не взлетит мне не хотелось. Лучше уж заплатить 27$ и получить что-то гарантировано рабочее.
Но не все оказалось так просто и быстро. Китайцы заболели дружно коронавирусом, посылку не отправляли более месяца, потому заказ пришлось отменить и пошариться на авито. Там нашелся очень и очень добрый мужик Иван, который просто так (да, за бесплатно!) отдал мне несколько FXO шлюзов, упомянув, что что-то не то у них с питанием и они иногда глючат. Судя по симптомам – что-то с питанием. Фигня, подумал я, перепаяем. Но об этом позже.
Софт
Создаем виртуалку для FreePBX и пробрасываем USB-модем
Собственно, FreePBX – это веб-интерфейс к серверу телефонии asterisk, который снискал популярность, так как позволяет быстро развернуть телефонию небольшого предприятия, и сделать это (если не брать коммерческие плагины) практически бесплатно. А простой железки с 2Gb памяти и одним-двум процессорным ядром хватит за глаза на офис из 20 человек. В моем случае, “для дома, для семьи”, потребуется даже меньше ресурсов.
Так как с некоторых пор я перевел все свое серверное хозяйство на proxmox, то и начнем мы с создания виртуальной машины.
Далее скачиваем свежий ISO образ FreePBX и закидываем его в /var/lib/vz/templates/iso на сервере с виртуальными машинами.
cd /var/lib/vz/templates/iso
wget https://downloads.freepbxdistro.org/ISO/SNG7-FPBX-64bit-1910-2.iso
2GB памяти, 2 ядра, 30GB более чем хватит. Можно, наверное, обойтись и меньшим, но так как памяти на сервере сейчас с запасом, решил ни в чем себе не отказывать.
Установка проходит вполне себе обыденно, а после нее надо зайти в веб-интерфейс и настроить наш новый VoIP шлюз. Для безопасности я решил отключить firewall, но и не показывать свою АТС в сеть, таким образом разрешив соединения до нее только через VPN.
Настраиваем FreePBX и подключаем мобильник в виде SoftPhone
Итак, поехали. Сначала нам надо подключить к нашей АТС парочку телефонов. Мобильный телефон проще всего использовать для тестов, но лучше поставить специализированную SIP звонилку. Я использовал MizuDroid. В терминологии Asterisk/FreePBX это называется SoftPhone (софтфон)
Так как я с телефонией до этого самого момента не сталкивался, то и терминологию я буду разжеввывать по ходу дела. Extensions – это так называются “внутренние” номера нашей АТС. Этот номер нам и надо создать. Мы его можем создать как sip или pjsip. Разница только в том, какой плагин нам будет обеспечивать подключение абонентского оборудования к этому экстеншну.
Для начала создадим наш первый chan_pjsip экстеншн для мобильника и подключим к нему софтфон. Для этого идем в Applications -> Extensions
При настройке надо обратить внимание на пару полей, и в первую очередь это поле Secret. Это пароль, который надо вбивать на софтфоне, чтобы соединиться с АТС.
Остальные настройки можно не менять, там все достаточно адекватно. Теперь подключаем телефон к домашней сети, настраиваем звонилку и проверяем все ли работает.
Но перед этим будет неплохо зайти в командную строку нашей АТС и остановить на время наладки fail2ban. Эта штука постоянно мониторит логи и в случае обнаружения неправильных попыток авторизации банит пользователя на продолжительное время. Полезно когда все сделано, вредно когда мы только налаживаем систему и будем часто ошибаться.
systemctl stop fail2ban
Как только мы добились того, что MizuDroid авторизовался, можем попробовать позвонить по любому номеру и услышать предупреждение приятным женским голосом на английском, что мы звоним куда-то не туда.
Создаем IVR на внутреннем номере и тестируем его
Для начала выгоняем всех из комнаты, ищем тихое место, и записываем голосовые менюшки. И поменьше ехидства в голосе 😉 Результат загружаем на страничку Admin -> System Recordings и даем записям понятные нам имена.
Теперь, идем в Applications -> IVR. Это и есть “интерактивное голосовое меню” и там создаем несколько менюшек. Один пункт может ссылаться на другой IVR, почему бы и нет? Тут мы ограничены только свободным временем и фантазией. Пожалуй, я отмечу тут только несколько заботливо разложенных граблей.
- Если мы хотим дать пользователю возможность набрать “внутренний номер”, то лучше это сделать отдельным IVR меню, который вызывать из основного по цифре. В нем не будет никаких цифр, только включен “Direct Dial” и пункт “Force Strict Dial Timeout”. При этом таймаут лучше установить в небольшое значение. Я поставил 5 секунд. Если этого не сделать, то от введенных цифр будет всегда отжираться одно число.
- При записи лучше оставлять секунд 5 тишины вначале, так как (забегая вперед) в случае соединения по мобильной связи немного времени в начале откусывается. Да и оператор колл-центра может не сразу начать говорить и выйдет небольшой конфуз.
Теперь надо направить звонки на IVR. Для этого создаем “виртуальный” экстеншн. Я, например, сделал 0000 и 0001 (экспериментируя с настройками). В пункте “Advanced” в разделе “Not Reachable” надо поставить IVR и имя созданного нами IVR меню.
Нажимаем “submit”, потом на красную кнопку “apply config” и звоним с нашего софтфона по номеру 0000. Мы должны услышать наше голосовое меню. Если услышали, то можно, потирая руки, переходить к следующему пункту – подключать это дело к мобильной сети.
Настраиваем GSM связь
Готовим и проверяем модем
Пожалуй, для самых маленьких надо немного рассказать, как работают GSM модемы и что они из себя (исторически) представляют.
Типичный модем, это составное USB устройство, из которого торчат несколько виртуальных ком-портов, сетевой интерфейс (на более новых модемах, qmi, ncm, ndis или тому подобные). Опционально – виртуальный дисковод с драйверами для виндовса, и usb mass storage для встроенного в модем кард-ридера. Набор доступных функций может меняться, и на некоторых модемах, чтобы увидеть что-то, кроме дисковода с драйверами в модем надо заслать какую-то ересь.
Ком-порты это самое любопытное, большая их часть кушает AT-команды, которыми можно звонить, регистрироваться в сети, читать СМС и делать практически все с модемом. У старых модемов соединение с интернетом идет по этому самому ком-порту, а у более новых по ком-порту только настраивается соединение, а для передачи данных используется виртуальный сетевой интерфейс. Вот такой вот экскурс.
Что касается голосовых звонков, то у некоторых чипсетов звуковой тракт если и предусмотрен, то аналоговый и не подключенный никак по усб, а у некоторых один из ком-портов как раз и может передавать аудио-данные. Такой-то модем нам и потребуется, и, хвала Богам Хаоса, я его таки добыл!
Пробрасываем модем в виртуальную машину
При переключении режима через USB ModeSwitch модем меняет vendor id и product id, потому пробрасывать в виртуальную машину надо либо весь usb порт, либо устанавливать usbmodeswitch на гипервизоре (proxmox) и пробрасывать модем уже в переключенном виде. Еще можно отключить режим диска с драйверами заслав в через ком-порт в модем команду:
AT^U2DIAG=0
Но я решил обойтись usbmodeswitch. Для этого выполняем в командной строке на сервере proxmox:
sudo apt install usbmodeswitch
Перетыкаем модем и проверяем, что в dmesg мы увидели порты модема
[ 7.664080] usbserial: USB Serial support registered for GSM modem (1-port)
[ 7.664111] option 2-1:1.0: GSM modem (1-port) converter detected
[ 7.664168] usb 2-1: GSM modem (1-port) converter now attached to ttyUSB0
[ 7.664193] option 2-1:1.3: GSM modem (1-port) converter detected
[ 7.664233] usb 2-1: GSM modem (1-port) converter now attached to ttyUSB1
[ 7.664240] option 2-1:1.4: GSM modem (1-port) converter detected
[ 7.664292] usb 2-1: GSM modem (1-port) converter now attached to ttyUSB2
[ 7.730440] ppdev: user-space parallel port driver
Теперь остается только пробросить модем в виртуальную машину с FreePBX и сделать настройки.
Устанавливаем chan_dongle
Настроили и проверили? Супер. Теперь самое время наладить мобильную связь. Для этого нам потребуется скомпилировать и установить chan_dongle. С ним будет несколько нюансов. Для начала заходим в консоль сервера и вбиваем от root’a.
yum -y install tcl asterisk16-devel make automake binutils git
git clone https://github.com/wdoekes/asterisk-chan-dongle.git
cd asterisk-chan-dongle/
aclocal && autoconf && automake -a
./configure --with-astversion=16.4.1 --prefix=/usr
make
make install
Что здесь важно? Во-первых указать правильную версию asterisk при установке заголовочных файлов (asterisk16-devel), во-вторых правильно указать точную версию asterisk на шаге ./configure. Ее можно узнать вбив asterisk -r, а потом exit. У меня на момент написания этой статьи был 16.4.1
[root@freepbx ~]# asterisk -r
Asterisk 16.4.1, Copyright (C) 1999 - 2018, Digium, Inc. and others.
Created by Mark Spencer <[email protected]>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
Connected to Asterisk 16.4.1 currently running on freepbx (pid = 2492)
freepbx*CLI>
Теперь создаем/редактируем /etc/asterisk/dongle.conf. Собственно, конфиг я собрал по куче разных туториалов в интернете методом проб и ошибок.
[general]
interval=15
[defaults]
rxgain=0 ; - это усиление принимаемого аудиосигнала (динамика)
txgain=0 ; - это усиление передаваемого аудиосигнала (микрофона)
language=ru ; - желательно указывать для корректного речевого информирования
dtmf=relax ; - желательно выключать, когда есть вероятность повреждения формы тональных сигналов
context=from-gsm ; На какой контекст приходят звонки и сообщения
autodeletesms=yes ; Автоматом удалять SMS из модема при получении
[dongle0]
extern=+7XXXXXXXXXX ;Наш номер
imei=XXXXXXXXXXXX ; IMEI модема
в секции dongle0 мы можем указать либо IMEI, либо вручную последовательные порты, которые будет использовать chan_dongle. Лучше это делать автоматом.
Прежде, чем мы сможем приступить к работе с chan_dongle остается несколько моментов, которые необходимо сделать, и которые большинство туториалов опускали.
Чиним права на /dev/ttyUSBx и /var/lock при старте
По умолчанию, у chan_dongle проблема с доступом к /dev/ttyUSBX и /var/lock directories.
Первое, мы можем починить, создав файл /etc/udev/rules.d/92-dongle.rules с таким вот содержимым.
KERNEL=="ttyUSB*", MODE="0666", OWNER="asterisk", GROUP="asterisk"
Второе… Ну, я в какой-то момент забил и сделал chmod 777 на каталог /var/lock во время загрузки, ибо остальные варианты не сработали. (Добавление asterisk в группу lock, и прочее) Я сделал это размещением в файлике /etc/systemd/system/lockperm.service вот этой магии. Не делайте так в продакшне, особенно если сервер будет смотреть наружу. У меня он только во внутренней сети и в виртуалке, потому я позволил себе схалтурить немного.
[Unit]
Description=Makes /var/lock world-writable
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/chmod 777 /var/lock/
TimeoutStartSec=0
[Install]
WantedBy=asterisk.service
Устанавливаем правильно собственный номер в модеме
Если этого не сделать, будут проблемы с передачей caller id, и прочие странности. Для этого, в консоли астериск вбиваем следующую магию:
asterisk -r
freepbx*CLI> dongle cmd dongle0 AT+CPBS=\"ON\"
freepbx*CLI> dongle cmd dongle0 AT+CPBW=1,\"+7номер_симки\",145
Переправляем СМС сообщения и результаты USSD запросов в телеграм
Итак, это не штатная фича FreePBX, поэтому придется опять вбивать заклинания, на этот раз на питоне и языке конфигурации asterisk.
Сначала открываем файлик /etc/extensions_custom.conf и вбиваем туда вот такую вот магию:
[from-gsm]
include => from-pstn
exten => sms,1,Verbose(Incoming SMS: From: ${CALLERID(num)} ${SMS_BASE64})
exten => sms,n,System(/usr/local/bin/sms2tg.py '${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)} - ${DONGLENAME} - ${CALLERID(num)}:' ${SMS_BASE64})
exten => sms,n,Hangup()
exten => ussd,1,Verbose(Incoming USSD: ${USSD})
exten => ussd,n,System(echo '${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)} - ${DONGLENAME}: ${USSD}' >> /var/log/asterisk/ussd.txt)
exten => ussd,n,Hangup()
Эта штука будет выписывать результаты всех USSD запросов в /var/log/asterisk/ussd.txt, а все смски кормить скрипту /usr/local/bin/sms2tg.py
sms2tg.py, как легко догадаться нам придется сделать самостоятельно. Для этого нам потребуется создать своего бота в телеграмме.
Вооружившись API key и chatid мы можем развернуть это на нашем сервере с freepbx. Для этого сначала ставим нужные нам компоненты
yum install python36u-pip
pip3.6 install pytelegrambotapi
А теперь сохраняем скрипт /usr/local/bin/sms2tg.py (Не забываем заменить API:KEY и CHATID на необходимые.
#!/usr/bin/python3.6
import base64
import telebot
import sys
bot = telebot.TeleBot('API:KEY')
chat_id = CHATID
import codecs
message = base64.b64decode(sys.argv[2])
message = message.decode('utf-8')
log = "SMS from: " + sys.argv[1] + " " + message + "\n\n"
text_file = open("/var/log/sms", "a+")
text_file.write(log)
text_file.close()
ret = bot.send_message(chat_id,
"Incoming SMS: \n" +
sys.argv[1] + "\n" +
message
)
Скрипт будет выписывать смс в файл /var/log/sms и отправлять их в телеграмм. Есть только один маааленький нюанс. В РФ сервера телеграмм блокируют, потому нам надо будет смаршрутизировать IP адрес api.telegram.org через VPN или использовать прокси. Оставлю это на совести того, кто будет повторять эти инструкции - эта статья и так выходит ооочень жирной.
Включаем запись вообще всех звонков, в т.ч. и во время взаимодействия с IVR
Вот это стоило мне досточно много мытарств. Эта настройка спрятана в очень глубоких недрах FreePBX и названа так, чтобы никто не догадался. Для этого открываем web-интерфейс FreePBX и двигаемся в Settings->Advanced Settings и находим пункт Call Record Option. Выставляем его в “No”. (Да, именно в No). Теперь звонки если будут писаться, то с самого начала, когда только только была поднята трубка. Главное не забывать соблюдать законодательство и предупреждать, что мы записываем звонок и оставляем за собой право ловить с этого лулзы 😉
Настройка транка
Еще не надоело? Отлично, теперь надо собственно настроить транк для наших звонков внутри FreePBX. Для этого в веб-интерфейсе надо зайти в Connectivity->Trunks и создать новый транк типа custom. Настройки выглядят как-то так. В OutBound Caller ID записываем номер нашей сим карты.
Входящая маршрутизация
Если Вы дочитали статью до этого момента, вы либо очень упорны, либо и впрямь настраиваете такую же штуку. В любом случае, удачи. А теперь настроим маршрутизацию звонков. Для этого идем в Connectivity -> Inbound Routes. И направляем все входящие звонки с мобильного номера на экстеншн, где сидит наше голосовое меню.
В расширенных опциях ставим галочку Force для принудительной записи всех звонков.
Исходящая маршрутизация
Приятный бонус. Если не хотим светить свой основной номер при звонке, мы можем позвонить через SIP звонилку с нашего “мусорного”номера. Бывает полезно, если нам позвонили и сбросили, а нас либо гложет любопытство, либо мы хотим завлечь рекламщиков в наш уютный “ханипот”. Также бывает полезно, если мы в отпуске, а надо позвонить на какой-то номер домой и не платить за роуминг. Эдакая колхозная альтернатива услуге WiFi Calling. Мои настройки выглядят как-то так:
Все остальное можно оставить в их дефолтных значениях.
Переправляем записи звонков в телеграмм
Задачей этого безумия было не только избавить меня от надоедливого спама, но еще и превратить его в регулярный источник хорошего настроения, в простонародье – “лулзов”. А их хочется регулярно получать себе на телефон. Для этого хорошо бы сжимать аудио и отправлять в телеграмм. Для этого опять придется воспользоваться не особенно хорошо документированными возможностями FreePBX.
Для начала разрешим отображать и менять read-only настройки FreePBX, установив вот эти пункты в положение Yes
Далее установим скрипт, который будет вызываться по окончании записи звука. У меня это будет
/usr/local/bin/voicecallhandler.sh ^{TIMESTR} ^{CALLFILENAME} ^{CALLERID(number)}
Теперь перейдем к самому скрипту. Выглядит он у меня как-то так. Серьезно адаптирован из того, что было найдено на просторах интернета. Его задача перекодировать аудиозапись из wav в mp3 и передать на отправку в телеграмм боту.
#!/bin/bash -x
# This script emails the recorded call right after the call is hung up. Below are the variables passed through asterisk
# $1 - Time String
# $2 - File
# $3 - Caller id
/bin/nice /bin/sleep 3
dy=$(date '+%Y')
dm=$(date '+%m')
dd=$(date '+%d')
file_age=35
dtpath=/var/spool/asterisk/monitor/$dy/$dm/$dd/
/bin/nice /usr/bin/lame -b 16 -m m -q 9-resample $dtpath$2.wav $dtpath$2.mp3
/bin/nice /bin/chown asterisk:asterisk $dtpath/$2.mp3
dt=$(date '+%m/%d/%Y %r')
echo $dt
exten=${str:4:4}
# the above exten takes the string of $4 which is the Channel name
# this is key in finding who recorded the call and who the call with
# Example: SIP/2212-00000100
# the exten =${str:4:4} takes the string str which is the example above
# then looks for the 4th position in string and it starts the extension number after that
# Then it takes the second number 4 and says to grab that number of characters and associate with the
# variable exten. leaving me with 2212 if your extensions are different then 4 characters only change the
# second number 4 above to the extension length you have
filename=$2
sfile=$dtpath$2.mp3
shift
shift
from=$*
/usr/local/bin/call2tg.py "$from" $sfile
Собственно, отправкой занимается второй скрипт (/usr/local/bin/call2tg.py), который как и наш предыдущий достаточно туп.
#!/usr/bin/python3.6
import base64
import telebot
import sys
import codecs
bot = telebot.TeleBot('API:KEY')
chat_id = CHATID
voice = open(sys.argv[2], 'rb')
bot.send_message(chat_id,
"Got a new voice call: \n" +
sys.argv[1]
)
bot.send_voice(chat_id, voice)
P.S. Сохранив все скрипты, не забываем сделать на них chmod +x, чтобы они стали исполняемыми.
Полевые испытания
Теперь номер сим карты, которая стояла в модеме я мог совершенно безжалостно давать всем подряд рекламщикам. Удивительно, но когда ты с удовольствием делишься номером для оформления дисконтных карт, это приносит почему-то такую радость некоторым продавцам, что и сам невольно радуешься. За них. Обдумывая это, я шел на работу.
– Пройдите соц. опрос и получите 200 рублей на телефон – орала дурным голосом тетка у метро.
“О! Наши пациенты”, – плотоядно усмехнулся я и решил пополнить баланс своей симки для спама…
Что дальше?
За последний месяц, я успел провести первые испытания, как на друзьях и знакомых (которых уже порядком задолбал просьбами позвонить боту), за что им огромадное спасибо, так и получить первые записи общения бота… с другими ботами, которые делают обзвон. Да, такая вот битва роботов, которую мы заслужили.
В планах пока следующее:
- Научить бота “правильно” отвечать на голосовые вопросы типа “хотите пройти соц. опрос”, и вообще всячески стараться выйти на живого оператора, прежде чем выдавать голосовое меню.
- Закончить и описать настройку FXO шлюза, который вывел
мое красноглазие на новый уровеньбота на городскую телефонную сеть, где рекламщиков пасется намного больше. - Научить его отправлять нужный DTMF код, когда звонят с предложениями юридической помощи.
Я все хочу чтоб кто-нибуть Lenny перевел и озвучил, было бы очень интересно насколько русские спамеры быстро распознают что это бот.
К сожалению, как я не стараюсь, голос у меня не тянет на стариковский. От слова совсем.
Спасибо за статью. Прошу совета. Объясните чайнику, что изменить в скрипте (голосовая почта -> телеграм) под голый астериск. Что-то с dtpath видимо. 😦