etc/sip-router-oob.cfg
0c1a09fe
 #
 # $Id$
 #
 #
 # Applicability of this Configuration File
 # ----------------------------------------
 #
 # This is default SER script as used for example at the iptel.org
 # SIP service; it can deal with NATs, terminate calls to a PSTN
 # gateway, and it implements a couple of basic signaling features
 # (few types of call forwarding). In this scenario you may have
 # multiple SIP proxies sharing one database for accessing provisioned
 # data, which are maintained for example using serweb. The proxy
 # servers also share write-access to user location database (and
 # keeps a full cache of all usrloc entries synchronized using
 # multicast).
f492982f
 #
0c1a09fe
 # If you look for a simpler version with a lot less dependencies
5d1a75a6
 # please refer to the sip-router-basic.cfg file in your SER distribution.
0c1a09fe
 #
99fab38d
 # If you look for documentation, try http://sip-router.org/wiki/.
 # The right mailing lists for questions about this file is
 # <sr-users@lists.sip-router.org>.
 #
f492982f
 # Requirements:
0c1a09fe
 # ---------------
 # running DB, running RTP proxy, one public IP address
 # for SIP service, one private IP address for administrative purposes;
 # optional: IP address of a PSTN gateway
 #
 # HOWTOs:
 # ---------
 # To get this config running you need to execute the following commands
d7cdf250
 # with the new serctl (the capital word are just place holders):
 #
 #    $ ser_ctl domain add DOMAINNAME
 #    $ ser_ctl user add USERNAME@DOMAINNAME -p PASSWORD
 #
99fab38d
 # (ser_ctl can be obtained from
 #   http://ftp.iptel.org/pub/serctl/daily-snapshots/ )
 #
d7cdf250
 # If you want to have P-Asserted-ID header for your user
 #
 #    $ ser_attr add uid=UID asserted_id="PID"
 #
 # If you want to have (PSTN) gateway support:
 #
 #    $ ser_db add attr_types name=gw_ip rich_type=string raw_type=2 \
 #      description="The gateway IP for the default ser.cfg" default_flags=33
 #    $ ser_attr add global gw_ip=GATEWAY-IP
 #
 # Alternatively, you can simple uncomment the relevant line in this file
 # right at the beginning of the main route.
 #
99fab38d
 # You can also use serweb to set all the values above
 # (http://ftp.iptel.org/pub/serweb/daily-snapshots/ or
 #  http://developer.berlios.de/projects/serweb).
0c1a09fe
 #
 # Users with permission to call PSTN using this script must have
 # the $gw_acl attribute set properly, and shall have $asserted_id
 # set to indicate their caller-id for calls to PSTN. For inbound
 # calls from PSTN, additional aliases may be also set.
 #
 # Warning:
 # -----------
d7cdf250
 # If this file is installed on Debian from package 'ser-oob' then some
 # options in this configuration file may be set by post-installation
 # script, according to values entered by user at installation time in
 # debconf configuration. These values are then applied automatically to
 # this file each time the 'ser-oob' package is upgraded or reconfigured by
5d1a75a6
 # calling 'dpkg-reconfigure sip-router-oob'.
d7cdf250
 #
 # The parts of this configuration file that may be altered by debconf are
 # enclosed between '#DEBCONF-something-START' and '#DEBCONF-something-END'
 # comment marks. Please do not remove them.
0c1a09fe
 #
 #
 # TODO (Future possible improvements):
 # ---------------------------------------
 # * protocol tuning
d7cdf250
 #   - AVP-based diversion for call-forwarding (as opposed to specialized
 #     module)
0c1a09fe
 #   - add Date header in 200s to REGISTERs (to be packaged with NTP!)
f492982f
 # * more security:
0c1a09fe
 #   - pike/rate-limit
 #   - identity
 #   - TLS
 #   - permissions
d7cdf250
 #   - Re-name all internal headers so that they start with a common prefix,
 #     such as P-SER and then wipe all such headers from requests received
 #     from untrusted sources, such as the user agents or foreign proxy
 #     servers
0c1a09fe
 # * refined DB use (e.g., flatstore for acc)
 # * miscellanous:
 #  - dialog module for monitoring purposes
 #  - more extensive logging using xlog (controlled by gflags/gAVPs)
 # * leveraging 2.1 features:
f492982f
 #  - removal of private IP address (it takes a multicast-specific
0c1a09fe
 #    command which will allow OS to determine source IP address)
f492982f
 #  - timer route:
0c1a09fe
 #     * don't use exec (it takes domain.reload as script command)
f492982f
 #     * compare last-stored timestamp with current timestamp (it takes
0c1a09fe
 #       assignment of gAVPs)
 #     * check multicast REGISTERs for their TTL (this is a simple and
 #       effective security check to prevent remote multicast messages
 #       to damage our traffic)
f492982f
 #  - numerous fine-tuning parameters which are only available in 2.1
0c1a09fe
 #   (mlock_pages, dns_try_naptr, etc.)
 #  - better support for preloaded routes with domain name
 #
 # Security considerations:
 # ------------------------
d7cdf250
 # The script has been tested against security leaks, but it comes
0c1a09fe
 # under terms of GPL "as is" without any warranties; better check
 # yourself that:
f492982f
 # - IP based authentication of PSTN gateway and multicast REGISTERs
d7cdf250
 #   is compliant to your network setup and security policy.
 # - Multiple gateway IPs can't be provisioned as security checks
 #   are applied only to one.
0c1a09fe
 #
 # Licensing
 # ----------
b5b7ced7
 # Copyright (C) 2005-2008 iptelorg GmbH
0c1a09fe
 # This file is part of SER, a free SIP server. It is available under the
 # terms of the  GNU General Public License.
 # Numerous folks have contributed to this file, including but not limited
d7cdf250
 # to Andrei, Jan, Jiri, Michal, Miklos, Nils.
0c1a09fe
 #
 #
d7cdf250
 # .... that's it, enough of yadiyada, here the real config begins!
0c1a09fe
 
99fab38d
 # ----------- Global Defines / Extra Features -------------------------------
 # (can be enabled either by uncommenting the corresponding #!define 
 #  statement or by starting with -A WITH_<FEATURE_NAME>, e.g.
 #  ser -A WITH_TLS -f /etc/ser/ser-oob.cfg )
 
 # enable TLS
 ##!define WITH_TLS
 
 #enable xmlrpc support
 ##!define WITH_XMLRPC
 
 # xmlrpc allowed only if it comes on TLS from a client with a valid cert
 ##!define XMLRPC_TLS_ONLY
 
 # xmlrpc allowed subnets (if defined XMLRPC requests with source ip matching
 # this network addresses will be allowed, if no XMLRPC_ALLOWED_SUBNETx is
 # defined only requests coming from localhost will be allowed).
 # E.g.: ser -A XMLRPC_ALLOW_NET1=192.168.1.0/24 -f ser-oob.cfg
 ##!define XMLRPC_ALLOW_NET1  192.168.0.0/16
 ##!define XMLRPC_ALLOW_NET2  10.0.0.0/255.0.0.0
 ##!define XMLRPC_ALLOW_NET3  172.16.0.0/12
 
 
 # started from compile directory (not installed)
 ##!define LOCAL_TEST_RUN
0c1a09fe
 
d7cdf250
 # ----------- Global Configuration Parameters -------------------------------
0c1a09fe
 
d7cdf250
 #debug=3    # debug level (cmd line: -ddd)
 #memdbg=10  # memory debug log level
 #memlog=10  # memory statistics log level
 #log_facility=LOG_LOCAL0 # the facility used for logging (see syslog(3))
0c1a09fe
 
cc30d600
 #DEBCONF-SERVERID-START
3b05d820
 server_id=0
cc30d600
 #DEBCONF-SERVERID-END
 
d7cdf250
 # Uncomment these lines to enter debugging mode or start SER with
5d1a75a6
 # sip-router -ED
d7cdf250
 #
 #fork=no
 #log_stderror=yes
0c1a09fe
 
d7cdf250
 check_via=no            # (cmd. line: -v)
 dns=no                  # (cmd. line: -r)
 rev_dns=no              # (cmd. line: -R)
0c1a09fe
 #port=5060
 #children=4
5d1a75a6
 #user=sip-router
 #group=sip-router
d7cdf250
 #disable_core=yes       # disables core dumping
3e493f4d
 #open_files_limit=20480  # sets the open file descriptors limit
d7cdf250
 #mhomed=yes             # usefull for multihomed hosts, small performance
                         # penalty
 disable_tcp=no          # be conservative about enabling TCP -- it can
                         # degrade performance a lot
 #tcp_accept_aliases=yes # accepts the tcp alias via option
 phone2tel=no            # ignore user=phone in request-URIs -- otherwise
                         # these URIs would be interpreted as equivalent
 			# to TEL URIs, and their lookup would fail in URI
 			# database
0c1a09fe
 reply_to_via=no
48c2ffc2
 sip_warning=yes
0c1a09fe
 # public IP address
 #DEBCONF-LISTEN-START
94789f36
 listen=127.0.0.1
0c1a09fe
 #DEBCONF-LISTEN-END
af15fe76
 # sip.mcast.net for REGISTER replication 	 
 #DEBCONF-LISTEN_REPL-START 	 
99fab38d
 listen=udp:224.0.1.75
af15fe76
 #DEBCONF-LISTEN_REPL-END
0c1a09fe
 # administrative interface -- needed for example for multicast source
 # or XML-RPC
 #DEBCONF-LISTEN_ADMIN-START
