
UID Domain Module

Juha Heinanen

   <jh@tutpro.com>

   Copyright © 2002-2010 Juha Heinanen
     _________________________________________________________________

   Table of Contents

   1. Admin Guide

        1. Overview

              1.1. Virtual Domains
              1.2. Domain-level Configuration Attributes
              1.3. Caching

        2. Dependencies
        3. Known Limitations
        4. Parameters

              4.1. db_url (string)
              4.2. db_mode (integer)
              4.3. domain_table (string)
              4.4. did_col (string)
              4.5. domain_col (string)
              4.6. flags_col (string)
              4.7. domattr_table (string)
              4.8. domattr_did (string)
              4.9. domattr_name (string)
              4.10. domattr_type (string)
              4.11. domattr_value (string)
              4.12. domattr_flags (string)
              4.13. load_domain_attrs (integer)

        5. Functions

              5.1. is_local(domain)
              5.2. lookup_domain(attr_group, domain)

        6. FIFO Interface

              6.1. domain.reload
              6.2. domain.dump

        7. Internal API

   List of Examples

   1.1. Virtual Domain iptel.org
   1.2. Database Representation of Virtual Domain
   1.3. Table domain_attrs
   1.4. Setting db_url parameter
   1.5. Setting db_mode parameter
   1.6. Setting domain_table parameter
   1.7. Setting did_col parameter
   1.8. Setting domain_col parameter
   1.9. Setting flags_col parameter
   1.10. Setting domattrs_table parameter
   1.11. Setting domattrs_did parameter
   1.12. Setting domattrs_name parameter
   1.13. Setting domattrs_type parameter
   1.14. Setting domattrs_value parameter
   1.15. Setting domattrs_flags parameter
   1.16. Setting load_domain_attrs parameter
   1.17. is_uri_host_local_local usage
   1.18. lookup_domain usage
   1.19. Calling load_domain_api

Chapter 1. Admin Guide

   Table of Contents

   1. Overview

        1.1. Virtual Domains
        1.2. Domain-level Configuration Attributes
        1.3. Caching

   2. Dependencies
   3. Known Limitations
   4. Parameters

        4.1. db_url (string)
        4.2. db_mode (integer)
        4.3. domain_table (string)
        4.4. did_col (string)
        4.5. domain_col (string)
        4.6. flags_col (string)
        4.7. domattr_table (string)
        4.8. domattr_did (string)
        4.9. domattr_name (string)
        4.10. domattr_type (string)
        4.11. domattr_value (string)
        4.12. domattr_flags (string)
        4.13. load_domain_attrs (integer)

   5. Functions

        5.1. is_local(domain)
        5.2. lookup_domain(attr_group, domain)

   6. FIFO Interface

        6.1. domain.reload
        6.2. domain.dump

   7. Internal API

1. Overview

   1.1. Virtual Domains
   1.2. Domain-level Configuration Attributes
   1.3. Caching

   Domain  modules, as the name suggests, implements support for multiple
   independent  virtual  domains  hosted on one SIP server. This is often
   useful if you have multiple domain names and you want to make them all
   work and appear as one. Alternatively you might find the module useful
   if  you  want  to  run  a  shared SIP service for multiple independent
   customers.  The  module  stores  all  supported domains and associated
   configuration  in  a  database  table.  Most of the information can be
   cached in memory for performance reasons.

1.1. Virtual Domains

   The  domain  module  adds  support  for  so-called  virtual domains. A
   virtual  domain  is  just  a collection of domain names and associated
   configuration  information identified by a unique identifier. We refer
   to  the  domain  identifier as DID elsewhere in the documentation. DID
   stands for "Domain IDentifier". In traditional POST world the term DID
   has a different meaning though. Please be aware that this is just pure
   coincidence.

   All   domain   names   that   belong   to   one   virtual  domain  are
   interchangeable.  From SIP server's perspective there is no difference
   between  them.  They  can  be used in SIP URIs interchangeably and the
   behavior  of  the  SIP  server  will  not  be affected. This is called
   "domain name normalization" and it is one of the steps performed early
   during SIP message processing.

   The  DID  identifier  can be anything. To the SIP server DIDs are just
   opaque strings and what format you choose depends on your requirements
   and  the  type  of the setup. You can use numbers in smaller setups if
   the  size  of  the  data  is  a  concern.  You  can set the DID to the
   canonical  domain name of the domain. You can use RFC 4122 style UUIDs
   if  your  setup is large and distributed. You can use anything as long
   as  it  can be represented as string. The only requirement is that the
   identifier of each virtual domain must be unique.

   The  following  example  illustrates  how  one  virtual  domain can be
   represented. The iptel.org domain runs a public SIP service. The users
   of  the  service  can use SIP URIs of form sip:username@iptel.org. The
   SIP  service is distributed, there is a number of SIP servers. The SIP
   servers  are  also  available  through a number of other domain names,
   such  as  sip.iptel.org,  proxy.iptel.org  and  so  on. We created one
   virtual domain in the domain module and added all such domain names to
   the virtual domain:

   Example 1.1. Virtual Domain iptel.org
