[Из песочницы] Как легко и просто научить ваш Asterisk звонить через нужного оператора

Приветствую тебя, %username%! Сегодня мне хотелось бы поделиться решением, позволяющим научить ваш Asterisk автоматически маршрутизировать звонки по соответствующим направлениям, не прибегая к громоздким регулярным выражениям.

image

Практика показывает, что все больше и больше компаний начинают задумываться о своих расходах на связь. Львиную часть расходов при этом составляют вызовы на мобильные номера. Отсюда и родилась задача обрабатывать исходящие вызовы и направлять через ту линию, где звонок будет совершен бесплатно или за наименьшую стоимость.В моем случае, необходимо было маршутизировать звонки на домашний регион операторов большой тройки через соответствующие сим-карты, вставленные в GSM-шлюз. Вместо выбранных операторов можно использовать любые другие направления по аналогии с сабжем.

В качестве шлюза выступал OpenVox VoxStack VS-GW1202–4G, в который предварительно были вставлены сим-карты известных вам операторов и настроены 3 транка до Asterisk.

Безусловно, путей решения проблемы великое множество, но мне хотелось бы остановиться на решении, которое я счел оптимальным: автоматическая сверка номеров из базы MySQL и дальнейшее перенаправление на нужную линию. Реализация довольно проста, хотя местами может показаться неказистой.

Разбить все работы можно на несколько этапов:

Создать и заполнить базу данных Подготовить Asterisk к работе с БД Написать диалплан для обработки исходящих вызовов Подготовка базыДля начала необходимо создать отдельную базу (опционально):

CREATE DATABASE telcodes; Рутовый доступ в нашей ситуации лучше не давать, т.к. в этом нет необходимости, да и дырка в безопасности в виде рутового логина и пароля к MySQL в открытом виде в конфигурационном файле никому не нужна. Поэтому даем доступ произвольному пользователю только к нашей БД (в моем случае пользователь: «mobile», пароль: «heavypass»)

CREATE DATABASE telcodes; GRANT ALL ON telcodes.* TO mobile@localhost IDENTIFIED BY 'mobile'; FLUSH PRIVILEGES; SET PASSWORD FOR 'mobile'@'localhost'=PASSWORD ('heavypass'); Создаем таблицу:

Скрытый текст CREATE TABLE telcodes ( code smallint (3) NOT NULL, begin int (11) NOT NULL, end int (11) NOT NULL, ammount int (11) NOT NULL, operator varchar (100) NOT NULL, region varchar (100) NOT NULL) DEFAULT CHARSET=utf8; А теперь можно перейти непосредственно к заполнению. Каждый волен сам выбирать для себя способ, я остановлюсь на следующем: wget http://www.rossvyaz.ru/docs/articles/Kody_DEF-9kh.csv cat Kody_DEF-9kh.csv | iconv -f pt154 -t utf8 >> telcodes.csv mysqlimport -umobile -p telcodes /usr/src/telcodes.csv --fields-terminated-by=';' --lines-terminated-by=»\r\n» Выкачиваем список кодов мобильных операторов с сайта Россвязи, преобразуем кодировку и заливаем в нашу базу. Путь до файла опционален.База заполнена, но чтобы избежать проблем с кодировками внесем небольшие изменения: т.к. мне необходимо отбирать номера большой тройки для звонков в домашнем регионе, то я меняю только их, регион помечаю как home, а названия меняю на beeline, mts и megafon соответственно:

UPDATE telcodes set region = 'home', operator = 'beeline' where operator = 'Вымпел-Коммуникации' and region = 'Москва и Московская область'; UPDATE telcodes set region = 'home', operator = 'mts' where operator = 'Мобильные ТелеСистемы' and region = 'Москва и Московская область'; UPDATE telcodes set region = 'home', operator = 'megafon' where operator = 'МегаФон' and region = 'Москва и Московская область'; База данных готова к использованию.

Подготовка asterisk Соединять Asterisk с БД будем при помощи ODBC, т.к. считаю это унифицированным решением. Для начала необходимо пересобрать Asterisk с поддержкой ODBC. В качесте ОС в моем случае выступает Ubuntu Server 12.04.

