123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618 |
- #
- # $Id$
- #
- # Example configuration file (simpler than ser-oob.cfg, but more
- # complex then ser-basic.cfg).
- #
- # First start SER sample config script with:
- # database, accounting, authentication, multi-domain support
- # PSTN GW section, named flags, named routes, global-,
- # domain- and user-preferences with AVPs
- # Several of these features are only here for demonstration purpose
- # what can be achieved with the SER config script language.
- #
- # If you look for a simpler version with a lot less dependencies
- # please refer to the ser-basic.cfg file in your SER distribution.
- #
- # If you look for documentation, try http://sip-router.org/wiki/.
- # The right mailing lists for questions about this file is
- # <[email protected]>.
- # To get this config running you need to execute the following commands
- # with the new serctl (the capital word are just place holders)
- # - ser_ctl domain add DOMAINNAME
- # - ser_ctl user add USERNAME@DOMAINNAME -p PASSWORD
- # ser_ctl can be obtained from
- # http://ftp.iptel.org/pub/serctl/daily-snapshots/.
- #
- # If you want to have PID header for your user
- # - ser_attr add uid=UID asserted_id="PID"
- # If you want to have 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
- # ----------- 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
- # started from compile directory (not installed)
- ##!define LOCAL_TEST_RUN
- # 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
- # ----------- global configuration parameters ------------------------
- debug=2 # debug level (cmd line: -dddddddddd)
- #memdbg=10 # memory debug log level
- #memlog=10 # memory statistics log level
- #log_facility=LOG_LOCAL0 # sets the facility used for logging (see syslog(3))
- /* Uncomment these lines to enter debugging mode
- fork=no
- log_stderror=yes
- */
- check_via=no # (cmd. line: -v)
- dns=no # (cmd. line: -r)
- rev_dns=no # (cmd. line: -R)
- #port=5060
- #children=4
- #user=ser
- #group=ser
- #disable_core=yes #disables core dumping
- #open_fd_limit=1024 # sets the open file descriptors limit
- #mhomed=yes # useful for multihomed hosts, small performance penalty
- #disable_tcp=yes
- #tcp_accept_aliases=yes # accepts the tcp alias via option (see NEWS)
- sip_warning=yes
- #!ifdef WITH_TLS
- enable_tls=yes
- #!endif
- #
- # ------------------ module loading ----------------------------------
- #!ifdef LOCAL_TEST_RUN
- loadpath "modules:modules_s"
- #!else
- loadpath "/usr/lib/ser/modules:/usr/lib/ser/modules_s"
- #!endif
- # load a SQL database for authentication, domains, user AVPs etc.
- loadmodule "db_mysql"
- loadmodule "tm"
- loadmodule "sl"
- loadmodule "rr"
- loadmodule "maxfwd"
- loadmodule "usrloc"
- loadmodule "registrar"
- loadmodule "xlog"
- loadmodule "textops"
- loadmodule "ctl"
- loadmodule "cfg_rpc"
- loadmodule "auth"
- loadmodule "auth_db"
- loadmodule "gflags"
- loadmodule "domain"
- loadmodule "uri_db"
- loadmodule "avp"
- loadmodule "avp_db"
- loadmodule "acc_db"
- loadmodule "xmlrpc"
- #!ifdef WITH_TLS
- loadmodule "tls"
- #!endif
- # ----------------- setting script FLAGS -----------------------------
- flags
- FLAG_ACC : 1, # include message in accounting
- FLAG_FAILUREROUTE : 2; # we are operating from a failure route
- avpflags
- dialog_cookie; # handled by rr module
- # ----------------- setting module-specific parameters ---------------
- # specify the path to you database here
- modparam("acc_db|auth_db|avp_db|domain|gflags|usrloc|uri_db", "db_url", "mysql://ser:[email protected]/ser")
- # -- usrloc params --
- # as we use the database anyway we will use it for usrloc as well
- modparam("usrloc", "db_mode", 1)
- # -- auth params --
- modparam("auth_db", "calculate_ha1", yes)
- modparam("auth_db", "plain_password_column", "password")
- # -- rr params --
- # add value to ;lr param to make some broken UAs happy
- modparam("rr", "enable_full_lr", 1)
- #
- # limit the length of the AVP cookie to only necessary ones
- modparam("rr", "cookie_filter", "(account)")
- #
- # you probably do not want that someone can simply read and change
- # the AVP cookie in your Routes, thus should really change this
- # secret value below
- modparam("rr", "cookie_secret", "MyRRAVPcookiesecret")
- # -- gflags params --
- # load the global AVPs
- modparam("gflags", "load_global_attrs", 1)
- # -- domain params --
- # load the domain AVPs
- modparam("domain", "load_domain_attrs", 1)
- # -- ctl params --
- # by default ctl listens on unixs:/tmp/ser_ctl if no other address is
- # specified in modparams; this is also the default for sercmd
- modparam("ctl", "binrpc", "unixs:/tmp/ser_ctl")
- # listen on the "standard" fifo for backward compatibility
- modparam("ctl", "fifo", "fifo:/tmp/ser_fifo")
- # listen on tcp, localhost
- modparam("ctl", "binrpc", "tcp:127.0.0.1:2046")
- # -- acc_db params --
- # failed transactions (=negative responses) should be logged to
- modparam("acc_db", "failed_transactions", 1)
- # comment the next line if you don't want to have accounting to DB
- modparam("acc_db", "log_flag", "FLAG_ACC")
- # -- tm params --
- # uncomment the following line if you want to avoid that each new reply
- # restarts the resend timer (see INBOUND route below)
- #modparam("tm", "restart_fr_on_each_reply", "0")
- #!ifdef WITH_TLS
- # -- tls params --
- modparam("tls", "verify_certificate", 0)
- #!ifdef LOCAL_TEST_RUN
- modparam("tls", "certificate", "./modules/tls/sip-router-selfsigned.pem")
- modparam("tls", "private_key", "./modules/tls/sip-router-selfsigned.key")
- #separate TLS config file
- #modparam("tls", "config", "./modules/tls/tls.cfg")
- #!else
- modparam("tls", "certificate", "ser-selfsigned.pem")
- modparam("tls", "private_key", "ser-selfsigned.key")
- #separate TLS config file
- #modparam("tls", "config", "tls.cfg")
- #!endif
- # -- xmlrpc params --
- # using a sub-route from the module is a lot safer than relying on the
- # request method to distinguish HTTP from SIP
- modparam("xmlrpc", "route", "RPC");
- # ------------------------- request routing logic -------------------
- # main routing logic
- 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
- #$gw_ip = "1.2.3.4"
- # first do some initial sanity checks
- route(INIT);
- # bypass the rest of the script for CANCELs if possible
- route(CATCH_CANCEL);
- # check if the request is routed via Route header or
- # needs a Record-Route header
- route(RR);
- # check if the request belongs to our proxy
- route(DOMAIN);
- # handle REGISTER requests
- route(REGISTRAR);
- # from here on we want to know you is calling
- route(AUTHENTICATION);
- # check if we should be outbound proxy for a local user
- route(OUTBOUND);
- # check if the request is for a local user
- route(INBOUND);
- # here you could for example try to do an ENUM lookup before
- # the call gets routed to the PSTN
- #route(ENUM);
- # lets see if someone wants to call a PSTN number
- route(PSTN);
- # nothing matched, reject it finally
- sl_reply("404", "No route matched");
- }
- route[FORWARD]
- {
- # here you could decide wether this call needs a RTP relay or not
- # if this is called from the failure route we need to open a new branch
- if (isflagset(FLAG_FAILUREROUTE)) {
- append_branch();
- }
- # if this is an initial INVITE (without a To-tag) we might try another
- # (forwarding or voicemail) target after receiving an error
- if (method=="INVITE" && strempty(@to.tag)) {
- t_on_failure("FAILURE_ROUTE");
- }
- # send it out now; use stateful forwarding as it works reliably
- # even for UDP2TCP
- if (!t_relay()) {
- sl_reply_error();
- }
- drop;
- }
- route[INIT]
- {
- # initial sanity checks -- messages with
- # max_forwards==0, or excessively long requests
- if (!mf_process_maxfwd_header("10")) {
- sl_reply("483", "Too Many Hops");
- drop;
- }
- if (msg:len >= 4096 ) {
- sl_reply("513", "Message too big");
- drop;
- }
- # you could add some NAT detection here for example
- # or you cuold call here some of the check from the sanity module
- # lets account all initial INVITEs
- # further in-dialog requests are accounted by a RR cookie (see below)
- if (method=="INVITE" && strempty(@to.tag)) {
- setflag(FLAG_ACC);
- }
- }
- route[RPC]
- {
- # allow XMLRPC from localhost
- if ((method=="POST" || method=="GET") &&
- (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
- )) {
- if (msg:len >= 8192) {
- sl_reply("513", "Request to big");
- drop;
- }
- # 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
- # lets see if a module wants to answer this
- dispatch_rpc();
- drop;
- }
- }
- route[RR]
- {
- # subsequent messages within a dialog should take the
- # path determined by record-routing
- if (loose_route()) {
- # mark routing logic in request
- append_hf("P-hint: rr-enforced\r\n");
- # if the Route contained the accounting AVP cookie we
- # set the accounting flag for the acc_db module.
- # this is more for demonstration purpose as this could
- # also be solved without RR cookies.
- # Note: this means all in-dialog request will show up in the
- # accounting tables, so prepare your accounting software for this ;-)
- if ($account == "yes") {
- setflag(FLAG_ACC);
- }
- # for broken devices which overwrite their Route's with each
- # (not present) RR from within dialog requests it is better
- # to repeat the RRing
- # and if we call rr after loose_route the AVP cookies are restored
- # automatically :)
- record_route();
- route(FORWARD);
- } else if (!method=="REGISTER") {
- # we record-route all messages -- to make sure that
- # subsequent messages will go through our proxy; that's
- # particularly good if upstream and downstream entities
- # use different transport protocol
- # if the initial INVITE got the ACC flag store this in
- # an RR AVP cookie. This is more for demonstration purpose
- if (isflagset(FLAG_ACC)) {
- $account = "yes";
- setavpflag($account, "dialog_cookie");
- }
- record_route();
- }
- }
- route[DOMAIN]
- {
- # check if the caller is from a local domain
- lookup_domain("$fd", "@from.uri.host");
- # check if the callee is at a local domain
- lookup_domain("$td", "@ruri.host");
- # we don't know the domain of the caller and also not
- # the domain of the callee -> somone uses our proxy as
- # a relay
- if (strempty($t.did) && strempty($f.did)) {
- sl_reply("403", "Relaying Forbidden");
- drop;
- }
- }
- route[REGISTRAR]
- {
- # if the request is a REGISTER lets take care of it
- if (method=="REGISTER") {
- # check if the REGISTER if for one of our local domains
- if (strempty($t.did)) {
- sl_reply("403", "Register forwarding forbidden");
- drop;
- }
- # we want only authenticated users to be registered
- if (!www_authenticate("$fd.digest_realm", "credentials")) {
- if ($? == -2) {
- sl_reply("500", "Internal Server Error");
- } else if ($? == -3) {
- sl_reply("400", "Bad Request");
- } else {
- if ($digest_challenge != "") {
- append_to_reply("%$digest_challenge");
- }
- sl_reply("401", "Unauthorized");
- }
- drop;
- }
- # check if the authenticated user is the same as the target user
- if (!lookup_user("$tu.uid", "@to.uri")) {
- sl_reply("404", "Unknown user in To");
- drop;
- }
- if ($f.uid != $t.uid) {
- sl_reply("403", "Authentication and To-Header mismatch");
- drop;
- }
- # check if the authenticated user is the same as the request originator
- # you may uncomment it if you care, what uri is in From header
- #if (!lookup_user("$fu.uid", "@from.uri")) {
- # sl_reply("404", "Unknown user in From");
- # drop;
- #}
- #if ($fu.uid != $tu.uid) {
- # sl_reply("403", "Authentication and From-Header mismatch");
- # drop;
- #}
- # everything is fine so lets store the binding
- if (!save_contacts("location")) {
- sl_reply("400", "Invalid REGISTER Request");
- drop;
- }
- drop;
- }
- }
- route[AUTHENTICATION]
- {
- if (method=="CANCEL" || method=="ACK") {
- # you are not allowed to challenge these methods
- break;
- }
- # requests from non-local to local domains should be permitted
- # remove this if you want a walled garden
- if (strempty($f.did)) {
- break;
- }
- # as gateways are usually not able to authenticate for their
- # requests you will have trust them base on some other information
- # like the source IP address. WARNING: if at all this is only safe
- # in a local network!!!
- #if (src_ip==a.b.c.d) {
- # break;
- #}
- if (!proxy_authenticate("$fd.digest_realm", "credentials")) {
- if ($? == -2) {
- sl_reply("500", "Internal Server Error");
- } else if ($? == -3) {
- sl_reply("400", "Bad Request");
- } else {
- if ($digest_challenge != "") {
- append_to_reply("%$digest_challenge");
- }
- sl_reply("407", "Proxy Authentication Required");
- }
- drop;
- }
- # check if the UID from the authentication meets the From header
- $authuid = $uid;
- if (!lookup_user("$fu.uid", "@from.uri")) {
- del_attr("$uid");
- }
- if ($fu.uid != $fr.authuid) {
- sl_reply("403", "Fake Identity");
- drop;
- }
- # load the user AVPs (preferences) of the caller, e.g. for RPID header
- load_attrs("$fu", "$f.uid");
- }
- route[OUTBOUND]
- {
- # if a local user calls to a foreign domain we play outbound proxy for him
- # comment this out if you want a walled garden
- if ($f.did != "" && $t.did == "") {
- append_hf("P-hint: outbound\r\n");
- route(FORWARD);
- }
- }
- route[INBOUND]
- {
- # lets see if know the callee
- if (lookup_user("$tu.uid", "@ruri")) {
- # load the preferences of the callee to have his timeout values loaded
- load_attrs("$tu", "$t.uid");
- # if you want to know if the callee username was an alias
- # check it like this
- #if (strempty($tu.uri_canonical)) {
- # if the alias URI has different AVPs/preferences
- # you can load them into the URI track like this
- #load_attrs("$tr", "@ruri");
- #}
- # check for call forwarding of the callee
- # Note: the forwarding target has to be full routable URI
- # in this example
- if ($tu.fwd_always_target != "") {
- attr2uri("$tu.fwd_always_target");
- route(FORWARD);
- }
- # native SIP destinations are handled using our USRLOC DB
- if (lookup_contacts("location")) {
- append_hf("P-hint: usrloc applied\r\n");
- # we set the TM module timers according to the preferences
- # 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
- if ($t.fr_inv_timer != 0) {
- if ($t.fr_timer != 0) {
- t_set_fr("$t.fr_inv_timer", "$t.fr_timer");
- } else {
- t_set_fr("$t.fr_inv_timer");
- }
- }
- route(FORWARD);
- } else {
- sl_reply("480", "User temporarily not available");
- drop;
- }
- }
- }
- route[PSTN]
- {
- # Only if the AVP 'gw_ip' is set and the request URI contains
- # only a number we consider sending this to the PSTN GW.
- # Only users from a local domain are permitted to make calls.
- # Additionally you might want to check the acl AVP to verify
- # that the user is allowed to make such expensives calls.
- if ($f.did != "" && $gw_ip != "" &&
- uri=~"sips?:\+?[0-9]{3,18}@.*") {
- # probably you need to convert the number in the request
- # URI according to the requirements of your gateway here
- # if an AVP 'asserted_id' is set we insert an RPID header
- if ($asserted_id != "") {
- xlset_attr("$rpidheader", "<sip:%$asserted_id@%@ruri.host>;screen=yes");
- replace_attr_hf("Remote-Party-ID", "$rpidheader");
- }
- # just replace the domain part of the RURI with the
- # value from the AVP and send it out
- attr2uri("$gw_ip", "domain");
- route(FORWARD);
- }
- }
- route[CATCH_CANCEL] {
- # check whether there is a corresponding INVITE to the CANCEL,
- # and bypass the rest of the script if possible
- if (method == CANCEL) {
- if (!t_relay_cancel()) { # implicit drop if the INVITE was found
- # INVITE was found but some error occurred
- sl_reply("500", "Internal Server Error");
- drop;
- }
- # bad luck, no corresponding INVITE was found,
- # we have to continue with the script
- }
- }
- failure_route[FAILURE_ROUTE]
- {
- # mark for the other routes that we are operating from here on 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
- if ($tu.fwd_busy_target != "") {
- attr2uri("$tu.fwd_busy_target");
- route(FORWARD);
- }
- # alternatively you could forward the request to SEMS/voicemail here
- }
- else if (t_check_status("408|480")) {
- # if we received no answer and the noanswer target is set,
- # forward it there
- # Note: again the target has to be a routeable URI
- if ($tu.fwd_noanswer_target != "") {
- attr2uri("$tu.fwd_noanswer_target");
- route(FORWARD);
- }
- # alternatively you could forward the request to SEMS/voicemail here
- }
- }
|