iptel
  |
  +---iptel.org
  +---sip.iptel.org
  +---proxy.iptel.org
  +---213.192.59.75

   In  the  example  above, we chose "iptel" as the unique identifier for
   the  virtual  domain.  This identifier is permanent. It never changes.
   Over  time we may change domain names assigned to this virtual domain,
   but  this identifier never changes. The main reason why virtual domain
   identifiers must never change is that because they are referenced from
   other  tables,  for  example  the  accounting  table.  The data in the
   accounting  table  is  long-lived,  usually archived, and this ensures
   that  the  data will still reference correct virtual domain, no matter
   what domain names are assigned to it.

   The  virtual domain described above will be stored in the domain table
   in the database:

   Example 1.2. Database Representation of Virtual Domain
+-------+-----------------+-------+
| did   | domain          | flags |
+-------+-----------------+-------+
| iptel | iptel.org       |    33 |
| iptel | sip.iptel.org   |    33 |
| iptel | proxy.iptel.org |    33 |
| iptel | 213.192.59.75   |    33 |
+-------+-----------------+-------+

   Because  all domain names that belong to one particular virtual domain
   are  equal,  it  does not matter which domain name is used in the host
   part  of  the  SIP  URI.  Thus  an  imaginary  user  joe  with SIP URI
   sip:joe@iptel.org  will  also  be  reachable as sip:joe@sip.iptel.org,
   sip:joe@proxy.iptel.org,  and  sip:joe@213.192.59.75.  If we add a new
   domain  name  to this virtual domain then joe will also be able to use
   the  new  domain  name  in  his  SIP  URI,  without the need to change
   anything.

1.2. Domain-level Configuration Attributes

   In  addition to a number of domain names, each virtual domain can also
   have   extra   configuration   information  associated  with  it.  The
   possibility  to  configure  the SIP server sightly differently in each
   virtual  domain  is,  in  fact,  the main reason why we introduced the
   concept  of  virtual  domains.  We wanted to have one SIP server which
   will  provide  SIP service to multiple different customers and each of
   the  customers may have slightly different configuration requirements.
   That's how domain-level configuration attributes were born.

   Because the administrator of the SIP server seldom knows configuration
   requirements  in  advance,  we decided to implement a generic solution
   and  store  all  configuration  options  in  named  attributes.  Named
   attributes  are  just like variables, they have a name and they have a
   value.  Attributes are accessible from the configuration script of the
   SIP server. Domain-level attributes are attributes that are associated
   with a particular virtual domain. They can be used to store additional
   configuration  for  the  entire virtual domain, that is all users that
   belong   (or   have  SIP  URI)  in  that  particular  virtual  domain.
   Domain-level  attributes  can  be  overridden be user-level attributes
   with  the same name configured for a particular user. In other words a
   domain  level  attribute  will  only  be  effective  if  no user-level
   attribute with the same name exists.

   Domain-level  attributes  are  stored in a separate table. The name of
   the table is domain_attrs and it is defined as follows:

   Example 1.3. Table domain_attrs
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| did   | varchar(64)      | YES  | MUL | NULL    |       |
| name  | varchar(32)      | NO   |     | NULL    |       |
| type  | int(11)          | NO   |     | 0       |       |
| value | varchar(255)     | YES  |     | NULL    |       |
| flags | int(10) unsigned | NO   |     | 0       |       |
+-------+------------------+------+-----+---------+-------+

   Each  attribute  has name, type and value. A single attribute can have
   multiple  values  and  in  that  case  it will occupy more rows in the
   table.  Each  attribute is associated with a particular virtual domain
   using  the  DID  identifier.  Domain-level attributes can contain just
   about  anything.  It is a generic configuration mechanism and it is up
   to you to define a list of attribute that are meaningful in your setup
   and  use  those  attributes  in  the routing part of the configuration
   file.

   Attributes  for  a  particular  virtual-domain  are  made available to
   script  function  by  the lookup_domain function. This is the function
   that  is  used to map domain names to DIDs. One of the side-effects of
   the  function  is  that  it makes domain-level attributes available to
   script function if a matching virtual domain is found.

   When  caching  is  enabled, all attributes from domain_attrs table are
   cached  in memory, just like virtual domain themselves. If you disable
   caching  then  the  domain module will attempt to load attributes from
   the  database  each  time you call lookup_domain. Attributes cached in
   memory can be realoaded with the domain.reload management function.

