Revision History | ||
---|---|---|
Revision $Revision: 1.2 $ | $Date: 2006/09/22 11:15:39 $ | |
Copyright (c) 2006 Philippe Sultan, INRIA. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".
INRIA has joined Internet2 SIP.edu initiative to offer its users the ability to be joined from a growing SIP network, and to help them getting familiar with VoIP tools.
About 5000 email addresses and PBX extensions are reachable from the Internet. This covers the users of every Research Units (located in different french cities) that are part of INRIA.
This picture gives an general view of the software and hardware set up to match the requirements of the SIP.edu architecture.
Main elements description
The OpenSER SIP proxy/registrar is responsible for the inria.fr zone. A script that retrieves regular INRIA phone numbers from the LDAP directory comes along with this server. REGISTER requests are processed locally, regular INVITE requests are forwarded to Asterisk.
The Asterisk server manages a small set of SIP phones. It is also in charge of processing the INVITE requests relayed by OpenSER, and forward them to the SIP - PSTN gateway.
The FreeRADIUS server is dedicated to softphone user authentication. Depending on the resource that is being called, user authentication may or may not be triggered.
INRIA's members are registered in an OpenLDAP directory.
OpenSER handles calls originating from the Internet. As of version 1.0.1, OpenSER's configuration file does not show noticeable differences from SER's, for our simple use. Call processing logic is stored in a single configuration file, detailed hereafter.
OpenSER's configuration file is divided into four main sections: global parameters, external module loading, module parameters and routing blocks, which contain request routing logic. SIP.edu's cookbook (thanks for this!) provides extensive information regarding SER's installation and configuration, that also apply to our version of OpenSER. Therefore, only the routing logic and RADIUS configuration are detailed in these notes. The link to the cookbook : http://mit.edu/sip/sip.edu/ser.shtml
OpenSER can rely on an external RADIUS server for authentication and accounting purposes. radiusclient-ng must be installed on the system to have this RADIUS client feature working. For more information about how to integrate RADIUS with OpenSER : http://www.openser.org/docs/openser-radius-1.0.x.html
As shown in the module loading configuration section in openser.cfg, both auth, auth_radius and acc modules must be loaded on OpenSER startup :
# ------------------ module loading ---------------------------------- # Uncomment this if you want to use SQL database loadmodule "/usr/local/lib/openser/modules/mysql.so" loadmodule "/usr/local/lib/openser/modules/maxfwd.so" loadmodule "/usr/local/lib/openser/modules/sl.so" loadmodule "/usr/local/lib/openser/modules/rr.so" loadmodule "/usr/local/lib/openser/modules/registrar.so" loadmodule "/usr/local/lib/openser/modules/tm.so" loadmodule "/usr/local/lib/openser/modules/usrloc.so" loadmodule "/usr/local/lib/openser/modules/textops.so" loadmodule "/usr/local/lib/openser/modules/uri.so" loadmodule "/usr/local/lib/openser/modules/uri_db.so" loadmodule "/usr/local/lib/openser/modules/auth.so" loadmodule "/usr/local/lib/openser/modules/auth_radius.so" loadmodule "/usr/local/lib/openser/modules/acc.so" loadmodule "/usr/local/lib/openser/modules/exec.so"
The module-specific parameters settings section, mainly to indicate the location of configuration file for radiusclient-ng.
# ----------------- setting module-specific parameters --------------- # -- acc params -- # set the reporting log level modparam("acc", "radius_flag", 1) modparam("acc", "radius_missed_flag", 2) modparam("acc", "radius_config", "/usr/local/etc/radiusclient-ng/radiusclient.conf") # -- auth_radius params -- modparam("auth_radius", "radius_config", "/usr/local/etc/radiusclient-ng/radiusclient.conf") modparam("auth_radius", "service_type", 15)
This section covers the call processing section in openser.cfg. The corresponding section, named request routing logic is splitted and analyzed here.
General rules for call processing
Simple request check is done, as well as setting accounting flags. Comments in the script explicitly mention the taken actions.
# ------------------------- request routing logic ------------------- # main routing logic route{ /* ********* ROUTINE CHECKS ********************************** */ # 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"); return; }; if (msg:len >= 2048 ) { sl_send_reply("513", "Message too big"); return; }; # set flag for Radius Accounting: if (!method=="OPTIONS") setflag(3); if (method=="INVITE") { log(1, "INVITE MESSAGE RECEIVED - START ACC\n"); setflag(1); /* set for accounting (the same value as in log_flag!) */ setflag(2); }; if (method=="BYE") { log (1, "BYE - STOP ACCOUNTING\n"); setflag(1); }; if (method=="CANCEL") { log (1, "CANCEL - STOP ACCOUNTING\n"); setflag(1); }; # subsequent messages withing a dialog should take the # path determined by record-routing if (loose_route()) { route(1); return; }; # 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(); lookup("aliases"); if (!uri==myself) { # mark routing logic in request append_hf("P-hint: OUTBOUND\r\n"); route(1); return; };
REGISTER requests are processed by OpenSER, authentication is tested against FreeRADIUS
# 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 (method=="REGISTER") { # Uncomment this if you want to use digest authentication if (!radius_www_authorize("inria.fr")) { www_challenge("inria.fr", "0"); return; }; save("location"); return; };
First, OpenSER checks its location database in order to forward the INVITE request to a registered SIP user. SIP users from INRIA can only register non numeric URIs that take the form of firstname.lastname@inria.fr.
# native SIP destinations are handled using our USRLOC DB # In case a user is not found, we dig into INRIA's LDAP directory if (lookup("location")) { # user found -- forward to him and label the request append_hf("P-hint: USRLOC\r\n"); forward(uri:host,uri:port); } else {
If this fails, it will dig into the LDAP directory to find out a regular phone number that matches the SIP URI, and forward the INVITE request to Asterisk (route block [3] in openser.cfg). Route block [3] forwards INVITE requests to Asterisk without authentication, thus allowing any SIP.edu member to call INRIA's extensions. After this step, the destination URI value is either numeric (eg. a PSTN number) or null.
if (exec_dset("/usr/local/etc/ser/sipldap")) { log(1," sipldap call"); route(3); return; }
If the user wants to call a non INRIA extension number, route block [4] is called. User authentication is triggered, and checked against FreeRADIUS
# now check for destinations through the gateway. 15, 17 and 18 # are always sent to the gateway. The assumption is # that other all numeric usernames between 4 and 20 # digits are really pstn numbers and so they are # routed to the gateway else if (uri=~"sip:[0-9]{4,20}@.*") { route(4); return; }; }; # user could not be retrieved from LDAP sl_send_reply("404", "User Not Found"); return; # end of main routing logic }
Users are not authenticated so that anyone can call INRIA's extensions
# ------------- process traffic from Internet to local PBX for SIP.edu route[3] { # The LDAP mapping script returned a regular phone number. Let's # pass it to Asterisk without authentication rewritehostport("10.1.1.253:5060"); append_hf("P-hint: LOCAL CALL FORWARDED TO IPBX\r\n"); if (!t_relay()) { sl_reply_error(); return; }; }
User authentication is necessary if someone wants to call a regular PSTN phone. Exceptions are 4-digits extensions and emergency calls.
# ------------- process traffic leaving INRIA for PSTN route[4] { # send out emergency calls to pstn gateway immediately if ( (uri=~"^sip:15@.*") | (uri=~"^sip:17@.*") | (uri=~"^sip:18@.*")) { append_hf("P-hint: EMERGENCY CALL TO GATEWAY\r\n"); rewritehostport("10.1.1.254:5060"); forward(uri:host, uri:port); return; }; # four digit numeric addresses are internal freebies sent to the pbx # without authentication if (uri=~"^sip:[0-9]{4}@(10\.1\.1\.252|(softswitch\.)?inria\.fr)") { append_hf("P-hint: LOCAL CALL FORWARDED TO IPBX\r\n"); rewritehostport("10.1.1.253:5060"); forward(uri:host, uri:port); return; }; # All numeric addresses beginning with 0 go to the pbx on the way # to the PSTN, authentication is triggered then if (uri=~"^sip:0[0-9]*@(10\.1\.1\.252|(softswitch\.)?inria\.fr)") { if (method=="INVITE") { if (!radius_proxy_authorize("inria.fr")) { log(1, "LOG: RADIUS authentication triggered\n"); proxy_challenge("inria.fr","0"); return; } else if (method=="INVITE" & !check_from()) { log(1, "LOG: Spoofed from attempt\n"); sl_send_reply("403", "Use From=id next time"); return; }; }; }; rewritehostport("10.1.1.253:5060"); append_hf("P-hint: OUTBOUND CALL FORWARDED TO IPBX\r\n"); if (!t_relay()) { sl_reply_error(); return; }; }
A copy of the GNU FDL is available here : GNU Free Documentation License