Ставим пакеты unixodbc, unixodbc-dev и libmyodbc apt-get install unixodbc unixodbc-dev libmyodbc В каталоге с исходниками Asterisk выполняем:

./configure && make menuselect Проверяем что модуль res_odbc доступен и включен, в функциях надо проверить доступность func_odbc. Затем сохраняем и выполняем:

make && make install Смотрим где лежат драйвера для ODBC

# dpkg -L libmyodbc Скрытый текст /. /usr /usr/lib /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/odbc /usr/lib/x86_64-linux-gnu/odbc/libmyodbc.so #Запоминаем месторасположение /usr/share /usr/share/libmyodbc /usr/share/libmyodbc/odbcinst.ini /usr/share/doc /usr/share/doc/libmyodbc /usr/share/doc/libmyodbc/README.Debian /usr/share/doc/libmyodbc/changelog.Debian.gz /usr/share/doc/libmyodbc/examples /usr/share/doc/libmyodbc/examples/odbc.ini /usr/share/doc/libmyodbc/copyright Смотрим где лежат конфигурационные файлики для ODBC

#odbcinst -j Скрытый текст unixODBC 2.2.14 DRIVERS…: /etc/odbcinst.ini SYSTEM DATA SOURCES: /etc/odbc.ini FILE DATA SOURCES…: /etc/ODBCDataSources USER DATA SOURCES…: /root/.odbc.ini SQLULEN Size…: 8 SQLLEN Size…: 8 SQLSETPOSIROW Size.: 8 Правим /etc/odbcinst.ini, добавляем в файл запись:

Скрытый текст [MySQL] Description = MySQL driver Driver = /usr/lib/x86_64-linux-gnu/odbc/libmyodbc.so #указываем запомненное местоположение Setup = /usr/lib/x86_64-linux-gnu/odbc/libodbcmyS.so #там же лежит файл libodbcmyS.so CPTimeout = CPReuse = Описываем подключение к БД в файлe /etc/odbc.ini

Скрытый текст [telcodes-mysql] Driver = MySQL Description = MySQL telcodes via ODBC Server = localhost #адрес сервера, где стоит база Port = 3306 User = mobile #Созданный ранее пользователь Password = heavypass #Пароль пользователя Database = telcodes #База данных, где будут храниться Socket = /var/run/mysqld/mysqld.sock А теперь непосредственно знакомим Asterisk с MySQL при помощи ODBC. Вносим изменения в /etc/asterisk/res_odbc.ini

Скрытый текст [telcodes] enabled => yes dsn => telcodes-mysql username => mobile password => heavypass pooling => no limit => 1 pre-connect => yes и прописываем загрузку модуля в /etc/asterisk/modules.conf

preload => res_odbc.so Теперь можно перезапустить сам Asterisk, ну или только загрузить модуль res_odbc.so. После чего в CLI выполняем команду:

odbc show all Скрытый текст aster*CLI> odbc show allODBC DSN Settings— Name: telcodesDSN: telcodes-mysqlLast connection attempt: 1970–01–01 03:00:00Pooled: NoConnected: Yes

На этом второй этап можно считать завершенным, мы создали и заполнили БД и подружили её с Asterisk.

Написание диалплана Ну, а теперь можно приступить непосредственно к написанию диалплана для обработки исходящих вызовов.

Каждый набранный номер обрабатывается макросом, в результе работы которого будет определена линия, через которую будет совершен вызов. В качестве аргумента передаваемого макросу будет выступать набираемый номер. Первый символ (8) будет отрезаться еще до попадания в макрос, после чего в SQL запросе мы будем отбирать дальнейшие первые 3 символа (123) для сравнения с кодом оператора и оставшиеся 7 символов (4567890) для определения принадлежности к той или иной номерной емкости.

Все работы с БД прописываются в конфигурационном файле func_odbc.conf. Здесь мы придумываем и составляем функции для взаимодействия с БД, а затем используем их результат в диалплане. Каждый раздел описывает свою функцию, название каждого раздела принято заполнять в верхнем регистре.В моем случае необходимо определить принадлежность номера к региону и оператору и передать результат для дальнейшей обработки макросом.

