[OpenSIPS-Users] [OpenSIPS] sample script that works with cdrtools, freeradius, nat, drouting
Jinsong Hu
jinsong_hu at hotmail.com
Mon May 11 08:31:21 CEST 2009
Hi, There:
It looks ag-projects is maintaining the cdrtools, media proxy. but I
searched around and didn't find anywhere there is a script that supports all
the needed feature: cdrtools, mediaproxy, nat_traversal, and drouting. so
now I'm trying to be a little brave and post my script that includes all
above. this script doesn't handle instance message, but only voice calls.
can any body spot problems with this script ?
The goal of the script is to let locally registered user to use gateway to
make outgoing call, and receive incoming call. the numbering plan is for US.
free radius should have good authenticaing and accounting for different
messages, and some special DID are mapped to several numbers and routed to
asterisk. Hopefully this script will be useful for a general VOIP carrier.
I try to paste the document to be comment. Hopefully, by going through
this exercise, we can get a good starting script for people to use as a
model starting script.
Jimmy
#######################################################################
#
# $Id: opensips.cfg,v 1.13 2009/05/11 06:06:00 jinsong Exp $
#
# OpenSIPS basic configuration script
# by Anca Vamanu <anca at voice-system.ro>
#
# Please refer to the Core CookBook at
http://www.opensips.org/dokuwiki/doku.php
# for a explanation of possible statements, functions and parameters.
#
#INVITE :Invites a user to a call
#ACK : Acknowledgement is used to facilitate reliable message exchange for
INVITEs.
#BYE :Terminates a connection between users
#CANCEL :Terminates a request, or search, for a user. It is used if a client
sends an INVITE and then changes its decision to call the recipient.
#OPTIONS :Solicits information about a server's capabilities.
#REGISTER :Registers a user's current location
#INFO :Used for mid-session signaling
#MESSAGE : IMS send message
#SUBSCRIBE : IMS presence subscribe message
#PUBLISH: IMS publish message
#1xx: Provisional -- request received, continuing to process the request;
#2xx: Success -- the action was successfully received, understood, and
accepted;
#3xx: Redirection -- further action needs to be taken in order to complete
the request;
#4xx: Client Error -- the request contains bad syntax or cannot be fulfilled
at this server;
#5xx: Server Error -- the server failed to fulfill an apparently valid
request;
#6xx: Global Failure -- the request cannot be fulfilled at any server.
#This function sets the value of the flag given as parameter to 1 (true).
The value of the parameter must be an integer between 0 and 31.
####### Global Parameters #########
debug=3
log_stderror=no
log_facility=LOG_LOCAL0
fork=yes
children=4
/* uncomment the following lines to enable debugging */
#debug=6
#fork=no
#log_stderror=yes
/* uncomment the next line to disable TCP (default on) */
#disable_tcp=yes
/* uncomment the next line to enable the auto temporary blacklisting of
not available destinations (default disabled) */
#disable_dns_blacklist=no
/* uncomment the next line to enable IPv6 lookup after IPv4 dns
lookup failures (default disabled) */
#dns_try_ipv6=yes
#disable dns to scale
dns=no
rev_dns=no
/* uncomment the next line to disable the auto discovery of local aliases
based on revers DNS on IPs (default on) */
#auto_aliases=no
alias=machinename.somedomain.com
/* uncomment the following lines to enable TLS support (default off) */
#disable_tls = no
#listen = tls:your_IP:5061
#tls_verify_server = 1
#tls_verify_client = 1
#tls_require_client_certificate = 0
#tls_method = TLSv1
#tls_certificate = "/etc/opensips/tls/user/user-cert.pem"
#tls_private_key = "/etc/opensips/tls/user/user-privkey.pem"
#tls_ca_list = "/etc/opensips/tls/user/user-calist.pem"
port=5060
/* uncomment and configure the following line if you want opensips to
bind on a specific interface/port/proto (default bind on all available)
*/
#listen=udp:192.168.1.2:5060
####### Modules Section ########
#set module path
mpath="/usr/lib/opensips/modules/"
/* uncomment next line for MySQL DB support */
loadmodule "db_mysql.so"
loadmodule "mi_fifo.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 "uri_db.so"
loadmodule "uri.so"
loadmodule "xlog.so"
loadmodule "acc.so"
/* uncomment next lines for MySQL based authentication support
NOTE: a DB (like db_mysql) module must be also loaded */
loadmodule "auth.so"
loadmodule "auth_db.so"
/* uncomment next line for aliases support
NOTE: a DB (like db_mysql) module must be also loaded */
loadmodule "alias_db.so"
/* uncomment next line for multi-domain support
NOTE: a DB (like db_mysql) module must be also loaded
NOTE: be sure and enable multi-domain support in all used modules
(see "multi-module params" section ) */
loadmodule "domain.so"
/* uncomment the next two lines for presence server support
NOTE: a DB (like db_mysql) module must be also loaded */
#loadmodule "presence.so"
#loadmodule "presence_xml.so"
#loadmodule "carrierroute.so"
loadmodule "drouting.so"
loadmodule "siptrace.so"
loadmodule "pike.so"
loadmodule "ratelimit.so"
loadmodule "auth_radius.so"
loadmodule "avp_radius.so"
#loadmodule "uri_radius.so"
loadmodule "group_radius.so"
loadmodule "dispatcher.so"
loadmodule "dialog.so"
loadmodule "mediaproxy.so"
#loadmodule "nathelper.so"
loadmodule "nat_traversal.so"
# ----------------- setting module-specific parameters ---------------
# ----- mi_fifo params -----
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
# ----- rr params -----
# add value to ;lr param to cope with most of the UAs
modparam("rr", "enable_full_lr", 1)
# ----- rr params -----
#modparam("registrar", "method_filtering", 1)
/* uncomment the next line to disable parallel forking via location */
# modparam("registrar", "append_branches", 0)
/* uncomment the next line not to allow more than 10 contacts per AOR */
modparam("registrar", "max_contacts", 10)
# ----- uri_db params -----
/* by default we disable the DB support in the module as we do not need it
in this configuration */
modparam("uri_db", "use_uri_table", 0)
modparam("uri_db", "db_url", "")
# ----- acc params -----
/* what sepcial events should be accounted ? */
#modparam("acc", "early_media", 1)
#modparam("acc", "report_ack", 1)
#modparam("acc", "report_cancels", 1)
/* by default ww do not adjust the direct of the sequential requests.
if you enable this parameter, be sure the enable "append_fromtag"
in "rr" module */
#modparam("acc", "detect_direction", 0)
/* uncomment the following lines to enable DB accounting also */
#modparam("acc", "db_flag", 1)
#modparam("acc", "db_missed_flag", 1)
# global acc parameters
modparam("acc", "failed_transaction_flag", 1)
modparam("acc", "report_cancels", 0)
modparam("acc", "report_ack", 0)
modparam("acc", "early_media", 0)
modparam("acc", "log_level", 1)
modparam("acc", "log_flag", 1)
modparam("acc", "log_missed_flag", 1)
modparam("acc|auth_radius|group_radius|avp_radius", "radius_config",
"/etc//radiusclient-ng/radiusclient.conf")
modparam("acc", "radius_flag", 1)
modparam("acc", "radius_missed_flag", 1)
modparam("acc", "radius_extra", "User-Name=$Au; \
Calling-Station-Id=$from; \
Called-Station-Id=$to; \
Sip-Translated-Request-URI=$ru; \
Sip-RPid=$avp(s:rpid); \
Source-IP=$avp(s:source_ip); \
Source-Port=$avp(s:source_port); \
SIP-Proxy-IP=$avp(s:sip_proxy_ip); \
Canonical-URI=$avp(s:can_uri); \
Billing-Party=$avp(s:billing_party);
\
Divert-Reason=$avp(s:divert_reason);
\
User-Agent=$hdr(user-agent); \
Contact=$hdr(contact); \
Event=$hdr(event); \
ENUM-TLD=$avp(s:enum_tld)")
modparam("siptrace", "db_url",
"mysql://opensips:password@localhost/opensips")
modparam("siptrace", "traced_user_avp", "$avp(s:traced_user)")
modparam("siptrace", "trace_on", 1)
modparam("siptrace", "trace_flag", 2)
# ----- usrloc params -----
#0 - This disables database completely. Only memory will be used. Contacts
will not survive restart.
#1 - Write-Through scheme. All changes to usrloc are immediately reflected
in database too.
#2 - Write-Back scheme. All changes are made to memory and database
synchronization is done in the timer.
#3 - DB-Only scheme. No memory
#modparam("usrloc", "db_mode", 0)
/* uncomment the following lines if you want to enable DB persistency
for location entries */
modparam("usrloc", "db_mode", 2)
modparam("usrloc", "db_url",
"mysql://opensips:password@localhost/opensips")
# ----- auth_db params -----
/* uncomment the following lines if you want to enable the DB based
authentication */
modparam("auth_db", "calculate_ha1", yes)
modparam("auth_db", "password_column", "password")
modparam("auth_db", "db_url",
"mysql://opensips:password@localhost/opensips")
modparam("auth_db", "load_credentials", "")
# ----- alias_db params -----
/* uncomment the following lines if you want to enable the DB based
aliases */
#modparam("alias_db", "db_url",
# "mysql://opensips:password@localhost/opensips")
# ----- domain params -----
/* uncomment the following lines to enable multi-domain detection
support */
#modparam("domain", "db_url",
# "mysql://opensips:password@localhost/opensips")
#modparam("domain", "db_mode", 1) # Use caching
# ----- multi-module params -----
/* uncomment the following line if you want to enable multi-domain support
in the modules (dafault off) */
#modparam("alias_db|auth_db|usrloc|uri_db", "use_domain", 1)
# ----- presence params -----
/* uncomment the following lines if you want to enable presence */
#modparam("presence|presence_xml", "db_url",
# "mysql://opensips:password@localhost/opensips")
#modparam("presence_xml", "force_active", 1)
#modparam("presence", "server_address", "sip:192.168.1.2:5060")
# ----- carrierroute params -----
/* uncomment the following line if you want to enable carrierroute support
in the modules (dafault off) */
#modparam("carrierroute", "db_url",
"mysql://opensips:password@localhost/opensips")
#modparam("carrierroute", "config_source", "db")
modparam("drouting", "db_url",
"mysql://opensips:password@localhost/opensips")
modparam("drouting", "ruri_avp", '$avp(dr_ruri)')
modparam("drouting", "config_source", "db")
modparam("dispatcher", "db_url",
"mysql://opensips:password@localhost/opensips")
modparam("nat_traversal", "keepalive_state_file",
"/var/run/opensips/keepalive_state")
modparam("mediaproxy","mediaproxy_socket",
"/var/run/mediaproxy/dispatcher.sock")
modparam("mediaproxy", "mediaproxy_timeout", 500)
modparam("mediaproxy", "signaling_ip_avp", "$avp(s:nat_ip)")
modparam("mediaproxy", "media_relay_avp", "$avp(s:media_relay)")
####### Routing Logic ########
# main request routing logic
route{
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;
};
#pike_check_req Process the source IP of the current request and returns
false if the IP was exceeding the blocking limit
if (!pike_check_req()) { exit; };
#rate limit
if (is_method("INVITE|REGISTER|SUBSCRIBE")) {
#rl_check The method will return an error code if the limit
for the matched algorithm is reached.
if (!rl_check()) {
#For the current request, a "503 - Server
Unavailable" reply is sent back.
rl_drop();
exit;
};
};
#we only handle voice, not any other things.
if (is_method("PUBLISH|MESSAGE|SUBSCRIBE"))
{
sl_send_reply("503", "Service Unavailable");
exit;
}
#1 - tests if client has a private IP address (as defined by RFC1918)
#in the Contact field of the SIP message.
#2 - tests if client has contacted OpenSIPS from an address that is
different
#from the one in the Via field. Both the IP and port are compared by this
test.
#4 - tests if client has a private IP address (as defined by RFC1918) in
the top
#Via field of the SIP message.
if (client_nat_test("3")) {
fix_contact();
if ((method=="REGISTER" ||(method=="INVITE" && !has_totag())) )
{
nat_keepalive();
}
}
# check if user is suspended
if(is_method("REGISTER|INVITE|OPTIONS"))
{
if (radius_is_user_in("From", "suspended")) {
sl_send_reply("403", "Forbidden - suspended");
exit;
};
};
#use engate media proxy to fully control the media
if (method==INVITE && (client_nat_test("3") ||
search("^Route:.*;nat=yes")) ) {
engage_media_proxy();
}
#has_totag() indicate in-dialog request. all in dialog request are
processed in this block
if (has_totag()) {
# sequential request withing a dialog should
# take the path determined by record-routing
#loose_route() is used to route is usually used to
#route in-dialog requests (like ACK, BYE, reINVITE).
#The loose_route function analyzes the Route: headers in the requests.
#If there is no Route: header, the function returns FALSE and routing
#should be done with normal lookup functions. If a Route: header is found,
#the function returns 1 and behaves as described in section 16.12 of RFC
3261.
#There is only one exception: If the request is out-of-dialog (no to-tag)
#and there is only one Route: header indicating the local proxy,
#then the Route: header is removed and the function returns FALSE.
if (loose_route()) {
# mark routing logic in request
append_hf("P-hint: rr-enforced\r\n");
#some provider GW (incorrectly) updated the contact info of an
established dialog when it got an ACK. fix it
if(is_method("ACK")) {
if(is_present_hf("Contact")) remove_hf("Contact");
};
route(1);
} else {
if ( is_method("ACK") ) {
#t_check_trans Returns true if the current request is associated to a
transaction
if ( t_check_trans() ) {
# non loose-route, but stateful ACK; must be an ACK after a 487 or e.g.
#404 from upstream server
t_relay();
exit;
} else {
# ACK without matching transaction ... ignore and discard.\n");
xlog("L_WARN", "[$mi] discarding ACK\n");
exit;
}
}
#in-dialog , not loose route, and not ACK, we discard.
sl_send_reply("404","Not here");
}
#regardless of whatever happens, all in-dialog has to end here.
exit;
}
t_check_trans();
# CANCEL processing.
if (is_method("CANCEL"))
{
setflag(1); # do accounting ...
setflag(2); # sip trace
#Returns true if the current request is associated to a transaction.
#CANCEL request - true if the cancelled INVITE transaction exists
if (t_check_trans())
t_relay();
exit;
}
#following must be initial requests, or register.
#command must be INVITE, ACK, BYE, OPTIONS, REGISTER
# authenticate if from local subscriber (uncomment to enable auth)
#if (!(method=="REGISTER") && from_uri==myself)
#{
# if (!proxy_authorize("", "subscriber")) {
# proxy_challenge("", "0");
# exit;
# }
# if (!check_from()) {
# sl_send_reply("403","Forbidden auth ID");
# exit;
# }
# consume_credentials();
# # caller authenticated
#}
# record routing
if (!is_method("REGISTER"))
record_route();
# account only INVITEs
if (is_method("INVITE")) {
setflag(1); # do accounting
setflag(2); # sip trace
}
#fraud detection block. we don't allow outsiders who are not authenticated
to use our gateway.
if (!uri==myself)
/* replace with following line if multi-domain support is used */
##if (!is_uri_host_local())
{
# check if user is allowed to do voip calls to other domains
if(is_method("INVITE")) {
#for caller calling outside, but not in our voip group, we
forbid.
#this is needed to fight against fraud.
if (!radius_is_user_in("From", "voip")) {
sl_send_reply("403", "Forbidden VoIP");
exit;
};
};
# mark routing logic in request
append_hf("P-hint: outbound\r\n");
route(1);
exit;
}
#process REGISTER to local server.
if (is_method("REGISTER"))
{
# authenticate the REGISTER requests (uncomment to enable auth)
if (!radius_www_authorize("machinename.somedomain.com")
&& !www_authorize("machinename.somedomain.com", "subscriber"))
{
www_challenge("machinename.somedomain.com", "0");
exit;
}
##
##if (!check_to())
##{
## sl_send_reply("403","Forbidden auth ID");
## exit;
##}
if (client_nat_test("3")) fix_nated_register();
if (!save("location"))
sl_reply_error();
exit;
}
#process INVITE, ACK, BYE, OPTIONS for local server in the following
blocks
if ($rU==NULL) {
# request with no Username in RURI
sl_send_reply("484","Address Incomplete");
exit;
}
#lookup(domain) extracts username from Request-URI and tries to find
#all contacts for the username in usrloc
#return codes
#1 - contacts found and returned.
#-1 - no contact found.
#-2 - contacts found, but method not supported.
#-3 - internal error during processing
#if (!lookup("location")) {
# switch ($retcode) {
# case -1:
# case -3:
# t_newtran();
# t_reply("404", "Not Found");
# exit;
# case -2:
# sl_send_reply("405", "Method Not Allowed");
# exit;
# }
#}
#process INVITE, ACK, BYE, OPTIONS for local server in the following
blocks
#It is critical to save $avp(s:can_uri) after the Proxy has performed
#all possible lookups except DNS.
#The Canonical-URI will be used for rating the session.
$avp(s:can_uri) = $ru;
route(1);
}
#route[1] process INVITE, ACK, BYE, OPTIONS
route[1] {
if (is_method("INVITE") ) {
# normalization to e164
# http://en.wikipedia.org/wiki/NANP
if($ruri.user =~ "^\+[1-9][0-9]+")
{
strip(1);
}
# if($ruri.user =~ "^00[1-9][0-9]+") {
# strip(2);
# }
# if($ruri.user =~ "^0[1-9][0-9]+") {
# strip(1);
# #prefix("49");
# }
#in the US , dialing 1NPANXXXXXX 11 digits
if($ruri.user =~ "^1[1-9][0-9]{9}") {
#do nothing
}
#in the US, dialing NPANXXXXXX 10 digits
else if($ruri.user =~ "^[1-9][0-9]{9}") {
prefix("1");
}
#in the US, dialing NXXXXXX 7 digits local number.
else if($ruri.user =~ "^[1-9][0-9]{6}") {
$rU = $(fU{s.substr, 0, 4}) + $rU;
}
# 411 Local Directory Assistance
else if (uri=~"^sip:411 at .*") {
# the uri with a default call to "local directory
assistance".
$rU = $(fU{s.substr, 0, 4}) + "5551212";
}
# 611 Local Directory Assistance
else if (uri=~"^sip:611 at .*") {
# the uri with a default call to "local directory
assistance".
rewriteuri("sip:17775551212 at machinename.somedomain.com");
}
#911 is handled by E911 service provider
else {
sl_send_reply("404", "Invalid destination");
exit;
}
# Set the callerid for the user from an AVP
#if (avp_db_load("$from/username", "s:callerid")) {
# subst('/^From: (.*)>(.*)$/From: $avp(callerid)>\2/ig');
#};
}
if (is_method("INVITE|BYE")) {
setflag(1); # do accounting ...
setflag(2); # sip trace
#call the accounting functions explicitly in local_route for
#the internally generated BYEs as they do not trigger accounting by just
#setting the accounting flag
acc_rad_request("200 ok");
acc_log_request("200 ok");
}
#change access point phone number to inbound route for asterisk
alias_db_lookup("dbaliases");
#forward asterisk inbound route with dispatcher as load balancer
if (is_method("INVITE") && $ruri =~ "^sip:17771000101 at .*" ) {
#dispatcher select from set 1 using algorithm 0.
if(!ds_select_dst("1", "0"))
{
sl_send_reply("404", "no destination");
}
if(!t_relay()) sl_reply_error();
exit;
};
#special relaying to asterisk finished, now we process regular
requests.
#INVITE, ACK, BYE, OPTIONS to locally registered user.
if (lookup("location"))
{
if (is_method("INVITE")) {
t_on_branch("1");
t_on_reply("1");
t_on_failure("1");
}
if (!t_relay()) {
sl_reply_error();
};
exit;
}
#INVITE to outgoing gateway, route it out.
if (is_method("INVITE") ) {
#if (cr_route("default", "machinename.somedomain.com",
"$rU", "$rU", "call_id")) {
if (do_routing()) {
t_on_failure("11");
if (!t_relay()) {
sl_reply_error();
};
exit;
};
exit;
};
if (!t_relay()) {
sl_reply_error();
};
exit;
}
branch_route[1] {
xlog("new branch at $ru\n");
}
onreply_route[1] {
xlog("incoming reply\n");
}
failure_route[1] {
if (t_was_cancelled()) {
exit;
}
# uncomment the following lines if you want to block client
# redirect based on 3xx replies.
##if (t_check_status("3[0-9][0-9]")) {
##t_reply("404","Not found");
## exit;
##}
# uncomment the following lines if you want to redirect the failed
# calls to a different new destination
##if (t_check_status("486|408")) {
## sethostport("192.168.2.100:5060");
## append_branch();
## # do not set the missed call flag again
## t_relay();
##}
}
######################
# "default" failover #
######################
failure_route[11] {
xlog("L_INFO", "entering failure_route[11] for reply code
'$T_reply_code'\n");
if (t_was_cancelled()) {
exit;
}
if (t_check_status("408|5[0-9][0-9]")) {
#xlog("L_INFO","cr_tree_rewrite_uri(\"default\", \"1\");\n");
#if (cr_route("default", "machinename.somedomain.com", "$rU", "$rU",
"call_id")) {
if (do_routing()) {
t_on_failure("12");
append_branch();
route(1);
};
exit;
} else if (t_check_status("3[0-9][0-9]")) {
t_reply("404","Not found");
exit;
}
}
failure_route[12] {
xlog("L_INFO", "entering failure_route[12] for reply code
'$T_reply_code'\n");
if (t_was_cancelled()) {
exit;
}
if (t_check_status("408|5[0-9][0-9]")) {
xlog("L_INFO","cr_tree_rewrite_uri(\"default\", \"2\");\n");
#if (cr_route("default", "machinename.somedomain.com", "$rU", "$rU",
"call_id")) {
if (do_routing()) {
t_on_failure("13");
append_branch();
route(1);
};
exit;
} else if (t_check_status("3[0-9][0-9]")) {
t_reply("404","Not found");
exit;
}
}
failure_route[13] {
xlog("L_INFO", "entering failure_route[13] for reply code
'$T_reply_code'\n");
if (t_was_cancelled()) {
exit;
}
}
More information about the Users
mailing list