100% found this document useful (1 vote)
378 views11 pages

Kamailio A2billing Asterisk

This document is part 3 of 3 discussing the configuration of OpenSIPS to work with A2Billing. It provides the full OpenSIPS configuration file, loading required modules, database connection details, and module parameters. The configuration allows SIP authentication of A2Billing customers via IP or username/password in OpenSIPS, which then passes calls to A2Billing/Asterisk for call completion.

Uploaded by

vbugaian
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
378 views11 pages

Kamailio A2billing Asterisk

This document is part 3 of 3 discussing the configuration of OpenSIPS to work with A2Billing. It provides the full OpenSIPS configuration file, loading required modules, database connection details, and module parameters. The configuration allows SIP authentication of A2Billing customers via IP or username/password in OpenSIPS, which then passes calls to A2Billing/Asterisk for call completion.

Uploaded by

vbugaian
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
You are on page 1/ 11

A2Billing and OpenSIPS – Part 1

26 January 2013MattA2Billing, OpenSIPS


This is part 1 of a 3 part post discussing A2Billing and OpenSIPS. A2Billing is a billing platform for
Asterisk, and OpenSIPS is an Open Source SIP Server. In this first part I’m going to talk about what
OpenSIPS is and why you may want to use it. In the second part I’ll talk about some prerequisites for
the setup I’m going to show, and in the third part will be the OpenSIPS config.
A2Billing works perfectly well without OpenSIPS, so why would you want to use them together? Well,
with OpenSIPS sitting in front of A2Billing/Asterisk and handling all of the SIP connections it can
provide the following benefits –
• load balance across multiple Asterisk/A2Billing servers
• failover – take an Asterisk server out of the cluster if it should fail
• limit SIP connections so that only the OpenSIPS server talks to Asterisk/A2Billing over SIP
• register all of your SIP customers in a single place – the OpenSIPS server (the config I show is
not going to cover SIP registrations)
• OpenSIPS has much better logging of SIP connections (than Asterisk) so we can use fail2ban
more efficiently to block attacks
There are probably many more benefits than those listed above. OpenSIPS has lots of modules that
provide flexibility to handle the SIP connections exactly as you need.
In the config that follows I am going to show how to do SIP termination. SIP clients authenticate to
OpenSIPS using either IP or USER/SECRET authentication and then calls are passed to
A2Billing/Asterisk for completion. This example does not cover SIP registrations or incoming DID
numbers.
OpenSIPS will sit between the A2Billing SIP customers and the A2Billing/Asterisk server. All
customer SIP connections will be to the OpenSIPS server, which will then pass these on to
Asterisk/A2Billing once authenticated. A2Billing/Asterisk will talk to the call provider directly (not via
OpenSIPS). So the setup looks something like this –

A2Billing SIP Customer --> OpenSIPS --> A2Billing/Asterisk --> Call provider
--> A2Billing/Asterisk --> Call provider
--> A2Billing/Asterisk --> Call provider

This diagram above shows calls going to 3 different A2Billing/Asterisk servers. In the example config
there is just one set up, but it will be obvious how to add more.
Also, in OpenSIPS there are 2 different ‘load balancing’ modules. There is one called ‘dispatcher’
which in unintelligent and just send the calls to a group of A2Billing/Asterisk servers. And there is a
module called ‘load-balancer’ which knows the state of each A2Billing/Asterisk server and evenly
distributes the load across them. For simplicity in this example I will be using the ‘dispatcher’ module.
This guide assumes that you have –
• a working A2Billing/Asterisk server in place
• a working OpenSIPS v1.8 server in place
• created a database called ‘opensips’ (as per the OpenSIPS install instructions) that is on MySQL
running on the A2BIlling/Asterisk server
We are going to have both the A2Billing and OpenSIPS databases running on the A2Billing server so
that we can integrate the two
In part 2 I’ll discuss some of the prerequisites and the database setup.

A2Billing and OpenSIPS – Part 2


