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 <[email protected]> # # 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:passw...@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:passw...@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:passw...@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:passw...@localhost/opensips") # ----- domain params ----- /* uncomment the following lines to enable multi-domain detection support */ #modparam("domain", "db_url", # "mysql://opensips:passw...@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:passw...@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:passw...@localhost/opensips") #modparam("carrierroute", "config_source", "db") modparam("drouting", "db_url", "mysql://opensips:passw...@localhost/opensips") modparam("drouting", "ruri_avp", '$avp(dr_ruri)') modparam("drouting", "config_source", "db") modparam("dispatcher", "db_url", "mysql://opensips:passw...@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:4...@.*") { # 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:6...@.*") { # the uri with a default call to "local directory assistance". rewriteuri("sip:[email protected]"); } #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:17771000...@.*" ) { #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; } } _______________________________________________ Users mailing list [email protected] http://lists.opensips.org/cgi-bin/mailman/listinfo/users
