SIP User Credentials in the ITSP environment – part 2

In part 1 of this article we reviewed the basic entities and concepts used to identify a user, a handset or service. It discussed in detail how these entities are used to register devices, either simple single-line devices or SIP trunks.

Now, in part 2, we will examine in more detail the handling of inbound calls, particularly in the context of using OpenSIPS as an ITSP front end server. Part 3 will look at handling of outbound calls.

Inbound calls and DID

We refer to calls arriving from the public telephone network as “inbound”. The alternative, an “outbound” call, is one that the end-user makes from their phone to a remote destination.

The term “DID” (or “DDI” in the UK) is widely used to describe the numbers that can be purchased from various Telecoms service providers. DID stands for Direct Inward Dialling. Once purchased by a business, these DID numbers can be published on a web site or printed on business stationery or advertising material. Anyone can then call the published number and their call is routed to a receptionist, a department or an individual. Typically, an individual’s DID would be printed on their business cards.

What must the ITSP do to correctly handle inbound calls?

The ITSP’s SIP Proxy must inspect the DID on each inbound call and identify the correct registered device. It then relays an INVITE request to that registered device, also ensuring that the request contains all required data in a valid format. Where the registered device is an IP-PBX using a SIP trunk, this is something of a challenge. However, first let us consider a simpler case.

Remember the diagram of the typical ITSP setup in part 1? In figure 5 here, the diagram is modified to show how an inbound call is routed to a simple IP phone (identified as Hosted account B):

Inbound DID Call route via ITSP SIP Proxy

Figure 5

Explanation of figure 5: The inbound call is shown arriving from the Public Switched Telephone Network (PSTN) via a direct connection to a carrier (or perhaps via a gateway). The SIP Proxy server can see what number was dialled (i.e. which DID was used), but then it must interpret the DID information, using mappings or lookups, to select the correct registered device from its list of known devices or location table. Once selected, the request is sent to that device.

The significance of the Request URI

In SIP, a call is initiated using an INVITE request. The destination (or dialled number) is sent in the INVITE in a field called the “Request URI”, or R-URI for short. The R-URI is one of the most important fields in a SIP request (far more important than the To header). SIP Proxy servers examine the R-URI to decide on the most appropriate way to manage and route each call. The SIP Proxy server may subsequently add prefixes, make adjustments or completely replace the R-URI before relaying the INVITE request to the next destination in the network path.

Mapping the DID to the User ID for the registered device

The R-URI for any inbound call arriving at the SIP Proxy server will almost always contain the dialled number or DID. To ensure each call reaches the correct device, the SIP Proxy server must be able to look up mappings between the DID number and the SIP User ID of the registered device. It can then find a record for that User ID in its location table

Simple routing model for inbound calls to an ITSP SIP Proxy

Figure 6

The actual mechanism used to map DID’s to User ID’s is not set in stone. It could be based on a simple algorithmic relationship. Here are some examples:

  • The SIP User ID and the DID could be identical.
  • The SIP User ID could be the last 6 digits of the DID.
  • The SIP User ID could be a constant prefix followed by the last 5 digits of the DID

Simple algorithmic translations are most appropriate when routing inbound calls to single-line devices requiring a simple one-to-one relationship between DID and SIP User ID. However, algorithmic translations are unlikely to be suitable for routing over SIP trunks to an IP-PBX because one IP-PBX may be responsible for handling many different DID numbers.

An alternative to the algorithmic mechanism is the use of a database table for mapping DID numbers to their corresponding SIP User ID. This could be generically termed an “alias table”. It offers the best solution when there is a “many-to-one” relationship of DID’s to SIP User ID.

A popular solution in OpenSIPS is to use the dbaliases table (part of the alias_db module). Here is a sample snippet of OpenSIPS code for performing simple alias table lookups. It would need to be inserted within your block of code that handles INVITE requests received from a carrier or gateway:

# Lookup destination based on dialled number
if (!alias_db_lookup("dbaliases", "d")) {
  xlog("L_INFO", " Inbound call: R-URI=$ru  DID Not found in dbaliases\n");
} else {
  xlog("L_INFO", " Inbound call: DID found in dbaliases.  Account ID is $rU\n");
};

The function alias_db_lookup performs a table-based lookup using the R-URI from the current SIP request which it attempts to match against a value stored in the ‘alias_username’ field of the dbaliases table. If a match is found the function returns True and the current request’s R-URI is overwritten with the value from the ‘username’ and ‘domain’ fields in the dbaliases table.

The “d” specified in the second argument of the function is optional – it tells the function to ignore the sip domain when it is searching the table for a match. It is simpler to ignore sip domains, but in some circumstances (e.g. multi-tenant solutions) you may wish to maintain alias tables where both the username and the sip domain are considered significant and both must match.

Please note, the above code can only work if the alias_db module is loaded.

Finding the registered device’s location from its SIP User ID

Once the SIP User ID is known, the network address of the destination IP device can be found from a lookup (or query) of the location table. After that has been done, the INVITE request can then be relayed to the destination address found in the location table.

Here is the sample snippet of code expanded to include a lookup from the location table:

# Lookup destination based on dialled number
if (!alias_db_lookup("dbaliases", "d")) {
  xlog("L_INFO", " Inbound call: R-URI=$ru  DID Not found in dbaliases\n");
} else {
  xlog("L_INFO", " Inbound call: DID found in dbaliases.  Account ID is $rU\n");
};

if (lookup("location"))
  # User is registered
  xlog("L_INFO", "    R-URI=$ru  Location=$du  User is registered\n");
  route(1);
} else {
  xlog("L_INFO", "    R-URI=$ru  Destination not registered\n");
  t_reply("404", "Not Found");
};

Note: SIP INVITE’s sent to a simple end-user device, such as an IP-phone or ATA, will be rejected if the username in the Request-URI does not match the device’s Contact URI. The Contact URI is sent during registration and is almost always based on the SIP User ID, although it may also contain special tag values (e.g. to identify a specific line in a multi-line device). The code shown above works because the alias_db_lookup() function converts DID to SIP User ID and then the lookup() function converts SIP User ID to Contact URI. The Contact URI is stored in the ‘contact’ field in the location table. If the address of the registered device is not the same as the one in the Contact URI, then the network address for the registered device will be stored in the ‘received’ field.

Figure 7 illustrates how the above OpenSIPS code would process an inbound call:

OpenSIPS SIP Proxy inbound call handling using dbaliases table

Figure 7

Adjusting OpenSIPS for inbound calls to SIP Trunks

We mentioned before that the ITSP’s SIP Proxy must inspect the DID on each inbound call and identify the correct registered device so it can relay an INVITE request to that device. But what if the registered device is an IP-PBX at the customer’s premises connected through a SIP Trunk? In this case there may be many DID’s which are all associated with the same SIP Trunk. In other words, there can be a many-to-one relationship between DID and SIP User ID. (It is theoretically possible for an IP-PBX to register once per DID, but in practice it is normal to only have one registration – and therefore one registered SIP User ID – at the ITSP’s Proxy server).

OpenSIPS must now map DID’s to User ID’s like this (figure 8):

OpenSIPS SIP Proxy sending inbound DID's to a SIP Trunk

Figure 8

In fact, the opensips.cfg code that deals with inbound calls to simple devices needs no adjustments to allow it to work with this type of many-to-one relationship. This is because the dbaliases table only requires uniqueness in the alias_idx index and it is quite acceptable to have duplicate values in the ‘username’ field. However, the story does not end here. While it is possible to use the sample code shown earlier in this article, in its current form it is not very convenient because every INVITE request sent to the customer premises IP-PBX will now use the same R-URI irrespective of the DID number called. The IP-PBX works much better when the R-URI contains the original DID username.

This more sophisticated requirement with SIP Trunks is best illustrated using an example:

Inbound DID Call route via ITSP SIP Proxy and SIP Trunk

Figure 9

Referring to the diagram above, an inbound call from the public telephone network (using a specific DID) is required to ring a particular handset, extension 201, on IP-PBX 1. Other DID’s would be linked to different extensions or to ring groups or possibly an IVR acting as an automated-attendant.

Bear in mind that the handsets would register directly with the IP-PBX which, in turn, has registered a SIP trunk connection over the Internet to the ITSP’s Proxy server. (To complicate matters further, the mapping of DID’s to handsets for inbound calls may not be the same as the mapping of handsets to Caller ID for outbound calls, but more on that in part 3).

The IP-PBX therefore has configuration facilities to allow it to map a received R-URI to a specific extension, ring group or automated service. On FreePBX, these configuration facilities are found under the heading “Inbound Routes”.

The challenge for OpenSIPS is therefore to send the INVITE to the correct IP-PBX, but to retain the original DID number in the R-URI. The following code snippet shows how a script variable can be used to store the original DID number, which is then restored once the address and SIP domain have been found using alias and location table lookups:

# Remember the DID number
$var(DID) = $rU;

# Lookup destination based on dialled number
if (!alias_db_lookup("dbaliases", "d")) {
  xlog("L_INFO", " Inbound call: R-URI=$ru  DID Not found in dbaliases\n");
} else {
  xlog("L_INFO", " Inbound call: DID found in dbaliases.  Account ID is $rU\n");
};

if (lookup("location")) {
  # User is registered. Overwrite the username part of the R-URI with the DID
  $rU = $var(DID);
  xlog("L_INFO", "    R-URI=$ru  Location=$du  User is registered\n");
  route(1);
} else {
  xlog("L_INFO", "    R-URI=$ru  Destination not registered\n");
  t_reply("404", "Not Found");
};

Using the above code allows the INVITE request to be sent to the IP-PBX at the customer’s premises with the original DID number still present in the R-URI. If the IP-PBX is an Asterisk box running FreePBX (or a variant thereof) then it is now very easy for the customer to configure any number of inbound routes based on DID. It keeps things simple for the ITSP who is able to provision a new SIP Trunk by allocating a block of DID’s, providing a single set of registration credentials to the customer and adding the DID-to-User-ID mappings into the dbaliases table.

Summing up

This part of the article has taken you through a detailed explanation of inbound call handling in the ITSP’s Proxy server. By providing quite lengthy explanations at each step, it should be useful both as an OpenSIPS beginners’ tutorial and a reference for more experienced coders.

As usual, feedback is welcome using the coloured voting buttons below or leave a comment. Part 3 covers the topic of outbound call handling, looking especially at ways to cater for situations where the Caller ID does not match the SIP User ID or Auth ID.

1 thought on “SIP User Credentials in the ITSP environment – part 2”

Comments are closed.