26 January 2013MattA2Billing, OpenSIPS
In this part of the guide I’m going to look at some of the set up required for the example config to
work.
We are going to enable IP and USER/SECRET authentication for our A2Billing SIP customer calls. To
do that we are going to create a couple of MySQL VIEWS in the ‘opensips’ database that point to
tables in the ‘a2billing’ database. This means we can create our A2Billing SIP users as normal, and they
will then become valid users in OpenSIPS.
Part 2 and Part 3 of the guide assume the following –
• OpenSIPS server IP = 1.1.1.1
• A2Billing server IP = 2.2.2.2
• MySQL server IP = 2.2.2.2 (same server as A2Billing)
• domain name for our calls = mya2billingcalls.com
On the A2Billing/Asterisk server
So now we create our VIEWS in the database. We are going to use the ‘address’ table for IP
authentications and the ‘subscriber’ table for USER/SECRET authentications.
Here we create the ‘address’ VIEW –
DROP TABLE opensips.address

CREATE VIEW opensips.address AS


SELECT id AS id,
CAST(1 AS DECIMAL) AS grp,
host AS ip,
CAST(32 AS DECIMAL) AS mask,
cast(port as DECIMAL) AS port,
'UDP' AS proto,
'' AS pattern,
accountcode AS context_info
from a2billing.cc_sip_buddies
WHERE host != 'dynamic';
So for any A2Billing SIP customer where the IP address is not set to ‘dynamic’ we are going to create
an OpenSIPS user. We are also going to store the A2Billing customers Account Code in a field called
context_info. This is not strictly what that field is designed for but it makes it easy for us to access the
customers account code from OpenSIPS
Now we create the ‘subscriber’ VIEW –
DROP TABLE opensips.subscriber

CREATE VIEW opensips.subscriber AS


SELECT id AS id,
username AS username,
'openhold.com' AS domain,
secret AS password,
'' AS email_address,
md5(concat(username,':','mya2billingcalls.com',':',secret)) AS ha1,
md5(concat(username,'@','mya2billingcalls.com',':','mya2billingcalls.com',':',secret)) AS ha1b,
accountcode AS rpid
from a2billing.cc_sip_buddies
where username != '';
You will want to change ‘mya2billingcalls.com’ to the domain name you are going to use. We are going
to store the customers Account Code in a field called ‘rpid’. Again this is not really what it’s designed
for, but it makes it easy to access from OpenSIPS. You can see the ‘where’ clause restricts this to
A2Billing customers that do not have a blank username field (they might have this if you were doing IP
authentication)
Next we need to modify the Asterisk dial plan a little to tell it to pass all calls coming form the
OpenSIPS server to the a2billing.php script.
To do that we are first going to create an entry in sip.conf with the sip details of the OpenSIPS server –
[opensips]
host=1.1.1.1
type=peer
context=a2billing-opensips-sip
So any calls coming from the OpenSIPS server will get passed to the ‘a2billing-opensips-sip’ context.
Now we create that context in extensions.conf –
[a2billing-opensips-sip]
exten => _X.,1,Set(CDR(accountcode)=${SIP_HEADER(P-Accountcode)})
exten => _X.,n,DeadAGI(a2billing.php,1)
exten => _X.,n,Hangup
So we set the A2Billing customer account code (this is going to be passed to us by OpenSIPS) and then
we run the a2billing.php script using agi-conf1
On the A2Billing customer PBX
I’m going to assume that our A2Billing SIP customer is using an Asterisk server to connect to us. They
could set up their trunk in 2 different ways. One using IP authentication like this –
[mya2billingcalls]
host=1.1.1.1
type=peer
For IP authentication we must have entered the customers PBX IP address in the HOST field in the
customers A2Billing SIP account
Or they could use username/password authentication like this –
[mya2billingcalls]
host=1.1.1.1
type=peer
username=XXXXX
secret=XXXXX
fromdomain=mya2billingcalls.com
The ‘fromdomain’ setting must be set to the same one we used when creating our MySQL views.
That’s the Asterisk and MySQL setup done, it part 3 we’ll look at the actual OpenSIPS config file.