94789f36
 listen=udp:127.0.0.1
0c1a09fe
 #DEBCONF-LISTEN_ADMIN-END
c19a9ff3
 
 #listen=tls:127.0.0.1:5061
 
17efc53f
 mlock_pages=yes
 shm_force_alloc=yes
 real_time=7
0c1a09fe
 
d7cdf250
 # ------------------- DNS Parameters ----------------------------------------
0c1a09fe
 # (see doc/dns.txt for more details)
d7cdf250
 #
f492982f
 # minimum timeouts
0c1a09fe
 dns_retr_time=1
 dns_retr_no=1
 dns_servers_no=1
 dns_use_search_list=no
 dns_try_ipv6=no
 # dns cache & failover
 use_dns_cache=on
 use_dns_failover=on
 # dns_cache_flags=0
 dns_cache_negative_ttl=300
 dns_cache_min_ttl=60
 dns_cache_max_ttl=86400 # 1 day
 dns_cache_mem=2048 # 2 MB
 dns_cache_gc_interval=60  # garbage collection every minute
3e493f4d
 # ser 2.1 specific options
 dns_try_naptr=yes
 dns_srv_lb=yes  # srv based load balancing
 dns_udp_pref=3  # prefer udp (when resolving naptr record)
99fab38d
 dns_tcp_pref=2  # if no udp available accept tcp (for naptr)
 dns_sctp_pref=2 # same preference as tcp
 #!ifdef WITH_TLS
 dns_tls_pref=1  # low preference (heavy resource use)
 #!else
3e493f4d
 dns_tls_pref=-1 # ignore / don't accept tls (for naptr)
99fab38d
 #!endif
0c1a09fe
 # dns_cache_delete_nonexpired=no
 
d7cdf250
 # ------------------- Blacklist Parameters ----------------------------------
0c1a09fe
 # (see doc/dst_blacklist.txt for more details)
d7cdf250
 #
0c1a09fe
 use_dst_blacklist=on
 dst_blacklist_mem=1024 # 1 MB
 dst_blacklist_expire=300  # blacklist default time
 dst_blacklist_gc_interval=150 # 2.5 min
5d1a75a6
 # for sip-router 2.1 to the above add tm blst_503* parameters and/or use the
0c1a09fe
 # blst module (see NEWS)
 
d7cdf250
 # ------------------- TCP Parameters ----------------------------------------
0c1a09fe
 # (see NEWS for more details)
 tcp_connection_lifetime=3600
 #tcp_max_connections=10240  # default is 2048
 tcp_connect_timeout=1
99fab38d
 tcp_async=yes
0c1a09fe
 
e6d55cc0
 # ------------------- TLS Parameters ----------------------------------------
 
99fab38d
 #!ifdef WITH_TLS
c19a9ff3
 # Enable TLS hooks so that the TLS module can be used
 tls_enable=yes
99fab38d
 #!endif
c19a9ff3
 
d7cdf250
 # -------------------- Custom Parameters ------------------------------------
6d4d32e3
 # These parameters can be modified runtime via RPC interface,
d7cdf250
 # read the documentation of cfg_rpc module.
 
6d4d32e3
 # Session Timer parameters, RFC 4028
 #
d7cdf250
 # Default session interval used by the proxy if the UAC does not support
 # session timer. Set it to "0" to disable session timer proxy support.
 #
6d4d32e3
 session_timer.default = "1800" desc "default session interval (in s)"
 #
d7cdf250
 # Minimum session interval accepted by the proxy, it must not be less
 # than 90 seconds.
 #
6d4d32e3
 session_timer.min_se = "90" desc "minimum session interval (in s)"
 
db4a1931
 # RTP Proxy options
 #
 # Whether to enable or disable the rtp proxy. Possible values are:
 # "0" -- always disable
 # "1" -- always enable regardless of whether UAC or UAS is behind NAT
 # "detect" -- detect whether the UAC or the UAS is behind NAT,
 #             and enable the rtp proxy when necessary
 #
5fdc47b1
 #DEBCONF-RTP_ENABLE-START
28b6f779
 rtp_proxy.enabled = "detect" desc "indicates whether the RTP Proxy is enabled or not (0/1/detect)"
5fdc47b1
 #DEBCONF-RTP_ENABLE-END
f492982f
 
d7cdf250
 # ------------------ Module Loading -----------------------------------------
99fab38d
 #!ifdef LOCAL_TEST_RUN
 loadpath "modules:modules_s"
 #!else
5d1a75a6
 loadpath "/usr/lib/sip-router/modules:/usr/lib/sip-router/modules_s"
99fab38d
 #!endif
0fe8b5f1
 
0c1a09fe
 # load a SQL database for authentication, domains, user AVPs etc.
ec8e49e8
 loadmodule "db_mysql"
4554a1c3
 #loadmodule "postgres"
0fe8b5f1
 
 loadmodule "tm"
99fab38d
 loadmodule "sl"
0fe8b5f1
 loadmodule "rr"
 loadmodule "maxfwd"
 loadmodule "usrloc"
 loadmodule "registrar"
 loadmodule "xlog"
 loadmodule "textops"
 loadmodule "ctl"
 loadmodule "auth"
 loadmodule "auth_db"
 loadmodule "gflags"
 loadmodule "domain"
 loadmodule "uri_db"
 loadmodule "avp"
 loadmodule "avp_db"
 loadmodule "acc_db"
99fab38d
 #!ifdef WITH_XMLRPC
 loadmodule "xmlrpc"
 #!endif
0fe8b5f1
 loadmodule "options"
 loadmodule "sanity"
 loadmodule "nathelper"
 loadmodule "uri"
 loadmodule "speeddial"
 loadmodule "timer"
 loadmodule "db_ops"
 loadmodule "exec"
 loadmodule "cfg_rpc"
 loadmodule "eval"
89f45812
 loadmodule "enum"
99fab38d
 #!ifdef WITH_TLS
 loadmodule "tls"
 #!endif
0c1a09fe
 
d7cdf250
 # ----------------- Declaration of Script Flags -----------------------------
0c1a09fe
 flags
d7cdf250
   FLAG_ACC            : 1, # the request will be recorded by ACC
0c1a09fe
   FLAG_FAILUREROUTE   : 2, # we are operating from the failure route
   FLAG_NAT            : 3, # the UAC is behind a NAT
0fe8b5f1
   FLAG_REPL_ENABLED   : 4, # REGISTER replication is enabled if set
d7cdf250
   FLAG_TOTAG          : 5, # request has a To tag
0c1a09fe
   FLAG_PSTN_ALLOWED   : 6, # the user is allowed to use the PSTN
   FLAG_DONT_RM_CRED   : 7, # do not remove the credentials
b5b7ced7
   FLAG_AUTH_OK        : 8, # authentication succeeded
0c1a09fe
   FLAG_SERWEB_RSVD1   : 9, # bit reserved for use with serweb
6d4d32e3
   FLAG_SERWEB_RSVD2   : 10, # bit reserved for use with serweb
   FLAG_SESSIONTIMER   : 11, # indicates that the UAC supports Session Timer
7750369e
   FLAG_RR_DONE        : 12, # the request got already one RR header
ffa10596
   FLAG_RTP_PROXY      : 13, # the RTP proxy is turned on
   FLAG_NAT_REG        : 14, # the UAC behind NAT, stored in location record
   FLAG_INIT_DLG       : 15, # init INVITE dialog
e8ced19c
   FLAG_REVERSE_DIR    : 16, # set if request goes callee -> caller direction, requires rr.append_fromtag=1
a0fdc9b7
   FLAG_ACC_MISSED     : 17, # the missed call will be recorded by ACC
   FLAG_USRLOC_FWD     : 18, # usrloc based forward
   FLAG_NEXT_ROUTE     : 19; # there is a route remaining
0c1a09fe
 
 avpflags
d7cdf250
   dialog_cookie;            # attribute will be stored in Route headers
0c1a09fe
 
d7cdf250
 # ----------------- Module-specific Parameters ------------------------------
0c1a09fe
 
d7cdf250
 # path to the database
 #
0c1a09fe
 #DEBCONF-DBURL-START
d7cdf250
 modparam("speeddial|auth_db|usrloc|domain|uri_db|gflags|avp_db|db_ops",
ffa10596
          "db_url", "mysql://ser:heslo@localhost/ser")
0c1a09fe
 #DEBCONF-DBURL-END
 
469b7fa0
 # specify the path to your database for accounting
 #DEBCONF-DBURLACC-START
ffa10596
 modparam("acc_db", "db_url", "mysql://ser:heslo@localhost/ser")
469b7fa0
 #DEBCONF-DBURLACC-END
 
0c1a09fe
 
d7cdf250
 # -- usrloc --
 
 # Database access mode: 0 -- memory cached, 1 -- write through,
 # 2 -- delayed write.  1 is generally safer than 2.  2 can help
 # to survive peaks in load.  However, it creates delayed peaks that can
 # impair request-processing latency later (usrloc would have to be
 # re-redesigned more lock-free to avoid it).
a12e33d9
 #DEBCONF-DBMODE-START
17efc53f
 modparam("usrloc", "db_mode", 1)
a12e33d9
 #DEBCONF-DBMODE-END
d7cdf250
 
 # Don't delete expired records from database on a per-contact basis -- that
0c1a09fe
 # results in bulky DB operations and can lead to synchronization issues
 # in server farm when for a time a server doesn't obtain re-reregistrations
 modparam("usrloc","db_skip_delete",1)
 
