Upgrade 3CX to v18 and get it hosted free!

SER example outboundproxy

Author image

SIP Express Router

example: SER as a multihomed outbound proxy

This is a stripped-down version of the ser.cfg file that powers a SIP application-level gateway (ALG). This configuration is based on the
OnSIP Getting Started 5.0 configuration and the alg.cfg included in SER 0.9.3 and later.

This configuration is currently running with SER 0.9.4 and uses rtpproxy from CVS. The internal NIC has been assigned IP address 192.168.0.1, and the external NIC has 192.168.255.1. Contrary to the example given in alg.cfg, you must start rtpproxy as follows:

rtpproxy -l 192.168.255.1/192.168.0.1

This puts the proxy into bridge mode, which enables the proxy to work properly when faced with user agents on either the internal network or the external network.

For this example to work, you must also follow the nathelper module instructions for creating new location_internal and location_external tables. Be careful to use underscores (“_”) and not hyphens (“-“) when creating the new tables.


  # $Id: ser.cfg,v 1.9 2005/10/03 01:06:51 root Exp root $
  
  # ----------- global configuration parameters ------------------------
  
  debug=3         # debug level (cmd line: -dddddddddd)
  fork=yes
  log_stderror=no # (cmd line: -E)
  
  port=5060
  check_via=no    # (cmd. line: -v)
  dns=no          # (cmd. line: -r)
  rev_dns=no      # (cmd. line: -R)
  children=3
  fifo="/tmp/ser_fifo"
  
  alias="mydomain.org"
  
  # mhomed -- enable calculation of outbound interface; useful on
  # multihomed servers.
  mhomed=1
  
  
  # ------------------ module loading ----------------------------------
  
  loadmodule "/usr/pkg/lib/ser/modules/mysql.so"
  loadmodule "/usr/pkg/lib/ser/modules/sl.so"
  loadmodule "/usr/pkg/lib/ser/modules/tm.so"
  loadmodule "/usr/pkg/lib/ser/modules/rr.so"
  loadmodule "/usr/pkg/lib/ser/modules/maxfwd.so"
  loadmodule "/usr/pkg/lib/ser/modules/usrloc.so" 
  loadmodule "/usr/pkg/lib/ser/modules/registrar.so"
  loadmodule "/usr/pkg/lib/ser/modules/auth.so"
  loadmodule "/usr/pkg/lib/ser/modules/auth_db.so"
  loadmodule "/usr/pkg/lib/ser/modules/uri.so"
  loadmodule "/usr/pkg/lib/ser/modules/uri_db.so"
  loadmodule "/usr/pkg/lib/ser/modules/group.so"
  loadmodule "/usr/pkg/lib/ser/modules/nathelper.so"
  loadmodule "/usr/pkg/lib/ser/modules/textops.so"
  loadmodule "/usr/pkg/lib/ser/modules/domain.so"
  
  # ----------------- setting module-specific parameters ---------------
  
  # -- usrloc params --
  # 2 enables write-back to persistent mysql storage for speed
  # disable=0, write-through=1
  modparam("usrloc", "db_mode", 2)
  
  # minimize write back window - default is 60 seconds
  modparam("usrloc", "timer_interval", 10)
  
  # database location
  modparam("usrloc", "db_url", "mysql://ser:heslo@localhost/ser")
  
  # -- auth params --
  modparam("auth_db", "calculate_ha1", yes)
  
  # database location
  modparam("auth_db", "db_url", "mysql://ser:heslo@localhost/ser")
  
  #
  # If you set "calculate_ha1" parameter to yes (which true in this config),
  # uncomment the following parameter as well
  #
  modparam("auth_db", "password_column", "password")
  
  # -- rr params --
  # add value to ;lr param to make some broken UAs happy
  modparam("rr", "enable_full_lr", 1)
  
  # -- nathelper --  
  # Enable NAT pinging
  modparam("nathelper", "natping_interval", 30)
  
  # Ping only contacts that are known to be  
  # behind NAT
  modparam("nathelper", "ping_nated_only", 1)
  
  modparam("nathelper", "rtpproxy_sock", "unix:/var/run/rtpproxy.sock")
  
  # -- multi-domain
  modparam("domain", "db_mode", 1)
  
  # -------------------------  request routing logic -------------------
   
  # main routing logic
  
  route{
  
          # -----------------------------------------------------------------
          # 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;
          };
  
          if (method == "REGISTER") { 
                  route(2);
                  break;
          };
  
          # -----------------------------------------------------------------
          # RTP Proxy Teardown Section
          # -----------------------------------------------------------------
  
          if (method == "BYE" || method == "CANCEL") {
                  unforce_rtp_proxy();
          };
  
          # -----------------------------------------------------------------
          # Loose Route Section
          # -----------------------------------------------------------------
  
          if (method != "REGISTER") {
                  record_route();
          };
          
          if (loose_route()) {
                  route(1);
                  break;
          };
          
          # -----------------------------------------------------------------
          # Call Type Processing Section
          # -----------------------------------------------------------------
  
          if (uri != myself) {
                  route(1);
                  break;
          };
  
          if (method == "CANCEL") {
                  route(1); 
                  break;
          } else if (method == "INVITE") {
                  route(3);
                  break;
          } else if (method == "MESSAGE") {
                  route(8);
                  break;
          };
  
          lookup("aliases");
          if (uri != myself) { 
                  route(1);
                  break;
          }; 
  
          if (!lookup("location_internal")) {
                  if (!lookup("location_external")) {
                          if (method != "ACK")
                                  sl_send_reply("403", "Call cannot be served here");             
                          break;
                  };
          };
          
          route(1);
  }
          
  route[1] {      
                  
          # -----------------------------------------------------------------
          # Default Message Handler
          # -----------------------------------------------------------------
                  
          if (!t_relay())
                  sl_reply_error();
  }               
                  
  route[2] {
                  
          # -----------------------------------------------------------------
          # REGISTER Message Handler
          # ----------------------------------------------------------------
          
          if (!search("^Contact:[ ]*\*") && nat_uac_test("19")) {
                  setflag(6);
                  fix_nated_register();
                  force_rport();
          };      
          
          sl_send_reply("100", "Trying");
  
          if (!www_authorize("mydomain.org","subscriber")) {
                  www_challenge("mydomain.org","0");
                  break;
          };
  
          consume_credentials();
  
          # -----------------------------------------------------------------
          # Save user location based on which interface the REGISTER
          # was sent to.
          # -----------------------------------------------------------------
  
          if (dst_ip == 192.168.0.1) {		#!! Internal IP address 
                  if (!save("location_internal")) {
                          sl_reply_error();
                  };
          } else if (dst_ip == 192.168.255.1) {	#!! External IP address
                  if (!save("location_external")) {
                          sl_reply_error();
                  };
          } else {
                  sl_send_reply("403", "Call cannot be served here");
          };
  }
          
  route[3] { 
                  
          # -----------------------------------------------------------------
          # INVITE Message Handler
          # -----------------------------------------------------------------
  
          # -----------------------------------------------------------------
          # Set flags based on which interface the INVITE was sent to.
          # -----------------------------------------------------------------
  
          if (dst_ip == 192.168.0.1) {		#!! Internal IP address 
                  setflag(11);
          } else if (dst_ip == 192.168.255.1) {	#!! External IP address
                  setflag(12);
          };
  
          if (!proxy_authorize("mydomain.org","subscriber")) {
                  proxy_challenge("mydomain.org","0");
                  break;
          };
  
          # -----------------------------------------------------------------
          # Perform custom INVITE rewriting that depends upon user
          # credentials here. For example, routing calls to the PSTN that
          # are limited by ACLs. Don't forget to drop any credentials
          # you've collected if control flow doesn't reach the next line.
          # -----------------------------------------------------------------
  
          consume_credentials();
          
          route(6);
  }
  
  route[6] {      
  
          # -----------------------------------------------------------------
          # Common Routing
          # -----------------------------------------------------------------
  
          if (uri == myself)
                  lookup("aliases"); 
          
          if (uri != myself) {
                  if (nat_uac_test("19")) {
                          if (isflagset(11)) { 
                                  if (force_rtp_proxy("FAEI"))
                                          t_on_reply("1");
                          } else if (isflagset(12)) {
                                  if (force_rtp_proxy("FAEE"))
                                          t_on_reply("1");
                          }
                  };      
                  route(1);
                  break;
          };      
          
          # -----------------------------------------------------------------
          # The logic here bears a tiny bit of explanation: recall that
          # flags 11 and 12 are set for SIP messages arriving on the internal
          # and external interfaces, respectively (see route[3]). We compare
          # the location of the called party (via lookup()) to the location
          # of the calling party (flags 11/12) to determine whether we need
          # to set up the RTP proxy.
          # -----------------------------------------------------------------
  
          if (lookup("location_internal")) {
                  if (isflagset(11)) {
                          # Only do internal-internal proxy if caller is behind NAT
                          if (nat_uac_test("16")) {
                                  if (force_rtp_proxy("FAII"))
                                          t_on_reply("1");
                          };
                  } else if (isflagset(12)) {
                          if (force_rtp_proxy("FAEI"))
                                  t_on_reply("1");
                  };
          } else if (lookup("location_external")) {
                  if (isflagset(11)) {
                          if (force_rtp_proxy("FAIE"))
                                  t_on_reply("1");
                  } else if (isflagset(12)) {  
                          if (force_rtp_proxy("FAEE"))
                                  t_on_reply("1");
                  };      
          } else {                
                  sl_send_reply("403", "Call cannot be served here");
                  break;                  
          };              
                  
          route(1);
  }
                  
  onreply_route[1] {              
                  
          if (!(status =~ "183" || status =~ "200"))
                  break;  
                  
          force_rtp_proxy("FA");
  }

See also


Back to SER tips and tricks


Create location_internal and location_external tables:

It seems that “nathelper module instructions for creating new location_internal and location_external tables” are nowhere to be found, so after many hours of searching and finding bits and pieces, I have come up with the following…

create table location_internal like location;
create table location_external like location;

Don’t forget to add entries in the “version” table for each of the newly created tables. Make sure to copy the version value from the original “location” table entry.

Before I did this I received the following errors:

register_udomain(): Invalid table version (use ser_mysql.sh reinstall)
domain_fixup(): Error while registering domain


Article Reviews

Write a Review

Your email address will not be published. Required fields are marked *

Required Field. Minimum 5 characters.

Required Field. Minimum 5 characters, maximum 50.

Required field.There is an error with this field.

Required Field.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

There are no reviews for this article. Be the first one to write a review.

Related Posts:

Get 3CX - Absolutely Free!
Link up your team and customers Phone System Live Chat Video Conferencing

Hosted or Self-managed. Up to 10 users free forever. No credit card. Try risk free.

3CX
A 3CX Account with that email already exists. You will be redirected to the Customer Portal to sign in or reset your password if you've forgotten it.