From 65262e9d46ca2dc956e316adad3a3be14296943c Mon Sep 17 00:00:00 2001
From: Alekzander Spiridonov <sipidronov@gmail.com>
Date: Fri, 22 Aug 2014 05:20:42 -0700
Subject: [PATCH] registrar: randomize expires value received from UAC

---
 modules/registrar/doc/registrar_admin.xml |   11 ++--
 modules/registrar/sip_msg.c               |   77 ++++++++++++++++-------------
 2 files changed, 48 insertions(+), 40 deletions(-)

diff --git a/modules/registrar/doc/registrar_admin.xml b/modules/registrar/doc/registrar_admin.xml
index 4cd2053..992e5fb 100644
--- a/modules/registrar/doc/registrar_admin.xml
+++ b/modules/registrar/doc/registrar_admin.xml
@@ -157,10 +157,9 @@ modparam("registrar", "default_expires", 1800)
 		<title><varname>default_expires_range</varname> (integer)</title>
 		<para>
 		This parameter specifies that the expiry used for newly created usrloc records
-		are not fixed(when <quote>default_expires</quote> applies), but a random value in the interval 
-		<quote>[default_expires-default_expires_range%, default_expires+default_expires_range%]</quote>.
-		The value is between 0 and 100 and represent the maximim percentage from default_expires that
-		will be substracted or added when computing the value. Default in 0, meaning default_expires
+		are not fixed, but a random value in the interval <quote>[default_expires-default_expires_range%, default_expires]</quote>.
+		The value is between 0 and 100 and represent the maximim percentage from expires that
+		will be substracted when computing the value. Default in 0, meaning default_expires
 		is left unmodified. This parameter can be modified via ser config framework.
 		</para>
 		<para>
@@ -181,8 +180,8 @@ modparam("registrar", "default_expires_range", 30) # +- 30% from default_expires
 		<title><varname>expires_range</varname> (integer)</title>
 		<para>
 		Similar to default_expires_range, but it applies to the incoming expires
-		value and it only lowers the value. Default in 0, meaning the expires
-		is left unmodified. This parameter can be modified via config framework.
+		value. Default in 0, meaning the expires is left unmodified. 
+		This parameter can be modified via config framework.
 		</para>
 		<para>
 		<emphasis>
diff --git a/modules/registrar/sip_msg.c b/modules/registrar/sip_msg.c
index 19ea3df..f5a84f2 100644
--- a/modules/registrar/sip_msg.c
+++ b/modules/registrar/sip_msg.c
@@ -44,45 +44,37 @@
 
 static struct hdr_field* act_contact;
 
-/*! \brief
- *  Return an expire value in the range [ default_expires - range%, default_expires + range% ]
+/* \brief
+ * Return randomized expires between expires-range% and expires.
+ * RFC allows only value less or equal to the one provided by UAC.
  */
-static inline int get_expire_val(void)
+static inline int randomize_expires( int expires, int range )
 {
-	int expires = cfg_get(registrar, registrar_cfg, default_expires);
-	int range = cfg_get(registrar, registrar_cfg, default_expires_range);
-	/* if no range is given just return default_expires */
-	if(range == 0) return expires;
-	/* select a random value in the range */
-	return expires - (float)range/100 * expires + (float)(rand()%100)/100 * 2 * (float)range/100 * expires;
+  /* if no range is given just return expires */
+  if(range == 0) return expires;
+
+  int range_min = expires - (float)range/100 * expires;
+
+  return range_min + (float)(rand()%100)/100 * ( expires - range_min );
 }
 
 
 /*! \brief
  * Return value of Expires header field
- * if the HF exists converted to absolute
- * time, if the HF doesn't exist, returns
- * default value;
+ * if the HF exists, if the HF doesn't exist,
+ * returns -1;
  */
 static inline int get_expires_hf(struct sip_msg* _m)
 {
 	exp_body_t* p;
-	int range;
+
 	if (_m->expires) {
 		p = (exp_body_t*)_m->expires->parsed;
 		if (p->valid) {
-			if (p->val != 0) {
-				range = cfg_get(registrar, registrar_cfg, default_expires_range);
-				if(likely(range==0))
-					return p->val + act_time;
-				return p->val + act_time - (float)range/100 * p->val
-						+ ((float)(rand()%100)/100) * ((float)range/100 * p->val);
-			} else return 0;
-		} else {
-			return act_time + get_expire_val();
+      return p->val;
 		}
-	} else
-		return act_time + get_expire_val();
+	}
+  return -1;
 }
 
 
@@ -159,7 +151,7 @@ int check_contacts(struct sip_msg* _m, int* _s)
 	if (((contact_body_t*)_m->contact->parsed)->star == 1) {
 		/* The first Contact HF is star */
 		/* Expires must be zero */
-		if (get_expires_hf(_m) > 0) {
+		if (get_expires_hf(_m) != 0) {
 			rerrno = R_STAR_EXP;
 			return 1;
 		}
@@ -252,22 +244,39 @@ contact_t* get_next_contact(contact_t* _c)
  */
 void calc_contact_expires(struct sip_msg* _m, param_t* _ep, int* _e)
 {
+  int range = 0;
 	if (!_ep || !_ep->body.len) {
-		*_e = get_expires_hf(_m);
+	  *_e = get_expires_hf(_m);
+
+	  if ( *_e < 0 ) {
+      *_e = cfg_get(registrar, registrar_cfg, default_expires);
+      range = cfg_get(registrar, registrar_cfg, default_expires_range);
+	  } else {
+      range = cfg_get(registrar, registrar_cfg, expires_range);
+	  }
 	} else {
 		if (str2int(&_ep->body, (unsigned int*)_e) < 0) {
-			*_e = get_expire_val();
+			*_e = cfg_get(registrar, registrar_cfg, default_expires);
+			range = cfg_get(registrar, registrar_cfg, default_expires_range);
+		} else {
+		  range = cfg_get(registrar, registrar_cfg, expires_range);
 		}
-		/* Convert to absolute value */
-		if (*_e != 0) *_e += act_time;
 	}
 
-	if ((*_e != 0) && ((*_e - act_time) < cfg_get(registrar, registrar_cfg, min_expires))) {
-		*_e = cfg_get(registrar, registrar_cfg, min_expires) + act_time;
-	}
+	if ( *_e != 0 )
+	{
+    *_e = randomize_expires( *_e, range );
+
+    if (*_e < cfg_get(registrar, registrar_cfg, min_expires)) {
+      *_e = cfg_get(registrar, registrar_cfg, min_expires);
+    }
+
+    if (cfg_get(registrar, registrar_cfg, max_expires) && (*_e > cfg_get(registrar, registrar_cfg, max_expires))) {
+      *_e = cfg_get(registrar, registrar_cfg, max_expires);
+    }
 
-	if ((*_e != 0) && cfg_get(registrar, registrar_cfg, max_expires) && ((*_e - act_time) > cfg_get(registrar, registrar_cfg, max_expires))) {
-		*_e = cfg_get(registrar, registrar_cfg, max_expires) + act_time;
+    /* Convert to absolute value */
+    *_e += act_time;
 	}
 }
 
-- 
1.7.1

