NOTE: The Contact: header will contain an Asterisk "*" character when a SIP client is requesting to be "unregistered"
from the SIP proxy. In fact, many SIP clients can and/or will send a REGISTER message with a
"Contact: *" header when they are rebooted.
31. If a client is indeed NATed, then we must inform the SER registrar module that it needs to store the actual
IP address and port that the SIP message came from. This information is then used by subsequent calls to
lookup(location) in order to find the public IP address of a SIP client that is behind a NAT device.
32. Fix_nated_register() is used specifically for processing REGISTER messages from NATed clients. This is
very different from fix_nated_contact() because the former will not alter the URI in the Contact: header
whereas the latter will.
Fix_nated_register() will only append parameters to the Contact: header URI, which follows RFC3261
Section 10.3 on handling REGISTER messages. If we had used fix_nated_contact() here then you will likely
have compatibility problems where SIP UAs do not honor the 200 OK response that SER replies with upon
successful REGISTRATION. This would then cause the SIP client to loose its registration.
33. Force_rport() adds the received IP port to the top most via header in the SIP message. This enables subsequent
SIP messages to return to the proper port later on in a SIP transaction.
34. Invite messages have slightly different NAT testing requirements than REGISTER messages. Here we only
test to see if the SIP message has an RFC1918 IP address in the Contact: header and whether or not the
SIP UA contacted SER on a different IP address or port from what is specified in the via header.
If it is determined that the SIP client is NATed, then we set flag 7 for later reference.
NOTE: This client_nat_test() only determines if the message sender is behind a NAT device. At this point
in the ser.cfg file we have not determined if the message recipient is NATed or not.
36. Add the received port to the VIA header.
37. Now we rewrite the messages Contact:header to contain the IP address and port of the public side of the
NATed SIP client.
38. Enable mediaproxy if needed before sending the message to its destination.
39. Now we find the contact record for the party being called.
NOTE: A subtle, but very important, detail here is that flag 6 will be set by the call to lookup(location) in
route[2] if the party being called is found in the MySQL location table and is NATed. The reason flag 6 will
be set is because we specified this as the registrar modules nat_flag parameter.
40. Enable mediaproxy if needed before sending the message to its destination.
Now that we have taken care of all the NAT related items, we can safely send the INVITE message to its
destination.
41. Route[4] is a convenience route block which enabled mediaproxy if either the message sender (flag 7) or the
message recipient (flag 6) are NATed.
42. Flag 8 is used to make sure the mediaproxy doesn't get invoked more than once for our call. If mediaproxy
were to erroneously be called more than once then the SIP message would end up with a corrupted SDP
payload because the call to use_media_proxy() would alter the message incorrectly.
43. If flag 8 is not set then set it to prevent calling route[4] again.
Here we introduce a reply_route handler. A reply_route is defined just like any other block in SER. The only
difference is that it is called onreply_route.
Any message that is passed to this block will be returning to the original sender. You can think of these
messages as the response to the original request that the caller made. The types of messages that will appear
here will have an integer response code, much like HTTP response codes. Examples here would be 200, 401,
403, and 404.
44. In this ser.cfg we are only interested in response codes of 180, 183, and all 2xx messages for NATed clients.
We can check the status as shown with a regular expression. If any of these response codes are found then
this statement will be TRUE.
An important thing to note is that we can check flags set in the other route blocks because their scope is still
valid. So our caller and callee NAT flags are still accessible. If flag 6 is set then the caller is NATed, and if
flag 7 is set then the callee is NATed.
45. We can only call use_media_proxy() for SIP messages that have a valid Contact parameter in the SDP
payload. So here we test to make sure the c= parameter is valid by simply checking the SDP payload length.
We assume that if we have an SDP payload then we will have a c= parameter and can call use_media_proxy().
46. If we were to simply call use_media_proxy() then we would likely see errors in syslog.
Finally we rewrite the messages header to contain the IP address and port of the public side of
the NATed SIP client.
Using the Mediaproxy Transparent NAT Traversal ser.cfg
We have now made SER 100% NAT aware while keeping all of our SIP clients unaware of NAT. To test this new
NAT functionality make sure you have an instance of mediaproxy running on the same physical server as SER.
Once mediaproxy is running you can start SER and register your SIP clients as normal. It should not matter
whether the SIP client is behind a NAT device or not.
To see if a calls RTP streams have been routed to mediaproxy you can execute the Python script located at
/usr/local/mediaproxy/sessions.py (assuming you installed mediaproxy at that location.)
You can also install the web monitoring tool located at /usr/local/mediaproxy/web/ if you have an Apache web
server running on your SIP proxy. A screen shot of this web monitoring tool is available at http://www.ag-projects.
com/docs/MediaSessions.pdf
Handling of NAT using RTPproxy
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
RTPproxy is one of two NAT traversal solutions for SER, the other is mediaproxy just descussed in the previous
section. Both RTPproxy and mediaproxy are known as far-end NAT traversal solutions which means that they
handle 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 RTPproxy are:
1. Is called by nathelper, the most configurable NAT helper modules (mediaproxy module is the other one)
2. Can handle almost twice as many calls as mediaproxy on the same hardware
3. Developed in C and is thus easily extendable for most programmers
4. RTPproxy can be installed on a remote server which is not running SER
RTPproxy is a standalone software and is thus not a part of the sip_router CVS and distribution. However, it can
be found in the same CVS repository as SER (on the same level as sip_router). Just replace the sip_router directory
name with rtpproxy (or use the ONsip.org Getting Started source package). The SER distribution only includes
the glue which gives SER the ability to communicate with a running instance of RTPproxy. This glue is known
as the nathelper module.
NOTE: In order for RTPproxy to function properly it must be configured to listen on a public IP address. Also, in
most real world configurations, RTPproxy will not be installed on the SER server, but on a remote machine. Refer
to the appendix for information on installing rtpproxy.
debug=3
fork=yes
log_stderror=no
listen=192.0.2.13 # INSERT YOUR IP ADDRESS HERE
port=5060
children=4
if (!www_authorize("","subscriber")) {
www_challenge("","0");
break;
};
if (!check_to()) {
sl_send_reply("401", "Unauthorized");
break;
};
consume_credentials();
if (!save("location")) {
sl_reply_error();
};
}
route[3] {
# -----------------------------------------------------------------
# INVITE Message Handler
# -----------------------------------------------------------------
if (!proxy_authorize("","subscriber")) {
proxy_challenge("","0");
break;
} else if (!check_from()) {
sl_send_reply("403", "Use From=ID");
break;
};
consume_credentials();
if (nat_uac_test("19")) { 18
setflag(6);
}
lookup("aliases");
if (uri!=myself) {
route(4); 19
route(1);
break;
};
if (!lookup("location")) {
sl_send_reply("404", "User Not Found");
break;
};
route(4); 20
route(1); 21
}
22route[4] {
# -----------------------------------------------------------------
# NAT Traversal Section
# -----------------------------------------------------------------
if (isflagset(6)) {
force_rport();
fix_nated_contact();
force_rtp_proxy();
}
}
23onreply_route[1] {
if (isflagset(6) && status=~"(180)|(183)|2[0-9][0-9]") { 24
if (!search("^Content-Length:[ ]*0")) { 25
force_rtp_proxy();
};
};
26if (nat_uac_test("1")) {
fix_nated_contact();
};
}
RTPproxy Transparent NAT Traversal ser.cfg Analysis
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 described below.
4. Here we load the nathelper module. Nathelper has functionality for rewriting SIP messages. It also communicates
with rtpproxy, which is a standalone program. Make sure that you have rtpproxy started before you
start SER. It can be found in the same cvs repository as SER or you can use the SER package provided on
http://www.onsip.org/ under Downloads. Start rtpproxy without parameters and make sure it is running using
the 'ps -ax | grep rtpproxy' command. If SER cannot communicate with rtpproxy, you will get errors in
/var/log/messages when staring SER."
5. The textops module provide utility functions for manipulating text, searching for substrings, and checking
for the existence of specific header fields.
6. Unlike mediaproxy, rtpproxy does not have a built-in ping keep-alive capability (i.e. sending packets regularly
to the clients to make sure the NAT binding is kept in place and thus incoming SIP messages or RTP streams
can come in). However, this functionality is instead built into nathelper.
The natping_interval is a very crucial setting which controls how often our ser proxy will ping registered SIP
UAs. 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 UA 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 UAs 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.
7. Nathelper can ping all UAs or only the ones that have been flagged with a special nat flag (see further below).
We only need to ping NATed clients as we assume all other clients have public addresses and keep-alive is
not needed.
8. Ser and rtpproxy communicate via a standard Unix socket, with the default socket path specified here.
NOTE: If you change the socket path here, you must be sure to start rtpproxy with the parameter: s
unix:socketpath
9. You can also start rtpproxy with f to let it run without forking. It will then show you what is happening.
When SIP clients attempt to REGISTER with our SIP proxy we need a way to tell the registrar module to
store NAT information for the UA. We do this by using flag 6, which has been arbitrarily chosen (but defined
earlier in the moduel parameter section). We could have specified another integer here, but 6 has become the
accepted default for nat_flag.
10. When nat_flag is set before calling the save() function to store contact information, then ser will also 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.
When we decide that a particular call must be proxied through our proxy server, we must also ensure that
the call is torn down when a call is hung up (BYE) or cancelled (CANCEL).
11. 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. The
has_totag() function will return true if the SIP message has a To header field. If it has, the message be will
be in-dialog.
force_rtp_proxy() has an l (lookup) parameter. When this parameter is specified, rtpproxy will only proxy
the call if a session already exists. The reason for doing this is that rtpproxy cannot really know that this is
a re-INVITE and we want to avoid unnecessary proxying calls that do not need it. All re-INVITEs will call
force_rtp_proxy(l), but only existing proxied sessions will be re-proxied. We cannot put the force_rtp_proxy()
call inside the nat_uac_test check, as this will prevent proxying to happen if the re-INVITE is sent from a
non-NATed UA to a NATed UA (because nat_uac_test() will be false).
The other things we do here are: if NAT is detected for the UA sending the INVITE, set the NAT flag, so
we know this is a NATed call (setflag(6)), add the received port to top-most via header (force_rport), as well
as rewrite the Contact header with the public IP address of the user client (fix_nated_contact).
11. 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 rtpproxy if needed before sending the message to its destination.
12. 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.
14. Enable rtpproxy if needed before sending the message to its destination.
15. When dealing with NATed clients, we must correctly handle response messages that are destined 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.
16. If something goes wrong and we have called force_rtp_proxy (so that rtpproxy set up a new proxy call), we
need to tell rtpproxy to tear it down again using unforce_rtp_proxy().
17. When SIP clients attempt to REGISTER with our SIP proxy we need a way to tell the registrar module to
store NAT information this particular UA. We do this by using flag 6, which has been arbitrarily chosen (but
defined earlier in the module parameter section). We could have specified another integer here, but 6 seems
to be the accepted standard for nat_flag.
When nat_flag is set before calling the save() function to store contact information, then ser will also preserve
the NAT contact information as well as set the flags column in the MySQL location table. By doing so, we
can later call lookup(location) when processing messages and flag 6 will be set for NATed clients.
In order to determine whether a SIP client is NATed we use the nathelper function nat_uac_test(), which
accepts an integer as a parameter. This parameter specifies which part of the SIP message to examine for
determining the NAT status of the client. 19 indicates a common subset of tests, and are the recommended
tests.
NOTE: These are the tests you can run using nat_uac_test (in the order they are employed):
1. (16) Is received port (source port of the packet) different from the port specified in the top-most Via
header? (this can be used to detect some broken STUN implementations)
2. (2) Is the received IP address (source IP of the packet) different from the IP address in the top-most Via
header?
3. (1) Does the Contact header contain an RFC1918 address? RFC1918 addresses are 10.0.0.0/24,
172.16.0.0.0/20, and 192.168.0.0/16
4. (8) Does the SDP payload of an INVITE or OK message contain an RFC1918 address?
5. (4) Does the top-most Via header contain an RFC1918 address?
The numbers in paranthesis indicate the number to be used to invoke the test in nat_uac_test(). To invoke
more than one test, add up the numbers of the tests you want to run. So, as we use nat_uac_test(19) in our
script, it means that test #1 (16) + #2 (2) + #3 (1) = 19, are run.
WARNING: Before changing the tests, you should know what you are doing. You should scrutinize the SIP
message coming from your UAs to determine which tests will be true.
You will notice that we first call the search() function to find out if the Contact: header contains an Asterisk
or not. We only test for NAT if the Contact: header is not an Asterisk .
NOTE: If the header is an Asterisk rather than a SIP URI, then this indicates that the SIP client
is attempting to unregister with the SIP proxy. The ser save() function has special provisions to remove all
binds for the AOR in this case. It is important to understand that we cannot accurately determine the NAT
status of a client when the contact information is missing
18. We test to see if the user client is behind NAT, if so, we set the NAT flag (6). This flag is used further below.
19. Enable rtpproxy if needed before sending the message to its destination.
20. Enable rtpproxy if needed before sending the message to its destination.
21. Now that we have taken care of all the NAT related items, we can safely send the INVITE message to its
destination.
22. Route[4] is a convenience route to enable rtpproxy.
If a client is NATed, we must do the following things: Add the received (public) port to the top-most Via
header (force_rport), rewrite the Contact header with the public IP address and port of the NAT in front of
the user client (fix_nated_contact), and set up the proxying using force_rtp_proxy(). Nathelper will then
communicate to rtpproxy, which will allocate RTP (UDP) ports and the SDP payload of the INVITE will be
rewritting (see the introductory section on NATing for details).
23.Here we introduce a reply_route. A reply_route is defined just like any other block in ser. The only difference
is that it is called onreply_route.
Any message that is passed to this block will be returning to the original sender. You can think of these
messages as the response to the original request that the caller made. The types of messages that will appear
here will have an integer response code, much like HTTP response codes. Examples here would be 200, 401,
403, and 404.
24. In this ser.cfg we are only interested in response codes of 180, 183, and all 2xx messages for NATed clients.
We can check the status as shown with a regular expression. If any of these response codes are found then
this statement will be TRUE.
An important thing to note is that we can check flags set in the other route blocks because their scope is still
valid. So our caller and callee NAT flags are still accessible.
We can only call force_rtp_proxy() for SIP messages that have a valid contact parameter in the SDP payload.
So here we test to make sure the c= parameter is valid by simply checking the SDP payload length. We assume
that if we have an SDP payload then we will have a c= parameter and can call force_rtp_proxy ().
26. Before our reply_route processing is complete we have one more NAT test to try. Here we make sure the
Contact: header does not contain an RFC1918 IP address. If it does, then we replace it with the public IP
address and port of the NAT in front of the user client.
Chapter 9. PSTN Gateway Connectivity
What this ser.cfg does:
1. Adds the ability to connect to the PSTN for inbound and outbound calling
Up until now we have focused on SIP only calls, which means you could only send and receive calls between IP
phones on your SIP proxy. But most people will need to call regular land lines as well as receive calls from them.
This is accomplished by means of a PSTN Gateway. SER itself does not provide PSTN access. You must install
external equipment for this. A very popular and cost effective solution is a Cisco AS5300. The Cisco AS5300 is
a multi-function chassis which allows you to plug in many different feature cards. In order for the Cisco AS5300
to operate as a PSTN gateway you must have a T1/E1 interface board and a Voice Card. The T1/E1 card is used
to connect the AS5300 to the actual PSTN by means of a PRI from your local telephone company. The voice card
contains DSP (digital signal processing) chips that convert audio streams between the SIP world and the PSTN
world.
NOTE: Some users have asked how do I get a real telephone number for my SIP phone and the answer to that
question is to get a PSTN gateway. When your local telephone company installs your PRI they will be able to allocate
DIDs (direct inward dial, or telephone numbers) to you. You can then assign the DIDs as usernames in the
MySQL subscriber table and when the DID is called from the PSTN it will cause your PSTN gateway to generate
an INVITE message and send it to SER which will ring the SIP phone just like a normal SIP-to-SIP call.
When dealing with PSTN calls, you can actually think of the SIP client as one end of the call and the PSTN gateway
as the other end. Many people get confused on this minor detail because they fail to understand that the actual
PSTN gateway is indeed a SIP client itself.
In order to call a PSTN phone from your SIP phone SER receives the INVITE message as usual. If the R-URI
(request URI) is determined to be a PSTN number then SER changes the host IP of the R-URI to be that of the
PSTN gateway and then it relays the message to the PSTN gateway. After this, the call behaves just like a normal
SIP-to-SIP call.
When receiving a call from the PSTN, the PSTN gateway will send a new INVITE message to SER and it will be
processed just like any normal SIP-to-SIP call.
So now that you have a brief understanding of how SIP-to-PSTN and PSTN-to-SIP calling works, lets take a look
at the PSTN-enabled ser.cfg configuration file.
NOTE: This ser.cfg file does not take in to consideration user ACLs. This means that all registered user accounts
will have PSTN access. We will introduce ACL control in a future example.
debug=3
fork=yes
log_stderror=no
listen=192.0.2.13 # INSERT YOUR IP ADDRESS HERE
port=5060
children=4
# -----------------------------------------------------------------
# Sanity Check Section
# -----------------------------------------------------------------
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483", "Too Many Hops");
break;
};
if (msg:len > max_len) {
sl_send_reply("513", "Message Overflow");
break;
};
# -----------------------------------------------------------------
# Record Route Section
# -----------------------------------------------------------------
if (method=="INVITE" && client_nat_test("3")) {
# INSERT YOUR IP ADDRESS HERE
record_route_preset("192.0.2.13:5060;nat=yes");
} else if (method!="REGISTER") {
record_route();
};
# -----------------------------------------------------------------
# Call Tear Down Section
# -----------------------------------------------------------------
if (method=="BYE" || method=="CANCEL") {
end_media_session();
};
# -----------------------------------------------------------------
# Loose Route Section
# -----------------------------------------------------------------
if (loose_route()) {
if ((method=="INVITE" || method=="REFER") && !has_totag()) {
sl_send_reply("403", "Forbidden");
break;
};
if (method=="INVITE") {
if (!allow_trusted()) {
if (!proxy_authorize("","subscriber")) {
proxy_challenge("","0");
break;
} else if (!check_from()) {
sl_send_reply("403", "Use From=ID");
break;
};
consume_credentials();
};
if (client_nat_test("3")||search("^Route:.*;nat=yes")){
setflag(6);
use_media_proxy();
};
};
route(1);
break;
};
# -----------------------------------------------------------------
# Call Type Processing Section
# -----------------------------------------------------------------
if (!is_uri_host_local()) {
if (is_from_local() || allow_trusted()) {
route(4);11
route(1);
} else {
sl_send_reply("403", "Forbidden");12
};
break;13
};
if (method=="ACK") {
route(1);
break;
} if (method=="CANCEL") {
route(1);
break;
} else if (method=="INVITE") {
route(3);
break;
} else if (method=="REGISTER") {
route(2);
break;
};
lookup("aliases");
if (!is_uri_host_local()) { 14
route(4);
route(1);
break;
};
if (!lookup("location")) {
sl_send_reply("404", "User Not Found");
break;
};
route(1);
}
route[1] {
# -----------------------------------------------------------------
# Default Message Handler
# -----------------------------------------------------------------
t_on_reply("1");
if (!t_relay()) {
if (method=="INVITE" || method=="ACK") {
end_media_session();
};
sl_reply_error();
};
}
route[2] {
# -----------------------------------------------------------------
# REGISTER Message Handler
# -----------------------------------------------------------------
sl_send_reply("100", "Trying");
if (!search("^Contact:[ ]*\*") && client_nat_test("7")) {
setflag(6);
fix_nated_register();
force_rport();
};
if (!www_authorize("","subscriber")) {
www_challenge("","0");
break;
};
if (!check_to()) {
sl_send_reply("401", "Unauthorized");
break;
};
consume_credentials();
if (!save("location")) {
sl_reply_error();
};
}
route[3] {
# -----------------------------------------------------------------
# INVITE Message Handler
# -----------------------------------------------------------------
if (client_nat_test("3")) {
setflag(7);
force_rport();
fix_nated_contact();
};
if (!allow_trusted()) { 15
if (!proxy_authorize("","subscriber")) {
proxy_challenge("","0");
break;
} else if (!check_from()) {
sl_send_reply("403", "Use From=ID");
break;
};
consume_credentials();
};
if (uri=~"^sip:1[0-9]{10}@") { 16
strip(1);
};
lookup("aliases");
if (!is_uri_host_local()) { 17
route(4);
route(1);
break;
};
if (uri=~"^sip:011[0-9]*@") { # International PSTN 18
route(4);
route(5);
break;
};
if (!lookup("location")) {
if (uri=~"^sip:[0-9]{10}@") { # Domestic PSTN 19
route(4);
route(5);
break;
};
sl_send_reply("404", "User Not Found");
break;
};
route(4);
route(1);
}
route[4] {
# -----------------------------------------------------------------
# NAT Traversal Section
# -----------------------------------------------------------------
if (isflagset(6) || isflagset(7)) {
if (!isflagset(8)) {
setflag(8);
use_media_proxy();
};
};
}
20route[5] {
# -----------------------------------------------------------------
# PSTN Handler
# -----------------------------------------------------------------
rewritehost("192.0.2.245");21 # INSERT YOUR PSTN GATEWAY IP ADDRESS
avp_write("i:45", "inv_timeout");22
route(1);
}
onreply_route[1] {
if ((isflagset(6) || isflagset(7)) &&
(status=~"(180)|(183)|2[0-9][0-9]")) {
if (!search("^Content-Length:[ ]*0")) {
use_media_proxy();
};
};
if (client_nat_test("1")) {
fix_nated_contact();
};
}
PSTN Gateway Connectivity ser.cfg Analysis
1. The avpops module is a very power library for manipulating SIP message headers, storing temporary or
persistent message data, and comparing data items. Avpops is also used to dynamically alter certain parts of
SER itself. We use avpops in this example to dynamically change the amount of time SER will wait for an
INVITE message to be forwarded to its destination.
The reason we need to do this is that a SIP-to-SIP call generally connects much faster than a SIP-to-PSTN
call. Therefore we will allow SER to wait a while longer when calling a PSTN telephone
2. The permissions module gives SER access to the trusted MySQL table. The trusted table is acts as a repository
of privileged devices. We must add our PSTN gateway device to the trusted table to prevent SER from
challenging the PSTN gateway for authentication credentials.
3. The permissions module needs to access MySQL so we add it to the db_url parameter list.
4. The default INVITE timer will be allowed 27 seconds to connect. If we are going to call a PSTN destination
then we will set the inv_timeout AVP to a higher value in order to allow additional time for the call to connect.
This is show in the PSTN route handler.
5. The permissions module needs to know that it should connect to the MySQL database to find its data.
6. The trusted_table parameter informs the permissions module as to which MySQL table it will read from. In
this case the table called trusted will be used.
7. Now that we can receive INVITE messages from registered SIP clients as well as our PSTN gateway, we
need to challenge INVITE messages in a more specialized fashion. The allow_trusted() function is provided
by the permissions module. It will access the MySQL table called "trusted" to get a list of privileged IP addresses.
When the PSTN gateway sends an INVITE to SER, the allow_trusted() should return TRUE to
prevent SER from replying with a 401 Unauthorized message.
As a general rule, the PSTN gateway should always be allowed to send messages to SER without being
challenged for credentials, however, all INVITE messages being sent to the PSTN gateway should be challenged
to prevent toll fraud for which the PSTN gateway owner is responsible for.
NOTE: It is very important to understand the significance of using proxy_authorize() and allow_trusted() in
the loose_route() code block. A re-INVITE should only be processed by SER if it originated from a SIP client
that can be authenticated or trusted by SER. Authentication is verified with the call to proxy_authorize(),
which will check the MySQL subscriber table whereas trust relationships are tested with the call to allow_trusted(),
which will check the MySQL trusted table. A PSTN gateway which cannot authenticate against SER
must be added to the MySQL trusted table, otherwise re-INVITE and REFER messages from the PSTN
gateway will not be routed by SER.
8. Our previous configuration files had a potential open relay problem where by SIP messages targeted at a
domain that is not locally served could be relayed without being challenged. This was exposed in the following
code
if (uri!=myself) {
route(4);
route(1);
break;
};
9. Now that our SIP proxy has PSTN access we need to close this potential open relay to prevent toll fraud.
In previous ser.cfg examples we used the test condition (uri != myself) to determine if the SIP message was
directed at our SIP router or not. From this point forward will will replace this test condition with a call to
is_uri_host_local(). which will determine if the domain portion of the Request URI is a domain that our SIP
proxy is responsible for. It does so by querying the MySQL table called domain. In order for this function
to return TRUE for messages that our SIP proxy is responsible for, we must add our domain to the MySQL
domain table. If your SIP proxy handles multiple domains, then you must add all domains to this table.
10. NOTE: The is_uri_host_local() function is exposed in the domain.so module.
If the SIP message is not targeted at our domain, we must now check to see if the message sender belongs
to our domain. We should only forward messages to external domains if the message sender belongs to our
domain.
The is_from_local() function will query the MySQL domain table for the host name that appears in the
From: header of the SIP message.
NOTE: The is_from_local() function is exposed in the domain.so module.
Another thing that we must allow is messages from our PSTN gateway. Since our PSTN gateway is a trusted
device, it must be allowed to forward messages to external domains. This is accomplished with the call to
allow_trusted().
11. If the message is permitted to leave our SIP proxy then we must take care of NAT traversal prior to relaying
the message.
12. If the message is not permitted to leave our SIP proxy then we reply with a 403 message to inform the message
sender that we are not an open relay.
13. Now that we have handled the message we simply stop processing.
14. Determine if the domain portion of the Request URI is a domain that our SIP proxy is responsible for.
15. INVITE message must be challenged for credentials here just as they were in the loose_route() section of
the main route code block.
NOTE: It is important to understand that INVITE messages can potentially pass through the SIP router in
either route[3] or in the loose_route() section of the main route. Generally, original INVITE messages will
be passed to route[3], whereas re-INVITE messages will get picked up by the loose_route() function.
Therefore it is very important to secure both sections with the appropriate calls as demonstrated here.
NOTE: Failure to properly secure your SIP route could result in toll charges that you are responsible for,
assuming your SIP router has access to the PSTN.
16. Many PSTN gateways do need or permit long distance prefixes when dialing. In North America we dial 1 +
a 10-digit number to place a call outside of our local calling area. So we remove the leading 1 from the RURI
before sending the message to the PSTN gateway.
17. Determine if the domain portion of the Request URI is a domain that our SIP proxy is responsible for.
18. This ser.cfg assumes that international numbers are prefixed with 011 and that domestic numbers are 10 numeric
digits.
Here we use regular expression matching to check the R-URI. If it starts with 011 and is followed by numeric
digits only, then we have a match for an international PSTN destination. If a match is found then we route
the message to the PSTN handler, route[4].
19. If the R-URI match 10 numeric digits then we know we have a domestic number and we route the INVITE
message to the PSTN hander, route[4].
NOTE: We know we have a PSTN number at this point because the call to lookup(location) on the previous
line returned FALSE.
20. Here we introduce route block 5 for handling PSTN destinations.
21. Rewritehost() is used to alter the R-URI so that the message will be relayed to our PSTN gateway. You must
pass the IP address of your PSTN gateway to this function. SER will then send the INVITE message to your
PSTN gateway properly when you call t_relay().
22. Avp_write() alters the amount of time allowed for a PSTN call to connect. If you recall we specified
inv_timeout as the loadparam value for fr_inv_timeout.
This line specifies that we want to allow 45 seconds before timing out.
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