1.3. Caching

   Domain  module  operates  in  caching or non-caching mode depending on
   value of module parameter db_mode. In caching mode domain module reads
   the  contents  of  domain  table  into cache memory when the module is
   loaded.  After  that domain table is re-read only when module is given
   domain_reload  fifo  command. Any changes in domain table must thus be
   followed  by  domain_reload command in order to reflect them in module
   behavior.  In  non-caching  mode  domain  module always queries domain
   table in the database.

   Caching  is implemented using a hash table. The size of the hash table
   is  given  by HASH_SIZE constant defined in domain_mod.h. Its "factory
   default"  value is 128. Caching mode is highly recommended if you want
   to use domain-level attributes.

2. Dependencies

   The  module  depends  on the following modules (in the other words the
   listed modules must be loaded before this module):
     * database - Any database module

3. Known Limitations

   There  is  an  unlikely  race  condition  on  domain list update. If a
   process uses a table, which is reloaded at the same time twice through
   FIFO, the second reload will delete the original table still in use by
   the process.

4. Parameters

   4.1. db_url (string)
   4.2. db_mode (integer)
   4.3. domain_table (string)
   4.4. did_col (string)
   4.5. domain_col (string)
   4.6. flags_col (string)
   4.7. domattr_table (string)
   4.8. domattr_did (string)
   4.9. domattr_name (string)
   4.10. domattr_type (string)
   4.11. domattr_value (string)
   4.12. domattr_flags (string)
   4.13. load_domain_attrs (integer)

4.1. db_url (string)

   This is URL of the database to be used.

   Default value is "mysql://serro:47serro11@localhost/ser"

   Example 1.4. Setting db_url parameter
modparam("domain", "db_url", "mysql://ser:pass@db_host/ser")

4.2. db_mode (integer)

   Database  mode. Value 0 means non-caching, 1 means caching is enabled.
   It  is  highly  recommended  to  enable  caching  if  you  want to use
   domain-level attributes.

   Default value is 1 (caching).

   Example 1.5. Setting db_mode parameter
modparam("domain", "db_mode", 0)   # Do not use caching

4.3. domain_table (string)

   Name  of  table  containing  names  of local domains that the proxy is
   responsible  for.  Local  users must have in their SIP URI a host part
   that is equal to one of the domains stored in this table.

   Default value is "domain".

   Example 1.6. Setting domain_table parameter
modparam("domain", "domain_table", "new_name")

4.4. did_col (string)

   This  is  the  name  of  the  column in domain table that contains the
   unique  identifiers  of  virtual  domains. Domains names found in this
   table are arranged into virtual domains. Each virtual domain must have
   a unique identifier and it can contain one or more domain names.

   Default value is "did".

   Example 1.7. Setting did_col parameter
modparam("domain", "did_col", "did")

4.5. domain_col (string)

   Name of column containing domain names in the domain table.

   Default value is "domain".

   Example 1.8. Setting domain_col parameter
modparam("domain", "domain_col", "domain")

4.6. flags_col (string)

   This  is  the  name of the column in domain table which stores various
   flags.  Each row in the table has a bunch of generic flags that can be
   used  mark  the  row  disabled, deleted, etc. The flags allow for more
   flexible  administration  of  the  data  in  the database and they are
   present in several other tables too.

   Default value is "flags".

   Example 1.9. Setting flags_col parameter
