How to easily and easily teach your Asterisk to call through the right operator
Greetings,% username%!
Today I would like to share a solution that allows you to teach your Asterisk to automatically route calls to the appropriate directions without resorting to cumbersome regular expressions.
Practice shows that more and more companies are starting to think about their communication costs. The bulk of the costs in this case are calls to mobile numbers. From here the task was born to process outgoing calls and route through the line where the call will be made free of charge or at the lowest cost.
In my case, it was necessary to route calls to the home region of the Big Three operators through the corresponding SIM cards inserted into the GSM gateway. Instead of the selected operators, you can use any other directions by analogy with the subject.
OpenVox VoxStack VS-GW1202-4G acted as a gateway, into which the SIM cards of the operators you know were previously inserted and 3 trunks to Asterisk were configured.
Of course, there are a great many ways to solve the problem, but I would like to dwell on the solution that I considered optimal: automatic reconciliation of numbers from the MySQL database and further redirection to the necessary line. The implementation is quite simple, although in some places it may seem ugly.
You can break all the work into several stages:
First you need to create a separate database (optional):
Route access in our situation is better not to give, because this is not necessary, and the security hole in the form of a root login and MySQL password in open form is not needed in the configuration file. Therefore, we give access to an arbitrary user only to our database (in my case, the user: "mobile", password: "heavypass")
Create a table:
And now you can go directly to the filling. Everyone is free to choose a method for himself, I will focus on the following:
We pump out the list of codes of mobile operators from the Rossvyaz website, convert the encoding and upload it to our database. The path to the file is optional.
The database is full, but in order to avoid encoding problems we’ll make small changes: I need to select the Big Three numbers for calls in the home region, then I only change them, mark the region as home , and change the names to beeline , mts and megafon, respectively:
The database is ready to use.
We will connect Asterisk with the database using ODBC, as I think this is a unified solution. First you need to rebuild Asterisk with ODBC support. The quality of the OS in my case is Ubuntu Server 12.04.
In the directory with the sources of Asterisk we do:
We check that the res_odbc module is available and enabled, in the functions we need to check the availability of func_odbc . Then save and execute:
We look where drivers for ODBC lie
We look where the configuration files for ODBC lie
Rules /etc/odbcinst.ini , add to the record file:
We describe the connection to the database in the file /etc/odbc.ini
And now we are directly introducing Asterisk to MySQL using ODBC. Making changes to /etc/asterisk/res_odbc.ini
and write the module load in /etc/asterisk/modules.conf
Now you can restart Asterisk itself, well, or just load the res_odbc.so module . Then in the CLI we execute the command:
At this point, the second stage can be considered completed, we created and filled in the database and made friends with Asterisk.
Well, now you can start directly writing a dialplan for processing outgoing calls.
Each dialed number is processed by a macro, as a result of which a line will be determined through which a call will be made. The dialed number will act as an argument passed to the macro. The first character (8) will be cut off even before entering the macro, after which in the SQL query we will select the further first 3 characters (123) for comparison with the operator code and the remaining 7 characters (4567890) to determine whether it belongs to a particular numbering capacity.
All database operations are registered in the func_odbc.conf configuration file. Here we invent and compose functions for interacting with the database, and then use their result in the dialplan. Each section describes its function, the name of each section is usually filled in upper case.
In my case, it is necessary to determine the number belonging to the region and the operator and transfer the result for further processing by the macro.
Add the entry in /etc/asterisk/func_odbc.conf
It is worth remembering that the result of the query will be 2 values, separated by a comma: the operator serving this number, as well as the service region.
Well, now you can directly write the number processing rules themselves. In the example, I will omit unnecessary rules, I will leave only what is relevant. All changes are made in the /etc/asterisk/extensions.conf file .
Create a context for outgoing calls.
We create contexts for calls to mobile providers, as well as for the default provider. In the configuration of each trunk, I limited the number of simultaneous sessions to one and added call forwarding to the trunk by default in case of busy or unavailable lines.
Well, now the macro itself:
As a result, in my opinion, it turned out to be a good unified solution for distributing calls to the desired directions by phone number. In addition, I can say that it can be automated even more by writing a bash script to download and process fresh databases from the RosSvyaz website and adding it to crontab for a monthly upgrade, but this will be considered homework;)
Today I would like to share a solution that allows you to teach your Asterisk to automatically route calls to the appropriate directions without resorting to cumbersome regular expressions.
Practice shows that more and more companies are starting to think about their communication costs. The bulk of the costs in this case are calls to mobile numbers. From here the task was born to process outgoing calls and route through the line where the call will be made free of charge or at the lowest cost.
In my case, it was necessary to route calls to the home region of the Big Three operators through the corresponding SIM cards inserted into the GSM gateway. Instead of the selected operators, you can use any other directions by analogy with the subject.
OpenVox VoxStack VS-GW1202-4G acted as a gateway, into which the SIM cards of the operators you know were previously inserted and 3 trunks to Asterisk were configured.
Of course, there are a great many ways to solve the problem, but I would like to dwell on the solution that I considered optimal: automatic reconciliation of numbers from the MySQL database and further redirection to the necessary line. The implementation is quite simple, although in some places it may seem ugly.
You can break all the work into several stages:
- Create and populate a database
- Prepare Asterisk for working with the database
- Write a dialplan to handle outgoing calls
Base preparation
First you need to create a separate database (optional):
CREATE DATABASE telcodes;
Route access in our situation is better not to give, because this is not necessary, and the security hole in the form of a root login and MySQL password in open form is not needed in the configuration file. Therefore, we give access to an arbitrary user only to our database (in my case, the user: "mobile", password: "heavypass")
CREATE DATABASE telcodes;
GRANT ALL ON telcodes.* TO mobile@localhost IDENTIFIED BY 'mobile';
FLUSH PRIVILEGES;
SET PASSWORD FOR 'mobile'@'localhost'=PASSWORD('heavypass');
Create a table:
Hidden text
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;
And now you can go directly to the filling. Everyone is free to choose a method for himself, I will focus on the following:
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"
We pump out the list of codes of mobile operators from the Rossvyaz website, convert the encoding and upload it to our database. The path to the file is optional.
The database is full, but in order to avoid encoding problems we’ll make small changes: I need to select the Big Three numbers for calls in the home region, then I only change them, mark the region as home , and change the names to beeline , mts and megafon, respectively:
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 = 'Москва и Московская область';
The database is ready to use.
Preparing asterisk
We will connect Asterisk with the database using ODBC, as I think this is a unified solution. First you need to rebuild Asterisk with ODBC support. The quality of the OS in my case is Ubuntu Server 12.04.
We put the packages unixodbc, unixodbc-dev and libmyodbc
apt-get install unixodbc unixodbc-dev libmyodbc
In the directory with the sources of Asterisk we do:
./configure && make menuselect
We check that the res_odbc module is available and enabled, in the functions we need to check the availability of func_odbc . Then save and execute:
make && make install
We look where drivers for ODBC lie
# dpkg -L libmyodbc
Hidden text
/.
/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
We look where the configuration files for ODBC lie
#odbcinst -j
Hidden text
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
Rules /etc/odbcinst.ini , add to the record file:
Hidden text
[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 =
We describe the connection to the database in the file /etc/odbc.ini
Hidden text
[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
And now we are directly introducing Asterisk to MySQL using ODBC. Making changes to /etc/asterisk/res_odbc.ini
Hidden text
[telcodes]
enabled => yes
dsn => telcodes-mysql
username => mobile
password => heavypass
pooling => no
limit => 1
pre-connect => yes
and write the module load in /etc/asterisk/modules.conf
preload => res_odbc.so
Now you can restart Asterisk itself, well, or just load the res_odbc.so module . Then in the CLI we execute the command:
odbc show all
Hidden text
aster * CLI> odbc show all
ODBC DSN Settings
- Name: telcodes
DSN: telcodes-mysql
Last connection attempt: 1970-01-01 03:00:00
Pooled: No
Connected: Yes
ODBC DSN Settings
- Name: telcodes
DSN: telcodes-mysql
Last connection attempt: 1970-01-01 03:00:00
Pooled: No
Connected: Yes
At this point, the second stage can be considered completed, we created and filled in the database and made friends with Asterisk.
Dialplan writing
Well, now you can start directly writing a dialplan for processing outgoing calls.
Each dialed number is processed by a macro, as a result of which a line will be determined through which a call will be made. The dialed number will act as an argument passed to the macro. The first character (8) will be cut off even before entering the macro, after which in the SQL query we will select the further first 3 characters (123) for comparison with the operator code and the remaining 7 characters (4567890) to determine whether it belongs to a particular numbering capacity.
All database operations are registered in the func_odbc.conf configuration file. Here we invent and compose functions for interacting with the database, and then use their result in the dialplan. Each section describes its function, the name of each section is usually filled in upper case.
In my case, it is necessary to determine the number belonging to the region and the operator and transfer the result for further processing by the macro.
Add the entry in /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}
It is worth remembering that the result of the query will be 2 values, separated by a comma: the operator serving this number, as well as the service region.
Well, now you can directly write the number processing rules themselves. In the example, I will omit unnecessary rules, I will leave only what is relevant. All changes are made in the /etc/asterisk/extensions.conf file .
Create a context for outgoing calls.
Hidden text
[from-users]
exten => _8XXXXX., 1, NoOp (Call from $ {CALLERID (num)} to $ {EXTEN})
same => n, Set (TARGETNO = $ {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
exten => _8XXXXX., 1, NoOp (Call from $ {CALLERID (num)} to $ {EXTEN})
same => n, Set (TARGETNO = $ {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
We create contexts for calls to mobile providers, as well as for the default provider. In the configuration of each trunk, I limited the number of simultaneous sessions to one and added call forwarding to the trunk by default in case of busy or unavailable lines.
Hidden text
[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, $ {TARGETNO}, 1)
exten => s-BUSY, 1, Goto (to-prov-trunk, $ {TARGETNO}, 1)
exten => s -., 1, Hangup ()
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, $ {TARGETNO}, 1)
exten => s-BUSY, 1, Goto (to-prov-trunk, $ {TARGETNO}, 1)
exten => s -., 1, Hangup ()
Well, now the macro itself:
Hidden text
[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))
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))
As a result, in my opinion, it turned out to be a good unified solution for distributing calls to the desired directions by phone number. In addition, I can say that it can be automated even more by writing a bash script to download and process fresh databases from the RosSvyaz website and adding it to crontab for a monthly upgrade, but this will be considered homework;)