#!/usr/bin/php for editor
# $Id: openser.cfg 3284 2007-12-06 18:56:59Z bogdan_iancu $
#
# OpenSER basic configuration script
# by Anca Vamanu <anca@voice-system.ro>
#
# Please refer to the Core CookBook at http://www.openser.org/dokuwiki/doku.php
# for a explanation of possible statements, functions and parameters.
#
####### Global Parameters #########
debug=2
log_stderror=yes
#log_facility=LOG_LOCAL0
fork=no
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
/* uncomment the next line to disable the auto discovery of local aliases
based on revers DNS on IPs (default on) */
#auto_aliases=no
/* 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 = "/usr/etc/openser/tls/user/user-cert.pem"
#tls_private_key = "/usr/etc/openser/tls/user/user-privkey.pem"
#tls_ca_list = "/usr/etc/openser/tls/user/user-calist.pem"
#port=5060
/* uncomment and configure the following line if you want openser to
bind on a specific interface/port/proto (default bind on all available) */
listen=udp:74.10.216.27:5060
####### Modules Section ########
#set module path
mpath="/usr/lib/openser/modules"
/* uncomment next line for MySQL DB support */
loadmodule "mysql.so"
loadmodule "sl.so"
loadmodule "tm.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "mi_fifo.so"
loadmodule "uri_db.so"
loadmodule "uri.so"
loadmodule "xlog.so"
loadmodule "acc.so"
#Load unixodbc
#loadmodule "unixodbc.so"
#modparam("unixodbc", "use_escape_common", 1)
/* uncomment next lines for MySQL based authentication support
NOTE: a DB (like mysql) module must be also loaded */
loadmodule "auth.so"
loadmodule "auth_db.so"
/* uncomment next line for aliases support
NOTE: a DB (like mysql) module must be also loaded */
#loadmodule "alias_db.so"
/* uncomment next line for multi-domain support
NOTE: a DB (like mysql) module must be also loaded
NOTE: be sure and enable multi-domain support in all used modules
(see "multi-module params" section ) */
# needed by mediaproxy
loadmodule "domain.so"
/* uncomment the next two lines for presence server support
NOTE: a DB (like mysql) module must be also loaded */
#loadmodule "presence.so"
#loadmodule "presence_xml.so"
# ----------------- setting module-specific parameters ---------------
# ----- mi_fifo params -----
modparam("mi_fifo", "fifo_name", "/tmp/openser_fifo")
# ----- rr params -----
# add value to ;lr param to cope with most of the UAs
modparam("rr", "enable_full_lr", 1)
# do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)
# ----- 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)
# ----- 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)
/* account triggers (flags) */
modparam("acc", "failed_transaction_flag", 3)
modparam("acc", "log_flag", 1)
modparam("acc", "log_missed_flag", 2)
/* uncomment the following lines to enable DB accounting also */
modparam("acc", "db_flag", 1)
modparam("acc", "db_missed_flag", 2)
# ----- usrloc params -----
# See: http://www.openser.org/docs/modules/1.3.x/usrloc.html#AEN285
modparam("usrloc", "db_mode", 1)
# ----- auth_db params -----
/* uncomment the following lines if you want to enable the DB based
authentication */
modparam("auth_db", "calculate_ha1", 1)
modparam("auth_db", "password_column", "password")
#modparam("auth_db|usrloc", "db_url","mysql://open129ser:blahblah@localhost/openser")
modparam("usrloc|auth_db|domain|uri_db|speeddial|acc", "db_url","mysql://openser:blahblah@localhost/openser")
#modparam("auth_db", "load_credentials", "")
# ----- alias_db params -----
/* uncomment the following lines if you want to enable the DB based
aliases */
# ----- domain params -----
/* uncomment the following lines to enable multi-domain detection
support */
#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_xml", "force_active", 1)
#modparam("presence", "server_address", "sip:192.168.1.2:5060")
loadmodule "nathelper.so"
loadmodule "mediaproxy.so"
/*
loadmodule ".so"
loadmodule ".so"
loadmodule ".so"
loadmodule ".so"
loadmodule ".so"
loadmodule ".so"
loadmodule ".so"
*/
/* removed in 1.3.x: you can achive the same by either not defining "rtpproxy_sock" (default NULL) or setting it to empty string
modparam("nathelper", "rtpproxy_disable", 1)
*/
modparam("nathelper", "sipping_from", "sip:pinger@sip.reachme.com")
modparam("nathelper", "natping_interval", 20)
modparam("nathelper|registrar", "received_avp", "$avp(i:42)")
#modparam("nathelper", "rtpproxy_sock", "/var/run/rtpproxy.sock")
modparam("nathelper", "rtpproxy_sock", "")
modparam("nathelper", "rtpproxy_disable_tout", 9)
modparam("mediaproxy","natping_interval", 30)
#modparam("mediaproxy","mediaproxy_socket", "")
modparam("mediaproxy","mediaproxy_socket", "/var/run/mediaproxy.sock")
#modparam("mediaproxy","mediaproxy_socket", "/var/run/rtpproxy.sock")
modparam("usrloc", "db_mode", 2)
modparam("usrloc", "use_domain", 0)
modparam("registrar", "default_expires", 60)
modparam("registrar", "min_expires", 30)
/* removed in 1.2.x: nat_flag module parameter removed as now it is automatically imported from USRLOC module
modparam("registrar", "nat_flag", 6)
*/
modparam("usrloc","nat_bflag",6)
modparam("nathelper","sipping_bflag",6)
/* removed in 1.2.x: The module internally loads this option from the "USRLOC' module. This was done in order to simplify the configuration. '"
modparam("registrar", "use_domain", 0)
*/
modparam("rr", "enable_full_lr", 1)
modparam("auth", "rpid_suffix", ";party=calling;id-type=subscriber;screen=yes")
#modparam("auth", "rpid_avp", "s:rpid")
####### Routing Logic ########
# main request routing logic
/*
From: http://www.jeremy-mcnamara.com/2007/03/28/how-to-configure-openser-sip-registar-sip-proxy-and-far-end-nat-traversal-for-media/
Same goes for the modparams — The OpenSER team has documented these quite nicely. I will point out that we disable the rtpproxy, enable mediaproxy, enable write-through database mode for the user location, enable full loose routing support (to appease broken SIP User Agents), and setup a few ‘flags’ for logging, accounting and NAT.
Flags are a fun concept - Generally speaking a flag in OpenSER is like sticking a PostIT® Note on to specific SIP messages. Then later on in the ‘route’ processing we can check to see if specific notes have been left, making for much cleaner and simpler configuration.
Now we get into the "main" section of the configuration. In the OpenSER configuration everything is ran through a route block — meaning every SIP message gets processed thru a block of code named route (or you can think about it as a ‘main’ function, if you are a programmer)
*/
route {
#$ai - reference to URI in request's P-Asserted-Identity header (see RFC 3325)
#$ct - reference to body of contact header
#$mi - reference to SIP message id
#$di - reference to Diversion header URI
#$dp - reference to port of destination uri
#$ci - reference to body of call-id header
#$si - reference to IP source address of the message
#$sp - reference to the source port of the message
#$rm - reference to request's method
#$mi - reference to SIP message id
#$fu - reference to URI of 'From' header
#xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: $si:$sp $rm from_uri <$fu> to_uri <$tu> contact <$ct> orig_uri <$ou>\n");
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: $rm orig_uri <$ou>\n");
# Sanity Check
# ------------
# The first two directives in our route block ensure we don’t process a message that is too large (buffer overflow) or a message that we believe to be looping or otherwise confused.
if (msg:len > max_len)
{
sl_send_reply("513", "Message Overflow\n");
return;;
};
if (!mf_process_maxfwd_header("10"))
{
sl_send_reply("483", "Too Many Hops");
return;
};
/*
The ‘if’ directive here checks to see if the current SIP message (in OpenSER terms this is called a ‘method’) is an INVITE and calls a function to determine if the entity sending the current SIP message is behind NAT or not. The ‘3′ instructs the function to test using the first two test methods, which are detailed on the NATHELPER module. If both of those conditions are true, we call a function that appends a small bit of information to the SIP message, which we will utilize later on in the route and its related blocks.
Then If the method is not a REGISTER, we setup the necessary SIP headers to ensure that further SIP messages come back through our SIP Proxy, by calling the record_route() function.
*/
# Record Route and NAT Preset
# --------------------
if (method == "INVITE")
{
if (client_nat_test("3"))
{
if (client_nat_test("1")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched client_nat_test(1)\n"); }
if (client_nat_test("2")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched client_nat_test(2)\n"); }
if (client_nat_test("4")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched client_nat_test(4)\n"); }
#if (nat_uac_test("8")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched nat_uac_test(8)\n"); }
#if (nat_uac_test("16")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched nat_uac_test(16)\n"); }
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched client_nat_test(3)\n");
# Must add valid IP address below
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: record_route_preset(74.10.216.27:5060;nat=yes)\n");
record_route_preset("74.10.216.27:5060;nat=yes");
#xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: record_route(;nat=yes)\n");
#record_route(";nat=yes");
}
else if (method != "REGISTER")
{
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: record_route()\n");
record_route();
};
};
/*
Then a call get hung up, we need to detect this to ensure our RTP MediaProxy gets informed to stop relaying audio. We also set our first flag. In this case we inform the accounting module that we would like to account for Bye and Cancel methods - meaning we want ’stop’ Call Detail Records. Since we defined ‘1′ as our accounting flag, we simply pass a ‘1′ to the setflag() function — Pretty simple. The accounting module takes care of everything else for us.
*/
# Call Tear down
if (method=="BYE" || method=="CANCEL")
{
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: end_media_session()\n");
end_media_session();
};
/*
This is a rather complex and powerful group of directives. Without getting into the gory details of the SIP Protocol, this block determines if we are using the ‘loose routing’ concept. If so, we need to check for NAT (possibly setting flag 6) and informing the MediaProxy we will need its services. Most often than not we will be using the loose routing conventions versus strict routing, as defined in RFC3261.
We also call route(1) - In our configuration this is what we call the ‘default’ route or the terminating route. We will document the implementation and usage of route(1) here in a few minutes.
*/
# Loose Route
# -----------
if (loose_route())
{
# XXX: maybe use check_route_param() instead of search()?
if (has_totag() && (client_nat_test("3") || search("^Route:.*;nat=yes")) && (method == "INVITE" || method == "ACK"))
{
if (search("^Route:.*;nat=yes")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched search(^Route:.*;nat=yes)\n"); }
if (client_nat_test("1")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched client_nat_test1\n"); }
if (client_nat_test("2")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched client_nat_test2\n"); }
if (client_nat_test("3")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: matched client_nat_test3\n"); }
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: setbflag(6)\n");
setbflag(6);
#if (!search("^Content-Length:\ +0"))
if ($cl > 0)
{
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> main: use_media_proxy()\n");
use_media_proxy();
}
};
route(1);
return;
};
/*
If the ‘call’ is no longer for this particular proxy - send the message on its way (via the ‘default’ route). This is sort of another sanity check for our simple configuration. However in more complex situations, examining the URI and properly routing the messages will become very important. Unfortunately those concepts are beyond the scope of this document.
*/
# Call Type Processing
# --------------------
if (uri != myself)
{
route(1);
return;
};
/*
Finally we reach the end of our route block. We test each SIP method type and send them to an appropriate ‘route’ blocks, with the exceptions being NOTIFY and OPTIONS methods. These two methods typcially get used (by Asterisk and many SIP Phones) to either assist in keeping firewall/NAT paths open and/or determining if the proxy is still allve or not. Asterisk can also calculate (qualify=1000) how long it takes for the message to be responded to, giving a sort of internet path health status. By processing the NOTIFY and OPTIONS methods here, we can avoid 404 and/or Too Many Hops message, which in themselves are not necessarily a bad thing, but could lead to confusion.
*/
if (uri == myself)
{
if (method == "BYE")
{
route(4);
return;
}
else if (method == "CANCEL")
{
route(4);
return;
}
else if (method == "INVITE")
{
route(3);
return;
}
else if (method == "REGISTER")
{
route(2);
return;
}
else if (method == "NOTIFY")
{
sl_send_reply("200", "Understood");
return;
}
else if (method == "OPTIONS")
{
sl_send_reply("200", "Got it");
return;
}
};
route(1);
}
# Default Message Handling
# -----------------------
/*
Now we are down to the specific route blocks. As we discussed above, route[1] is the default message route. Here we ensure the SIP message gets properly responded to or sent on to its intended location, if the message is intended for another SIP Proxy.
We also check to see if we are processing an INVITE or ACK (to an invite) so we can inform the MediaProxy to end its session.
*/
route[1] {
t_on_reply("1");
if (!t_relay())
{
if (method=="INVITE" || method=="ACK")
{
xlog("L_INFO", "route1: <$ci> end_media_session()\n");
end_media_session();
};
sl_reply_error();
};
}
/*
route[2] is our REGISTER method processing block. This is where we examine the credentials and determine if we are going to allow the SIP UA to register or not.
Notice the call to consume_credentials(), this is a very useful function that removes the unnecessary SIP headers that can contain sensitive authentication details.
*/
# REGISTER Message Handling
# -------------------------
route[2] {
if (!search("^Contact:\ +\*") && client_nat_test("7"))
{
if (client_nat_test("1")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route2: matched client_nat_test1\n"); }
if (client_nat_test("2")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route2: matched client_nat_test2\n"); }
if (client_nat_test("4")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route2: matched client_nat_test4\n"); }
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route2: matched client_nat_test7\n");
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route2: setbflag(6)\n");
setbflag(6);
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route2: fix_natted_register()\n");
fix_nated_register();
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route2: force_rport()\n");
force_rport();
};
sl_send_reply("100", "Trying");
# XXX: how does this differ from proxy_authorize?
if (!www_authorize("","subscriber"))
{
www_challenge("","0");
return;
};
if (!check_to())
{
sl_send_reply("401", "Unauthorized");
return;
};
consume_credentials();
if (!save("location"))
{
sl_reply_error();
};
}
# INVITE Message Handling
# ----------------------------------
/*
route[3] is our INVITE (or call setup) processing occurs. I have set this configuration up to match on 3 and 4 digit ‘extensions’ to send them to our Asterisk PBX. Then match on 1+10 digits to send off to our VoIP Provider, making sure to set the accounting flag (1) so we can get proper ’start’ Call Detail Records.
*/
route[3] {
# Test for nat, perhaps fix headers
if (client_nat_test("3"))
{
if (client_nat_test("1")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: matched client_nat_test1\n"); }
if (client_nat_test("2")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: matched client_nat_test2\n"); }
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: matched client_nat_test3\n");
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: setbflag(7)\n");
setbflag(7);
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: force_rport()\n");
force_rport();
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: fix_contact()\n");
fix_contact();
};
# 3 and 4 digits URIs are sent to our Asterisk PBX
if ((uri =~ "^sip:[0-9]{2,}@.*"))
# if ((uri =~ "^sip:[0-9]{3}@.*") || (uri =~ "^sip:[0-9]{4}@.*"))
# if ((uri =~ "^sip:[^@]*") || (uri =~ "^sip:[0-9]{1,6}@.*"))
{
rewritehostport("74.10.216.26:5060");
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: use_media_proxy() and send to asterisk\n");
use_media_proxy();
route(1);
return;
};
# Any URI that begins with 1 plus 10 digits authenticate and pass on
# to our SIP Provider
/*
if (uri =~ "^sip:1[0-9]{10}@.*")
{
# Authenticate these calls
if (!proxy_authorize("","subscriber"))
{
proxy_challenge("","0");
return;
} else if (!check_from())
{
sl_send_reply("403", "Use From ID");
return;
};
consume_credentials();
rewritehostport("74.10.216.26:5060");
route(1);
return;
};
*/
if (!lookup("location"))
{
sl_send_reply("404", "User Not Found, Sorry");
return;
};
# If NAT is previously detected, proxy
if (isbflagset(6) || isbflagset(7))
{
if (isbflagset(6)) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: matched isbflagset(6)\n"); }
if (isbflagset(7)) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: matched isbflagset(7)\n"); }
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route3: use_media_proxy()\n");
use_media_proxy();
};
route(1);
}
# CANCEL and BYE Message Handling
# ----------------------------------
/*
route[4] is pretty straight forward - If its a CANCEL or BYE Message, ensure the message gets sent back to the proper location (ip:port). Then inform the MediaProxy to stop processing audio, since the call is ending.
*/
route[4] {
if (client_nat_test("3"))
{
if (client_nat_test("1")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route4: matched client_nat_test1\n"); }
if (client_nat_test("2")) { xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route4: matched client_nat_test2\n"); }
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route4: matched client_nat_test3\n");
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route4: setflag(7)\n");
setflag(7);
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route4: force_rport()\n");
force_rport();
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route4: fix_contact()\n");
fix_contact();
};
xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> route4: end_media_session()\n");
end_media_session();
route(1);
}
/*
The onreply_route[1] block gets called when we are expected to reply to a message (like a progress message or an OK). We ensure the MediaProxy gets used if NAT has been previously set or detected and the Contact SIP header is properly ‘fixed’ for NAT situations.
*/
onreply_route[1] {
if (status=~"(180)|(183)|2[0-9][0-9]")
{
xlog("L_WARN", "cs<$cs> si<$si:$sp> ci<$ci> onreply_route1: content_length<$cl>\n");
#if ((isbflagset(6) || isbflagset(7)) && !search("^Content-Length:\ +0"))
# if ((isbflagset(6) || isbflagset(7)) && $cl > 0)
if (isbflagset(6) || isbflagset(7))
{
if (isbflagset(6)) { xlog("L_WARN", "cs<$cs> si<$si:$sp> ci<$ci> onreply_route1: matched isbflagset(6)\n"); }
if (isbflagset(7)) { xlog("L_WARN", "cs<$cs> si<$si:$sp> ci<$ci> onreply_route1: matched isbflagset(7)\n"); }
xlog("L_WARN", "cs<$cs> si<$si:$sp> ci<$ci> onreply_route1: use_media_proxy()\n");
use_media_proxy();
};
};
if (client_nat_test("1"))
{
xlog("L_WARN", "cs<$cs> si<$si:$sp> ci<$ci> onreply_route1: matched client_nat_test1\n");
#$var(orig_ct) = $ct;
fix_contact();
#xlog("L_INFO", "cs<$cs> si<$si:$sp> ci<$ci> onreply_route1: fix_contact() <$var(orig_ct)> -> <$ct> retcode: $retcode\n");
xlog("L_WARN", "cs<$cs> si<$si:$sp> ci<$ci> onreply_route1: fix_contact()\n");
};
}