d7cdf250
 
 # -- registrar --
 
 # Maximum expires time.  Forces users to re-register every 10 min.
0c1a09fe
 modparam("registrar", "max_expires", 600)
d7cdf250
 
 # Minimum expires time. Even if they try, clients cannot register
 # for a shorter time than this.
0c1a09fe
 modparam("registrar", "min_expires", 240)
 
d7cdf250
 # Identify natted contacts using a flag.
ffa10596
 modparam("registrar", "load_nat_flag", "FLAG_NAT_REG")
 modparam("registrar", "save_nat_flag", "FLAG_NAT_REG")
0c1a09fe
 
d7cdf250
 # Maximum number of contacts.
88a2f11f
 modparam("registrar", "max_contacts", 10)
0c1a09fe
 
d7cdf250
 
 # -- auth --
 
0c1a09fe
 #modparam("auth_db", "calculate_ha1", yes)
d2040d53
 #modparam("auth_db", "password_column", "password")
d7cdf250
 
 # Minimize replay-attack window.
0c1a09fe
 modparam("auth", "nonce_expire", 10)
8cbe6777
 
 # Enable/disable extra authentication checks using the following modparams.
d7cdf250
 # The values are: 1 -- Request-URI, 2 -- Call-ID, 4 -- From tag,
 # 8 -- source IP. The options are disabled by default.
8cbe6777
 
 # For REGISTER requests we hash the Request-URI, Call-ID, and source IP of the
 # request into the nonce string. This ensures that the generated credentials
 # cannot be used with another registrar, user agent with another source IP
 # address or Call-ID. Note that user agents that change Call-ID with every
 # REGISTER message will not be able to register if you enable this.
 #modparam("auth", "auth_checks_register", 11)
 
 # For dialog-establishing requests (such as the original INVITE, OPTIONS, etc)
 # we hash the Request-URI and source IP. Hashing Call-ID and From tags takes
 # some extra precaution, because these checks could render some UA unusable.
 #modparam("auth", "auth_checks_no_dlg", 9)
 
 # For mid-dialog requests, such as re-INVITE, we can hash source IP and
 # Request-URI just like in the previous case. In addition to that we can hash
 # Call-ID and From tag because these are fixed within a dialog and are
 # guaranteed not to change. This settings effectively restrict the usage of
 # generated credentials to a single user agent within a single dialog.
 #modparam("auth", "auth_checks_in_dlg", 15)
 
d7cdf250
 # Deal with clients who can't do qop properly
0c1a09fe
 modparam("auth", "qop", "")
 #DEBCONF-AUTHSECRET-START
 modparam("auth", "secret", "aqwedrftredswqwddcft")
 #DEBCONF-AUTHSECRET-END
 
 
d7cdf250
 # -- rr --
 
 # Add value to lr param to make some broken UAs happy.
0c1a09fe
 modparam("rr", "enable_full_lr", 1)
d7cdf250
 
 # Limit the length of the AVP cookie to necessary attributes only
ffa10596
 modparam("rr", "cookie_filter", "(account|rproxy|stimer|dialog_id)")
d7cdf250
 
 # You probably do not want that someone can simply read and change
0c1a09fe
 # the AVP cookie in your Routes, thus should really change this
 # secret value below
 modparam("rr", "cookie_secret", "sgsatewgdbsnmpoiewh")
 
d7cdf250
 # The ftag Route parameter may be used to easily determine if a BYE
 # is coming from caller or callee, but we prefer shorter messages
ffa10596
 # Enable when FLAG_REVERSE_DIR is to be used
0c1a09fe
 modparam("rr", "append_fromtag", 0)
 
d7cdf250
 
 # -- gflags --
 
 # Load global attributes.
0c1a09fe
 modparam("gflags", "load_global_attrs", 1)
 
d7cdf250
 
 # -- domain --
 
 # Load domain attributes.
0c1a09fe
 modparam("domain", "load_domain_attrs", 1)
 
d7cdf250
 
 # -- ctl --
 
5d1a75a6
 # By default, ctl listens on unixs:/tmp/sip-router_ctl if no other address is
d7cdf250
 # specified in modparams; this is also the default for sercmd.
99fab38d
 modparam("ctl", "binrpc", "unixs:/tmp/ser_ctl")
d7cdf250
 # Listen on the "standard" fifo for backward compatibility.
99fab38d
 modparam("ctl", "fifo", "fifo:/tmp/ser_fifo")
d7cdf250
 # Listen on tcp on localhost.
99fab38d
 modparam("ctl", "binrpc", "tcp:127.0.0.1:2046")
0c1a09fe
 
d7cdf250
 
 # -- acc_db --
 
 # Failed transactions (those with negative responses) should be logged, too.
0c1a09fe
 modparam("acc_db", "failed_transactions", 1)
 
d7cdf250
 # If you don't want to have accounting entries written into the database,
 # comment the next line out.
0c1a09fe
 modparam("acc_db", "log_flag", "FLAG_ACC")
e8ced19c
 # seems "log_flag" and "log_flag_missed" cannot share the same flag!
 modparam("acc_db", "log_missed_flag", "FLAG_ACC_MISSED")
0c1a09fe
 
 # if you would like to customize your CDRs, do it here....
d7cdf250
 #modparam("acc_db", "attrs",
 #         "$f.sop_billing_category,$f.isPrepaidCustomer,$f.sop_cf_orig_uid")
 
 
 # -- tm --
0c1a09fe
 
d7cdf250
 # Do not restart the resend timer with each reply. (See INBOUND route
 # below.)
0c1a09fe
 modparam("tm", "restart_fr_on_each_reply", 0)
 
d7cdf250
 
 # -- xmlrpc --
 
99fab38d
 #!ifdef WITH_XMLRPC
d7cdf250
 # Use a sub-route. This is a lot safer then relying on the request method
 # to distinguish HTTP from SIP
99fab38d
 modparam("xmlrpc", "route", "XMLRPC");
 #!endif
0c1a09fe
 
d7cdf250
 
 # -- nathelper --
 
 # RTP Proxy address
0c1a09fe
 #DEBCONF-RTTPPROXY-START
94789f36
 modparam("nathelper", "rtpproxy_sock", "udp:127.0.0.1:22222")
0c1a09fe
 #DEBCONF-RTTPPROXY-END
d7cdf250
 
0c1a09fe
 # TCP keepalives as simple as CRLF
800682a9
 modparam("nathelper", "natping_crlf", 0)
d7cdf250
 
 # How often to send a NAT ping. Set this to 0 to turn NAT ping off.
0c1a09fe
 #DEBCONF-NATPING_INTERVAL-START
 modparam("nathelper", "natping_interval", 15)
 #DEBCONF-NATPING_INTERVAL-END
d7cdf250
 
 # Only ping contacts that have the NAT flag set.
b5b7ced7
 modparam("nathelper", "ping_nated_only", 1)
d7cdf250
 
 # Send an OPTIONS SIP request as NAT ping. If this is not set, a simple
 # 4-byte ping is used.
b5b7ced7
 modparam("nathelper", "natping_method", "OPTIONS")
d7cdf250
 
 # Temporary statefull natping test (only in future versions)
0c1a09fe
 #modparam("nathelper", "natping_stateful", 1)
 
d7cdf250
 
 # -- exec --
0c1a09fe
 modparam("exec", "time_to_kill", 200);
 modparam("exec", "setvars", 0);
 
d7cdf250
 # -- timer --
0c1a09fe
 
d7cdf250
 # Register route ON_1MIN_TIMER to be called every minute.
 modparam("timer", "declare_timer",
          "ON_1MIN_TIMER=ON_1MIN_TIMER,60000,slow,enable");
17efc53f
 
99fab38d
 #!ifdef WITH_TLS
c19a9ff3
 # -- tls --
99fab38d
 #!ifdef LOCAL_TEST_RUN
 modparam("tls", "config", "./modules/tls/tls.cfg");
 #!else
 modparam("tls", "config", "tls.cfg");
 #!endif
 #!endif
0c1a09fe
 
d7cdf250
 # -- db_ops --
0c1a09fe
 
d7cdf250
 modparam("db_ops", "declare_handle", "reload")
6351694a
 modparam("db_ops", "declare_handle", "gattr_reload")
0c1a09fe
 
 
d7cdf250
 # -------------------------  Request Routing Logic --------------------------
0c1a09fe
 
