#relayed or blocked.
20. If the test for loose routing returns 'true' then we must relay the message without other processing. To do so
we pass execution control to route block number one (ie, route[1]). This route block is documented later but
it suffices now to say that it is the default message handler.
Since loose routing was required we cannot process the message any further so we must use a break command
to exit the main route block.
21. Since loose routing was required we cannot process the message any further so we must use a break command
to exit the main route block.
22. Now we have come to a part of the SIP configuration file were we are processing out-of-dialogue messages.
In other words, we are processing either a message that will begin a new dialogue, or we are processing a
SIP message that is not destined for our sip proxy (but we are relaying or proxying the message).
The keyword 'uri' is defined in the SER core and is a synonym for the request URI or R-URI for short. The
'myself' keyword is also defined in the SER core and is a synonym for the SER proxy itself.
So this line tests to see if the R-URI is the same as the SIP proxy itself. Another way to look at it is by saying
that if this statement is TRUE then the SIP message is not being sent to our SIP proxy but rather to some
other destination, such as a third party SIP phone.
23. Relay the message to the destination without further interrogation.
24. Stop processing the current message because we have sent it to its destination on the previous line.
25. ACK messages are explicitly handled, so we need to find out if we are processing an ACK request.
26. Relay the message to the destination without further interrogation
27. Stop processing because the ACK message has already been fully processed.
28. REGISTER messages are explicitly handled, so we need to find out if we are processing a registration request.
29. All registration requests are passed to route[2] for processing. We do this to somewhat segregate the workload
of the main route block. By doing so we keep our ser.cfg from becoming unmanageable.
30. Stop processing because the REGISTER message has already been fully processed.
31. Lookup(aliases) attempts to retrieve any aliases for the Requested URI. An alias is just another way to refer
to a SIP destination. For example, if you have a SIP user 4075559938 and a toll free number 8885551192
that rings to 4075559938, then you can create the toll free number as an alias for 4075559938. When someone
dials the toll free number the SIP client configured as 4075559938 will ring.
The lookup(aliases) function is not strictly needed for this example, however, serctl, which is a command
line utility included with SER requires this line for it to operate properly.
32. If an alias was found and the Requested URI is no longer a locally served destination, then we relay the SIP
message using our default message handler route[1]. After the message is relayed we stop processing by
means of the break command.
33. lookup(location) attempts to retrieve the AOR for the Requested URI. In other words it tries to find out where
the person you are calling is physically located. It does this by searching the location table that the save()
function updates. If an AOR is located, we can complete the call, otherwise we must return an error to the
caller to indicate such a condition.
34. If the party being called cannot be located then SER will reply with a 404 User Not Found error. This is done
in a stateless fashion.
35. Since the user cannot be found we stop processing.
36. If the current SIP message is not a REGISTER request, then we just relay it to its destination without further
processing. We do this by passing control to route[1], the default message handler.
37. Route[1] is the default message handler that is used throughout the ser.cfg file to relay messages. Notice how
the route block definition uses square brackets, but to call a route block you use parenthesis.
38. t_relay() is a function exposed by the tm.so module and is perhaps one of the most important functions in
any ser.cfg file. t_relay() is responsible for sending a message to it's destination and keep track of any resends
or replies. If the message cannot be sent successfully, then t_relay() will return an error condition.
See section 1 for more in-depth background information on transactions.
39. If t_relay() cannot send the SIP message then sl_reply_error() will send the error back to the SIP client to
inform it that a server error has occurred.
40. Route[2] is the registration message handler. This is where we store user contact data.
41. All REGISTER messages are happily honoured because we have not yet implemented authorization checks.
The save() function is responsible for storing SIP client registration information in the location table. However,
recall that the usrloc db_mode has been set to zero on line 5.1. This means that the save() function will only
save the registration information to memory rather than to disk.
42. If SER is unable save the contact information then we just return the error to the client and return to the main
route block.
Using The Hello World ser.cfg Configuration
Now that we have described our first SIP proxy configuration it is time to start up the server and configure two
SIP phones so that we can make telephone calls between the two registered clients.
To start SER as a non-daemon process that runs in the foreground you need to open up your favourite terminal,
such as a BASH shell.
Then issue the following command:
/usr/local/sbin/ser D E
The D parameter tells SER to not run as a daemon (ie, dont run in the background) while the E parameter tells
SER to send any errors to stderr.
SER should start up and say that it is listening for TCP and UDP on the IP address of the computer that you are
using. The IP must not be 127.0.0.1 because this IP is your loopback interface and SIP phones will not be able to
contact your SIP proxy.
Please note that unless SER is compiled with mode=debug, this may not work on all architectures. SER will just
print some basic stuff and then be quiet.
Now that SER is running you should configure two (2) or more SIP phones. A good example of a SIP phone is a
Grandstream BT100 because they are inexpensive and work well for basic SIP testing.
When configuring your SIP phones you should use the following settings:
You should now be able to boot up your SIP phones and call each other. The numbers you would dial are whatever
values you keyed in to the User Name fields. So in our example SIP phone 1000 can dial 1001 and SIP phone
1001 can dial 1000.
Chapter 7. SER - Adding Authentication and
MySQL
What this ser.cfg does:
1. Adds authentication of IP phones by using credentials stored in MySQL
2. Contact information is stored persistently in MySQL
Now that you have tested a basic SIP environment, we need to add more functionality. This section we talk about
authentication.
In normal circumstances, we must restrict the use of the SIP server to those telephones (i.e., users) that we want.
Authentication is about ensuring only those telephones that we have given a password to are allowed to use our
sip services.
To support authentication, we need a way to store information that does not get lost when we stop the sip server.
We need a database and the most popular is MySQL as it comes with all Linux configurations. Support is provided
for other databases, such as PostgreSQL, but in this Quick Start guide we focus on MySQL.
To add support for MySQL you need to go back to the source code and modify a few parameters. In Chapter 11
- Supporting MySQL describes how to do this and re-install the binaries. Once you have updated your SER environment
you need to modify your ser.cfg file as described below.
MySQL ser.cfg Listing
Listed below is the SIP proxy configuration to which builds upon subject matter covered in the Hello World section.
debug=3
fork=no
log_stderror=yes
listen=192.0.2.13 # INSERT YOUR IP ADDRESS HERE
port=5060
children=4
# -----------------------------------------------------------------
# REGISTER Message Handler
# ----------------------------------------------------------------
sl_send_reply("100", "Trying");12
25
SER - Adding Authentication and MySQL
XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
if (!www_authorize("","subscriber")) { 13
www_challenge("","0");14
break;15
};
if (!check_to()) { 16
sl_send_reply("401", "Unauthorized");17
break;
};
consume_credentials();18
if (!save("location")) { 19
sl_reply_error();
};
}
Authenticating ser.cfg Analysis
Our new SIP proxy configuration is quickly maturing to meet real world requirements. We now store all user registration
data to MySQL which enables us to restart the SIP proxy without affecting user registrations. This means
that you can quickly restart SER without the clients knowing about it.
Another very important feature that we have introduced is authentication. Authentication happens during two different
times in order to secure our SIP router. The first place we need to look at is the area that handles REGISTER
messages because we do not want anonymous users to have the ability to register with our SIP proxy.
The second area we must secure is the handler that processes INVITE messages because we do not want unauthenticated
users to make telephone calls. If we allowed this then we would have what is called an open relay and
if your SIP proxy is connected to a PSTN gateway you could be responsible for excessive toll charges.
An important thing to note is that comments from the Hello World configuration have been removed for clarity
so that you can quickly find new areas in this ser.cfg file, which have been commented.
1. The fifo_db_url directive is also included to suppress start up warnings that would otherwise appear when
adding MySQL support. We do not directly use the fifo_db_url from ser.cfg, however, other ancillary tools,
such as serctl use it to add users to the database.
2. MySQL support is added easily by including the mysql.so module in the loadmodule section. A very important
thing to notice is that mysql.so is loaded before all other modules. The reason is that mysql.so does not have
any module dependencies, however, other modules, such as uri_db, do depend on the mysql.so module.
3. The auth.so module is not directly used by ser.cfg, however it is necessary to enable authentication functionality.
The authentication functionality in this ser.cfg file is provided by the auth.so and auth_db.so modules.
4. Auth_db.so is the module that we invoke directly. This module interoperates with auth.so to perform its
function.
5. Uri_db.so is the module that exposes some authentication functions that we will use in this ser.cfg example,
namely check_to().
6. The auth_db module exposes a db_url parameter which is required in order to tell SER where to find a MySQL
database for user authentication. If you notice we have included auth_db, uri_db, AND usrloc in a single
modparam by using the pipe symbol. We do this as a short cut, however it is perfectly legal in SER syntax
to have included these in separate modparam statements.
7. The auth_db parameter calculate_ha1 tells SER whether or not to use encrypted passwords in the MySQL
subscriber table. In a production system you will want to set this parameter to zero, but in our development
system we use unencrypted passwords so the value is set to one.
8. The auth_db module defaults the password column name to ha1, however the MySQL schema that SER uses
calls the password column password. Therefore we must inform SER that the column name has changed.
9. The usrloc parameter db_mode must be changed from zero, used in the Hello World example to 2 in this
example to configure SER to use MySQL for storing contact information and authentication data.
10. We now explicitly define an INVITE handle route[3]. This handler is responsible for setting up a call
11.Pass control to route[3] for all INVITE messages that have not been loose routed. Invite messages hitting
this statement are original INIVITEs rather than re-INVITEs. After an INVITE message is processed we exit
by calling break.
12. When we receive a REGISTER message, we immediately send a 100 Trying message back to the SIP client
to stop it from retransmitting REGISTER messages. Since SER is UDP based there is no guaranteed delivery
of SIP messages, so if the sender does not get a reply back quickly then it will retransmit the message.
13. By replying with a 100 Trying message we tell the SIP client that we're processing its request.
The www_authorize() function is used to check the user's credentials against the values stored in the MySQL
subscriber table. If the supplied credentials are correct then this function will return TRUE, otherwise FALSE
is returned.
If credentials were not supplied with the REGISTER message, then this function will return FALSE.
The first parameter specifies the realm in which to authenticate the user. Since we are not using realms, we
can just use an empty string here. You can think of the realm in exactly the same way you think of a web
server realm (domain).
14. The second value tells SER which MySQL table to use for finding user account credentials. In this case we
specified the subscriber table.
Here we actually send back a 401 Unauthorized message to the SIP client which tell it to retransmit the request
with digest credentials included.
www_challenge() takes two arguments. The first is a realm, which will appear in the WWW-Authorize
header that SER sends back to the SIP client. If you put a value in here then that realm will appear to the SIP
client when it is challenged for credentials.
The second value affects the inclusion of the qop parameter in the challenge request. It is recommended to
keep this value set to 1. See RFC2617 for a complete description of digest authentication. Please note though
that some IP phones do not support qop authentication. You may try to use 0 if you experience Wrong password
problems.
15. Since we sent back a 401 error the SIP client on the previous line we no longer need to service this REGISTER
message. Therefore we use the break command to return to the main route block.
16. When operating a SIP proxy you must be certain that valid user accounts that have been successfully registered
cannot be used by unauthenticated users. SER includes the check_to() function for this very reason
We call check_to() prior to honouring the REGISTER message. This causes SER to validate the supplied
To: header against the previously validated digest credentials. If they do not match then we must reject the
REGISTER message and return an error.
17. If check_to() returned FALSE then we send a 401 Unauthorized message back to the SIP client. Then we
call the break command to return to the main route block.
18. We do not want to risk sending digest credentials to upstream or downstream servers, so we remove any
WWW-Authorize or Proxy-Authorize headers before relaying further messages.
19. If execution of ser.cfg makes it to this line then the SIP user has successfully been validated against the
MySQL subscriber table, so we use the save(location) function to add the user's contact record to the MySQL
location table. By saving this contact record to MySQL we can safely restart SER without affecting this registered
SIP client.
20. Route[3] is introduced here to handle INVITE messages.
21. We use proxy_authorize() to make sure we are not an open relay. Proxy_authorize() will require INVITE
messages to have digest credentials included in the request. If they are included the function will try to validate
them against the subscriber table to make sure the caller is valid.
22. Like www_authorize(), proxy_authorize() also takes two arguments. The first is a realm and the second is
the MySQL table in which to look for credentials. In our example this is the MySQL subscriber table.
If the user did not properly authenticate then SER must reply with a 401 Unauthorized message. The
proxy_challenge() function takes two arguments that are the same as the www_challenge() function, namely
a realm and a qop specifier.
Now that we've sent a 401 challenge to the caller we execute a break command to return to the main route
block.
23. Here we call check_from() to make sure the INVITE message is not using hi-jacked credentials. This function
checks the user name against the digest credentials to verify their authenticity.
24. If check_from() returned false then we reply to the client with a 401 unauthorized message and return to the
main route block.
25. We do not want to risk sending digest credentials to upstream or downstream servers, so we remove any
WWW-Authorize or Proxy-Authorize headers before relaying further messages.
26. Look up any associated aliases with the dialed number. If there is an aliases and it is not a locally served
domain then just relay the message.
27. Now that all request URI transformations have been done, we can attempt to look for the correct contact record
in the MySQL location table. If an AOR (aka, address of record) cannot be found then we reply with a 404
error.
28. Finally, if execution has made it here, then the caller has been properly authenticated and we can safely relay
the INVITE message.
Using the Authenticating ser.cfg Proxy
Before you can use this new SIP route configuration you must configure SIP user accounts by using the serctl shell
script. We'll continue with user 1000 and 1001. In the Hello World example we happily registered any user that
sent a REGISTER message.
Now we require authentication. So open up a terminal window and execute the following two commands:
You will be prompted for a password. This will be your MySQL SER user's password. Refer to the section on
setting up MySQL for further instructions on configuring the MySQL user account.
Once the accounts are created you need to update your SIP phones by changing the passwords to whatever you
used in the serctl commands. Then reboot your SIP phones and you should be able to complete telephone calls.
Chapter 8. Handling of NAT
There are two implementations for handling of NAT, use of mediaproxy and the use of rtpproxy. The following
sections describe each of these methods.
There is considerable debate on the serusers mailing forum about which is better! Both are described in this document,
but due to the simple fact that the authors of this document have deployed mediaproxy in their own installations
means that the rest of this Getting Started document builds upon the mediaproxy solution. If there are users who
would like to contribute material supporting the rtpproxy solution then this will be considered for future issues.
Handling of NAT using Mediaproxy
What this ser.cfg will do:
1. Introduce specialized processing which is necessary when dealing with SIP clients that are behind a NAT
device such as a DSL router or corporate firewall
Mediaproxy is one of two NAT traversal solutions for SER, the other being rtpproxy. Mediaproxy is known as a
far-end NAT traversal solution which means that it handles all aspects of NAT at the SIP proxy location rather
than at the SIP client location.
There are many advantages to handling NAT issues at the SIP proxy server, the primary benefit being that SIP
client configuration is much simpler. Some of the important features of mediaproxy are:
1. DNS SRV record capabilities for load distribution
2. Mediaproxy can be installed on remote servers which are not running SER. By doing this your SIP proxy
load is lightened
3. Web monitoring is included with the mediaproxy distribution
Mediaproxy is a separate software product that is not distributed with SER. The SER distribution only includes
the glue which gives SER the ability to communicate with a running instance of mediaproxy. This glue is known
as the mediaproxy module. It is really a dispatcher module that can control one or more actual mediaproxy servers.
NOTE: In order for mediaproxy to function properly it must be configured to listen on a public IP address. Also,
in most real world configurations, mediaproxy will not be installed on the SER server, but on a remote machine.
Refer to the appendix for information on installing mediaproxy. Also, the mediaproxy version used for testing
these configuration files can be downloaded from http://ONsip.org/
debug=3
fork=yes
log_stderror=no
listen=192.0.2.13 # INSERT YOUR IP ADDRESS HERE
port=5060
children=4
dns=no
rev_dns=no
fifo="/tmp/ser_fifo"
fifo_db_url="mysql://ser:heslo@localhost/ser"
Mediaproxy Transparent NAT Traversal ser.cfg Analysis
Our NAT traversal implementation is referred to as transparent NAT traversal because there are no differences
between SIP clients with public IP addresses and SIP clients sitting behind a NAT device.
This SER configuration handles all NAT related issues invisibly so that configuring SIP phones is a breeze. We
do not use STUN because STUN generally adds another layer of complexity that can be avoided.
To handle NATed devices we have introduced the use of mediaproxy. Mediaproxy is an RTP proxy application
which is not part of SER. Mediaproxy installation and start script are shown in the appendix.
The issue of NAT is complicated because there are several aspects of NATed SIP clients that all must be addressed
properly in order to effectively perform transparent RTP proxying. Please refer to NAT, STUN, and RTP proxy,
section 3.5, for an in-depth review of these aspects.
A brief re-cap of the main NAT issues that must be addressed are:
1. NATed clients must maintain an open SIP port, usually 5060 at all times. If this port closes on the clients
NAT device then incoming calls will not be successful because the SIP proxy will be unable to notify the
NATed SIP client that an INVITE message is being sent to it. In this case it is possible for the NATed SIP
client to still make outbound calls.
2. RTP ports can, and usually do use a random port. This means that users cannot just open a port on their NAT
device for RTP.
3. re-INVITE messages must be handled in a special manner in order to prevent RTP media streams from being
lost mid-call. If this were to happen you usually end up with one-way audio or no audio after a re-INVITE
message is processed. NOTE: The reason for this is that SIP RFC3261 specifies that a SIP UA may change
CODECs, RTP ports, etc during mid-call. To compound this issue, it is difficult to determine if either SIP
party in a call is NATed when processing re-INVITE messages.
So how do we handle these NAT issues? The solutions to these problems are:
1. The SER configuration presented in this section takes advantage of the fact that we can use the SER proxy
to keep NAT bindings open with the use of the natping_interval setting in mediaproxy. By doing so we can
be certain that port 5060 for NATed clients will be accessible to our SIP proxy and therefore we will be able
to send INVITE messages to those clients at any time.
2. Mediaproxy gives SER the ability to be oblivious to the specific RTP port that a SIP client uses. The way it
does this is that the two SIP clients think they are talking directly to each other, when in reality they are
talking to the media proxy, which then forwards RTP data to the other SIP client. This is all handled automatically
when the original SIP INVITE message is being processed and the call is set up.NOTE: In this ser.cfg
example, we only proxy RTP media when one or more SIP clients are behind a NAT device. In cases where
both SIP clients are on the public Internet, then we do not proxy RTP streams since both SIP clients can directly
contact each other. This is a key to building a scaleable VoIP platform.
3. We take advantage of the fact that we can embed our own NAT indicator in the Record-Route header of the
original INVITE message. By doing so we can look for this special NAT tag when processing re-INVITE
messages. If we find this tag then we know we must proxy the RTP media.NOTE: This technique of embedding
a NAT flag in the Record-Route header has been suggested by Jan Janak of IPtel. He is one of the projects
core developers and is an authoritative person on the subject.NOTE: This technique of embedding a NAT
flag in the INVITE message is not required when using rtpproxy because the rtpproxy server has the ability
to handle this situation without additional help.
1. Up until now we have run SER as a foreground process. From this point forward we will run SER as a daemon.
The fork directive tells the SER daemon to run in the background. This is a requirement for using the init.d
start script shown in the appendix.
2. Since we are running SER as a background process we must set the log_stderror directive equal to no in order
to not keep SER in the foreground.
3. The uri module is introduced here to access the has_totag() function. This function is necessary for processing
re-INVITEs and is describe below.
4. The domain module is needed because the mediaproxy module has dependencies to it for the
is_uri_host_local() and is_from_local() functions.
5. Here we introduce the use of mediaproxy. This line has confused many SER novices because it implies that
mediaproxy is included with SER, however, mediaproxy is an external application. This line only invokes
the mediaproxy module, which is the glue between SER and the actual mediaproxy application.
6. We use some of the nathelper library functions to determine whether or not a SIP UA is NATed. An important
item to understand is that just because nathelper is included here does not indicate that we are using rtpproxy
(another RTP proxy application comparable to mediaproxy). Also note here that nathelper is generally referred
to in the same context as rtpproxy because most people that use rtpproxy also use nathelper.
7. The textops module provide utility functions for manipulating text, searching for substrings, and checking
for the existence of specific header fields.
8. Since we are using mediaproxy rather than rtpproxy, we need to tell the nathelper module to not attempt to
bind to a running instance of rtpproxy. If we were to omit this line then syslog would contain many errors
stating that rtpproxy could not be found.
9. Our NAT traversal is using mediaproxy, and therefore we have decided to use the mediaproxy keep-alive
mechanism, which will ping NATed SIP clients on a regular basis. Because of this we need to disable the
rtpproxy ping mechanism since we do not need it.
10. The mediaproxy natping_interval is a very crucial setting, which controls how often our SER proxy will ping
registered SIP clients. Most NAT devices will only hold port bindings open for a minute or two, so we specify
30 seconds here.
This causes SER to send a 4-byte UDP packet to each SIP client every 30 seconds. This is all that is required
to keep NATed clients alive.
NOTE: Some NAT devices have been reported to not allow incoming keep-alives. Thus, many user clients
have their own implementations of keep-alive. If you experience one-way audio problems after a while, you
may have run into this problem. The only solution is to turn on user client keep-alives. Also, keep in mind
that it is perfectly acceptable to have the SER proxy send keep-alive traffic as well as the SIP traffic to the
client.
11. SER and the mediaproxy dispatcher communicate via a standard Unix socket, which is specified here.
12. Mediaproxy may need to know when a SIP UA is asymmetric with respect to its SIP messaging port. Most
SIP UAs are symmetric, meaning that they listen for incoming SIP messages on the same port as they use
for sending their own SIP messages. However, if you find asymmetric clients that are not handled correctly,
you can specify their User-Agent headers in this file.
A default example of this file can be found in the SER distribution under /modules/mediaproxy/
config/sip-asymmetric-clients. This example file has been copied and renamed to the path specified
on this line.
Mediaproxy may need to know when a SIP UA is asymmetric with respect to its RTP port. If you find
asymmetric clients that not handled correctly you can specify their User-Agent headers in this file.
A default example of this file can be found in the SER distribution under /modules/mediaproxy/
config/rtp-asymmetric-clients. This example file has been copied and renamed to the path specified
on this line.
11. When SIP clients attempt to REGISTER with our SIP proxy we need a way to tell the registrar module to
store NAT information for any particular UA. We do this by using flag 6, which has been arbitrarily chosen
(but defined earlier in the loadmodule parameter section). We could have specified another integer here, but
flag 6 seems to be the accepted standard for nat_flag.
15. If the nat_flag is set before calling the save() function to store contact information, SER will preserve the
NAT contact information as well as set the flags column in the MySQL location table. By doing so, we can
call lookup(location) when processing messages and flag 6 will be set for NATed clients.
If the received message is an INVITE and it is from a SIP client that is behind a NAT we need to embed a
special NAT flag, which will be returned to our SIP proxy in the case of a re-INVITE. This embedded flag
can then be located in our loose route processing logic to determine if the message originator is NATed or
not.
16. If the message originator is NATed we specify the Record-Route header explicitly by using the record_
route_preset() function. We pass to this function the IP address of our SIP proxy. If your SIP proxy sits
behind a router that has Application Level Gateway (ALG) support, such as a Cisco 3600 series, then you
will use the physical RFC1918 address of your SIP proxy here because the ALG-enabled router will rewrite
private IP addresses.
NOTE: For those that are familiar with rtpproxy you may be wondering why this step is necessary since
rtpproxy doesnt require the embedded ;nat=yes tag. The reason mediaproxy requires this and rtpproxy does
not is that the use_media_proxy() function, which is introduced later in this example, will set up a new RTP
proxy channel if you call the function and the header is not found it mediaproxys list of active
sessions.
The corresponding function in rtpproxy has the ability to instruct rtpproxy to only take action if a previous
header is found in the list of active rtpproxy sessions.
This difference also affects the loose_route() code block because mediaproxy users must look for the ;nat=yes
tag when processing re-INVITE messages and rtpproxy users do not. So from this aspect, rtpproxy is somewhat
easier to use.
17. If the message is not an INVITE from a NATed SIP client and it is not a REGISTER then we just call record_
route() as normal to ensure that messages return to our SIP proxy from upstream or downstream SIP
proxy servers or PSTN gateways.
18. Anytime we receive a BYE or CANCEL message we should assume that it is for a call that has been set up
with mediaproxy. So here we just attempt to tear down the RTP proxy session. It is perfectly safe to call
end_media_session(), even for calls that were not RTP proxied.
19. Tell mediaproxy to end the session for the current call.
20. Our NAT traversal requirements must handle re-INVITE messages in a special manner to prevent RTP media
streams from dropping off during a re-INVITE. So we do special re-INVITE NAT processing here.
In order to ensure that we are dealing only with an actual re-INVITE, we must make sure the has_totag()
function returns TRUE and loose_route() is also TRUE. The reason for this is that it is possible for an original
INVITE message to include predefined route headers, which would cause loose_route() to return TRUE.
Therefore the has_totag() is checked because only connected calls will have a tag= entry in the header
(ie, calls where a 200 OK as been generated by the callee).
21. In other words this new security check is based on the fact that established SIP dialogs will have a "totag"
whereas calls in the process of being established will not. To ensure that our loose routing logic is not exposed
to malicious users we make sure that INVITE and REFER messages are only accepted for established dialogs.
If the message is an INVITE then we need to challenge the message sender for credentials. If the message
sender cannot provide valid credentials then SER will reply with a 403 error message.
NOTE: This current example requires that the caller and callee are registered with the SIP router. Future
examples will expand on this section to allow "trusted" SIP devices, such as a PSTN gateway.
22. Now we check the NAT status of the re-INVITE to see if the message originator is NATed or not by calling
client_nat_test("3"). We also search for a header that contains the ";nat=yes" embedded tag which
would have been included by our record_route_preset() discussed earlier. If the ;nat=yes tag is found, then
the caller is NATed.
23. If the message sender is NATed or the re-INVITE contains the ;nat=yes flag, we set flag 6 for later reference.
This flag can then be checked in the reply_route.
24. In order to proxy RTP streams we just call use_media_proxy(). This will communicate to the external mediaproxy
server causing it to open UDP ports for both clients, or maintain an existing RTP proxy session for
an existing call, based on the header. Calling use_media_proxy() causes the SDP payload to be
rewritten with the IP address of the mediaproxy server and the allocated ports.
25. In the event that our message is no longer to be handled by our SIP router, we call our NAT handling route
block to enable mediaproxy if needed before sending the message to its destination.
26. We now explicitly handle CANCEL messages. CANCEL messages can be safely processed with a simple
call to t_relay() because SER will automatically match the CANCEL message to the original INVITE message.
So here we just route the message to the default message handler.
27. Enable mediaproxy if needed before sending the message to its destination.
28. When dealing with NATed clients we must correctly handle response messages that may be heading back
to the client. These response messages are accessible in SER by using a reply_route block.
SER allows you to specify multiple reply_route blocks which can perform many tasks. Here we specify that
any reply messages must be passed to reply_route[1] which is defined at the end of the ser.cfg file.
In order to invoke a reply_route, you simply need to set the handler prior to calling t_relay(), as we have
done here.
29. If the message could not be sent and it is an INVITE or ACK then we should attempt to release any previously
established mediaproxy session.
30. If client_nat_test() returns true then we must set flag 6 to inform the registrar module that the client is NATed.
Also note that we must only invoke client_nat_test() if the SIP message being processed contains an actual
Contact: header. Otherwise an error will be written to syslog.
NOTE: An interesting side note here is that the regular expression for the header is ^Contact:[
]*\* which reads like this;
If the line starts with the text Contact: and is followed by any number of spaces (ie: [ ]*) and then followed
by an Asterisk (ie: \*). The reason for this is that a SIP client can include the header just the
same as and both are valid. By testing for one or more white space characters we catch
all formatting styles.
Download Information
Worldwide voip billing solution provider since 1999
Address: 850 Ives Dairy Rd., Ste. T/57-320 - Miami, FL 33179 - United States
Tel: +1.305.655.0311 - +1-305-655-1605
E-mail: info@cyneric.com