IP Telephony Cookbook by Saverio Niccolini, Jorg Ott, et al - HTML preview

PLEASE NOTE: This is an HTML preview only and some elements such as links or page numbers may be incorrect.
Download the book in PDF, ePub, Kindle for a complete version.

loadmodule "modules/sl/sl.so"

loadmodule "modules/tm/tm.so"

# ----------------- setting module-specific parameters ---------------

# -- tm params --

# set time for which ser will be waiting for a final response;

# fr_inv_timer sets value for INVITE transactions, fr_timer

# for all others

modparam("tm", "fr_inv_timer", 15 )

modparam("tm", "fr_timer", 10 )

# ------------------------- request routing logic -------------------

# main routing logic

route{

# for testing purposes, simply okay all REGISTERs

if (method=="REGISTER") {

log("REGISTER");

sl_send_reply("200", "ok");

break;

};

# try these two destinations first in parallel; the second

# destination is targeted to sink port -- that will make ser

# wait until timer hits

seturi("sip:nobody@iptel.org");

append_branch("sip:parallel@iptel.org:9");

# if we do not get a positive reply, continue at reply_route[1]

t_on_failure("1");

# forward the request to all destinations in destination set now

t_relay();

}

failure_route[1] {

# forwarding failed -- try again at another destination

append_branch("sip:nonsense@iptel.org");

P.110

[IP Telephony Cookbook] / Setting Up Basic Services

log(1,"first redirection\n");

# if this alternative destination fails too, proceed to ...

t_on_failure("2");

t_relay();

}

failure_route[2] {

# try out the last resort destination

append_branch("sip:foo@iptel.org");

log(1, "second redirection\n");

# we no more call t_on_negative here; if this destination

# fails too, transaction will complete

t_relay();

}

4.6.2.4.5 Accounting

In some scenarios, like termination of calls in the PSTN, SIP administrators may wish to keep track of placed calls. SER can be configured to report on completed transactions. Reports are sent by default to the syslog facility. Support for RADIUS and MySQL accounting exists as well.

Note that SER is by no means call-stateful. It reports on completed transactions, i.e., after a successful call set up is reported, it drops any call-related state.When a call is terminated, a transactional state for the BYE request is created and forgotten again after the transaction completes.This is a feature and not a bug. Keeping the state information during transactions only allows the achievement of significantly higher scalability. It is then up to the accounting application to correlate call initiation and termination events.

To enable call accounting, tm and acc modules need to be loaded and requests need to be processed statefully and labelled for accounting.This means that if you want a transaction to be reported, the initial request must have taken the path setflag(X), t_relay in the SER script. X

must have the value configured in the acc_flag configuration option.

Also note, that, by default, only transactions that initiate a SIP dialogue (typically INVITE) visit a proxy server. Subsequent transactions are exchanged directly between end-devices, do not visit proxy server and cannot be reported.To be able to report on subsequent transactions, you need to force them to visit the proxy server by turning on record routing.

Example 4.6 Configuration with enabled accounting

#

# example: accounting calls to numerical destinations

#

# ------------------ module loading ----------------------------------

loadmodule "modules/tm/tm.so"

loadmodule "modules/acc/acc.so"

loadmodule "modules/sl/sl.so"

P.111

[IP Telephony Cookbook] / Setting Up Basic Services

loadmodule "modules/maxfwd/maxfwd.so"

loadmodule "modules/rr/rr.so"

# ----------------- setting module-specific parameters ---------------

# -- acc params --

# set the reporting log level

modparam("acc", "log_level", 1)

# number of flag, which will be used for accounting; if a message is

# labeled with this flag, its completion status will be reported

modparam("acc", "log_flag", 1 )

# ------------------------- request routing logic -------------------

# main routing logic

route{

/* ********* ROUTINE CHECKS ********************************** */

# filter too old messages

if (!mf_process_maxfwd_header("10")) {

log("LOG: Too many hops\n");

sl_send_reply("483","Too Many Hops");

break;

};

if (len_gt( max_len )) {

sl_send_reply("513", "Wow -- Message too large"); break;

};

# Process record-routing

if (loose_route()) { t_relay(); break; };

# labeled all transaction for accounting

setflag(1);

# record-route INVITES to make sure BYEs will visit our server too if (method=="INVITE") record_route();

P.112

[IP Telephony Cookbook] / Setting Up Basic Services

# forward the request statefuly now; (we need *stateful* forwarding,

# because the stateful mode correlates requests with replies and

# drops retransmissions; otherwise, we would have to report on

# every single message received)

if (!t_relay()) {

sl_reply_error();

break;

};

}

4.6.2.4.6 Reporting missed calls

SER can report missed calls via the syslog facility or to MySQL. Mysql reporting can be utilised by SER's complementary Web interface, Serweb.

Reporting of missed calls is enabled by the acc module.There are two cases, in which you want to report.The first case is when a called party is offline.The other case is when a user is online, but call establishment fails.There may be many reasons for failure (call cancellation, inactive phone, busy phone, server timer, etc.), all of them leading to a negative (>=300) reply sent to the calling party.The acc module can be configured to issue a missed-call report whenever a transaction completes with a negative status.

The following configuration fragment reports a missed call in both cases.The top half of the condition reports on calls missed due to offline called party status, using the acc_request action.

The action is wrapped in transactional processing (t_newtran) to guarantee that reports are not duplicated on receipt of retransmissions.

The bottom half of the condition marks transactions to online users in order to be reported on failure.That is what the setflag (3) action is responsible for, along with the configuration option log_missed_flag.This option configures SER to report on all transactions, which were marked with flag 3.

loadmodule("modules/tm/tm.so");

loadmodule("modules/acc/acc.so");

....

# if a call is labeled using setflag(3) and is missed, it will

# be reported

...

modparam("acc", "log_missed_flag", 3 );

if (!lookup("location")) {

# call invitations to off-line users are reported using the

# acc_request action; to avoid duplicate reports on request

# retransmissions, request is processed statefuly (t_newtran,

# t_reply)

if ((method=="INVITE" || method=="ACK") && t_newtran() ) {

t_reply("404", "Not Found");

acc_request("404 Not Found");

break;

P.113

[IP Telephony Cookbook] / Setting Up Basic Services

};

# all other requests to off-line users are simply replied

# statelessly and no reports are issued

sl_send_reply("404", "Not Found");

break;

} else {

# user on-line; report on failed transactions; mark the

# transaction for reporting using the same number as

# configured above; if the call is really missed, a report

# will be issued

setflag(3);

# forward to user's current destination

t_relay();

break;

};

4.6.2.4.7 User aliases

Frequently, it is desirable for a user to have multiple addresses in a domain. For example, a user with username ‘john.doe’ wants to be reachable at a shorter address ‘john’ or at a numerical address ‘12335’, so that PSTN calling parties with numeric-only key-pads can reach him as well.

With SER, you can maintain a special user location table and translate existing aliases to canonical usernames using the lookup action from the usrloc module.The following script fragment demonstrates the use of lookup for this purpose.

Example 4.7 Configuration of use of aliases

if (!uri==myself) { # request not for our domain...

route(1); # go somewhere else, where outbound requests are processed break;

};

# the request is for our domain -- process registrations first

if (method=="REGISTER") { route(3); break; };

# look now, if there is an alias in the "aliases" table; do not care

# about return value: whether there is some or not, move ahead then lookup("aliases");

# there may be aliases which translate to other domain and for which

# local processing is not appropriate; check again, if after the

# alias translation, the request is still for us

if (!uri==myself) { route(1); break; };

# continue with processing for our domain...

...

P.114

[IP Telephony Cookbook] / Setting Up Basic Services

The table with aliases is updated using the serctl tool.The command serctl alias add <alias>

<uri> adds a new alias, the command serctl alias show <user> prints an existing alias, and the command serctl alias rm <user> removes it.

[jiri@cat sip_router]$ serctl alias add 1234 sip:john.doe@foo.bar

sip:john.doe@foo.bar

200 Added to table

('1234','sip:john.doe@foo.bar') to 'aliases'

[jiri@cat sip_router]$ serctl alias add john sip:john.doe@foo.bar

sip:john.doe@foo.bar

200 Added to table

('john','sip:john.doe@foo.bar') to 'aliases'

[jiri@cat sip_router]$ serctl alias show john

<sip:john.doe@foo.bar>;q=1.00;expires=1073741811

[jiri@cat sip_router]$ serctl alias rm john

200 user (aliases, john) deleted

Note that the persistence of records needs to be turned on in the usrloc module. All changes to aliases would otherwise be lost on server reboot.To enable the persistence, set the db_mode usrloc parameter to a non-zero value.

# ....load module ...

loadmodule "modules/usrloc/usrloc.so"

# ... turn on persistence -- all changes to user tables are immediately

# flushed to mysql

modparam("usrloc", "db_mode", 1)

# the SQL address:

modparam("usrloc", "db_url","mysql://ser:secret@dbhost/ser")

~ 4.6.2.5 Operation

4.6.2.5.1 User management

There are two tasks related to the management of SIP users: maintaining user accounts and maintaining user contacts. Both of these jobs can be done using the serctl command-line tool.

The complimentary Web interface, Serweb, can be used for this purpose as well.

If user authentication is turned on, which is highly advisable, user accounts must be created before users can log in.To create a new user account, use the serctl add utility with the username, password and e-mail as parameters. It is important that the environment variable SIP_DOMAIN

is set to your domain and matches the realm values used in your script.The realm value is used for calculation of credentials stored in the subscriber database, which are bound permanently to this value.

[jiri@cat gen_ha1]$ export SIP_DOMAIN=foo.bar

[jiri@cat gen_ha1]$ serctl add newuser secret newuser@foo.bar

MySql Password:

new user added

P.115

[IP Telephony Cookbook] / Setting Up Basic Services

serctl can also change the user's password or remove existing accounts from the system permanently.

[jiri@cat gen_ha1]$ serctl passwd newuser newpassword

MySql Password:

password change succeeded

[jiri@cat gen_ha1]$ serctl rm newuser

MySql Password:

user removed

Typically, user contacts are automatically uploaded by SIP phones to the server during the registration process and administrators do not need to worry about them. However, users may wish to append permanent contacts to PSTN gateways or to locations in other administrative domains.To manipulate the contacts in such cases, use the serctl ul tool. Note that this is the only correct way to update contacts -- direct changes of the back-end MySQL database do not affect a server's memory. Also note, that if persistence is turned off (usrloc db_mode parameter set to 0), all contacts will be lost on server reboot. Make sure that the persistence is enabled if you add permanent contacts.

To add a new permanent contact for a user, call serctl ul add <username> <contact> .To delete all users’ contacts, call serctl ul rm <username> .The command serctl ul show

<username> prints all current contacts of this user.

[jiri@cat gen_ha1]$ serctl ul add newuser sip:666@gateway.foo.bar

sip:666@gateway.foo.bar

200 Added to table

('newuser','sip:666@gateway.foo.bar') to 'location'

[jiri@cat gen_ha1]$ serctl ul show newuser

<sip:666@gateway.foo.bar>;q=1.00;expires=1073741812

[jiri@cat gen_ha1]$ serctl ul rm newuser

200 user (location, newuser) deleted

[jiri@cat gen_ha1]$ serctl ul show newuser

404 Username newuser in table location not found

4.6.2.5.2 Access control (PSTN gateway)

It is often important to exercise some sort of access control. A typical case is when SER is used to guard a PSTN gateway. If a gateway could not be well-guarded, unauthorised users would be able to use it to make calls to the PSTN, inflicting high costs.

There are a few issues you need to understand when configuring SER for this purpose. First, if a gateway is built or configured to accept calls from anywhere, calling parties may easily bypass your access control server and communicate with the gateway directly.You then need to enforce, at transport layer, that signalling is only accepted if coming via SER and deny SIP packets coming from other hosts and port numbers.Your network must be configured not to allow forged IP

addresses. Also, you need to turn on record routing to assure that all session requests will travel via SER. Otherwise, calling party’s devices would send subsequent SIP requests directly to your gateway, which would fail because of transport filtering.

P.116

[IP Telephony Cookbook] / Setting Up Basic Services

Authorisation (i.e., the process of determining who may call where) is facilitated in SER using the group membership concept. Scripts make decisions on whether a calling party is authorised to make a call to a specific destination, based on the user's membership in a group. For example, a policy may be set up to allow calls to international destinations, only to users who are members of

‘int’ group. Before a user's group membership is checked, his identity must be verified.Without cryptographic verification of the user's identity, it would be impossible to confirm that a calling party really is who he claims to be.

The following script demonstrates how to configure SER as an access control server for a PSTN

gateway.The script verifies user identity using digest authentication, checks user's privileges, and forces all requests to visit the server.

Example 4.8 Script for gateway access control

loadmodule "modules/sl/sl.so"

loadmodule "modules/tm/tm.so"

loadmodule "modules/acc/acc.so"

loadmodule "modules/rr/rr.so"

loadmodule "modules/maxfwd/maxfwd.so"

loadmodule "modules/mysql/mysql.so"

loadmodule "modules/auth/auth.so"

loadmodule "modules/auth_db/auth_db.so"

loadmodule "modules/group/group.so"

loadmodule "modules/uri/uri.so"

# ----------------- setting module-specific parameters ---------------

modparam("auth_db", "db_url","mysql:ser:heslo@localhost/ser") modparam("auth_db", "calculate_ha1", yes)

modparam("auth_db", "password_column", "password")

# -- acc params --

modparam("acc", "log_level", 1)

# that is the flag for which we will account -- don't forget to

# set the same one :-)

modparam("acc", "log_flag", 1 )

# ------------------------- request routing logic -------------------

# main routing logic

route{

/* ********* ROUTINE CHECKS ********************************** */

# filter too old messages

if (!mf_process_maxfwd_header("10")) {

log("LOG: Too many hops\n");

sl_send_reply("483","Too Many Hops");

break;

P.117

[IP Telephony Cookbook] / Setting Up Basic Services

};

if (len_gt( max_len )) {

sl_send_reply("513", "Wow -- Message too large"); break;

};

/* ********* RR ********************************** */

/* grant Route routing if route headers present */

if (loose_route()) { t_relay(); break; };

/* record-route INVITEs -- all subsequent requests must visit us */

if (method=="INVITE") {

record_route();

};

# now check if it really is a PSTN destination which should be handled

# by our gateway; if not, and the request is an invitation, drop it --

# we cannot terminate it in PSTN; relay non-INVITE requests -- it may

# be for example BYEs sent by gateway to call originator

if (!uri=~"sip:\+?[0-9]+@.*") {

if (method=="INVITE") {

sl_send_reply("403", "Call cannot be served here");

} else {

forward(uri:host, uri:port);

};

break;

};

# account completed transactions via syslog

setflag(1);

# free call destinations ... no authentication needed

if ( is_user_in("Request-URI", "free-pstn") /* free destinations */

| uri=~"sip:[79][0-9][0-9][0-9]@.*" /* local PBX */

| uri=~"sip:98[0-9][0-9][0-9][0-9]") {

log("free call");

} else if (src_ip==192.168.0.10) {

# our gateway does not support digest authentication;

# verify that a request is coming from it by source

# address

log("gateway-originated request");

} else {

# in all other cases, we need to check the request against

# access control lists; first of all, verify request

# originator's identity

if (!proxy_authorize( "gateway" /* realm */,

"subscriber" /* table name */)) {

proxy_challenge( "gateway" /* realm */, "0" /* no qop */ ); P.118

[IP Telephony Cookbook] / Setting Up Basic Services

break;

};

# authorise only for INVITEs -- RR/Contact may result in weird

# things showing up in d-uri that would break our logic; our

# major concern is INVITE which causes PSTN costs

if (method=="INVITE") {

# does the authenticated user have a permission for local

# calls (destinations beginning with a single zero)?

# (i.e., is he in the "local" group?)

if (uri=~"sip:0[1-9][0-9]+@.*") {

if (!is_user_in("credentials", "local")) {

sl_send_reply("403", "No permission for local calls"); break;

};

# the same for long-distance (destinations begin with two zeros")

} else if (uri=~"sip:00[1-9][0-9]+@.*") {

if (!is_user_in("credentials", "ld")) {

sl_send_reply("403", " no permission for LD "); break;

};

# the same for international calls (three zeros)

} else if (uri=~"sip:000[1-9][0-9]+@.*") {

if (!is_user_in("credentials", "int")) {

sl_send_reply("403", "International permissions needed"); break;

};

# everything else (e.g., interplanetary calls) is denied

} else {

sl_send_reply("403", "Forbidden");

break;

};

}; # INVITE to authorised PSTN

}; # authorised PSTN

# if you have passed through all the checks, let your call go to GW!

rewritehostport("192.168.0.10:5060");

# forward the request now

if (!t_relay()) {

sl_reply_error();

break;

};

}