d7cdf250
 # Main request route.
 #
 # Each request starts here.
 #
 route
 {
 	# if you have a PSTN gateway just un-comment the follwoing line and
 	# specify the IP address of it to route calls to it.
0c1a09fe
 	#$gw_ip = "1.2.3.4"
 
d7cdf250
 	# Alternatively (even better), set it as global persistent parameter
 	# using serweb or ser_attrs). If using a PSTN GW, per-subscriber
 	# options must ($gw_acl) or may (asserted_id) be set to enable calls
 	# to PSTN. If email-like URIs are used, having a URI alias for
 	# processing incoming PSTN-to-ip requests may be useful, too.
 	# Important: the script is assuming one global pstn-gw for all
 	# domains! Failure to allow gw_ip to be a domain-specic attribute
 	# would result in security gaps (onsend_route checks only for one
 	# gateway).
 
 	# First, do some initial sanity checks.
0c1a09fe
 	route(INIT);
 
d7cdf250
 	# Bypass the rest of the script for CANCELs if possible.
0c1a09fe
 	route(CATCH_CANCEL);
 
d7cdf250
 	# Check if the request is routed via Route header.
3e493f4d
 	route(PROCESS_ROUTES);
0c1a09fe
 
d7cdf250
 	# Look up domain IDs
0c1a09fe
 	route(DOMAIN);
 
d7cdf250
 	# Answer OPTIONS requests to our system.
0c1a09fe
 	route(OPTIONS_REPLY);
 
d7cdf250
 	# Enforce domain policy.
9ca93d22
 	route(DOMAIN_POLICY);
 
d7cdf250
 	# Handle REGISTER requests.
0c1a09fe
 	route(REGISTRAR);
 
d7cdf250
 	# From here on we want to know who is calling.
0c1a09fe
 	route(AUTHENTICATION);
 
d7cdf250
 	# We are finished with all the precaution work -- let's
 	# try to locate the callee. The first route that matches
 	# "wins" and relays the request.  If none matches, SER will
 	# send a 404.
0c1a09fe
 
d7cdf250
 	# Check if we should be outbound proxy for a local user.
0c1a09fe
 	route(OUTBOUND);
 
d7cdf250
 	# Redirect in case user dialed a speed dial entry.
0c1a09fe
 	route(SPEEDDIAL);
 
d7cdf250
 	# Place various site-specific routes here.
0c1a09fe
 	route(SITE_SPECIFIC);
 
d7cdf250
 	# Check if the request is for a local user.
0c1a09fe
 	route(INBOUND);
 
d7cdf250
 	# There is SIP user for the called address. Before trying PSTN,
 	# you may have to convert the adress, for instance by using
 	# ENUM.
0c1a09fe
 	#route(ENUM);
 
d7cdf250
 	# Last resort: if none of the previous route has found
 	# the recepient, try PSTN.
0c1a09fe
 	route(PSTN);
 
d7cdf250
 	# nothing matched
0c1a09fe
 	sl_reply("404", "No route matched");
 }
 
d7cdf250
 # Forward a request to the destination set.
 #
0c1a09fe
 route[FORWARD]
 {
d7cdf250
 	# If this is called from the failure route we need to add a new
 	# branch.
0c1a09fe
 	if (isflagset(FLAG_FAILUREROUTE)) {
599a6209
 		if (!append_branch()) {
 			t_reply("500", "Too many branches");
 			drop;
 		}
0c1a09fe
 	}
 
d7cdf250
 	# If this is an initial INVITE (without a To-tag) we might try
 	# another target (call forwarding or voicemail) after receiving
 	# an error.
ffa10596
 	if (isflagset(FLAG_INIT_DLG)) {
0c1a09fe
 		t_on_failure("FAILURE_ROUTE");
 	}
 
d7cdf250
 	# Always use the reply route to check for NATed UAS.
0c1a09fe
 	t_on_reply("REPLY_ROUTE");
 
d7cdf250
 	# Remove credentials to keep requests shorter
0c1a09fe
 	if (isflagset(FLAG_AUTH_OK) && !isflagset(FLAG_DONT_RM_CRED) ) {
 		consume_credentials();
 	}
 
3e493f4d
 	# Activate the RTP proxy as the second last step because it modifies the
 	# body but also sets an dialog AVP cookie.
 	route(RTPPROXY);
 
 	# Insert a Record-Route header into all requests.
 	# This has to be done as one of the last steps to include all the
 	# RR cookies which might have been created during the script run.
 	route(RECORD_ROUTE);
 
d7cdf250
 	# Send it out now.
0c1a09fe
 	if (!t_relay()) {
93faf522
 		if (isflagset(FLAG_FAILUREROUTE)) {
d7cdf250
 			# XXX This should be replaced with
 			#     t_reply_error() similar to sl_reply_error()
 			#     in order to return the proper failure code.
 			#     Only, there is no such function yet.
93faf522
 			t_reply("500", "Request cannot be forwarded");
d7cdf250
 		}
 		else {
93faf522
 			sl_reply_error();
 		}
0c1a09fe
 	}
 	drop;
 }
 
d7cdf250
 
 # Perform initial checks on an incoming request.
 #
 # Rejects the request if it fails any of the checks.
 #
0c1a09fe
 route[INIT]
 {
d7cdf250
 	# Messages with a Max-Forwards header of zero.
0c1a09fe
 	if (!mf_process_maxfwd_header("10")) {
 		sl_reply("483","Too Many Hops");
 		drop;
 	}
 
3e493f4d
 	# Set flag for use in the onsend route (because it does not
 	# allow to use "select" statements)
ec8e49e8
 	if (@to.tag != "") {
0c1a09fe
 		setflag(FLAG_TOTAG);
 	}
d7cdf250
 
 	# Check if the UAC is NATed and fix the message accordingly
3e493f4d
 	route(UAC_NAT_DETECTION);
0c1a09fe
 
d7cdf250
 	# Activate accounting for all initial INVITEs. In-dialog requests
 	# are accounted by a RR cookie (see below).
ffa10596
 	# It should work also when the call has been already forked at a previous router
 	if (method == "INVITE" && !isflagset(FLAG_TOTAG)) {
 		$dialog_id = @sys.unique; # make unique dialogid
0c1a09fe
 		setflag(FLAG_ACC);
e8ced19c
 		setflag(FLAG_ACC_MISSED);
ffa10596
 		setflag(FLAG_INIT_DLG);
 	} else if (isflagset(FLAG_TOTAG) && @hf_value.route[0].params.ftag != @from.tag) {
 		setflag(FLAG_REVERSE_DIR);  # callee -> caller
0c1a09fe
 	}
 
e8ced19c
 	# if needed then we MUST put after force_rport() which is located in NAT_DETECTION!!!
 	# also must be called after FLAG_ACC is set !!!
 	# Check t_reply() vs. sl_reply() usage in script
 	#if (!t_newtran()) {
 	#	sl_reply("500", "Internal tm error");
 	#	drop;
 	#}
 														
d7cdf250
 	# Set flag and use it instead of the attribute.
 	if ($replicate==1) {
cc30d600
 		setflag(FLAG_REPL_ENABLED);
0c1a09fe
 	}
 }
 
d7cdf250
 
 # Reply OPTIONS requests sent to the proxy itself.
 #
0c1a09fe
 route[OPTIONS_REPLY]
 {
d7cdf250
 	# OPTIONS requests without a username in the Request-URI but one
 	# of our domains or IPs are addressed to the proxy itself and
 	# can be answered statelessly.
ec8e49e8
 	if (method == "OPTIONS" && strempty(@ruri.user) &&
 		(uri == myself || $t.did != ""))
d7cdf250
 	{
0c1a09fe
 		options_reply();
 		drop;
 	}
 }
 
d7cdf250
 
 # Check if the sender of the request is behind a NAT device. If so,
ffa10596
 # fix the request so that other devices can talk to the sender nonetheless.
d7cdf250
 #
3e493f4d
 route[UAC_NAT_DETECTION]
0c1a09fe
 {
d7cdf250
 	# Lots of UAs do not include the rport parameter in there Via
 	# header, so we put it there regardless.
0c1a09fe
 	force_rport();
3e493f4d
 
 	# If a reliable transport was used store the connection internally
 	# so that SERs core can re-use the connection later.
 	if (proto==TCP || proto == TLS)
 	{
 		force_tcp_alias();
 	}
0c1a09fe
 
d7cdf250
 	# Check if the request contains hints for a NATed UAC. Also, try to
 	# rewrite contacts using maddr. Using maddr is a really dubious
 	# technique and we better replace such with transport address.
 	# Downside: it fails for clients fronted by another server, in
 	# which case a valid contact we dislike because of maddr will be
 	# substituted inapproprietely (e.g., WM from other domains will
 	# fail). If you are worried about that, remove tests for maddr and
 	# recompile SER using HONOR_MADDR.  Also note that rewriting
 	# contacts may possibly lead to client denying subseqent requests
 	# to them because they don't recognized fixed contacts as their
 	# own.  Should you encounter such a case, a possible solution
 	# would be to store the original information as a contact parameter
 	# and restore it on its way back.
3e493f4d
 
 	# In case of UDP we test for
 	#  - private IPs in Contact
 	#  - mismatch of transport IP and IP in Via
 	#  - mismatch of transport port and port in Via
 	# in all other cases we skip the port test, because lots of clients
 	# do not correctly advertise their emphemeral port number in their Via
 	# header in case of reliable transports (although they are not behind
 	# a NAT).
 
 	# Warning: if you are dealing with SIP implementations which are
 	# running on public IP and do as-symmertic signaling for whatever
 	# reason the following check will make their signaling symmetric.
 	# If you need to support as-symmertic signaling reduce the following
 	# nat_uac_test for UDP to "3" or even "1".
 	if ((proto == UDP && nat_uac_test("19")) ||
 		(nat_uac_test("3")) ||
89f45812
 		(@hf_value["contact"] != "" && @contact.uri.params.maddr != ""))
d7cdf250
 	{
0c1a09fe
 		setflag(FLAG_NAT);
d7cdf250
 		if (method == "REGISTER") {
 			# Prepare the Contact so that the registrar module
 			# saves the source address and port as well.
0c1a09fe
 			fix_nated_register();
d7cdf250
 		}
 		else {
 			# Overwrite the Contact to allow proper in-dialog
 			# routing.
ffa10596
 			# but do not override if there is already a proxy in the path, we'll route by record-route,
 			# RURI responsibility takes to previous proxy
 			# TODO: shouldn't we rather limit to methods which are dialog aware (INVITE, UPDATE, SUBSCRIBE, ..)
 			if (strempty(@hf_value.record_route) || (@hf_value["contact"]!="" && @contact.uri.params.maddr!="")) {
 				fix_nated_contact();
 			}
 
0c1a09fe
 		}
 	}
 }
 