modparam("domain", "flags_col", "domain")

4.7. domattr_table (string)

   This  parameter can be used to configure the name of the table that is
   used  to  store  domain-level  attributes. Domain level attributes are
   attributes  that are associated with a particular virtual domain. They
   are  typically  used  to  store  additional  domain-wide settings that
   should apply to all users who belong to the domain.

   Default value is "domain_attrs".

   Example 1.10. Setting domattrs_table parameter
modparam("domain", "domattr_table", "domain_attrs")

4.8. domattr_did (string)

   Use this parameter to configure the name of the column in domain_attrs
   table  that  is  used  to  store  the  did  of  the virtual domain the
   attribute  belongs  to.  Normally  there  is no need to configure this
   parameter,  unless  you  want  adapt to module to a different database
   schema.

   Default value is "did".

   Example 1.11. Setting domattrs_did parameter
modparam("domain", "domattr_did", "did")

4.9. domattr_name (string)

   Use this parameter to configure the name of the column in domain_attrs
   table  that is used to store the name of the attribute. Normally there
   is  no  need  to  configure  this  parameter, unless you want adapt to
   module to a different database schema.

   Default value is "name".

   Example 1.12. Setting domattrs_name parameter
modparam("domain", "domattr_name", "name")

4.10. domattr_type (string)

   Use this parameter to configure the name of the column in domain_attrs
   table  that is used to store the type of the attribute. Normally there
   is  no  need  to  configure  this  parameter, unless you want adapt to
   module to a different database schema.

   Default value is "type".

   Example 1.13. Setting domattrs_type parameter
modparam("domain", "domattr_type", "type")

4.11. domattr_value (string)

   Use this parameter to configure the name of the column in domain_attrs
   table that is used to store the value of the attribute. Normally there
   is  no  need  to  configure  this  parameter, unless you want adapt to
   module to a different database schema.

   Default value is "value".

   Example 1.14. Setting domattrs_value parameter
modparam("domain", "domattr_value", "value")

4.12. domattr_flags (string)

   This  is  the  name  of  the column in domain_attrs table which stores
   various flags. Each row in the table has a bunch of generic flags that
   can  be  used mark the row disabled, deleted, etc. The flags allow for
   more  flexible administration of the data in the database and they are
   present  in  several  other  tables too. You do not have to touch this
   parameter under normal circumstances.

   Default value is "flags".

   Example 1.15. Setting domattrs_flags parameter
modparam("domain", "domattr_flags", "flags")

4.13. load_domain_attrs (integer)

   This  parameter  can  be  used  to enable/disable user of domain-level
   attributes.  Domain-level attributes are variables that can be used to
   store  additional  configuration  that  applies  to  the whole virtual
   domain   and   all  users  within  the  virtual  domain.  Domain-level
   attributes  are stored in domain_attrs. If you set this parameter to a
   non-zero  value  then  the  server  will  make domain-level attributes
   available to the script every time you call function lookup_domain. If
   you  set  the  parameter  to  0  then  domain-level attributes will be
   ignored,  the  domain  module will not load them from the database and
   the lookup function will not make them available to the script.

   Default value is 0.

   Example 1.16. Setting load_domain_attrs parameter
modparam("domain", "load_domain_attrs", 1)

5. Functions

   5.1. is_local(domain)
   5.2. lookup_domain(attr_group, domain)

5.1. is_local(domain)

   This  function  can  be  used  to  test whether a given domain name in
   parameter  belongs to one of the virtual domains defined in the domain
   table. Such domain name is said to be local. The function returns 1 if
   the domain name is found in the domain table and -1 otherwise.

   The  first  parameter  of  the function can be anything that returns a
   string  with domain name. In its simplest form it can be a string with
   domain  name:  is_local("iptel.org").  You can also test a domain name
   stored  in  an  attribute: is_local("$my_domain"). And finally you can
   test   a  domain  name  present  in  the  SIP  message  with  selects:
   is_local("@ruri.host").

   Note:  Unlike  function  lookup_domain,  this  function  does not make
   domain  attributes  of  the  virtual  domain  available to the script.
   Domain attributes are simply ignored by this function.

   Example 1.17. is_uri_host_local_local usage