P.119

[IP Telephony Cookbook] / Setting Up Basic Services

Use the serctl tool to maintain group membership.The command serctl acl grant <username>

<group> makes a user member of a group, the command serctl acl show <username> shows groups of which a user is member, and the command serctl acl revoke <username>

[<group>] revokes a user's membership in one or all groups.

[jiri@cat sip_router]$ serctl acl grant john int

MySql Password:

+------+-----+---------------------+

| user | grp | last_modified |

+------+-----+---------------------+

| john | int | 2002-12-08 02:09:20 |

+------+-----+---------------------+

~ 4.6.3 Asterisk

In this section we will describe an example configuration of the Asterisk PBX.We will focus mainly on the configuration of the SIP part.

~ 4.6.3.1 Getting Asterisk

Asterisk can be downloaded from http://www.digium.com

~ 4.6.3.2 Installation

Download the tarball and untar it using:

tar xvfz asterisk-0.5.0.tar.gz

Compile the sources:

- # cd asterisk-0.5.0

- # make

- # make install

- # make samples

~ 4.6.3.3 Configuration

The configuration files can be found in the /etc/asterisk directory.The most important files are: sip.conf which contains configuration of SIP user agent and extensions.conf which defines the dialling plan.

In this simple example, Asterisk is configured to act as a simple back-to-back user agent. It will allow SIP user agents to register to it and make calls which will be routed to an outbound proxy.

P.120

[IP Telephony Cookbook] / Setting Up Basic Services

The file sip.conf contains the following settings:

;

; SIP Configuration for Asterisk

;

[general]

port = 5060 ; Port to bind to

bindaddr = 0.0.0.0 ; Address to bind to

context = from-sip ; Default for incoming calls

;

register => asterisk:password@iptel.org/jan ; Register with a SIP

provider

[iptel]

type=friend

username=asterisk

secret=password

fromdomain=iptel.org

host=iptel.org

[jan]

type=friend

username=jan

;secret=blah

host=dynamic

canreinvite=no

Section general contains some generic settings. Configure Asterisk to listen on port 5060 and to listen on all available interfaces. Specify context to be from-sip.The same context must be later configured in extensions.conf !

The line beginning with register instructs Asterisk to act as a user agent and register with the iptel.org server as user asterisk with password, password.The /jan part indicates that all incoming calls to user asterisk will be forwarded to user ‘jan’, registered at the Asterisk server.

Section iptel contains configuration of a peer. In this case, it is the iptel.org proxy server, because we will be using this server as an outbound proxy. In this section, the parameter fromdomain is specified, because we want all outgoing messages to have this domain in the From header field.

The last section, jan, contains credentials and data for a user that will be able to register with the Asterisk server. In this case, one SIP phone is configured with username jan and with an empty password and with a phone that will be registered with the Asterisk server to receive calls for username jan.

P.121

[IP Telephony Cookbook] / Setting Up Basic Services

The file extensions.conf contains the following settings:

[from-sip]

exten => jan,1,Dial(SIP/jan)

exten => jan,2,Hangup

exten => _3.,1