d7cdf250
 
3e493f4d
 # Check if the receiver of the request is behind a NAT device. If so,
 # fix the Contact header to allow proper routing of in-dialog requests.
 route[UAS_NAT_DETECTION]
 {
 	# Fix the Contact in the reply if it contains a private IP to
 	# allow proper routing of in-dialog messages.
 	# Do the same if the contact is maddred.
 
 	# But skip 3XX responses, because we do not know the right IP for that,
 	# even if they contain private IPs.
 	if (status=~"(3[0-9][0-9])") {
 		break;
 	}
 
a0fdc9b7
 	# prevent contact overwriting when a proxy between ser and UAS.
 	# We get it from record-route but it's rather difficult or
 	# do it only for UAS which is registered in usrloc database and has no
 	# proxy on path.
 	# Note: destination forced by $fwd_always_target is not NAT detected and contact left untouched!
 	if (isflagset(FLAG_INIT_DLG) && !isflagset(FLAG_USRLOC_FWD)) {
 		break;
 	}
 	# for in-dialog requests we get it easily because it provides loose_route()
 	if (!isflagset(FLAG_INIT_DLG) && isflagset(FLAG_NEXT_ROUTE)) {
 		break;
 	}
 
3e493f4d
 	# Prevent that we over-write the Contact with the IP of our proxy when
 	# the reply loops through ourself.
 	if (src_ip == myself) {
 		break;
 	}
 
 	# In this case we check only if the Contact URI contains a private
 	# IP, because the Via header contains only informations from the UAC.
 	# Additionally we check if the port in the Contact URI differs from
 	# the port of the transport to catch UAS or ALG which put the public
 	# IP address into the Contact header, but "forget" about the port.
 
 	# Warning: if you are dealing with SIP implementations which are
 	# running on public IP and do as-symmertic signaling for whatever
 	# reason the following check will make their signaling symmetric.
 	# If you need to support as-symmertic signaling reduce the following
 	# nat_uac_test for UDP to just "1".
 	if ( (proto == UDP && nat_uac_test("33")) ||
 		(nat_uac_test("1") ||
89f45812
 		(@hf_value["contact"] != "" && @contact.uri.params.maddr != "")))
3e493f4d
 	{
ffa10596
 		# TODO: check if no proxy between UAS&myself
3e493f4d
 		fix_nated_contact();
 	}
 }
 
 
d7cdf250
 # Activates RTP proxy if necessary.
 #
0c1a09fe
 route[RTPPROXY]
 {
28b6f779
 	if (@cfg_get.rtp_proxy.enabled == "0") {
db4a1931
 		# RTP Proxy is disabled
0c1a09fe
 		break;
28b6f779
 	} else if (@cfg_get.rtp_proxy.enabled == "detect") {
db4a1931
 		if (!isflagset(FLAG_NAT)) {
 			# If no NAT is involved we don't have to do here anything.
 			break;
 		}
28b6f779
 	} else if (@cfg_get.rtp_proxy.enabled != "1") {
db4a1931
 		# This is not a valid setting
28b6f779
 		xlog("L_ERR", "Unknown option for rtp_proxy.enabled: %@cfg_get.rtp_proxy.enabled\n");
db4a1931
 		break;
 	} # else rtp proxy is permanently enabled
0c1a09fe
 
3e493f4d
 	# If the message terminates a dialog for which the RTP proxy 
 	# was turned on, turn it off again.
 	if ((method == "BYE" && isflagset(FLAG_RTP_PROXY)) ||
 		(method == "CANCEL")) {
0c1a09fe
 		unforce_rtp_proxy();
3e493f4d
 		append_hf("P-RTP-Proxy: Off\r\n");
0c1a09fe
 		break;
 	}
 
3e493f4d
 	# Turn the RTP proxy on for INVITEs and UPDATEs, if they 
 	# have a body
ec8e49e8
 	if (((method=="INVITE" || method == "UPDATE") && @msg.body != "")
d7cdf250
 	    && !isflagset(FLAG_RTP_PROXY))
 	{
0c1a09fe
 		force_rtp_proxy('r');
3e493f4d
 		append_hf("P-RTP-Proxy: On\r\n");
c779fdf6
 		setflag(FLAG_RTP_PROXY);
3e493f4d
 		$rproxy = 1;
 		setavpflag($rproxy, "dialog_cookie");
0c1a09fe
 	}
 }
 
d7cdf250
 
3e493f4d
 # Handling of Route headers
d7cdf250
 #
3e493f4d
 route[PROCESS_ROUTES]
0c1a09fe
 {
 	# subsequent messages withing a dialog should take the
d7cdf250
 	# path determined by the Route headers.
0c1a09fe
 	if (loose_route()) {
ffa10596
 		if (!defined $dialog_id) {
 			$dialog_id = $t.dialog_id; # there is only 1 dialog_id
 		}
a0fdc9b7
 		if (@rr.next_route != "") {
 			setflag("FLAG_NEXT_ROUTE");
 		}
ffa10596
 		xlog("L_DEBUG", "\n%mb\n\ndialogid -/from/to=%$dialog_id/%$f.dialog_id/%$t.dialog_id");
 		if (method == "INVITE" || method == "UPDATE" || method == "ACK" || method == "BYE") {
 			if (!defined $dialog_id) {
 				sl_reply("400", "Missing cookie");
 				drop;
 			}
 		}
 
d7cdf250
 		# Mark routing logic in request.
 		append_hf("P-hint: rr-enforced\r\n");
0c1a09fe
 
d7cdf250
 		# If the Route contained the accounting AVP cookie we
0c1a09fe
 		# set the accounting flag for the acc_db module.
d7cdf250
 		# This is more for demonstration purpose as this could
0c1a09fe
 		# also be solved without RR cookies.
d7cdf250
 		# Note: this means all in-dialog request will show up in
0ee79c04
 		# the accounting tables, so prepare your accounting software
d7cdf250
 		# for this.
0c1a09fe
 		if ($account == "yes") {
 			setflag(FLAG_ACC);
e8ced19c
 			setflag(FLAG_ACC_MISSED);
0c1a09fe
 		}
 
3e493f4d
 		# Restore the RTP proxy flag if present
 		if ($rproxy == "1") {
 			setflag(FLAG_RTP_PROXY);
0c1a09fe
 		}
 
d7cdf250
 		# Restore Session Timer flag and headers.
ec8e49e8
 		if ( defined $stimer && ($stimer != "0")) {
6d4d32e3
 			route(SESSION_TIMER);
 		}
 
d7cdf250
 		# Some broken devices overide the dialog route set with the
 		# Record-Route headers from each in-dialog request. So, we
 		# better add Record-Route headers again. If we call
 		# record_route() after loose_route(), the AVP cookies are
 		# restored automatically. Additionally, there is a scenario
 		# where Record-Route headers are necessary if an initial
 		# SUBSCRIBE is forked.
 		#
 		# Note that here we forward before authentication checks
 		# are executed. Generally, we only authenticate
 		# out-of-dialog requests. Some in-dialog requests can't be
 		# authenticated at all, see the call-forwarding example in
 		# route[DOMAIN].
3e493f4d
 		route(RECORD_ROUTE);
0c1a09fe
 
 		route(FORWARD);
6d4d32e3
 	}
 }
 
d7cdf250
 
 # Add a Record-Route header
 #
3e493f4d
 route[RECORD_ROUTE]
6d4d32e3
 {
d7cdf250
 	if (!isflagset(FLAG_RR_DONE) && method != "REGISTER") {
 		# We record-route all messages to make sure that
 		# subsequent messages will go through our proxy. This is
0c1a09fe
 		# particularly good if upstream and downstream entities
d7cdf250
 		# use different transport protocols.
0c1a09fe
 
d7cdf250
 		# If the ACC flag is set, store this in a Record-Route
 		# AVP cookie. This is more for demonstration purposes.
0c1a09fe
 		if (isflagset(FLAG_ACC)) {
 			$account = "yes";
 			setavpflag($account, "dialog_cookie");
 		}
 
ffa10596
 		setavpflag("$f.dialog_id", "dialog_cookie");
 
d7cdf250
 		# Insert the RR header.
0c1a09fe
 		record_route();
6d4d32e3
 
d7cdf250
 		# This flag allows to call this route several times
 		# without inserting several RR headers.
6d4d32e3
 		setflag(FLAG_RR_DONE);
0c1a09fe
 	}
 }
 
d7cdf250
 
 # Look up the domains of the caller and the callee.
 #
0c1a09fe
 route[DOMAIN]
 {
d7cdf250
 	# Check whether the caller is from a local domain.
0c1a09fe
 	lookup_domain("$fd", "@from.uri.host");
 
d7cdf250
 	# Check whether the callee is at a local domain
0c1a09fe
 	lookup_domain("$td", "@ruri.host");
9ca93d22
 }
 
d7cdf250
 
 # Check domain usage policies and reject illegal requests.
 #
9ca93d22
 route[DOMAIN_POLICY]
 {
0c1a09fe
 
d7cdf250
 	# If we don't know the domain of the caller nor the domain of the
 	# callee, somone tries to use our proxy as a relay.  However, we
 	# can only apply this check out-of-dialog requests without a To
 	# tag.  In some cases such as call-forwarding, subsequent requests
 	# may not include served domain neither as origination nor
 	# destination (a@A calls b@B who forwards to c@C. A BYE by c@C is
 	# then From b@B and To a@A. There is no mentioning of c@C despite
 	# legitimate behaviour of c@C).
ec8e49e8
 	if (!isflagset(FLAG_TOTAG) && strempty($t.did) && strempty($f.did)) {
0c1a09fe
 		sl_reply("403", "Relaying Forbidden");
 		drop;
 	}
 }
 
 