Добавляем в /etc/asterisk/func_odbc.conf запись

[MOBILE] dsn=telcodes-mysql read=SELECT operator, region FROM `telcodes` WHERE ${ARG1:3:9} BETWEEN `begin` AND `end` AND `code`=${ARG1:0:3} Стоит запомнить, что результатом запроса будут служить 2 значения, разделенных запятой: оператор, обслуживающий данный номер, а так же регион обслуживания.Ну, а теперь можно непосредственно написать сами правила обработки номера. В примере буду опускать лишние правила, оставлю только то, что относится к делу. Все изменения производим в файле /etc/asterisk/extensions.conf

Создаем контекст для исходящих звонков.

Скрытый текст [from-users]exten => _8XXXXX.,1, NoOp (Call from ${CALLERID (num)} to ${EXTEN})same => n, Macro (seeknumber-odbc,${EXTEN:1:10})same => n, Noop (${TRUNK_MOB})same => n, Goto (to-${TRUNK_MOB},${EXTEN},1)same => n, Hangup

Создаем контексты для звонков на провайдеров мобильной связи, а так же для провайдера по-умолчанию. В настройке каждого транка я ограничил количество одновременных сессий до одной и добавил переадресацию вызова на транк по-умолчанию в случае занятости или недоступности линии.

Скрытый текст [to-prov-trunk]exten => _8XXXXX.,1, NoOp (Call from ${CALLERID (num)} to ${EXTEN} other)same => n, Dial (SIP/prov-trunk/${EXTEN},140, Tt)same => n, Hangup ()[to-beeline]exten => _8XXXXX.,1, NoOp (Call from ${CALLERID (num)} to ${EXTEN} beeline)same => n, Dial (SIP/beeline/${EXTEN},140, Tt)same => n, Goto (status, s-${DIALSTATUS},1)

[to-megafon]exten => _8XXXXX.,1, NoOp (Call from ${CALLERID (num)} to ${EXTEN} megafon)same => n, Dial (SIP/megafon/${EXTEN},140, Tt)same => n, Goto (status, s-${DIALSTATUS},1)

[to-mts]exten => _8XXXXX.,1, NoOp (Call from ${CALLERID (num)} to ${EXTEN} mts)same => n, Dial (SIP/mts/${EXTEN},140, Tt)same => n, Goto (status, s-${DIALSTATUS},1)

[status]exten => s-ANSWER,1, Hangup ()exten => s-CHANUNAVAIL,1, Goto (to-prov-trunk,1)exten => s-BUSY,1, Goto (to-prov-trunk,1)exten => s-.,1, Hangup ()

Ну и теперь непосредственно сам макрос:

Скрытый текст [macro-seeknumber-odbc]exten => s,1, NoOp (== tel nomber == ${ARG1:0:3} == ${ARG1:3:9} ==)same => n, Set (result=${ODBC_MOBILE ()})same => n, Set (operator=${CUT (result,\,,1)})same => n, Set (region=${CUT (result,\,,2)})same => n, NoOp (name of region = ${region})same => n, NoOp (name of operator = ${operator})same => n, Set (TRUNK_MOB=prov-trunk)same => n, ExecIf ($[»${operator}»=«beeline»&»${region}»=«home»]? Set (TRUNK_MOB=beeline))same => n, ExecIf ($[»${operator}»=«mts»&»${region}»=«home»]? Set (TRUNK_MOB=mts))same => n, ExecIf ($[»${operator}»=«megafon»&»${region}»=«home»]? Set (TRUNK_MOB=megafon))

В итоге получилось, на мой взгляд, неплохое унифицированное решение для распределения вызовов на нужные направления по номеру телефона. В дополнение скажу, что его можно автоматизировать еще больше, написав bash-скрипт на загрузку и обработку свежих баз с сайта РосСвязи и добавив его в crontab для ежемесячного апгрейда, но это будем считать домашним заданием ;)

© Habrahabr.ru