A2Billing and OpenSIPS – Part 3


26 January 2013MattA2Billing, OpenSIPS
This post has the actual config of OpenSIPS described in part 1 and part 2. Some of this config will not
make sense unless you read those parts.
First a warning … many, many people want to use your call credit!! Make sure that your systems
are secure. If only the OpenSIPS server needs to talk to your A2Billing/Asterisk servers over SIP
then use a fierwall to block other connections.
In the configuration below OpenSIPS does not handle the Audio/RTP traffic, this is passed directly to
the Asterisk/A2Billing server.
The code below is the whole opensips.cfg file, just broken up with some description. All indentation
has been removed, apologies if this sometimes makes it difficult to read.
First some global settings, including the IP address of the OpenSIPS server –
listen=udp:1.1.1.1:5060 # CUSTOMIZE ME
debug=1
log_stderror=no
log_facility=LOG_LOCAL6
fork=yes
children=4
dns_try_ipv6=no
auto_aliases=no
disable_tcp=yes
disable_tls=yes
server_signature=no
next we load the modules that are required –
mpath="/usr/local/lib/opensips/modules/"
loadmodule "signaling.so"
loadmodule "sl.so"
loadmodule "tm.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "sipmsgops.so"
loadmodule "mi_fifo.so"
loadmodule "uri.so"
loadmodule "db_mysql.so"
loadmodule "avpops.so"
loadmodule "acc.so"
loadmodule "dispatcher.so"
loadmodule "permissions.so"
loadmodule "dialog.so"
loadmodule "siptrace.so"
loadmodule "auth.so"
loadmodule "auth_db.so"
now we set the database URL for the modules that are going to use our MySQL database. This database
is on the A2Billing server –
modparam("acc|dispatcher|permissions|dialog|siptrace|auth_db|
avpops","db_url","mysql://username:[email protected]/opensips")
now we set some other module options –
modparam("tm", "fr_inv_timer", 30)
modparam("tm", "restart_fr_on_each_reply", 0)
modparam("tm", "onreply_avp_mode", 1)
modparam("rr", "append_fromtag", 0)
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)
modparam("uri", "use_uri_table", 0)
modparam("acc", "db_flag", 1)
modparam("acc", "early_media", 0)
modparam("acc", "report_cancels", 0)
modparam("acc", "detect_direction", 0)
modparam("acc", "failed_transaction_flag", 3)
modparam("acc", "log_flag", 1)
modparam("acc", "log_missed_flag", 2)
modparam("dispatcher", "ds_ping_method", "OPTIONS")
modparam("dispatcher", "ds_probing_mode", 0)
modparam("dispatcher", "flags", 2)
modparam("dispatcher", "force_dst", 1)
modparam("dispatcher", "ds_ping_interval", 30)
modparam("dialog", "db_mode", 1)
modparam("dialog", "dlg_match_mode", 2)
modparam("siptrace", "trace_on", 0)
modparam("siptrace", "trace_flag", 22)
modparam("auth_db", "load_credentials", "")
modparam("auth_db", "skip_version_check", 1)
and now to the actual routing. The first block has some general default code that rejects some packets
and also immediately relays sip dialogs that have already been established –
route{
if (!mf_process_maxfwd_header("10") && $retcode==-1) {
sl_send_reply("483","Too Many Hops");
exit;
}
if (has_totag()) {
if (loose_route()) {
if (is_method("BYE")) {
setflag(1); # do accounting ...
setflag(3); # ... even if the transaction fails
} else if (is_method("INVITE")) {
record_route();
}
route(RELAY);
} else {
if ( is_method("ACK") ) {
if ( t_check_trans() ) {
t_relay();
exit;
} else {
exit;
}
}
sl_send_reply("404","Not here");
}
exit;
}
next more generic checks. Relay CANCEL messages and reject others with incomplete URIs –
if (is_method("CANCEL")) {
if (t_check_trans())
t_relay();
exit;
} else if (!is_method("INVITE")) {
send_reply("405","Method Not Allowed");
xlog("$rm FAILED: $si / $ct / $fu\n");
exit;
}
if ($rU==NULL) {
sl_send_reply("484","Address Incomplete");
exit;
}
next drop some more invalid packets –
if (loose_route()) {
xlog("L_ERR","Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");
if (!is_method("ACK"))
sl_send_reply("403","Preload Route denied");
exit;
}
next we are going to create a route header on the packet and switch on some accounting –
record_route();
setflag(1);
now we are going to choose the Asterisk server that the call is passed to. This uses the ds_select_dst
command which is part of the dispatcher module. The available Asterisk servers are selected from the
‘dispatcher’ table in the MysQL database. The ‘1’ relates to the ‘setid’ field in the ‘dispatcher’ table,
and the ‘destination’ field should be in the format ‘sip:2.2.2.2:5060’ –
if ( !ds_select_dst("1","0") ) {
send_reply("500","No Destination available");
xlog("$rm FAILED: NO DESTINATION: $si / $tu / $ru\n");
exit;
}
t_on_failure("GW_FAILOVER");
Now the good stuff! This is where we do IP authentication, and route the call if it is valid. We use the
‘check_source_address’ command which is part of the permissions module. This is going to look in the
MySQL database for a matching IP address. The “1” is a group ID that we hard coded when we set up
the VIEW in MySQL. If the IP address matches then the account code is returned to us (because we
stored it in the context_info field in MySQL), and we set this to the variable “$avp(accountcode”. We
then set this variable in a header on the SIP INVITE packet and send it to A2Billing. In part 2 I showed
how to extract this SIP header and set the account code in the Asterisk dialplan, so that A2Billing
knows which customer to charge for the call –
if (check_source_address("1","$avp(accountcode)")) {
xlog("L_INFO", "IP $rm DIALLED: $si / $ru / Accountcode: $avp(accountcode) ");
remove_hf("P-Accountcode");
append_hf("P-Accountcode: $avp(accountcode)\r\n");
route(RELAY);
};
next, if IP authentication above failed we want to challenge the caller (the IP address sending the SIP
INVITE) for a Username and Secret. “subscriber” is the name of the VIEW in MySQL where we are
storing the customer credentials. These are picked up straight from the A2BIlling customers SIP
account –
if (!proxy_authorize("", "subscriber")) {
$var(debug) = proxy_authorize("", "subscriber");
xlog("Not Proxy Authorize: $var(debug)");
proxy_challenge("", "0");
exit;
}
now, if the customer passed the authorisation above, we want to send the call to our Asterisk/A2billing
server. First though we want to set the Account Code so that A2Billing knows which customer to
charge the call to. This is similar to what we did for IP authentication, but we need to run a separate
command to retrieve the account code from the ‘rpid’ field in the ‘subscriber’ table where we stored it.
$au is the authorized username –
avp_db_query("select rpid from subscriber where username='$au'","$avp(accountcode)");
remove_hf("P-Accountcode");
append_hf("P-Accountcode: $avp(accountcode)\r\n");
xlog("L_INFO", "AUTH $rm DIALLED: $si / $ru / Accountcode: $avp(accountcode) ");
consume_credentials();
route(RELAY);

}
Finally, we called route(RELAY) several times in the script above, and we define that here, and a
couple of other bits, we forward the packets with t_relay –
route[RELAY] {
if (!t_relay()) {
sl_reply_error();
};
exit;
}

failure_route[GW_FAILOVER] {
if (t_was_cancelled()) {
exit;
}
if (t_check_status("(408)|([56][0-9][0-9])")) {
xlog("Failed trunk $rd/$du detected \n");
if ( ds_next_dst() ) {
t_on_failure("GW_FAILOVER");
t_relay();
exit;
}
send_reply("500","All GW are down");
}
}
And that’s the end of the config file!
The code above is definitely not designed to be totally cut and paste. You are going to have to check
some documentation and have a fair understanding of what’s going on and how the call is being
handled. I would also suggest learning the xlog command and some of the variables available. This you
can use at various points in the script to log some output and see why you calls might be failing.
If anyone experienced with OpenSIPS (or Kamailio) can offer any suggestions for how to improve the
config I’d be interested to hear them. Also, of anyone with Kamailio experience could let me know
how different that config would look in that I’d be interested to hear that too. Thanks!

A2billing with OpenSIPS and DID calls


31 January 2013MattA2Billing, OpenSIPS
This post follows on from these posts about using A2Billing and OpenSIPS together
– http://sysadminman.net/blog/2013/integrating-opensips-with-asterisk-and-a2billing-4843
In those posts we looked at customers outgoing calls from a2billing. This time we’re going to look at
one idea for setting up DID numbers. This is only one suggestion, there are others.
Below we are going to get OpenSIPS to look at the called number (which in this case will be incoming
from our DID provider) and if it matches a DID number set up in A2Billing then we will send the call
to the A2Billing/Asterisk server for processing. We will add a custom SIP header to the call before
sending it to the A2Billing/Asterisk server so that Asterisk knows this is a DID call, rather than an
outbound call for an A2Billing customer.
ON ASTERISK/A2BILLING
If you check in the previous posts you will see that we had this SIP PEER set up in Asterisk –
[opensips]
host=1.1.1.1
type=peer
context=a2billing-opensips-sip

So any call coming from our OpenSIPS server is sent to the context called a2billing-opensips-sip in
Asterisk. We will add a few lines to that context now (which is in extensions.conf) so that it looks like
this –
[a2billing-opensips-sip]
exten => _X.,1,Gotoif($["${SIP_HEADER(P-didnumber)}" != "yes"]?notdid)
exten => _X.,n,DeadAgi(a2billing.php,1,did)
exten => _X.,n,Hangup
exten => _X.,n(notdid),Set(CDR(accountcode)=${SIP_HEADER(P-Accountcode)})
exten => _X.,n,DeadAGI(a2billing.php,2)
exten => _X.,n,Hangup
So if the incoming SIP INVITE has a SIP HEADER called P-didnumber set to yes then we send the
call to a2billing.php as a DID call. We will set the P-didnumber header in OpenSIPS before we pass the
call to Asterisk. If the call doesn’t have that header set then we assume it’s a customer call and pass it to
A2Billing for processing.
IN THE MYSQL OPENSIPS DATABASE
If you check out the previous posts you will see we have our OpenSIPS and A2Billing database on the
same server. We are going to create a view in the ‘opensips’ database that looks at the ‘did’ table in the
A2Billing database –
mysql -p opensips
CREATE VIEW opensips.did_number AS
SELECT did AS did
from mya2billing.cc_did
So now when you create a DID number in A2Billing it becomes a valid DID number in OpenSIPS too.
ON THE OPENSIPS SERVER
Finally we do the OpenSIPS config in /etc/opensips/opensips.cfg. This is a modification to the setup
described in the previous post. These lines should go just before we check if the call is coming from the
IP address of an A2Billing customer –
avp_db_query("select did from did_number where did='$rU'","$avp(didnumber)");
if ($rU = $avp(didnumber)) {
remove_hf("P-didnumber");
append_hf("P-didnumber: yes\r\n");
route(RELAY);
};
So we’re doing a SQL query on the did_number table we created in MysQL, and if we find a matching
DID number we create a P-didnumber SIP header and set it to yes. Then we route the call to Asterisk
for processing.
Our DID provider will send the call to our OpenSIPS server, that checks that the call is coming to a
valid DID number on the database, and then sends it to A2Billing for processing.
Bear in mind that we will do this query for every SIP INVITE that hits the OpenSIPS server. I’d
definitely recommend getting used to the xlog command. That way if the above code doesn’t work as
expected you can insert some logging in the script to figure out what’s going on as the call is being
processed.
THE DID PROVIDER AND TESTING
Now if we want to set up the DID number 17062221111 and our OpenSIPS server IP is 1.1.1.1 we
would get our DID provider to send the call to the SIP URI – [email protected]
and in A2Billing we would create the DID number as normal –

You might also like