d7cdf250
 # The Registrar
 #
0c1a09fe
 route[REGISTRAR]
 {
d7cdf250
 	# Process only REGISTERs here.
 	if (method != "REGISTER") {
0c1a09fe
 		break;
 	}
 
d7cdf250
 	# If this is a replica (sent to the multicast address), trust it to
 	# be secure and store it in usrloc
0c1a09fe
 	if (dst_ip==224.0.1.75) {
cc30d600
 		if (!isflagset(FLAG_REPL_ENABLED)) {
d7cdf250
 			# Multicast replication administratively disabled.
 			# Ignore.
0c1a09fe
 			drop;
 		}
d7cdf250
 
 		# Read marker from master
 		if (search("^Repl-Marker: nated")) {
0c1a09fe
 			setflag(FLAG_NAT);
 		}
0fe8b5f1
 
d7cdf250
 		# If the replicating server added its own server id to the
 		# request, obtain the value and store it in an attribute.
 		# This is used by registrar.
 		$server_id = @msg.header["SER-Server-ID"];
0fe8b5f1
 
d7cdf250
 		# Assume URI in form of UID@mydomain and store contacts
 		# under this UID.  Note that this only works if local policy
 		# causes UIDs to have form compliant to RFC3261 URI
 		# usernames.
ffa10596
 		if (@ruri.user!="")
 			$tu.uid = @ruri.user;
 		if (isflagset(FLAG_NAT)) {
 			setflag(FLAG_NAT_REG);
 		}
0c1a09fe
 		if (!save_mem_nr("location")) {
d7cdf250
 			log(1, "Error while saving replicated REGISTER.\n");
0c1a09fe
 		}
 		drop;
d7cdf250
 	}
 	else {
 		# This is a REGISTER request received from the UA. Remove
 		# our internal header fields if they are present. The may
 		# have been added maliciously.
 		remove_hf("SER-Server-ID");
 		remove_hf("Repl-Marker");
 	}
 
 	# Check if the REGISTER if for one of our local domains.
ec8e49e8
 	if (strempty($t.did)) {
d7cdf250
 		sl_reply("403", "Register Forwarding Forbidden");
0c1a09fe
 		drop;
 	}
 
d7cdf250
 	# The REGISTER target is in the To header, so reload the domain.
0c1a09fe
 	if (!lookup_domain("$td", "@to.uri.host")) {
 		sl_reply("404", "Unknown Domain");
 		drop;
 	}
 
d7cdf250
 	# Useful for clients that ignore expires in 200 (OK). This is an
 	# attempt to keep them sticking to our value of 600.
0c1a09fe
 	append_to_reply("Expires: 600\r\n");
 	append_to_reply("Min-Expires: 240\r\n");
 
d7cdf250
 	# We want only authenticated users to be registered.
0c1a09fe
 	if (!www_authenticate("$fd.digest_realm", "credentials")) {
 		if ($? == -2) {
 			sl_reply("500", "Internal Server Error");
d7cdf250
 		}
 		else if ($? == -3) {
0c1a09fe
 			sl_reply("400", "Bad Request");
d7cdf250
 		}
 		else {
ec8e49e8
 			if ($digest_challenge != "") {
0c1a09fe
 				append_to_reply("%$digest_challenge");
 			}
 			sl_reply("401", "Unauthorized");
 		}
 		drop;
 	}
 
d7cdf250
 	# Check if the authenticated user is the same as the target user.
0c1a09fe
 	if (!lookup_user("$tu.uid", "@to.uri")) {
 		sl_reply("404", "Unknown user in To");
 		drop;
 	}
 
 	# the authentication ID does not match the ID in the To header
 	if ($f.uid != $t.uid) {
 		sl_reply("403", "Authentication and To-Header mismatch");
 		drop;
 	}
 
d7cdf250
 	# Check if the authenticated user is the same as the request
 	# originator. You may uncomment it if you care, which URI is in
 	# the From header.
c3a077de
 	#if (!lookup_user("$fr.uid", "@from.uri")) {
0c1a09fe
 	#	sl_reply("404", "Unknown user in From");
 	#	drop;
 	#}
c3a077de
 	#if ($fu.uid != $fr.uid) {
0c1a09fe
 	#	sl_reply("403", "Authentication and From-Header mismatch");
 	#	drop;
 	#}
 
ffa10596
 	if (isflagset(FLAG_NAT)) {
 		setflag(FLAG_NAT_REG);
 	}
d7cdf250
 	# Everything is fine. Store the binding.
0c1a09fe
 	if (!save_contacts("location")) {
 		sl_reply("400", "Invalid REGISTER Request");
 		drop;
 	}
af15fe76
 # do not delete the following 3 lines, they are used by debconf
 #DEBCONF-REPLICATION1-START
 #
 #DEBCONF-REPLICATION1-END
cc30d600
 	if (isflagset(FLAG_REPL_ENABLED)) {
0c1a09fe
 		if (isflagset(FLAG_NAT)) {
 			append_hf("Repl-Marker: nated\r\n");
 		}
cc30d600
 		# Append this server's unique ID to the request
 		append_hf_value("SER-Server-ID", "%@sys.server_id");
d7cdf250
 		# We are multicasting a successful REGISTER to all proxies
 		# on the multicast network to replicate the contact
 		# addresses to all of them. In case they share the same IP
 		# address (VIP) it is important to set the sending IP
 		# address to an unshared one (in the future a special mcast
 		# module may use unbound sockets for sending and leave
 		# the source IP address decision up to kernel routing
 		# tables).
0c1a09fe
 		#DEBCONF-REPL_SEND_ADDR-START
94789f36
 		force_send_socket(udp:127.0.0.1);
0c1a09fe
 		#DEBCONF-REPL_SEND_ADDR-END
d7cdf250
 		# Put the UID in the Request-URI so that it doesn't have to
 		# be looked up in the database by all multicast receivers.
0c1a09fe
 		attr2uri("$tu.uid","user");
 		forward_udp(224.0.1.75,5060);
 	}
af15fe76
 #DEBCONF-REPLICATION2-START
 #
 #DEBCONF-REPLICATION2-END
 
0c1a09fe
 	drop;
 }
 
 
d7cdf250
 # Authentication of request originators claiming to belong to one of our
 # domains.
 #
0c1a09fe
 route[AUTHENTICATION]
 {
d7cdf250
 	# CANCELs and ACKs cannot be challenged.
0c1a09fe
 	if (method=="CANCEL" || method=="ACK") {
 		break;
 	}
 
d7cdf250
 	# Requests from non-local to local domains should be permitted.
 	# Remove this if you want a walled garden.
ec8e49e8
 	if (strempty($f.did)) {
0c1a09fe
 		break;
 	}
 
d7cdf250
 	# Gateways are usually not able to authenticate for their requests.
 	# You have to trust them base on some other information such as the
 	# source IP address.
 	# WARNING: If at all this is only safe in a local network!
d010f59e
 	if (src_ip == $gw_ip) {
0c1a09fe
 		break;
 	}
 
 	if (!proxy_authenticate("$fd.digest_realm", "credentials")) {
 		if ($? == -2) {
 			sl_reply("500", "Internal Server Error");
d7cdf250
 		}
 		else if ($? == -3) {
0c1a09fe
 			sl_reply("400", "Bad Request");
d7cdf250
 		}
 		else {
89f45812
 			if (defined $digest_challenge && $digest_challenge != "") {
0c1a09fe
 				append_to_reply("%$digest_challenge");
 			}
 			sl_reply("407", "Proxy Authentication Required");
 		}
 		drop;
 	}
 
d7cdf250
 	# Check if the UID derived from authentication matches that from
 	# the From header.
695adc69
 	if (!lookup_user("$fr.uid", "@from.uri")) {
d471b01a
 		sl_reply("403", "Fake Identity");
 		drop;
0c1a09fe
 	}
695adc69
 	if ($fu.uid != $fr.uid) {
0c1a09fe
 		sl_reply("403", "Fake Identity");
 		drop;
 	}
 	setflag(FLAG_AUTH_OK);
d7cdf250
 
 	# Load the user attributes of the caller.
0c1a09fe
 	load_attrs("$fu", "$f.uid");
 }
 
d7cdf250
 
 # Process request targeted to non-local domains.
 #
0c1a09fe
 route[OUTBOUND]
 {
d7cdf250
 	# If a local user calls to a foreign domain we play outbound
 	# proxy for them.
 	# Comment this out if you want a walled garden.
ec8e49e8
 	if ($f.did != "" && strempty($t.did)) {
0c1a09fe
 		append_hf("P-hint: outbound\r\n");
 		route(FORWARD);
 	}
 }
 
d7cdf250
 
 # Process speeddial addresses.
 #
0c1a09fe
 route[SPEEDDIAL]
 {
d7cdf250
 	# If the caller is local and uses two digits only, we redirect the
 	# UA to the real target.
ec8e49e8
 	if ($fd.did != "" && uri =~ "sip:[0-9][0-9]@") {
0c1a09fe
 		if (sd_lookup("speed_dial")) {
 			sl_reply("302", "Speed Dial Redirect");
d7cdf250
 		}
 		else {
0c1a09fe
 			sl_reply("404", "Speed Dial Not Found");
 		}
 		drop;
 	}
 }
 
