http://wiki.disorder.sk/howto:sip_pbx_-_opensips_and_asterisk_configuration
http://www.slideshare.net/saghul/opensips-workshop
This document explains how to install and configure Asterisk 1.6 PBX and OpenSIPS (OpenSER or Kamailio will probably work too).
OpenSIPS will handle registrations and SIP/SIMPLE IM and presence. Asterisk will do everything else. This will not scale well but OpenSIPS configuration can be modified to not route all calls through Asterisk but this will make some services unavailable.
Configuration in this document implements:
9)777, 778)600, 601)*21, *61)*5)Latter three services requires routing through Asterisk (forwarding and redial could be implemented within OpenSIPS).
We'll be using one host with IP address 10.0.0.105. OpenSIPS will run listen on port 5060 and Asterisk on 50600. Don't forget to alter your firewall.
Tested with these SIP clients (both can be really weird sometimes):
You can test only with Ekiga on the same host. Start gconf-editor and change SIP port (e.g. 5059).
On Debian you can use official Asterisk 1.6 packages and OpenSIPS binaries from repository in Links section. Tested on amd64architecture.
Note: We will use MySQL database. Uncomment DBENGINE=MYSQL in /etc/opensips/opensipsctlrc.
Warning: This howto was reconstructed from installation notes. Please improvise if some error pops up :)
Initialise the OpenSIPS database with opensipsdbctl create command:
# opensipsdbctl create MySQL password for root: INFO: test server charset INFO: creating database opensips ... INFO: Core OpenSIPS tables succesfully created. Install presence related tables? (y/n): y INFO: creating presence tables into opensips ... INFO: Presence tables succesfully created. Install tables for imc cpl siptrace domainpolicy carrierroute userblacklist? (y/n): n
Create some users (default database password is opensipsrw):
opensipsctl add 10001@10.0.0.105 1111 opensipsctl add 10002@10.0.0.105 1111
We need to alter OpenSIPS tables for Asterisk integration:
mysql -p -u root
USE opensips; -- vmail_password from 8 to 10 in asterisk 1.6 ALTER TABLE subscriber ADD COLUMN `vmail_password` varchar(10) NOT NULL DEFAULT '1'; ALTER TABLE subscriber ADD COLUMN `first_name` varchar(25) NOT NULL DEFAULT ''; ALTER TABLE subscriber ADD COLUMN `last_name` varchar(45) NOT NULL DEFAULT ''; ALTER TABLE subscriber ADD COLUMN `email_address` varchar(50) NOT NULL DEFAULT ''; ALTER TABLE subscriber ADD COLUMN `datetime_created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00';
Now create database for Asterisk:
CREATE DATABASE asterisk; GRANT ALL PRIVILEGES ON asterisk.* TO 'asterisk' IDENTIFIED BY 'heslo';
Now create the tables (actually we will not be using the voicemessages table):
USE asterisk; -- create table to store the voicemail massages CREATE TABLE `voicemessages` ( `id` int(11) NOT NULL AUTO_INCREMENT, `msgnum` int(11) NOT NULL DEFAULT '0', `dir` varchar(80) DEFAULT '', `context` varchar(80) DEFAULT '', `macrocontext` varchar(80) DEFAULT '', `callerid` varchar(40) DEFAULT '', `origtime` varchar(40) DEFAULT '', `duration` varchar(20) DEFAULT '', `mailboxuser` varchar(80) DEFAULT '', `mailboxcontext` varchar(80) DEFAULT '', `recording` longblob, PRIMARY KEY (`id`), KEY `dir` (`dir`) ) ENGINE=MyISAM; -- create the asterisk users tables as a view over the OpenSIPS subscriber table CREATE VIEW `asterisk`.`sipusers` AS SELECT `opensips`.`subscriber`.`username` AS `name`, `opensips`.`subscriber`.`username` AS `defaultuser`, _latin1'friend' AS `type`, NULL AS `secret`, `opensips`.`subscriber`.`domain` AS `host`, concat(`opensips`.`subscriber`.`rpid`,_latin1' ',_latin1'<',`opensips`.`subscriber`.`username`,_latin1'>') AS `callerid`, _latin1'default' AS `context`, `opensips`.`subscriber`.`username` AS `mailbox`, _latin1'yes' AS `nat`, _latin1'no' AS `qualify`, `opensips`.`subscriber`.`username` AS `fromuser`, NULL AS `authuser`, `opensips`.`subscriber`.`domain` AS `fromdomain`, NULL AS `insecure`, _latin1'no' AS `canreinvite`, NULL AS `disallow`, NULL AS `allow`, NULL AS `restrictcid`, `opensips`.`subscriber`.`domain` AS `defaultip`, `opensips`.`subscriber`.`domain` AS `ipaddr`, _latin1'05060' AS `port`, NULL AS `regseconds` FROM `opensips`.`subscriber`; -- create the asterisk voceimail users table as a view over the OpenSIPS subscriber table CREATE VIEW `asterisk`.`vmusers` AS SELECT concat(`opensips`.`subscriber`.`username`,`opensips`.`subscriber`.`domain`) AS `uniqueid`, `opensips`.`subscriber`.`username` AS `customer_id`, _latin1'default' AS `context`, `opensips`.`subscriber`.`username` AS `mailbox`, `opensips`.`subscriber`.`vmail_password` AS `password`, concat(`opensips`.`subscriber`.`first_name`,_latin1' ',`opensips`.`subscriber`.`last_name`) AS `fullname`, `opensips`.`subscriber`.`email_address` AS `email`, NULL AS `pager`, `opensips`.`subscriber`.`datetime_created` AS `stamp` FROM `opensips`.`subscriber`; -- create the asterisk voicemail aliases table as a view over the OpenSIPS dbaliases table CREATE VIEW `asterisk`.`vmaliases` AS SELECT `opensips`.`dbaliases`.`alias_username` AS `alias`, _latin1'default' AS `context`, `opensips`.`dbaliases`.`username` AS `mailbox` FROM `opensips`.`dbaliases`; -- create the meetme database (conference bridge) CREATE TABLE rooms ( confno varchar(80) NOT NULL DEFAULT 0, pin varchar(20), adminpin varchar(20), members int NOT NULL DEFAULT 0, PRIMARY KEY (confno) );
You can restrict access by setting pin:
INSERT INTO rooms(confno,pin,adminpin) VALUES(99999,1111,1234); INSERT INTO rooms(confno,adminpin) VALUES(99998,1234);
MeetMe conference service will need dahdi.ko and dahdi_dummy.ko modules:
modprobe dahdi_dummy
Debian way for creating these modules is:
apt-get install dahdi-source m-a a-i dahdi-linux
Install odbcinst and libmyodbc.
/etc/odbcinst.ini:
[MySQL] Description = MySQL driver Driver = /usr/lib/odbc/libmyodbc.so Setup = /usr/lib/odbc/libodbcmyS.so CPTimeout = CPReuse = UsageCount = 1
/etc/odbc.ini
[MySQL-asterisk] Description = MySQL Asterisk database Trace = Off TraceFile = stderr Driver = MySQL SERVER = localhost USER = asterisk PASSWORD = heslo PORT = 3306 DATABASE = asterisk
/etc/asterisk/res_odbc.conf:
[asterisk] enabled => yes dsn => MySQL-asterisk username => asterisk password => heslo pre-connect => yes
/etc/asterisk/extconfig.conf:
[settings] sipusers => odbc,asterisk,sipusers sippeers => odbc,asterisk,sipusers voicemail => odbc,asterisk,vmusers meetme => odbc,asterisk,rooms
Registrations, presence and messages go to OpenSIPS server. Extensions prefixed with ”**” are routed directly (with voicemail fallback). Everything else goes to Asterisk.
Services at Asterisk:
1000 – demo, along with other somewhat functional extensions444 – echo test600, 601 – time, date announcements777 – global voicemail login (access any mailbox)778 – personal voicemail login (can be altered to bypass auth)VMR_… – voicemail recording9XXXX – conference bridge1XXXX – phones (only these are stored for redial)*5 – redial*21*… / #21# – set/reset unconditional forwarding*61*… / #61# – set/reset busy forwarding#
# $Id$
#
# ----------- global configuration parameters ------------------------
debug=3 # debug level (cmd line: -dddddddddd)
fork=yes # daemonize
#fork=no
log_stderror=no # (cmd line: -E)
#log_stderror=yes
check_via=no # (cmd. line: -v)
dns=no # (cmd. line: -r)
rev_dns=no # (cmd. line: -R)
children=4
listen=udp:10.0.0.105:5060
#listen=tcp:10.0.0.105:5060
#
# ------------------ module loading ----------------------------------
# Uncomment this if you want to use SQL database
mpath="/usr/lib/opensips/modules"
loadmodule "db_mysql.so"
#loadmodule "nathelper.so"
loadmodule "xlog.so"
loadmodule "sl.so"
loadmodule "tm.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "signaling.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "avpops.so"
loadmodule "auth.so"
loadmodule "auth_db.so"
loadmodule "group.so"
loadmodule "uri.so"
loadmodule "presence.so"
loadmodule "presence_xml.so"
loadmodule "presence_mwi.so"
# -- presence params --
modparam("presence|presence_xml", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
modparam("presence_xml", "force_active", 1)
modparam("presence", "server_address", "sip:10.0.0.105:5060" )
modparam("presence", "max_expires_publish", 100)
#modparam("presence", "max_expires_subscribe", 140)
modparam("presence", "expires_offset", 5)
modparam("presence", "fallback2db", 1)
loadmodule "mi_fifo.so"
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
# ----------------- setting module-specific parameters ---------------
modparam("usrloc|auth_db|avpops|group",
"db_url", "mysql://opensips:opensipsrw@localhost/opensips")
# -- usrloc params --
# persistent storage
modparam("usrloc", "db_mode", 2)
# -- auth params --
# Uncomment if you are using auth module
#
modparam("auth_db", "calculate_ha1", yes)
#
# If you set "calculate_ha1" parameter to yes (which true in this config),
# uncomment also the following parameter)
#
modparam("auth_db", "password_column", "password")
# -- rr params --
# add value to ;lr param to make some broken UAs happy
modparam("rr", "enable_full_lr", 1)
modparam("avpops", "avp_table", "usr_preferences")
# ------------------------- request routing logic -------------------
# main routing logic
route{
# initial sanity checks -- messages with
# max_forwards==0, or excessively long requests
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too Many Hops");
exit;
};
if (msg:len >= 2048 ) {
sl_send_reply("513", "Message too big");
exit;
};
#initial requests
# CANCEL processing
if (is_method("CANCEL")) {
if (t_check_trans())
t_relay();
exit;
}
t_check_trans();
# we record-route all messages -- to make sure that
# subsequent messages will go through our proxy; that's
# particularly good if upstream and downstream entities
# use different transport protocol
if (!method=="REGISTER")
record_route();
# subsequent messages withing a dialog should take the
# path determined by record-routing
if (loose_route()) {
# mark routing logic in request
append_hf("P-hint: rr-enforced\r\n");
route(1);
};
if (!uri==myself) {
# mark routing logic in request
append_hf("P-hint: outbound\r\n");
# if you have some interdomain connections via TLS
#if(uri=~"@tls_domain1.net") {
# t_relay("tls:domain1.net");
# exit;
#} else if(uri=~"@tls_domain2.net") {
# t_relay("tls:domain2.net");
# exit;
#}
route(1);
};
# if the request is for other domain use UsrLoc
# (in case, it does not work, use the following command
# with proper names and addresses in it)
if (uri==myself) {
# presence handling
if( is_method("PUBLISH|SUBSCRIBE"))
route(2);
if (method=="REGISTER") {
# Uncomment this if you want to use digest authentication
if (!www_authorize("opensips.org", "subscriber")) {
www_challenge("opensips.org", "0");
exit;
};
save("location");
exit;
};
if (is_method("INVITE")) {
setflag(1); # do accounting
if (!uri=~"sip:\*\*") {
route(3);
} else {
strip(2);
}
}
# conference
if(is_method("INVITE") && $rU=~"^9[0-9]{4}$") {
xlog("conference\n");
route(3);
}
# special services (3-4 digits)
if(is_method("INVITE") && $rU=~"^[0-9]{3,4}$") {
xlog("other service\n");
route(3);
}
# native SIP destinations are handled using our USRLOC DB
if (!lookup("location")) {
#sl_send_reply("404", "Not Found");
# voicemail
xlog("native fallback to voicemail\n");
prefix("VMR_");
rewritehostport("10.0.0.105:50600");
route(1);
exit;
};
append_hf("P-hint: usrloc applied\r\n");
};
# when routing via usrloc, log the missed calls also
setflag(2);
# arm a failure route in order to catch failed calls
# targeting local subscribers; if we fail to deliver
# the call to the user, we send the call to voicemail
t_on_failure("1");
route(1);
}
route[1] {
# send it out now; use stateful forwarding as it works reliably
# even for UDP2TCP
if (!t_relay()) {
sl_reply_error();
};
exit;
}
# presence handling route
route[2]
{
# absorb retransmissions
if (! t_newtran())
{
sl_reply_error();
exit;
};
#handle presence requests
if(is_method("PUBLISH"))
{
if($hdr(Sender)!= NULL) {
handle_publish("$hdr(Sender)");
} else {
handle_publish();
#t_release();
}
} else if(is_method("SUBSCRIBE")) {
handle_subscribe();
#t_release();
};
exit;
}
# asterisk services
route[3] {
xlog("forwarding to asterisk\n");
# to asterisk
rewritehostport("10.0.0.105:50600");
if (!t_relay()) {
sl_reply_error();
};
exit;
}
failure_route[1] {
if (t_was_cancelled()) {
exit;
}
# if the failure code is "408 - timeout" or "486 - busy",
# forward the calls to voicemail recording
if (t_check_status("486|408")) {
xlog("L_INFO", "failure_route - call forward to Voice Mail - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n");
rewritehostport("10.0.0.105:50600");
prefix("VMR_");
t_relay();
exit;
}
}
[globals]
CONSOLE=Console/dsp ; Console interface for demo
;;; apps context
[default]
include => local
[apps]
include => demo
exten => 444,1,Answer()
;exten => 444,n,SendText(Here is the place where you write the text for your advertisement)
;exten => 444,n,NoOp(===== ${SENDTEXTSTATUS} =====)
exten => 444,n,Wait(1)
exten => 444,n,Echo
; conference
exten => _9XXXX,1,Ringing
exten => _9XXXX,2,Wait(1)
exten => _9XXXX,3,MeetMe(${EXTEN})
exten => _9XXXX,4,Hangup
; voicemail
exten => 777,1,Ringing
exten => 777,n,Wait(1)
exten => 777,n,Answer
exten => 777,n,Wait(1)
exten => 777,n,VoiceMailMain(@default)
exten => 777,n,Hangup
exten => 778,1,Ringing
exten => 778,n,Wait(1)
exten => 778,n,Answer
exten => 778,n,Wait(1)
exten => 778,n,NoOp(=== Mailbox: ${CALLERID(all)} ===)
; add ,s to auth automatically
exten => 778,n,VoiceMailMain(${CALLERID(num)}@default)
exten => 778,n,Hangup
; announcement: time
exten => 600,1,Ringing
exten => 600,2,Wait(1)
;exten => 600,3,SayUnixTime(,Europe/Bratislava,HMp)
exten => 600,3,SayUnixTime(,Europe/Bratislava,HM)
exten => 600,4,Hangup
; announcement:date
exten => 601,1,Ringing
exten => 601,2,SayUnixTime(,Europe/Bratislava,ABdY)
exten => 601,3,Hangup
; voicemail
exten => _VMR_.,1,NoOp(===== EXTENSION --> ${EXTEN} =====)
exten => _VMR_.,n,Ringing
exten => _VMR_.,n,Wait(1)
exten => _VMR_.,n,Answer
exten => _VMR_.,n,Wait(1)
exten => _VMR_.,n,Voicemail(${EXTEN:4}@default,u)
exten => _VMR_.,n,Hangup
; redial
exten = *5,1,Set(temp=${DB(RepeatDial/${CALLERID(num)})})
exten = *5,2,Dial(SIP/**${temp}@10.0.0.105)
;exten = *5,3,NoOp(= ${temp} =)
; Unconditional Call Forward
exten => _*21*X.,1,Set(DB(CFIM/${CALLERID(num)})=${EXTEN:4})
exten => _*21*X.,2,Hangup
exten => _*21*X.,3,NoOp(=HERE=)
exten => #21#,1,NoOp(${DB_DELETE(CFIM/${CALLERID(NUM)})})
exten => #21#,2,Hangup
; Call Forward on Busy or Unavailable
exten => _*61*X.,1,Set(DB(CFBS/${CALLERID(num)})=${EXTEN:4})
exten => _*61*X.,2,Hangup
exten => #61#,1,NoOp(${DB_DELETE(CFBS/${CALLERID(NUM)})})
exten => #61#,2,Hangup
;;; incoming calls context
[incoming]
;exten => 3221234567,1,Dial(SIP/10001,30)
;exten => 3221234567,n,Dial(SIP/10002,30)
;exten => 3221234567,n,Dial(SIP/10000,30)
;;; outgoing calls context
; local calls only
[local]
include => apps
; dial and mailbox
;exten => _1XXXX,1,Dial(SIP/${EXTEN},5)
;exten => _1XXXX,n,NoOp(===== DIAL STATUS --> ${DIALSTATUS} =====)
;exten => _1XXXX,n,VoiceMail(${EXTEN}@default,u)
;exten => _1XXXX,n,Hangup()
; mailbox only
;exten => _1XXXX,1,GotoIf(${MAILBOX_EXISTS(${EXTEN}@default)}?3:2)
;exten => _1XXXX,2,Hangup()
;; mailbox exists, continue
;exten => _1XXXX,3,Ringing
;exten => _1XXXX,n,Wait(1)
;exten => _1XXXX,n,Answer
;exten => _1XXXX,n,Wait(1)
;exten => _1XXXX,n,VoiceMail(${EXTEN}@default,u)
;exten => _1XXXX,n,Hangup()
;; DIAL
; save dialed number (redial)
exten => _1XXXX,1,Set(DB(RepeatDial/${CALLERID(num)})=${EXTEN})
; unconditional forward
exten => _1XXXX,n,Set(temp=${DB(CFIM/${CALLERID(num)})})
exten => _1XXXX,n,GotoIf(${temp}?cfim:nocfim)
exten => _1XXXX,n(cfim),Dial(SIP/**${temp}@10.0.0.105) ; Unconditional forward
exten => _1XXXX,n,Goto(hup)
exten => _1XXXX,n(nocfim),NoOp
; dial number with delay
exten => _1XXXX,n,Dial(SIP/**${EXTEN}@10.0.0.105, 5)
; busy forward
exten => _1XXXX,n,Set(temp=${DB(CFBS/${CALLERID(num)})})
exten => _1XXXX,n,GotoIf(${temp}?cfbs:nocfbs)
exten => _1XXXX,n(cfbs),Dial(SIP/**${temp}@10.0.0.105) ; Forward on busy or unavailable
exten => _1XXXX,n,Goto(hup)
; exten => _1XXXX,n(nocfbs),Busy
exten => _1XXXX,n(nocfbs),NoOp
; fallback to vmail instead of busy
; voicemail
exten => _1XXXX,n,NoOp(===== DIAL STATUS --> ${DIALSTATUS} =====)
exten => _1XXXX,n,GotoIf(${MAILBOX_EXISTS(${EXTEN}@default)}?vm:hup)
;; mailbox exists, continue
exten => _1XXXX,n(vm),Ringing
exten => _1XXXX,n,Wait(1)
exten => _1XXXX,n,Answer
exten => _1XXXX,n,Wait(1)
exten => _1XXXX,n,VoiceMail(${EXTEN}@default,u)
exten => _1XXXX,n(hup),Hangup()
Software:
Server configuration:
Services: