Один из краеугольных вопросов в зарубежных поездках — это вопрос связи. С одной стороны — вроде как проблемы и нет, к вашим услугам туристические и предоплаченные сим-карты, точки доступа Wi-Fi, на худой конец есть обыкновенный роуминг. Но стоит попробовать залогиниться в какой-нибудь сервис с многофакторной аутентификацией (будь то криптобиржа или банк-клиент) — тут же всплывают нюансы. SMS не приходят или приходят слишком поздно, когда срок действия одноразового кода уже вышел. В некоторых регионах возникают сложности как с исходящими, так и с входящими вызовами. В лучшем случае все это становится мелкими неудобствами, а в худшем — часть ваших возможностей существенно ограничивается или вовсе недоступна. Возможно, пришло время добавить очередную сущность в инфраструктуру — АТС с GSM шлюзом.
Несмотря на то, что есть готовые шлюзы типа GOIP-1, я предлагаю собрать собственное решение. Немного забегаю вперёд — помимо типовых функций АТС (голосовое меню, запись разговоров) мне нужно организовать пересылку входящих SMS в Telegram — а на «готовых» железных решениях такой функционал не всегда можно реализовать.
В самую первую очередь нужен модем. Лучше всего разжиться 3G модемом от Huawei — несмотря на то, что сами по себе 3G модемы считаются морально устаревшими, именно на них удобнее всего организовать GSM шлюз. Я использую модем Huawei E1550, но можно смело рассматривать модели E169, E620, E800. Перед дальнейшими действиями нужно убедиться, что соблюдены необходимые критерии:
• На модеме активированы голосовые вызовы
• Модем разлочен от оператора (если используете «брендированную» версию модема)
• Выставлен режим «только модем» (без виртуального CD-ROM, Card Reader и т.д.)
По этим моментам я не буду проходиться отдельно, подробные сведения можно найти на 4pda или других ресурсах — всё, что связано с этими модемами относительно прошивки, отвязки от оператора и активации передачи голоса — было разжевано множество раз. Единственное, что уточню — во время подготовки модема и работы с утилитами следует заранее себе выписать IMEI модема и IMSI номер SIM карты — они еще пригодятся. Соответствующие АТ команды привожу ниже:
AT+CGSN (информация о IMEI модема)
AT+CIMI (информация об IMSI SIM карты)
Во вторую очередь — нужна АТС. Раньше для этих целей у меня жил отдельный компьютер (который когда-то был тонким клиентом), сейчас же я держу АТС в виртуальной машине, используя VMware с проброшенным USB портом — к которому и подключен 3G модем. В качестве дистрибутива я использую MikoPBX версии 2024.1.114 (у меня он пришел на смену Kerio Operator), подробные инструкции по установке можно найти на официальном Wiki проекта. Особо стоит оговориться, что «фирменная» инструкция по сопряжению MikoPBX с 3G модемами Huawei есть, но в ней присутствует несколько ошибок — одну из которых (а она «блокирующая») пользователь без опыта работы с Asterisk просто не распознает.
Итак, продолжим. Подключаем 3G модем к АТС и сами подключаемся к АТС через SSH — нас встретит меню MikoPBX. Выходим из меню в консоль (Shell), командой lsusb проверяем перечень подключенных USB устройств:
Bus 001 Device 002: ID 12d1:1001
Bus 001 Device 001: ID 1d6b:0002
Bus 002 Device 003: ID 0e0f:0002
Bus 002 Device 002: ID 0e0f:0003
Bus 002 Device 001: ID 1d6b:0001
Вот такой вывод получился у меня. Причем, несколько лет назад эта же самая команда в MikoPBX выдавала и текстовое описание, помимо «сырых» ID устройств:
Bus 001 Device 002: ID 12d1:1001 Huawei E1550 HSDPA Modem
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB Hub
Bus 002 Device 002: ID 0e0f:0003 VMware, Inc. Virtual Mouse
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Так или иначе, нас интересует устройство с ID 12d1:1001 — это наш искомый модем.
12d1 — идентификатор производителя.
1001 — идентификатор модема
Важно! На некоторых устройствах режим «только модем» отображается как 140c, а не 1001, в таком случае делаем все то же самое, но с ID 12d1:140c
Чтобы убедиться, что это действительно модем, используем команду lsusb -v с параметром расширенного вывода и ищем в выдаче секцию с ID 12d1:1001
Bus 001 Device 002: ID 12d1:1001
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x12d1
idProduct 0x1001
bcdDevice 0.00
iManufacturer 3 HUAWEI Technology
iProduct 2 HUAWEI Mobile
Дальше ищем информацию о модеме по идентификатору производителя, вводим в консоль команду dmesg | grep 12d1 и получаем вывод:
usb 1-1: New USB device found, idVendor=12d1, idProduct=1001, bcdDevice= 0.00
Отлично, теперь вводим в консоль команду dmesg | grep ‘usb 1-1’ для получения информации по устройству usb 1-1:
usb 1-1: new high-speed USB device number 2 using ehci-pci
usb 1-1: New USB device found, idVendor=12d1, idProduct=1001, bcdDevice= 0.00
usb 1-1: New USB device strings: Mfr=3, Product=2, SerialNumber=0
usb 1-1: Product: HUAWEI Mobile
usb 1-1: Manufacturer: HUAWEI Technology
usb 1-1: GSM modem (1-port) converter now attached to ttyUSB0
usb 1-1: GSM modem (1-port) converter now attached to ttyUSB1
usb 1-1: GSM modem (1-port) converter now attached to ttyUSB2
Теперь нам известны идентификаторы COM-портов модема: ttyUSB0, ttyUSB1, ttyUSB2. Если вы видите похожую картину — то половина пути уже позади, если же COM-портов нет, то, возможно, вы не перевели модем в режим «только модем».
Третий этап, идём в веб-интерфейс MikoPBX, слева в меню ищем раздел «Система», в нём — «Кастомизация системных файлов». Открываем файл /etc/asterisk/modules.conf в режиме «Добавлять в конец файла», дописываем:
load => chan_dongle.so
load => app_system.so
load => func_base64.so
Нажимаем кнопку «Сохранить». Теперь открываем файл /etc/asterisk/dongle.conf в режиме «Заменять полностью», копируем конфигурацию:
[general]
interval=15
[defaults]
context=public-direct-dial
group=0; Настройки усиления TX/RX модема
txgain=0
rxgain=0; Автоматическое удаление SMS
autodeletesms=yes
resetdongle=yes
u2diag=-1
usecallingpres=yes
callingpres=allowed_passed_screen
disablesms=no
language=en
smsaspdu=yes
mindtmfgap=45
mindtmfduration=80
mindtmfinterval=200
callwaiting=auto
disable=no
initstate=start
dtmf=relax
[dongle0]
audio=/dev/ttyUSB1
data=/dev/ttyUSB2imei=123456789098765
imsi=987654321012345
Вот где нужны ранее выписанные IMEI и IMSI, без их указания в конфигурации у меня не получалось добиться работоспособности. В этом же файле можно задать свои значения параметрам txgain и rxgain — тем самым отрегулировать уровень (gain) передающего или принимающего сигнала модема соответственно. Значения задаются в дБ (децибелах) и могут принимать положительные и отрицательные значения. Положительное значение увеличивает уровень приемного сигнала, а отрицательное — снижает его. Необходимо быть осторожным с настройками усиления, так как слишком высокие значения могут привести к искажению сигнала и ухудшить качество связи.
dongle0 — произвольное имя линии (модема)
audio, data — значения этих параметров — COM-порты устройств, определенных на предыдущем этапе. Если не будет звука, то поменять местами.
Теперь нужно создать контексты для USSD и SMS. И, если USSD меня не сильно интересует как явление, то вот SMS — один из ключевых пунктов ради чего всё это затевалось. Наиболее удобным способом принимать SMS для меня является Telegram, особенно это актуально для тех случаев, когда физически модем и АТС расположены в зоне устойчивого покрытия, а сам я нахожусь в дальних далях, где сотовой связи практически нет, но в моем распоряжении рабочая станция или ноутбук с проводным подключением к сети Интернет. Перед дальнейшими действиями нужно создать бота Telegram (просто получить токен, больше ничего не нужно) и узнать свой ID (пользователя или чата) для отправки уведомлений. Когда токен и ID на руках — открываем файл /etc/asterisk/extensions.conf в режиме «Добавлять в конец файла» и вписываем контексты:
; Блок обработки Caller ID и связанные сценарии
[add-trim-prefix-clid-custom]
exten => _[0-9*#+a-zA-Z][0-9*#+a-zA-Z]!,1,NoOp(start check blacklist)
same => n,Set(CHANNEL(hangup_handler_push)=hangup-ext-queues,h,1);
same => n,return
; Блок обработки пропущенных звонков
[hangup-ext-queues]
exten => h,1,ExecIf($["${M_DIALSTATUS}" = "ANSWER"]?return)
same => n,Set(TOKEN=<TOKEN>)
same => n,Set(CHAT_ID=<CHAT_ID>)
same => n,Set(URL=https://api.telegram.org/bot${TOKEN}/sendMessage)
same => n,Set(TEXT=[${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)}] [${CALLERID(name)}] [Пропущенный входящий вызов] Абонент${CALLERID(num)})
same => n,System(curl -s -X POST '${URL}' -d chat_id='${CHAT_ID}' -d text='${TEXT}')
same => n,return
; Блок обработки USSD
[dongle-incoming-ussd]
exten => ussd,1,Noop(Incoming USSD: ${BASE64DECODE(${USSDBASE64})})
same => n,Set(TOKEN=<TOKEN>)
same => n,Set(CHAT_ID=<CHAT_ID>)
same => n,Set(URL=https://api.telegram.org/bot${TOKEN}/sendMessage)
same => n,Set(TEXT=[${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)}] [${DONGLENAME}] [USSD] ${BASE64DECODE(${USSDBASE64})})
same => n,System(curl -s -X POST '${URL}' -d chat_id='${CHAT_ID}' -d text='${TEXT}')
exten => ussd,n,Hangup()
; Блок обработки SMS
[public-direct-dial]
exten => sms,1,Noop(Incoming SMS from ${CALLERID(num)}: ${BASE64_DECODE(${SMS_BASE64})})
same => n,Set(TOKEN=<TOKEN>)
same => n,Set(CHAT_ID=<CHAT_ID>)
same => n,Set(URL=https://api.telegram.org/bot${TOKEN}/sendMessage)
same => n,Set(TEXT=[${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)}] [${DONGLENAME}] [SMS] ${CALLERID(num)}: ${BASE64_DECODE(${SMS_BASE64})})
same => n,System(curl -s -X POST '${URL}' -d chat_id='${CHAT_ID}' -d text='${TEXT}')
exten => sms,n,Hangup()
Где <CHAT_ID> — это ID пользователя или чата, а <TOKEN> — токен вашего бота, бонусом сделаны уведомления о пропущенных вызовах. Особо стоит отметить, что после модификации файла dongle.conf и сохранения изменений в нём требуется перезагрузить АТС чтобы произведенные изменения вступили в силу, однако работа с этим файлом еще не закончена.
Возвращаемся к SSH сеансу. Командой asterisk -r запускаем консоль Asterisk, после чего с помощью команды dongle show devices смотрим на перечень модемов:
ID Group State RSSI Mode Submode Provider Name Model Firmware IMEI IMSI Number
dongle0 0 Free 14 0 0 AT&T E1550 11.609.20.00.00 123456789098765 987654321012345 +79998877666
Если после IMEI и IMSI не указан номер, то его следует указать вручную через АТ команды:
dongle cmd dongle0 AT+CPBS=\"ON\"
dongle cmd dongle0 AT+CPBW=1,\"+79998877666\",145
Настраиваем маршрут входящих. В веб-интерфейсе MikoPBX слева в меню ищем раздел «Маршрутизация», переходим в пункт «Входящие маршруты». Создаем новый маршрут после удаление дефолтного или полностью переделываем дефолтный:

Суть сводится к тому, что в поле «Дополнительный номер» (он же DID) нужно указать номер SIM-карты, куда дальше пойдет переадресация вызова — тут смотрите сами.
Следующий этап — настройка исходящего маршрута. Здесь чуть сложнее и не совсем очевидно, но я постараюсь провести короткой дорогой. В разделе «Маршрутизация» выбираем пункт «Провайдеры», удаляем дефолтную запись и создаём новую, нажав на кнопку «Подключить SIP». Конечно, никакого SIP-провайдера мы здесь подключать не будем, достаточно задать имя оператора, указываем хост 127.0.0.1, а тип учетной записи ставим «Аутентификация по IP адресу без пароля». Сохраняем изменения.

Теперь самое важное — в адресной строке браузера из URL вычленяем ID только что созданного провайдера:
https://domain.com/admin-cabinet/providers/modifysip/SIP-TRUNK-1150B6D2
Слева в меню идём в раздел «Система», выбираем пункт «Кастомизация системных файлов». Снова открываем файл файл /etc/asterisk/extensions.conf в режиме «Добавлять в конец файла» (я ведь обещал, что к этому файлу мы еще вернемся) и дописываем в самом конце контекст исходящих звонков:
[SIP-TRUNK-1150B6D2-outgoing-custom]
exten => _[0-9*#+]!,1,Set(DIAL_COMMAND=Dongle/dongle0/${number})
same => n,return
Последние штрихи — возвращаемся в раздел «Маршрутизация», переходим в пункт «Исходящие маршруты». Изменяем дефолтный или создаём новый:

Здесь можете «поиграться» с параметрами отсечения и добавления цифр в начале номера.
Итак, что мы получили на выходе:
• Полноценную АТС с голосовым меню, расписанием, записью звонков и прочими возможностями из мира серьезной телефонии
• Возможность звонить в GSM-сети из SIP клиента
• Входящие SMS и USSD запросы нам пересылает бот в Telegram
• Для пропущенных вызывов тоже приходят уведомления
PS: При работе с модемом и приёме SMS сообщений требуется время от времени чистить памятью. За автоматическое удаление SMS отвечает параметр autodeletesms=yes в файле /etc/asterisk/dongle.conf, но если вы хотите сделать это вручную, то ниже привожу соответствующие команды:
asterisk -rvx 'dongle cmd dongle0 AT+CPMS=\"ME\",\"ME\",\"ME\"'
asterisk -rvx 'dongle cmd dongle0 AT+CMGD=1,4'