d7cdf250
 
 # Process requests targeted to a local user.
 #
0c1a09fe
 route[INBOUND]
 {
 	# lets see if know the callee
d7cdf250
 	if (!lookup_user("$tu.uid", "@ruri")) {
66de7b4c
 		break;
d7cdf250
 	}
 
 	# Load the attributes of the callee.
66de7b4c
 	load_attrs("$tu", "$t.uid");
 
d7cdf250
 	# You can check if the called URI is in fact an alias like this.
66de7b4c
 	#if (! $tu.uri_canonical) {
d7cdf250
 	#	# If the alias URI has different attributes, you can load
 	#	# them into the URI track like this.
 	#	load_attrs("$tr", "@ruri");
66de7b4c
 	#}
0c1a09fe
 
d7cdf250
 	# Check for call forwarding of the callee.
 	# Note: The forwarding target has to be full routable URI
 	#       in this example.
89f45812
 	if (defined $tu.fwd_always_target && $tu.fwd_always_target != "") {
66de7b4c
 		attr2uri("$tu.fwd_always_target");
 
d7cdf250
 		# If we are forwarding to ourselves, don't remove
 		# credentials. Otherwise the request would be challenged
 		# again.
 		# Note: This doesn't apply to failure_route which may
 		# still be problematic -- credentials are already
 		# removed when we forward. Consider using a 3xx.
66de7b4c
 		lookup_domain("$td", "@ruri.host");
89f45812
 		if (defined $t.did && $t.did != "") {
66de7b4c
 			setflag(FLAG_DONT_RM_CRED);
0c1a09fe
 		}
66de7b4c
 		route(FORWARD);
 	}
0c1a09fe
 
d7cdf250
 	# Native SIP destinations are handled using the usrloc database.
66de7b4c
 	if (lookup_contacts("location")) {
 		append_hf("P-hint: usrloc applied\r\n");
 
ffa10596
 		# destination is behind NAT
 		if (isflagset(FLAG_NAT_REG)) {
 			setflag(FLAG_NAT); /* client was behind NAT when made registration */
 		}
d7cdf250
 		# We set the tm module timers according to the prefences
 		# of the callee (avoid too long ringing of his phones).
 		# Note1: Timer values have to be in ms now!
 		# Note2: This makes even more sense if you switch to a
 		#        voicemail from the FAILURE_ROUTE below.
66de7b4c
 		if ($t.fr_inv_timer) {
 			if ($t.fr_timer) {
 				t_set_fr("$t.fr_inv_timer", "$t.fr_timer");
d7cdf250
 			}
 			else {
66de7b4c
 				t_set_fr("$t.fr_inv_timer");
 			}
0c1a09fe
 		}
66de7b4c
 
d7cdf250
 		# This enables session timer support as long as one side
 		# supports it.  If you want to have session timmer support
 		# only for calls from your PSTN gateway but not between pure
 		# VoIP calls you can remove the comment marks from the if
 		# clause in the next line and closing bracket below.
 		# WARNING: If at all you should trust IP addresses only in
 		#          your local network!
d010f59e
 		#if (src_ip == $gw_ip) {
6d4d32e3
 			route(SESSION_TIMER);
 		#}
 
66de7b4c
 		route(FORWARD);
d7cdf250
 	}
 	else {
 		sl_reply("480", "Temporarily unavailable");
66de7b4c
 		drop;
0c1a09fe
 	}
 }
 
d7cdf250
 
 # Process calls for PSTN.
 #
0c1a09fe
 route[PSTN]
 {
d7cdf250
 	# Check some conditions first:
 	# PSTN is available for our own users only.
ec8e49e8
 	if (strempty($f.did)) {
d7cdf250
 		break;
 	}
0c1a09fe
 
d7cdf250
 	# If the attribute $gw_ip isn't set, there is no PSTN service
 	# active.
ec8e49e8
 	if (!defined $gw_ip) {
d7cdf250
 		break;
 	}
0c1a09fe
 
d7cdf250
 	# And finally, the username of the Request-URI must look like
 	# a phone number.
 	if (!uri =~ "^sips?:\+?[0-9]{3,18}@") {
 		break;
 	}
 
 	# You may have to convert the number in the Request-URI into a
 	# format that is accepted by your gateway here.
 
 	# Check permissions of the caller for initial INVITEs.
ffa10596
 	if (isflagset(FLAG_INIT_DLG)) {
ec8e49e8
 		if ($f.gw_acl != "1") {
d7cdf250
 			sl_reply("403", "PSTN Not Permitted");
0c1a09fe
 			drop;
 		}
 	}
 
d7cdf250
 	# If the attribute $asserted_id is set, we add its contents as a
 	# Remote-Party-ID header.
 	# Depending on your gateway, you may have to add a
 	# P-Asserted-Identity header here instead.
ec8e49e8
 	if (defined $asserted_id) {
d7cdf250
 		xlset_attr("$rpidheader",
 			"<sip:%$asserted_id@%@ruri.host>;screen=yes");
0c1a09fe
 		replace_attr_hf("Remote-Party-ID", "$rpidheader");
 	}
 
d7cdf250
 	# Enable Session Timer support with the gateway.
6d4d32e3
 	route(SESSION_TIMER);
 
d7cdf250
 	# Replace the domain part of the Request-URI with the value from
 	# the attribute  and send it out.
0c1a09fe
 	attr2uri("$gw_ip", "domain");
d7cdf250
 
 	# Set the PSTN_ALLOWED flag. This will be checked on the
 	# onsend_route.
0c1a09fe
 	setflag(FLAG_PSTN_ALLOWED);
 	route(FORWARD);
 }
 
 
d7cdf250
 # Try to process CANCEL requests quickly.
 #
 route[CATCH_CANCEL]
 {
0c1a09fe
 	if (method == CANCEL) {
d7cdf250
 		# t_relay_cancel() will stop processing if a matching
 		# INVITE was found.
ffa10596
 		xlog("L_DEBUG", "catching cancel dialogid=%$dialog_id\n");
d7cdf250
 		if (!t_relay_cancel()) {
 			# An INVITE was found but some error occurred.
6d4d32e3
 			sl_reply("500", "Internal Server Error");
 			drop;
 		}
d7cdf250
 		# Bad luck, no corresponding INVITE was found, we have to
 		# continue with the script.
0c1a09fe
 	}
 }
 
d7cdf250
 
 # Site specific policy.
 #
 route[SITE_SPECIFIC]
 {
 	# This is only relevant for requests for one of our domains.
ec8e49e8
 	if (strempty($t.did)) {
d7cdf250
 		break;
 	}
f492982f
 
d7cdf250
 	# Do site specific routing such as peering.
 	# For example:
0c1a09fe
 	if (uri=~"^sip:000777") {
 		rewritehostport("sems01.iptel.org:5074");
 		route(FORWARD);
 	}
 }
 
d7cdf250
 # Process Session-Timer.
 #
6d4d32e3
 route[SESSION_TIMER]
 {
d7cdf250
 	# We are only interested in session establishment or session
 	# refreshing.
 	#
1b5741d0
 	if (method != "INVITE" && method != "UPDATE") {
6d4d32e3
 		break;
 	}
 
d7cdf250
 	# Let's check if the Session-Expires header is already present.
ec8e49e8
 	if (@hf_value.session_expires != "") {
d7cdf250
 		# Compare the Session-Expires header value with the
 		# configured Min-SE.
6d4d32e3
 		eval_push("x:%@hf_value.session_expires.uri");
 		eval_oper("(int)", -1);
 		eval_push("x:%@cfg_get.session_timer.min_se");
 		eval_oper("(int)", -1);
83c22ad8
 		eval_oper(">=", -2);
6d4d32e3
 
d7cdf250
 		# Let's check for the Suported header.
19c36b69
 		if (hf_value_exists("Supported", "timer")) {
d7cdf250
 			# The UAC supports Session-Timer, so we
6d4d32e3
 			# only need to take a look at the values
 			if (@eval.pop[-1] == "0") {
d7cdf250
 				# Session interval is lower than the
 				# configured Min-SE
6d4d32e3
 				append_to_reply("Min-SE: %@cfg_get.session_timer.min_se\r\n");
 				sl_reply("422", "Session Interval Too Small");
 				drop;
 			}
 
d7cdf250
 			# We store the session expires value for the reply
 			# route and mark the attribute for inserting as
 			# Record-Route cookie.
6d4d32e3
 			$stimer = @hf_value.session_expires.uri;
 			setavpflag($stimer, "dialog_cookie");
 
d7cdf250
 			# Set the session timer flag that indicates the
6d4d32e3
 			# UAC supports the extension.
 			setflag(FLAG_SESSIONTIMER);
d7cdf250
 		}
 		else {
 			# Session epxires was already inserted by some other
 			# proxy
6d4d32e3
 			if (@eval.pop[-1] == "0") {
d7cdf250
 				# Session interval is lower than the
 				# configured Min-SE. There is no point in
 				# sending 422 response, because the UAC
 				# does not support the extension, the values
 				# can be corrected instead.
 				assign_hf_value("Session-Expires",
 					"%@cfg_get.session_timer.min_se");
6d4d32e3
 				remove_hf_value("Min-SE");
d7cdf250
 				append_hf_value("Min-SE",
 					"%@cfg_get.session_timer.min_se");
6d4d32e3
 			}
 		}
d7cdf250
 	}
 	else {
 		# No Session Timer is requested yet, neither by UAC nor by
 		# proxy
6d4d32e3
 		if (@cfg_get.session_timer.default != "0") {
d7cdf250
 			# Add a Session Expires header to see if the UAS
 			# supports Session Timer. We do not insert a
 			# Required header because then the call might fail.
 			append_hf_value("Session-Expires",
 				"%@cfg_get.session_timer.default");
 			if (@cfg_get.session_timer.min_se != "90") {
 				append_hf_value("Min-SE",
 					"%@cfg_get.session_timer.min_se");
6d4d32e3
 			}
 
d7cdf250
 			# Mark the attribute to be inserted as a
 			# Record-Route cookie
6d4d32e3
 			$stimer = @cfg_get.session_timer.default;
 			setavpflag($stimer, "dialog_cookie");
 		}
 	}
 }