...
if (is_local("@ruri.host")) {
    /* Domain part of Request-URI is local */
}
...

5.2. lookup_domain(attr_group, domain)

   This  is  the  main  function  of the domain module. It can be used to
   implement  support for virtual domains in the SIP server. Each virtual
   domain is identified by a unique identifier (opaque string) and it can
   have  one  or more associated domain names. Given a domain name in the
   second  parameter,  this  function finds the associated virtual domain
   identifier  (known  as  DID)  and  stores it in an attribute for later
   user.  In  addition  to  that the function also loads all domain-level
   attributes  for  the  virtual  domain  and makes them available to the
   configuration script.

   The first parameter of the function identifies the group of attributes
   where  the  DID and domain-level attributes shall be stored. The value
   of  the  first  parameter  can  be  either  "$fd" for the domain-level
   attribute group that belongs to the calling party (From), or "$td" for
   the  domain-level  attribute  group  that  belongs to the called party
   (Request-URI).

   The value of the second parameter can be a simple string, an attribute
   name, or a select. See the documentation of function is_local for more
   details.

   If  a match is found then the DID of the virtual domain will be stored
   either  in  $fd.did or in $td.did, depending on the value of the first
   parameter.  In  addition to that domain-level attributes, if any, will
   be available as either $fd.<name> or $td.</name>.

   The  function  returns  1 when a matching virtual domain for the given
   domain name was found and -1 otherwise.

   The  following example shows a typical use of the function. In a multi
   domain  setup,  one  has  to  typically  figure out where the both the
   calling  and  the  called  domains  are  local (i.e. configured on the
   server  as  the  domains  the  server  is  responsible  for).  This is
   typically  done by calling function lookup_domain twice, once with the
   hostname  part  of  the From header as parameter and secondly with the
   hostname part of the Request-URI as parameter.

   The  type  of  the  situation can be then determined from the value of
   corresponding   attributes   ($td.did  and  $fd.did).  A  non-existing
   attribute  value  indicates that the domain name is not local (it does
   not belong to any virtual domain configured in the domain table).

   Example 1.18. lookup_domain usage
lookup_domain("$fd", "@from.uri.host");
lookup_domain("$td", "@ruri.host");

if (strempty($fd.did) && strempty($td.did)) {
    # Neither the calling nor the called domain is local
    # This is a relaying attempt which should be forbidden
    sl_reply("403", "Relaying Forbidden");
    drop;
}
if (strempty($fd.did) && $td.did) {
    # The calling domain is not local and the called domain
    # is local, this is an inbound call from a 3rd party
    # user to one of local users
}
if ($fd.did && strempty($td.did)) {
    # The calling domain is local and the called domain
    # is not local, this is an outbound call from one of
    # our users to a 3rd party user
}
if ($fd.did && $td.did) {
    # Both the calling and the called domains are local,
    # one of our local users calls another local user,
    # either in the same virtual domain or in another
    # virtual domain hosted on the same server
}

6. FIFO Interface

   6.1. domain.reload
   6.2. domain.dump

6.1. domain.reload

   Causes  domain  module  to  re-read  the contents of domain table into
   cache  memory.  If  domain-level attributes are used then it will also
   re-load the contents of the domain_attrs table in the memory cache.

6.2. domain.dump

   Causes  domain  module  to  dump  hash indexes and domain names in its
   cache memory.

7. Internal API

   The  domain  module  has  an  internal API which can be used to access
   additional  functions  of the module (i.e. functions that are normally
   not available from the routing script). Currently the API exports only
   the  function  is_domain_local. That function can be used to determine
   whether  a  given  domain  name  is  on the list of locally configured
   domain names.

   If  you want to use the internal API of domain module from your module
   then  you  need  to  include  the  header  file  domain_api.h and call
   load_domain_api first.

   Example 1.19. Calling load_domain_api
#include "../domain/domain_api.h"

domain_api_t dom_api;

if (load_domain_api(&dom_api) != 0) {
    /* error */
}

   After  that  you  can  call  function is_domain_local whose pointer is
   stored in the initialized data structure:
str tmp = STR_STATIC_INIT("mydomain.com");

if (dom_api.is_domain_local(&tmp) == 1) {
    /* Domain is local */
} else {
    /* Domain is not local or an error was encountered */
}
