# # simple quick-start config script # # ----------- global configuration parameters ------------------------ debug=3 # debug level (cmd line: -dddddddddd) fork=yes log_stderror=no # (cmd line: -E) # memlog=5 # memory debug log level # log_facility=LOG_LOCAL0 # sets the facility used for logging (see syslog(3)) children = 1 check_via=no # (cmd. line: -v) dns=no # (cmd. line: -r) rev_dns=no # (cmd. line: -R) listen=127.0.0.1:5060 listen=1.2.3.4:5060 loadmodule "/usr/local/lib/ser/modules/maxfwd.so" # Database drivers loadmodule "/usr/local/lib/ser/modules/mysql.so" loadmodule "/usr/local/lib/ser/modules/sl.so" # AVP loadmodule "/usr/local/lib/ser/modules/avp.so" loadmodule "/usr/local/lib/ser/modules/avp_db.so" loadmodule "/usr/local/lib/ser/modules/avpops.so" loadmodule "/usr/local/lib/ser/modules/domain.so" # Authentication loadmodule "/usr/local/lib/ser/modules/auth.so" loadmodule "/usr/local/lib/ser/modules/auth_db.so" # Registrar loadmodule "/usr/local/lib/ser/modules/usrloc.so" loadmodule "/usr/local/lib/ser/modules/registrar.so" loadmodule "/usr/local/lib/ser/modules/gflags.so" loadmodule "/usr/local/lib/ser/modules/rr.so" # NAT traversal loadmodule "/usr/local/lib/ser/modules/nathelper.so" loadmodule "/usr/local/lib/ser/modules/tm.so" loadmodule "/usr/local/lib/ser/modules/textops.so" loadmodule "/usr/local/lib/ser/modules/xlog.so" # Management loadmodule "/usr/local/lib/ser/modules/xmlrpc.so" loadmodule "/usr/local/lib/ser/modules/uri.so" loadmodule "/usr/local/lib/ser/modules/uri_db.so" loadmodule "/usr/local/lib/ser/modules/acc_syslog.so" loadmodule "/usr/local/lib/ser/modules/eval.so" # ----------------- setting script FLAGS ----------------------------- flags FLAG_NAT_UAC :1, # UA will be marked as behind NAT if this flag is set FLAG_NAT_UAS :2; avpflags dialog_cookie; # handled by rr module modparam("usrloc|domain|avp_db|uri_db|auth_db|gflags|msilo|speeddial|acc_db", "db_url", "mysql://ser:heslo@localhost/ser") modparam("auth_db", "calculate_ha1", yes) modparam("auth_db", "password_column", "password") modparam("domain", "db_mode", 1) modparam("domain", "load_domain_attrs", yes) modparam("gflags", "load_global_attrs", yes) modparam("usrloc", "db_mode", 1) modparam("registrar", "save_nat_flag", "FLAG_NAT_UAC") modparam("registrar", "load_nat_flag", "FLAG_NAT_UAS") # modparam("usrloc|registrar", "use_domain", 1) modparam("nathelper", "natping_interval", 30) modparam("nathelper", "ping_nated_only", 1) # If using more RTP proxies they are addressed by index starting from index 0 modparam("nathelper", "rtpproxy_sock", "unix:/var/run/rtpproxy.sock udp:5.6.7.8:22222") modparam("acc_syslog", "early_media", no) modparam("acc_syslog", "failed_transactions", no) modparam("acc_syslog", "report_ack", no) modparam("acc_syslog", "report_cancels", no) modparam("acc_syslog", "log_flag", "acc.log") modparam("acc_syslog", "log_missed_flag", "acc.missed"); modparam("rr", "enable_full_lr", 1) # testing purpose route { ############### Generic processing independend of domains ################ route("generic"); lookup_domain("$fd","@from.uri.host"); # lookup_domain("From"); lookup_domain("$td","@ruri.host"); # lookup_domain("Request-URI"); # First of all check for 3rd party relaying attempts. This must be at # The beginning of the script, because rewrite actions below can change # local destination domain to 3rd party domain. In such a case 3rdparty # Inbound calls would match this condition (if it was at the end of # the configuration file) and reject an otherwise valid call. if (!$f.did && !$t.did) { sl_reply("400", "No Relaying"); drop; } # Processing based purely on From domain, that includes authentication # and identity verification, caller profile loading, NAT testing if ($f.did) { route("nat.detect"); # NAT detection comes here, this section sets flag FLAG_NAT_UAC route("authenticate"); if (!lookup_user("From")) { # if (!lookup_user("$fu", "@from.uri.user")) { sl_reply("400", "Fake Identity"); drop; } load_attrs("$fu", "$f.uid"); } ################ Processing based on the called domain #################### if ($t.did) { if (method == REGISTER) { route("registrar"); exit(1); } # (redirect) if ($f.did) { ; } # Once we get here, the request can be either from one of our # domains or from a 3rd party domain. Thus we can put actions # independent of the initiator of the request here. # 1) Access control # 2) ENUM # 3) Test for PSTN gateways and other SIP servers that belong # to the same domain #route("enum"); # Test whether $t.did has changed # We have finished all the destination rewrites here, the request # is neither for another server in our domain nor for a 3rd party # domain, thus try to lookup end-user in the user location database. if (!lookup_user("Request-URI")) { # if (!lookup_user("$tu", "@ruri.user")) { sl_reply("404", "Not Found"); drop; } # User found, load his profile load_attrs("$tu", "$t.uid"); # load_attrs("t.uid"); if (!lookup_contacts("location")) { sl_reply("483", "Temporarily Unavailable"); xlog("L_ERR","LXLOG: 483 - Callee temporarily unavailable"); drop; } if (isflagset("FLAG_NAT_UAS")) { xlog("L_ERR","LXLOG: callee is behind NAT - setting t.nat = true"); $t.nat = true; } else $t.nat = false; } # Outbound requests # NAT traversal based on $f.nat and $t.nat route("send"); } route["generic"] { # Handle XMLRPC requests first if (method == "POST" || method == "GET") { route("xmlrpc"); drop; } if (!process_maxfwd("10")) { sl_reply("483", "Too Many Hops"); drop; } if (msg:len >= max_len) { sl_reply("513", "Message Too Large"); drop; } loose_route(); ################### Mid-dialog requests need special treatment ############ if (has_totag()) { route("in_dialog"); drop; } } # # Handling of in-dialog requests # route["in_dialog"] { dump_attrs(); route("send"); drop; } # # Handle REGISTER requests # route["registrar"] { # Make sure this is domain our registrar is responsible for if (!lookup_domain("$td","@to.uri.host")) { # if (!lookup_domain("To")) { sl_reply("404", "Domain Not Local For Registrar"); drop; } # Make sure that this is one of our users # if (!lookup_user("$tu", "@to.uri.user")) { if (!lookup_user("To")) { sl_reply("404", "Registrant Not Found"); drop; } # Load registrant's profile load_attrs("$tu", "$t.uid"); # load_attrs("t.uid"); # Do whatever is needed here based on registrant's profile if (!save_contacts("location")) { sl_reply("400", "Invalid REGISTER Request"); drop; } } # # Digest authentication using database # route["auth_db"] { if (!proxy_authenticate("@to.uri.host", "credentials")) { append_to_reply("%$digest_challenge"); sl_reply("407", "Proxy Authentication Required"); drop; } } # # Authentication stanza # route["authenticate"] { # Test for trusted peers here that will not be authenticated if (proto == TLS) { route("auth_tls"); } else { route("auth_db"); # route("auth_radius"); } } # # XML-RPC based management interface # route["xmlrpc"] { xlog("L_ERR","LXLOG: SIP message trace - entered xmlrpc route"); create_via(); # XML-RPC requests must be secured using TLS if (proto != TCP) { sl_reply("490", "Invalid Transport Protocol"); drop; } dispatch_rpc(); drop; } ############### Forward blocks ############### # # Forward the request, do NAT mangling if necessary before # forwarding # route["send"] { xlog("L_ERR","LXLOG: SIP message trace - entered send route - From <%fu> To <%tu> request <%rm>"); route("nat.mangle"); t_on_reply("nat.mangle"); # if record routed store following AVPs to Record Route header if ($record_route) { setavpflag("$f.nat", "dialog_cookie"); setavpflag("$t.nat", "dialog_cookie"); setavpflag("$rtpproxy", "dialog_cookie"); setavpflag("$con_realm", "dialog_cookie"); setavpflag("$rtp_proxy_node", "dialog_cookie"); setavpflag("$f.comedia", "dialog_cookie"); setavpflag("$t.comedia", "dialog_cookie"); record_route(); } if (!t_relay()) { sl_reply_error(); drop; } } # # NAT detection, this block is executed early in the script and it's # purpose is to detect whether the UAC is behind NAT. This block does # no NAT mangling, this is postponed till the end of the script. This # block only sets FLAG_NAT_UAC flag if the UAC is behind NAT # route["nat.detect"] { xlog("L_ERR","LXLOG: SIP message trace - entered nat.detect route"); # Skip spiralling requets if (src_ip == 127.0.0.1) return; # Skip requests that already passed a proxy if (is_present_hf("^Record-Route:")) { xlog("L_ERR","LXLOG: Record Route header is present"); return; } if (nat_uac_test("3")) { force_rport(); setflag("FLAG_NAT_UAC"); $f.nat = true; } else $f.nat = false; return; } # # This block does whatever is necessary to make UAS behind NAT # reachable, that includes rewriting contact and forcing RTP # proxy if necessary. The logic in this block is base on # the value of FLAG_NAT_UAC and FLAG_NAT_UAS flags # onreply_route["nat.mangle"] { xlog("L_ERR","LXLOG: SIP message trace - entered onreply nat.mangle route <%rr><%rs>"); # Rewrite Contact in 200 OK if UAS is behind NAT if ($t.nat || $tr.nat) { xlog("L_ERR","LXLOG: Onreply - fixing NATed contact"); fix_nated_contact(); } # Apply RTP proxy if necessary, but only for INVITE transactions # and 183 or 2xx replie if (!$f.nat && (!$t.nat || !$tr.nat)) return; # checks if both UAC and UAS are in the same connectivity realm if ($con_realm || $tr.con_realm) return; if (@cseq.method != "INVITE") return; if ((status =~ "(183)|2[0-9][0-9]") && !search("^Content-Length: 0")) { if (!$rtpproxy && !$tr.rtpproxy) { xlog("L_ERR","LXLOG: UA supports symmettric RTP and passive role"); if ($t.nat || $tr.nat) { fix_nated_sdp("8"); return; } else return; } if ($rtp_proxy_node) eval_push("x:N%$rtp_proxy_node"); else if ($tr.rtp_proxy_node) eval_push("x:N%$tr.rtp_proxy_node"); force_rtp_proxy("@eval.pop[-1]"); } return; } # # This block does whatever is necessary to make UACs behind NAT # reachable, that includes rewriting contact and forcing RTP # proxy if necessary. The logic in this block is based on # the value of FLAG_NAT_UAC and FLAG_NAT_UAS flags # route["nat.mangle"] { xlog("L_ERR","LXLOG: SIP message trace - entered nat.mangle route"); # Rewrite Contact if the UAC is behind NAT if ($f.nat) { if (method == "REGISTER") { fix_nated_register(); } else { fix_nated_contact(); } } # AVP $rtp_proxy_node is stored in Record-Route HF and in URI CLASS # If this AVP attribute appears in this TO URI CLASS then it must be checked # by $tr.rtpproxy if (($tr.rtpproxy || $fr.rtpproxy) && (method == "BYE" || method == "CANCEL")) { xlog("L_ERR","LXLOG: BYE or CANCEL - UNFORCING RTP proxy"); if ($tr.rtp_proxy_node) unforce_rtp_proxy("$tr.rtp_proxy_node"); else unforce_rtp_proxy("$rtp_proxy_node"); } else if (method == "INVITE") { # If either UAC or UAS is behind NAT then go on # if (!$f.nat && (!$t.nat || !$tr.nat)) return; # Force record routing if either party is behind NAT $record_route = true; # Checks if both UAC and UAS are in the same # connectivity realm if ($con_realm || $tr.con_realm) return; if ($f.connectivity_realm == $t.connectivity_realm) { $con_realm = true; return; } xlog("L_ERR","LXLOG: reguest message - is not in connectivity realm"); # Checking if one UA is behind NAT and its peer # in public supports symmetric RTP and passive attribute if (($f.sym_pass || $fr.comedia) && ($t.nat || $tr.nat) && !$f.nat) { $f.comedia = $f.sym_pass; xlog("L_ERR","LXLOG: Caller supports sym_pass and callee is behind NAT"); return; } if (($t.sym_pass || $tr.comedia) && $f.nat && (!$t.nat || !$tr.nat)) { $t.comedia = $t.sym_pass; fix_nated_sdp("8"); xlog("L_ERR","LXLOG: Caller is behind NAT and callee supports sym_pass"); xlog("L_ERR","LXLOG: Appending passive attr to INVITE for public UA"); return; } # This section is for re-INVITEs : If RTP proxy was forced during initiating # a new call then here is performed a check for flags $rtpproxy and $rtp_proxy_node. # This will use the same RTP proxy as was chosen while initiating the call. # Parameter L performs lookup which only rewrite SDP when # corresponding session is already existing in RTP proxy. # Parameter N followed by AVP attribute is stored index(integer) of a particular # RTP proxy defined at the beginning of this script in modparam xlog("L_ERR","LXLOG: INVITE - rewriting IP and port in SDP - force_rtp_proxy"); if ($tr.rtpproxy || $rtpproxy) { if ($tr.rtp_proxy_node) eval_push("x:LN%$tr.rtp_proxy_node"); else eval_push("x:LN%$rtp_proxy_node"); force_rtp_proxy("@eval.pop[-1]"); } # For initial call: sets the rtpproxy attribute to true and assign different AVP attribute # for RTP_proxy_node to make sure it is stored in Record-Route HF # $node comes from user_attrs table else { $rtpproxy = true; $rtp_proxy_node = $node; # this will simply makes a string e.g. N0 # which is inserted in force_rtp_proxy function # as first parameter eval_push("x:N%$rtp_proxy_node"); force_rtp_proxy("@eval.pop[-1]"); } } return 1; }