|
@@ -1,15 +1,32 @@
|
|
|
#
|
|
|
# $Id$
|
|
|
#
|
|
|
-# simple quick-start config script
|
|
|
+
|
|
|
+# 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-simple.cfg file in your SER distribution.
|
|
|
+
|
|
|
+# 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
|
|
|
+# 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 configuration parameters ------------------------
|
|
|
|
|
|
-#debug=3 # debug level (cmd line: -dddddddddd)
|
|
|
-#fork=yes
|
|
|
-#log_stderror=no # (cmd line: -E)
|
|
|
-#memlog=5 # memory debug log level
|
|
|
+debug=3 # 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
|
|
@@ -17,8 +34,8 @@ fork=no
|
|
|
log_stderror=yes
|
|
|
*/
|
|
|
|
|
|
-check_via=no # (cmd. line: -v)
|
|
|
-dns=no # (cmd. line: -r)
|
|
|
+check_via=no # (cmd. line: -v)
|
|
|
+dns=no # (cmd. line: -r)
|
|
|
rev_dns=no # (cmd. line: -R)
|
|
|
#port=5060
|
|
|
#children=4
|
|
@@ -37,8 +54,8 @@ rev_dns=no # (cmd. line: -R)
|
|
|
|
|
|
# ------------------ module loading ----------------------------------
|
|
|
|
|
|
-# Uncomment this if you want to use SQL database
|
|
|
-#loadmodule "/usr/local/lib/ser/modules/mysql.so"
|
|
|
+# load a SQL database for authentication, domains, user AVPs etc.
|
|
|
+loadmodule "/usr/local/lib/ser/modules/mysql.so"
|
|
|
|
|
|
loadmodule "/usr/local/lib/ser/modules/sl.so"
|
|
|
loadmodule "/usr/local/lib/ser/modules/tm.so"
|
|
@@ -46,40 +63,62 @@ loadmodule "/usr/local/lib/ser/modules/rr.so"
|
|
|
loadmodule "/usr/local/lib/ser/modules/maxfwd.so"
|
|
|
loadmodule "/usr/local/lib/ser/modules/usrloc.so"
|
|
|
loadmodule "/usr/local/lib/ser/modules/registrar.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/xlog.so"
|
|
|
loadmodule "/usr/local/lib/ser/modules/textops.so"
|
|
|
loadmodule "/usr/local/lib/ser/modules/ctl.so"
|
|
|
-#loadmodule "/usr/local/lib/ser/modules/fifo.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/fifo.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/auth.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/auth_db.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/gflags.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/domain.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/uri_db.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/avp.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/avp_db.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/acc_db.so"
|
|
|
+loadmodule "/usr/local/lib/ser/modules/xmlrpc.so"
|
|
|
+
|
|
|
+# ----------------- setting script FLAGS -----------------------------
|
|
|
+flags
|
|
|
+ FLAG_ACC : 1 # include message in accouting
|
|
|
|
|
|
-# Uncomment this if you want digest authentication
|
|
|
-# mysql.so must be loaded !
|
|
|
-#loadmodule "/usr/local/lib/ser/modules/auth.so"
|
|
|
-#loadmodule "/usr/local/lib/ser/modules/auth_db.so"
|
|
|
+avpflags
|
|
|
+ dialog_cookie; # handled by rr module
|
|
|
|
|
|
# ----------------- setting module-specific parameters ---------------
|
|
|
|
|
|
-# -- usrloc params --
|
|
|
+# specify the path to you database here
|
|
|
+modparam("acc_db|auth_db|domain|gflags|usrloc|uri_db", "db_url", "mysql://ser:[email protected]/ser")
|
|
|
|
|
|
-modparam("usrloc", "db_mode", 0)
|
|
|
+# -- usrloc params --
|
|
|
|
|
|
-# Uncomment this if you want to use SQL database
|
|
|
-# for persistent storage and comment the previous line
|
|
|
-#modparam("usrloc", "db_mode", 2)
|
|
|
+# as we use the database anyway we will use it for usrloc as well
|
|
|
+modparam("usrloc", "db_mode", 1)
|
|
|
|
|
|
# -- auth params --
|
|
|
-# Uncomment if you are using auth module
|
|
|
-#
|
|
|
-#modparam("auth_db", "calculate_ha1", yes)
|
|
|
-#
|
|
|
-# If you set "calculate_ha1" parameter to yes (which true in this config),
|
|
|
-# uncomment also the following parameter)
|
|
|
-#
|
|
|
-#modparam("auth_db", "password_column", "password")
|
|
|
+modparam("auth_db", "calculate_ha1", yes)
|
|
|
+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)
|
|
|
+#
|
|
|
+# 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
|
|
|
+# -- 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")
|
|
@@ -88,85 +127,320 @@ modparam("ctl", "fifo", "fifo:/tmp/ser_fifo")
|
|
|
# listen on tcp, localhost
|
|
|
#modparam("ctl", "binrpc", "tcp:localhost:2046")
|
|
|
|
|
|
+# -- acc_db params --
|
|
|
+modparam("acc_db", "failed_transactions", 1)
|
|
|
+
|
|
|
+# comment the next line if you dont want to have accouting to DB
|
|
|
+modparam("acc_db", "log_flag", "FLAG_ACC")
|
|
|
+
|
|
|
# ------------------------- 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);
|
|
|
+
|
|
|
+ # 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 coud for example try to 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_send_reply("404", "No route matched");
|
|
|
+}
|
|
|
+
|
|
|
+route[FORWARD]
|
|
|
+{
|
|
|
+ # here you could decide wether this call needs a RTP relay or not
|
|
|
+
|
|
|
+ # send it out now; use stateful forwarding as it works reliably
|
|
|
+ # even for UDP2TCP
|
|
|
+ if (!t_relay()) {
|
|
|
+ sl_reply_error();
|
|
|
+ };
|
|
|
+ drop;
|
|
|
+}
|
|
|
+
|
|
|
+route[INIT]
|
|
|
+{
|
|
|
+ # as soon as it is save to distinguish HTTP from SIP
|
|
|
+ # we can un-comment the next line
|
|
|
+ route(RPC);
|
|
|
|
|
|
# initial sanity checks -- messages with
|
|
|
# max_forwards==0, or excessively long requests
|
|
|
if (!mf_process_maxfwd_header("10")) {
|
|
|
sl_send_reply("483","Too Many Hops");
|
|
|
- break;
|
|
|
+ drop;
|
|
|
};
|
|
|
+
|
|
|
if (msg:len >= max_len ) {
|
|
|
sl_send_reply("513", "Message too big");
|
|
|
- break;
|
|
|
+ drop;
|
|
|
};
|
|
|
-
|
|
|
- # 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 (!method=="REGISTER") record_route();
|
|
|
|
|
|
+ # 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 and the BYEs
|
|
|
+ # if (method=="INVITE" && @to.tag=="" || method=="BYE") {
|
|
|
+ if (method=="INVITE" && @to.tag=="") {
|
|
|
+ setflag(FLAG_ACC);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+route[RPC]
|
|
|
+{
|
|
|
+ # allow XMLRPC from localhost
|
|
|
+ if ((method=="POST" || method=="GET") &&
|
|
|
+ src_ip==127.0.0.1) {
|
|
|
+
|
|
|
+ # add a Via header to the HTTP
|
|
|
+ create_via();
|
|
|
+
|
|
|
+ if (msg:len >= 8192) {
|
|
|
+ sl_send_reply("513", "Request to big");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+
|
|
|
+ # lets see if a module want to answer this
|
|
|
+ dispatch_rpc();
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+route[RR]
|
|
|
+{
|
|
|
# subsequent messages withing 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");
|
|
|
- route(1);
|
|
|
- break;
|
|
|
- };
|
|
|
|
|
|
- if (!uri==myself) {
|
|
|
- # mark routing logic in request
|
|
|
- append_hf("P-hint: outbound\r\n");
|
|
|
- route(1);
|
|
|
- break;
|
|
|
- };
|
|
|
+ # 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
|
|
|
+ # accouting tables, so prepare your accounting software for this ;-)
|
|
|
+ if ($account == "yes") {
|
|
|
+ setflag(FLAG_ACC);
|
|
|
+ }
|
|
|
|
|
|
- # if the request is for other domain use UsrLoc
|
|
|
- # (in case, it does not work, use the following command
|
|
|
- # with proper names and addresses in it)
|
|
|
- if (uri==myself) {
|
|
|
+ # 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();
|
|
|
|
|
|
- if (method=="REGISTER") {
|
|
|
+ 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
|
|
|
|
|
|
-# Uncomment this if you want to use digest authentication
|
|
|
-# if (!www_authorize("iptel.org", "subscriber")) {
|
|
|
-# www_challenge("iptel.org", "0");
|
|
|
-# break;
|
|
|
-# };
|
|
|
+ # if the inital 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");
|
|
|
+ }
|
|
|
|
|
|
- save("location");
|
|
|
- break;
|
|
|
- };
|
|
|
+ record_route();
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- lookup("aliases");
|
|
|
- if (!uri==myself) {
|
|
|
- append_hf("P-hint: outbound alias\r\n");
|
|
|
- route(1);
|
|
|
- break;
|
|
|
- };
|
|
|
+route[DOMAIN]
|
|
|
+{
|
|
|
+ # check if the caller is from a local domain
|
|
|
+ lookup_domain("$fd", "@from.uri.host");
|
|
|
|
|
|
- # native SIP destinations are handled using our USRLOC DB
|
|
|
- if (!lookup("location")) {
|
|
|
- sl_send_reply("404", "Not Found");
|
|
|
- break;
|
|
|
+ # check if the callee is at a local domain
|
|
|
+ lookup_domain("$td", "@ruri.host");
|
|
|
+
|
|
|
+ # we dont know the domain of the caller and also not
|
|
|
+ # the domain of the callee -> somone uses our proxy as
|
|
|
+ # a relay
|
|
|
+ if (!$t.did && !$f.did) {
|
|
|
+ sl_send_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 (!$t.did) {
|
|
|
+ sl_send_reply("403", "Register forwarding forbidden");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+
|
|
|
+ # we want only authenticated users to be registered
|
|
|
+ if (!www_authenticate("$fd.digest_realm", "credentials")) {
|
|
|
+ if ($? == -2) {
|
|
|
+ sl_send_reply("500", "Internal Server Error");
|
|
|
+ } else if ($? == -3) {
|
|
|
+ sl_send_reply("400", "Bad Request");
|
|
|
+ } else {
|
|
|
+ if ($digest_challenge) {
|
|
|
+ append_to_reply("%$digest_challenge");
|
|
|
+ }
|
|
|
+ sl_send_reply("401", "Unauthorized");
|
|
|
+ }
|
|
|
+ drop;
|
|
|
};
|
|
|
+
|
|
|
+ # check if the authenticated user is the same as the target user
|
|
|
+ if (!lookup_user("$tu", "@from.uri")) {
|
|
|
+ sl_send_reply("404", "Unknown user");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($f.uid != $t.uid) {
|
|
|
+ sl_send_reply("403", "3rd Party regsitration rejected");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+
|
|
|
+ # everyhting is fine so lets store the binding
|
|
|
+ save_contacts("location");
|
|
|
+ drop;
|
|
|
};
|
|
|
- append_hf("P-hint: usrloc applied\r\n");
|
|
|
- route(1);
|
|
|
}
|
|
|
|
|
|
-route[1]
|
|
|
+route[AUTHENTICATION]
|
|
|
{
|
|
|
- # send it out now; use stateful forwarding as it works reliably
|
|
|
- # even for UDP2TCP
|
|
|
- if (!t_relay()) {
|
|
|
- sl_reply_error();
|
|
|
+ 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 (! $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_send_reply("500", "Internal Server Error");
|
|
|
+ } else if ($? == -3) {
|
|
|
+ sl_send_reply("400", "Bad Request");
|
|
|
+ } else {
|
|
|
+ if ($digest_challenge) {
|
|
|
+ append_to_reply("%$digest_challenge");
|
|
|
+ }
|
|
|
+ sl_send_reply("407", "Proxy Authentication Required");
|
|
|
+ }
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+
|
|
|
+ # check if the UID from the authentication meets the From header
|
|
|
+ $authuid = $uid;
|
|
|
+ if (!lookup_user("$fu", "@from.uri")) {
|
|
|
+ del_attr("$uid");
|
|
|
+ }
|
|
|
+ if (! ($uid == $authuid)) {
|
|
|
+ sl_send_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", "@ruri")) {
|
|
|
+
|
|
|
+ # maybe you want to consider the preferences of the callee,
|
|
|
+ # e.g. voicemail, then load his attributes here
|
|
|
+ #load_attrs("$tu", "$t.uid");
|
|
|
+
|
|
|
+ # if you want to know if the callee username was alias
|
|
|
+ # check it like this
|
|
|
+ #if (! $tu.uri_canonical) { }
|
|
|
+
|
|
|
+ # native SIP destinations are handled using our USRLOC DB
|
|
|
+ if (lookup_contacts("location")) {
|
|
|
+ append_hf("P-hint: usrloc applied\r\n");
|
|
|
+ route(FORWARD);
|
|
|
+ } else {
|
|
|
+ sl_send_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);
|
|
|
+ }
|
|
|
+}
|