Browse Source

modified ser.cfg to work with all the new functions and code. this new
version contains a lot more "features" but mainly for demonstration
purposes so that the users get an idea what you can do with the config
script language/commands.
ser-simple.cfg is the successor of the original ser.cfg.
ser-simple.cfg contains only the very basic commands for a proxy and regitrar.

Nils Ohlmeier 19 years ago
parent
commit
bfb7651e63
2 changed files with 486 additions and 75 deletions
  1. 137 0
      etc/ser-simple.cfg
  2. 349 75
      etc/ser.cfg

+ 137 - 0
etc/ser-simple.cfg

@@ -0,0 +1,137 @@
+#
+# $Id$
+#
+# This a very basic config file w aliases and anamed route but
+# w/o authentication, accouting, database, multi-domain support etc.
+# Please refer to ser.cfg for a more complete example
+#
+
+# ----------- global configuration parameters ------------------------
+
+debug=3         # debug level (cmd line: -dddddddddd)
+#memdbg=10 # memory debug message 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
+#fifo_user=ser # owner of the ser fifo
+#fifo_group=ser
+#fifo_mode=0660 # fifo's permissions
+#disable_core=yes #disables core dumping
+#open_fd_limit=1024 # sets the open file descriptors limit
+#mhomed=yes  # usefull for multihomed hosts, small performance penalty
+#disable_tcp=yes 
+#tcp_accept_aliases=yes # accepts the tcp alias via option (see NEWS)
+
+#
+
+# ------------------ module loading ----------------------------------
+
+loadmodule "/usr/local/lib/ser/modules/sl.so"
+loadmodule "/usr/local/lib/ser/modules/tm.so"
+loadmodule "/usr/local/lib/ser/modules/rr.so"
+loadmodule "/usr/local/lib/ser/modules/textops.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/ctl.so"
+
+# ----------------- setting module-specific parameters ---------------
+
+# -- usrloc params --
+
+modparam("usrloc", "db_mode",   0)
+
+# -- rr params --
+# add value to ;lr param to make some broken UAs happy
+modparam("rr", "enable_full_lr", 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:localhost:2046")
+
+# -------------------------  request routing logic -------------------
+
+# main routing logic
+
+route{
+
+	# 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;
+	};
+	if (msg:len >=  max_len ) {
+		sl_send_reply("513", "Message too big");
+		break;
+	};
+	
+	# 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();	
+
+	# 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(FORWARD);
+		break;
+	};
+
+	if (!uri==myself) {
+		# mark routing logic in request
+		append_hf("P-hint: outbound\r\n"); 
+		route(FORWARD);
+		break;
+	};
+
+	# 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) {
+
+		if (method=="REGISTER") {
+
+			save_contacts("location");
+			break;
+		};
+
+		# native SIP destinations are handled using our USRLOC DB
+		if (!lookup_contacts("location")) {
+			sl_send_reply("404", "Not Found");
+			break;
+		};
+		append_hf("P-hint: usrloc applied\r\n"); 
+	};
+	route(FORWARD);
+}
+
+route[FORWARD] 
+{
+	# send it out now; use stateful forwarding as it works reliably
+	# even for UDP2TCP
+	if (!t_relay()) {
+		sl_reply_error();
+	};
+}
+

+ 349 - 75
etc/ser.cfg

@@ -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);
+	}
+}