Избавляемся от телефонного спама, Часть 1

Частые звонки рекламщиков и шпионаж, это одна из причин, почему я очень редко использую дисконтные карты, а когда использую – выношу мозг, чтобы мне не названивали и не рассылали спам. Но тем не менее, телефоны так или иначе просачиваются к рекламщикам. Девочек в кол-центрах тоже можно пожалеть, очень часто на них орут, требуют исключить из обзвона и так далее. Когда от одного такого звонка в не очень удобный момент у меня очень бомбануло, и я высказал все, что я думаю о звонящих, я понял что так дальше жить нельзя, и надо что-то делать. И таки сделал. Демонстрация на видео ниже, а в блоге куча деталей реализации.

Теория и планирование

Для успешной контр-атаки на телефонных рекламщиков необходимо было сделать следующее:

  • Брать трубку и держать звонящего на линии. Входящие звонки бесплатны, исходящие нет. Бюджет любой рекламы конечен.
  • Делать это автоматически, чтобы не отвлекаться и не вникать в происходящее
  • Сохранить возможность дозвониться до тебя для дальних знакомых, которым не очень хочется давать “основной” номер.
  • ОПЦИОНАЛЬНО: сделать бесполезными данные геопозиционирования со стороны оператора. Вообще не понятно как и кому эти данные продаются, как хранятся и обрабатываются

Как это все провернуть? Элементарно, Уатсон! Нам надо поднять свою цифровую АТС! Развернем Asterisk, воткнем в сервер голосовой USB модем. Так как по городу он двигаться не будет, геопозиционирование бесполезно. А для выхода на город придумаем костыль, либо прикупим дешманский FXO шлюз. Ну, за работу, красноглазые!

Железо

Для реализации задумки из хлама было извлечено несколько старых 3g/4g модемов, которые валялись без дела с давних времен.

Один из них отлично поддерживал голосовую связь и поддерживался chan_dongle.

Megafon E173 (Ну, или Huawei E173, если быть точным)

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

3 thoughts on “Избавляемся от телефонного спама, Часть 1

  1. Я все хочу чтоб кто-нибуть Lenny перевел и озвучил, было бы очень интересно насколько русские спамеры быстро распознают что это бот.

  2. Спасибо за статью. Прошу совета. Объясните чайнику, что изменить в скрипте (голосовая почта -> телеграм) под голый астериск. Что-то с dtpath видимо. 😦

Добавить комментарий для LEXASOFTОтменить ответ

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.