|
@@ -57,7 +57,6 @@
|
|
|
# TODO (Future possible improvements):
|
|
|
# ---------------------------------------
|
|
|
# * protocol tuning
|
|
|
-# - session-timer (port existing textops-based scripts)
|
|
|
# - AVP-based diversion for call-forwarding (as opposed to specialized module)
|
|
|
# - add Date header in 200s to REGISTERs (to be packaged with NTP!)
|
|
|
# * more security:
|
|
@@ -196,6 +195,20 @@ tcp_connection_lifetime=3600
|
|
|
#tcp_max_connections=10240 # default is 2048
|
|
|
tcp_connect_timeout=1
|
|
|
|
|
|
+# -------------------- custom parameters ----------------------------
|
|
|
+# These parameters can be modified runtime via RPC interface,
|
|
|
+# read the documentation of cfg_rpc module!
|
|
|
+#
|
|
|
+# Session Timer parameters, RFC 4028
|
|
|
+#
|
|
|
+# default session interval value used by the proxy if the UAC does not support
|
|
|
+# session timer. Set it to "0" to disable session timer proxy support
|
|
|
+session_timer.default = "1800" desc "default session interval (in s)"
|
|
|
+#
|
|
|
+# minimum session interval value accepted by the proxy,
|
|
|
+# it must not be less than 90 seconds
|
|
|
+session_timer.min_se = "90" desc "minimum session interval (in s)"
|
|
|
+
|
|
|
|
|
|
# ------------------ module loading ----------------------------------
|
|
|
|
|
@@ -228,6 +241,8 @@ loadmodule "/usr/lib/ser/modules/speeddial.so"
|
|
|
loadmodule "/usr/lib/ser/modules/timer.so"
|
|
|
loadmodule "/usr/lib/ser/modules/db_ops.so"
|
|
|
loadmodule "/usr/lib/ser/modules/exec.so"
|
|
|
+loadmodule "/usr/lib/ser/modules/cfg_rpc.so"
|
|
|
+loadmodule "/usr/lib/ser/modules/eval.so"
|
|
|
|
|
|
# ----------------- setting script FLAGS -----------------------------
|
|
|
flags
|
|
@@ -240,7 +255,9 @@ flags
|
|
|
FLAG_DONT_RM_CRED : 7, # do not remove the credentials
|
|
|
FLAG_AUTH_OK : 8, # authentication succeeded
|
|
|
FLAG_SERWEB_RSVD1 : 9, # bit reserved for use with serweb
|
|
|
- FLAG_SERWEB_RSVD2 :10; # bit reserved for use with serweb
|
|
|
+ FLAG_SERWEB_RSVD2 : 10, # bit reserved for use with serweb
|
|
|
+ FLAG_SESSIONTIMER : 11, # indicates that the UAC supports Session Timer
|
|
|
+ FLAG_RR_DONE : 12; # the request got already one RR header
|
|
|
|
|
|
avpflags
|
|
|
dialog_cookie; # handled by rr module
|
|
@@ -302,7 +319,7 @@ modparam("auth", "secret", "aqwedrftredswqwddcft")
|
|
|
modparam("rr", "enable_full_lr", 1)
|
|
|
#
|
|
|
# limit the length of the AVP cookie to only necessary ones
|
|
|
-modparam("rr", "cookie_filter", "(account|uac_nat)")
|
|
|
+modparam("rr", "cookie_filter", "(account|uac_nat|stimer)")
|
|
|
#
|
|
|
# you probably do not want that someone can simply read and change
|
|
|
# the AVP cookie in your Routes, thus should really change this
|
|
@@ -405,9 +422,8 @@ route{
|
|
|
# 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 is routed via Route header
|
|
|
+ route(LOOSE_ROUTE);
|
|
|
|
|
|
# look up domain IDs
|
|
|
route(DOMAIN);
|
|
@@ -454,8 +470,6 @@ route{
|
|
|
|
|
|
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();
|
|
@@ -467,8 +481,15 @@ route[FORWARD]
|
|
|
t_on_failure("FAILURE_ROUTE");
|
|
|
}
|
|
|
|
|
|
+ # always use the reply route to check for NATed UAS
|
|
|
t_on_reply("REPLY_ROUTE");
|
|
|
|
|
|
+ # 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(RR);
|
|
|
+
|
|
|
+ # turn on or off the RTP proxy as the last step because it modifies the SDP
|
|
|
route(RTPPROXY);
|
|
|
|
|
|
|
|
@@ -552,6 +573,7 @@ route[NAT_DETECTION]
|
|
|
if (nat_uac_test("19") || (@hf_value["contact"] && @contact.uri.params.maddr) ) {
|
|
|
setflag(FLAG_NAT);
|
|
|
$uac_nat=1;
|
|
|
+ setavpflag($uac_nat, "dialog_cookie");
|
|
|
if (method=="REGISTER") {
|
|
|
# prepare the Contact so that the registrar module saves the
|
|
|
# source as well
|
|
@@ -579,17 +601,17 @@ route[RTPPROXY]
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- # turn the RTP proxy on for INVITEs
|
|
|
- if (method=="INVITE") {
|
|
|
+ # turn the RTP proxy on for INVITEs and UPDATEs
|
|
|
+ if ((method=="INVITE" || method == "UPDATE") && @msg.body != "") {
|
|
|
force_rtp_proxy('r');
|
|
|
append_hf("P-RTP-Proxy: YES\r\n");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-route[RR]
|
|
|
+route[LOOSE_ROUTE]
|
|
|
{
|
|
|
# subsequent messages withing a dialog should take the
|
|
|
- # path determined by record-routing
|
|
|
+ # path determined by the Route header
|
|
|
if (loose_route()) {
|
|
|
# mark routing logic in request
|
|
|
append_hf("P-hint: rr-enforced\r\n");
|
|
@@ -609,19 +631,31 @@ route[RR]
|
|
|
setflag(FLAG_NAT);
|
|
|
}
|
|
|
|
|
|
+ # restore Session Timer flag and headers
|
|
|
+ if ($stimer && ($stimer != "0")) {
|
|
|
+ route(SESSION_TIMER);
|
|
|
+ }
|
|
|
+
|
|
|
# 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 :)
|
|
|
+ # There is also one scenario where subsequent indialog RR is
|
|
|
+ # required if the initial SUBSCRIBE forked.
|
|
|
# note that here we forward before authentication check is executed;
|
|
|
# generally we only authenticate dialog-initiating requests; some
|
|
|
# in-dialog requests can't be authenticated at all, see the
|
|
|
# call-forwarding example in route[DOMAIN]
|
|
|
- record_route();
|
|
|
+ route(RR);
|
|
|
|
|
|
route(FORWARD);
|
|
|
- } else if (!method=="REGISTER") {
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+route[RR]
|
|
|
+{
|
|
|
+ if (!isflagset(FLAG_RR_DONE) && !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
|
|
@@ -634,7 +668,12 @@ route[RR]
|
|
|
setavpflag($account, "dialog_cookie");
|
|
|
}
|
|
|
|
|
|
+ # let's insert the RR header now
|
|
|
record_route();
|
|
|
+
|
|
|
+ # this flag simply allows to call this route several times
|
|
|
+ # without inserting several RR headers
|
|
|
+ setflag(FLAG_RR_DONE);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -914,6 +953,15 @@ route[INBOUND]
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ # 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 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!!!
|
|
|
+ #if (@src.ip == $gw_ip) {
|
|
|
+ route(SESSION_TIMER);
|
|
|
+ #}
|
|
|
+
|
|
|
route(FORWARD);
|
|
|
} else {
|
|
|
sl_reply("480", "User temporarily not available");
|
|
@@ -951,6 +999,9 @@ route[PSTN]
|
|
|
replace_attr_hf("Remote-Party-ID", "$rpidheader");
|
|
|
}
|
|
|
|
|
|
+ # enable Session Timer support with the GW
|
|
|
+ route(SESSION_TIMER);
|
|
|
+
|
|
|
# just replace the domain part of the RURI with the
|
|
|
# value from the AVP and send it out
|
|
|
attr2uri("$gw_ip", "domain");
|
|
@@ -965,12 +1016,12 @@ route[CATCH_CANCEL] {
|
|
|
|
|
|
if (method == CANCEL) {
|
|
|
# ser 2.1 only
|
|
|
- #if (!t_relay_cancel()) { # implicit drop if the INVITE was found
|
|
|
+ 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;
|
|
|
- #}
|
|
|
+ sl_reply("500", "Internal Server Error");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
# bad luck, no corresponding INVITE was found,
|
|
|
# we have to continue with the script
|
|
|
;
|
|
@@ -989,6 +1040,74 @@ route[SITE_SPECIFIC] {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+route[SESSION_TIMER]
|
|
|
+{
|
|
|
+ # we are only interested in session establishment or
|
|
|
+ # session refresher
|
|
|
+ if (!(method == "INVITE" || method == "UPDATE")) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ # lets check if the Session-Expires header is already present
|
|
|
+ if (@hf_value.session_expires) {
|
|
|
+ # compare the Session-Expires header value with the
|
|
|
+ # configured Min-SE
|
|
|
+ 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);
|
|
|
+ eval_oper(">", -2);
|
|
|
+
|
|
|
+ # lets check for the Suported header
|
|
|
+ if (hf_value_exists("Supported", "timer"))
|
|
|
+ # the UAC supports Session Timer, so we
|
|
|
+ # only need to take a look at the values
|
|
|
+
|
|
|
+ if (@eval.pop[-1] == "0") {
|
|
|
+ # session interval is lower than the configured Min-SE
|
|
|
+ append_to_reply("Min-SE: %@cfg_get.session_timer.min_se\r\n");
|
|
|
+ sl_reply("422", "Session Interval Too Small");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+
|
|
|
+ # we store the session expires value for the reply route
|
|
|
+ $stimer = @hf_value.session_expires.uri;
|
|
|
+ # and mark the AVP to be inserted as RR cookie
|
|
|
+ setavpflag($stimer, "dialog_cookie");
|
|
|
+
|
|
|
+ # set the session timer flag that indicates the
|
|
|
+ # UAC supports the extension.
|
|
|
+ setflag(FLAG_SESSIONTIMER);
|
|
|
+ } else {
|
|
|
+ #session epxires was already inserted by some other proxy
|
|
|
+ if (@eval.pop[-1] == "0") {
|
|
|
+ # 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");
|
|
|
+ remove_hf_value("Min-SE");
|
|
|
+ append_hf_value("Min-SE", "%@cfg_get.session_timer.min_se");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ # no Session Timer is requested yet, neither by UAC nor by proxy
|
|
|
+
|
|
|
+ if (@cfg_get.session_timer.default != "0") {
|
|
|
+ # 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") { # not the default value
|
|
|
+ append_hf_value("Min-SE", "%@cfg_get.session_timer.min_se");
|
|
|
+ }
|
|
|
+
|
|
|
+ # mark the AVP to be inserted as RR cookie
|
|
|
+ $stimer = @cfg_get.session_timer.default;
|
|
|
+ setavpflag($stimer, "dialog_cookie");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
failure_route[FAILURE_ROUTE]
|
|
|
{
|
|
@@ -1038,9 +1157,24 @@ onreply_route[REPLY_ROUTE]
|
|
|
# which contains a body, start to use the RTP proxy
|
|
|
if (isflagset(FLAG_NAT) &&
|
|
|
status=~"(18[03])|(2[0-9][0-9])" &&
|
|
|
- !search("^(Content-Length|l): 0")) {
|
|
|
+ @msg.body != "") {
|
|
|
force_rtp_proxy('r');
|
|
|
}
|
|
|
+
|
|
|
+ # lets check for session timer support
|
|
|
+ if (isflagset(FLAG_SESSIONTIMER) && status =~ "2[0-9][0-9]") {
|
|
|
+ # the UAC wanted to have a session timer
|
|
|
+
|
|
|
+ if (!@hf_value.session_expires) {
|
|
|
+ # 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");
|
|
|
+
|
|
|
+ if (!hf_value_exists("Require", "timer")) {
|
|
|
+ include_hf_value("Require", "timer");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|