0c1a09fe
 
3e493f4d
 # Route which checks and performs ENUM queries
 # #
 route[ENUM]
 {
 	# perform ENUM query only if the RURI contains an E.164
 	# number as uer part
 	if (uri =~ "sip:\+[0-9]?@") {
 		# if the ENUM query was successful send it right
 		# away of to the new target, otherwise do nothing
 		if (enum_query()) {
 			route(FORWARD);
 		}
 	}
 }
 
d7cdf250
 
 # Failure route for initial INVITEs.
 #
0c1a09fe
 failure_route[FAILURE_ROUTE]
 {
ffa10596
 	if (isflagset(FLAG_INIT_DLG)) {
 		# Mark that we are operating from a failure route.
 		setflag(FLAG_FAILUREROUTE);
 
 		if (t_check_status("486|600")) {
 			# If we received a busy and a busy target is set, forward
 			# it there.
 			# Note: Again, the forwarding target has to be a routeable
 			# URI. We redirect using 3xx to avoid possible issues with
 			# credentials (if we consumed them, they may be missing in
 			# a loop, if we don't consume them, messages are bigger and
 			# more vulnerable)
 			if ($tu.fwd_busy_target != "") {
 				attr2uri("$tu.fwd_busy_target");
 				#attr_destination("$tu.fwd_busy_target");
 				#route(FORWARD);
 				t_reply("302", "Redirect On Busy");
 			}
 			# Alternatively, you could forward the request to
 			# SEMS/voicemail here
0c1a09fe
 		}
ffa10596
 		else if (t_check_status("408|480")) {
 			# If we received no answer and the noanswer target is set,
 			# forward it there.
 			# Note: See above.
 			if ($tu.fwd_noanswer_target != "") {
 				attr2uri("$tu.fwd_noanswer_target");
 				#attr_destination("$tu.fwd_noanswer_target");
 				#route(FORWARD);
 				t_reply("302", "Redirect On No Answer");
 			}
0c1a09fe
 		}
ffa10596
 	} # if (isflagset...
0c1a09fe
 }
 
d7cdf250
 
 # Onreply route that fixes NAT in responses.
 #
0c1a09fe
 onreply_route[REPLY_ROUTE]
 {
3e493f4d
 	# Check and fix the Contact in the reply to
d7cdf250
 	# allow proper routing of in-dialog messages.
3e493f4d
 	route(UAS_NAT_DETECTION);
0c1a09fe
 
d7cdf250
 	# If RTP proxy was activated and this is a 18x or 2xx reply with a
 	# body, inform RTP proxy.
 	if (isflagset(FLAG_RTP_PROXY)
 	    && status=~"(18[03])|(2[0-9][0-9])"
ec8e49e8
 	    && @msg.body != "")
d7cdf250
 	{
0c1a09fe
 		force_rtp_proxy('r');
 	}
6d4d32e3
 
d7cdf250
 	# Let's check for session timer support.
6d4d32e3
 	if (isflagset(FLAG_SESSIONTIMER) && status =~ "2[0-9][0-9]") {
d7cdf250
 		# The UAC wanted to have a session timer.
ec8e49e8
 		if (strempty(@hf_value.session_expires)) {
d7cdf250
 			# But the UAS does not support it, so we will try
 			# to convince the UAC to do it.
 			append_hf_value("Session-Expires",
 				"%$stimer;refresher=uac");
6d4d32e3
 			if (!hf_value_exists("Require", "timer")) {
 				include_hf_value("Require", "timer");
 			}
 		}
 	}
0c1a09fe
 }
 
 
d7cdf250
 # Do some final checks before a request is sent out.
 onsend_route
 {
 	# Bypass check: Eliminate requests to the PSTN gateway if they have
 	# not passed ACL checks and are not marked with FLAG_PSTN_ALLOWED
 	# but are dialog-initiating requests (no to-tag, no CANCEL, no ACK).
 	# This helps to stop policy bypasses (gateway IP uploaded as a
 	# forked contact, or a call-forwarding destination, or a DNS name,
 	# or a preloaded route, or something else possibly)
89f45812
 	if (defined $g.gw_ip && to_ip==$g.gw_ip && !isflagset(FLAG_PSTN_ALLOWED)
d7cdf250
 	    && !isflagset(FLAG_TOTAG)
 	    && method != "ACK" && method != "CANCEL")
 	{
0c1a09fe
 		log(1, "ALERT: non authorized packet for PSTN, dropping...\n%mb\n");
f492982f
 
d7cdf250
 		# You can't use advanced features from onsend_route.
 		# xlog("L_ALERT", "non authorized packet for PSTN, dropping...\n%mb\n");
0c1a09fe
 		drop;
 	}
f492982f
 
d7cdf250
 	# RFC 1918 relay protection: Useful if SER is attached to an
 	# administrative network using private IP address space and you
 	# wish to prevent UACs from relaying their packets there.
 	#
 	# You will have to comment this out, if you are regularly serving
 	# an RFC 1918 address space.
 	if (to_ip==10.0.0.0/8 || to_ip==172.16.0.0/12
 	    || to_ip==192.168.0.0/16)
 	{
b5b7ced7
 		log(1, "ALERT: Packet targeted to an RFC1918 address dropped\n");
 		drop;
 	}
0c1a09fe
 }
 
d7cdf250
 
 # Run every minute by the timer module.
 #
0c1a09fe
 route[ON_1MIN_TIMER] {
d7cdf250
 	# Cleanup expired location records
 	# MySQL version:
 	db_query("delete from location where expires<utc_timestamp()");
 	# PostgreSQL version:
 	#db_query("delete from location where expires<now()");
0c1a09fe
 
 
d7cdf250
 	# Reload domains if domain table has been changed recently.
 	# Note: because global attributes are read-only and we can't
 	# easily remember the "last" status, we check for changed
 	# timestamp in 2 minute time-interval.
 	# MySQL version:
17efc53f
 	db_query("select value from global_attrs where name='domain_data_version' and type=0 and cast(value as unsigned int) between unix_timestamp(now())-120 and unix_timestamp(now())", "reload");
d7cdf250
 	# PostgreSQL version:
 	#db_query("select value from global_attrs where name='domain_data_version' and type=0 and cast(value as integer) between date_part('epoch', now() - interval '120 seconds') and date_part('epoch', now())", "reload");
17efc53f
 	if (@db.fetch.reload.count=="1") {
d7cdf250
 		# Domain reload only available as fifo command.
f492982f
 		exec_msg("sercmd domain.reload");
0c1a09fe
 	}
17efc53f
 	db_close("reload");
6351694a
 
 	# Reload global attributes (they are cached in memory) if the contents of
 	# the global_attrs table has been changed recently.
 	db_query("select value from global_attrs where name='gattr_timestamp' and type=0 and cast(value as unsigned int) between unix_timestamp(now())-120 and unix_timestamp(now())", "gattr_reload");
 	if (@db.fetch.gattr_reload.count=="1") {
 	   exec_msg("sercmd global.reload");
 	}
 	db_close("gattr_reload");
0c1a09fe
 }
 
99fab38d
 
 #!ifdef WITH_XMLRPC
 # handle xmlrpcs
 route[XMLRPC]{
 	# accept xmlrpc requests only from localhost
 	if (src_ip!=127.0.0.1
 	#!ifdef XMLRPC_ALLOW_NET1
 		&& src_ip != XMLRPC_ALLOW_NET1
 	#!endif
 	#!ifdef XMLRPC_ALLOW_NET2
 		&& src_ip != XMLRPC_ALLOW_NET2
 	#!endif
 	#!ifdef XMLRPC_ALLOW_NET3
 		&& src_ip != XMLRPC_ALLOW_NET3
 	#!endif
 		) {
 		xmlrpc_reply("400", "xmlrpc not allowed from this address");
 		return;
 	}
 	if (method!="POST" && method!="GET") {
 		xmlrpc_reply("400", "unsupported HTTP method");
 		return;
 	}
 	if (msg:len >= 8192) {
 		xmlrpc_reply("513", "request too big");
 		return;
 	}
 #!ifdef XMLRPC_TLS_ONLY
 	# allow xmlrpc only on TLS and only if the client certificate is valid
 	if (proto!=TLS){
 		xmlrpc_reply("400", "xmlrpc allowed only over TLS");
 		return;
 	}
 	if (@tls.peer.verified!=""){
 		xmlrpc_reply("400", "Unauthorized");
 		return;
 	}
 #!endif
 
 	# close connection only for xmlrpclib user agents (there is a bug in
 	# xmlrpclib: it waits for EOF before interpreting the response).
 	if (search("^User-Agent:.*xmlrpclib"))
 		set_reply_close();
 	set_reply_no_connect(); # optional
 	dispatch_rpc();
 }