[Users] RE: [Serusers] Re: [Serdev] Inaccurate Radius Accounting

'Jan Janak' jan at iptel.org
Sun Dec 25 18:55:56 CET 2005


Hello,

Attached is a patch that implements "swap_direction" parameter of acc
module. If you turn the parameter on in the configuration file:

modparam("acc", "swap_direction", 1)

then the acc module will swap Calling-Station-ID and Called-Station-ID
values when necessary (in this case BYE comming from the callee).

Put the patch in top level source directory (ser-0.9.x) and type:
patch -p0 < swap.patch

The patch should work with any 0.9.x release.

Note that Alan DeKok is wrong in thinking that this is a bug in SER.
This particular problem is a result of incomplete specification of
RADIUS use with SIP. I will commit the patch in CVS so it will be
included in future SER releases.

   Jan.

On 23-12-2005 17:10, Lenir wrote:
> Please read the reply below from one of the maintainers of freeradius:
> 
> "Lenir" <lenirsantiago at yahoo.com> wrote:
> > But if UserB hangs up on UserA: SER generates a stop-record where the 
> > Calling-Station-Id is UserB and the Called-Station-Id is UserA, this 
> > is the undesired and incorrect behavior.
> 
>   It would appear to be a bug in SER.
> 
> > To me the Calling-Station-Id and the Called-Station-Id should be the 
> > same for both start and stop records, am I right by thinking that?
> 
>   Yes.
> 
> > According to the developers of SER/OpenSER, this is the correct 
> > behavior, whoever sends the hangup signal (BYE or CANCEL) is 
> > considered the Calling-Station-Id, and they are unwilling to modify or 
> > create a patch to "fix" this.
> 
>   What they do for something inside of SER is their business.  When they
> generate RADIUS packets, they should follow RADIUS standards and
> interoperability.  The expectation, as you said, is that the
> Calling/Called-Station-Id doesn't change during a session.  If it does, it's
> a bug and they should fix it.
> 
>   Alan DeKok.
> -
> List info/subscribe/unsubscribe? See
> http://www.freeradius.org/list/users.html
> 
> 
> 
> -----Original Message-----
> From: 'Jan Janak' [mailto:jan at iptel.org] 
> Sent: Thursday, November 17, 2005 10:33 AM
> To: Lenir
> Cc: 'Klaus Darilion'; serdev at iptel.org; serusers at iptel.org;
> devel at openser.org; users at openser.org
> Subject: Re: [Users] RE: [Serusers] Re: [Serdev] Inaccurate Radius
> Accounting
> 
> On 17-11-2005 10:21, Lenir wrote:
> > In this case the radius proxy wont work, because you never can anticipate
> > who hangs up the call, thus radius wont know who hung up the
> call...Besides
> > all other voice applications/hardware (SIP and H323) that use radius do
> not
> > behave like that, the Called-Station-ID ALWAYS remains the same, as with
> the
> > Calling-Station-ID.
> 
>   Could you name those SIP applications that behave the way you describe ?
> 
>     Jan.
> 
-------------- next part --------------
RCS file: /cvsroot/ser/sip_router/modules/acc/Attic/acc.c,v
retrieving revision 1.26.2.1
diff -u -r1.26.2.1 acc.c
--- modules/acc/acc.c	14 Jun 2005 20:25:19 -0000	1.26.2.1
+++ modules/acc/acc.c	25 Dec 2005 17:35:19 -0000
@@ -49,6 +49,9 @@
 #include "acc_mod.h"
 #include "acc.h"
 #include "dict.h"
+#include "../../parser/parse_rr.h"
+#include "../../trim.h"
+#include "../../parser/parse_uri.h"
 #ifdef RAD_ACC
 #  ifdef RADIUSCLIENT_NG_4
 #    include <radiusclient.h>
@@ -71,6 +74,8 @@
 #define M_NAME	"acc"
 #endif
 
+extern int swap_dir;
+
 #define ATR(atr)  atr_arr[cnt].s=A_##atr;\
 				atr_arr[cnt].len=A_##atr##_LEN;
 
@@ -101,6 +106,94 @@
 #endif
 
 
+static int check_ftag(struct sip_msg* msg, str* uri)
+{
+	param_hooks_t hooks;
+	param_t* params;
+	char* semi;
+	struct to_body* from;
+	str t;
+
+	t = *uri;
+	params = 0;
+	semi = q_memchr(t.s, ';', t.len);
+	if (!semi) {
+		DBG("No ftag parameter found\n");
+		return -1;
+	}
+	
+	t.len -= semi - uri->s + 1;
+	t.s = semi + 1;
+	trim_leading(&t);
+	
+	if (parse_params(&t, CLASS_URI, &hooks, &params) < 0) {
+		LOG(L_ERR, "Error while parsing parameters\n");
+		return -1;
+	}
+
+	if (!hooks.uri.ftag) {
+		DBG("No ftag parameter found\n");
+		goto err;
+	}
+
+	from = get_from(msg);
+
+	if (!from || !from->tag_value.len || !from->tag_value.s) {
+		DBG("No from tag parameter found\n");
+		goto err;
+	}
+
+	if (from->tag_value.len == hooks.uri.ftag->body.len &&
+	    !strncmp(from->tag_value.s, hooks.uri.ftag->body.s, hooks.uri.ftag->body.len)) {
+		DBG("Route ftag and From tag are same\n");
+		free_params(params);
+		return 0;
+	} else {
+		DBG("Route ftag and From tag are NOT same\n");
+		free_params(params);
+		return 1;
+	}
+
+ err:
+	if (params) free_params(params);
+	return -1;
+}
+
+static int get_direction(struct sip_msg* msg)
+{
+	int ret;
+	if (parse_orig_ruri(msg) < 0) {
+		return -1;
+	}
+
+	if (!msg->parsed_orig_ruri_ok) {
+		LOG(L_ERR, "Error while parsing original Request-URI\n");
+		return -1;
+	}
+
+	ret = check_self(&msg->parsed_orig_ruri.host, 
+			 msg->parsed_orig_ruri.port_no ? msg->parsed_orig_ruri.port_no : SIP_PORT, 0);/* match all protos*/
+	if (ret < 0) return -1;
+	if (ret > 0) {
+		     /* Route is in ruri */
+		return check_ftag(msg, &msg->first_line.u.request.uri);
+	} else {
+		if (msg->route) {
+			if (parse_rr(msg->route) < 0) {
+				LOG(L_ERR, "Error while parsing Route HF\n");
+				return -1;
+			}
+		        ret = check_ftag(msg, &((rr_t*)msg->route->parsed)->nameaddr.uri);
+			if (msg->route->parsed) free_rr((rr_t**)&msg->route->parsed);
+			return ret;
+		} else {
+			DBG("No Route headers found\n");
+			return -1;
+		}
+	}
+}
+
+
 static inline struct hdr_field *valid_to( struct cell *t, 
 				struct sip_msg *reply)
 {
@@ -156,9 +249,10 @@
 	static str mycode;
 	str *cr;
 	struct cseq_body *cseq;
+	int dir;
 
 	cnt=tl=al=0;
-
+	dir = -2;
 	/* we don't care about parsing here; either the function
 	 * was called from script, in which case the wrapping function
 	 * is supposed to parse, or from reply processing in which case
@@ -218,10 +312,19 @@
 				}
 				/* fallback to from-uri if digest unavailable ... */
 			case 'F': /* from-uri */
-				if (rq->from && (from=get_from(rq))
-							&& from->uri.len) {
+
+				if (swap_dir && dir == -2) dir = get_direction(rq);
+				if (dir <= 0) {
+					if (rq->from && (from=get_from(rq))
+					    && from->uri.len) {
 						val_arr[cnt]=&from->uri;
-				} else val_arr[cnt]=&na;
+					} else val_arr[cnt]=&na;
+				} else {
+					if (rq->to && (pto=get_to(rq))
+					    && pto->uri.len) {
+						val_arr[cnt]=&pto->uri;
+					} else val_arr[cnt]=&na;
+				}
 				ATR(FROMURI);
 				break;
 			case '0': /* from user */
@@ -255,10 +358,19 @@
 				ATR(TOTAG);
 				break;
 			case 'T': /* to-uri */
-				if (rq->to && (pto=get_to(rq))
-							&& pto->uri.len) {
+
+				if (swap_dir && dir == -2) dir = get_direction(rq);
+				if (dir <= 0) {
+					if (rq->to && (pto=get_to(rq))
+					    && pto->uri.len) {
 						val_arr[cnt]=&pto->uri;
-				} else val_arr[cnt]=&na;
+					} else val_arr[cnt]=&na;
+				} else {
+					if (rq->from && (from=get_from(rq))
+					    && from->uri.len) {
+						val_arr[cnt]=&from->uri;
+					} else val_arr[cnt]=&na;
+				}
 				ATR(TOURI);
 				break;
 			case '1': /* to user */ 
Index: modules/acc/acc_mod.c
===================================================================
RCS file: /cvsroot/ser/sip_router/modules/acc/Attic/acc_mod.c,v
retrieving revision 1.39.2.3
diff -u -r1.39.2.3 acc_mod.c
--- modules/acc/acc_mod.c	20 Sep 2005 16:03:14 -0000	1.39.2.3
+++ modules/acc/acc_mod.c	25 Dec 2005 17:35:20 -0000
@@ -115,6 +115,7 @@
 int radius_flag = 0;
 int radius_missed_flag = 0;
 static int service_type = -1;
+int swap_dir = 0;
 void *rh;
 struct attr attrs[A_MAX];
 struct val vals[V_MAX];
@@ -206,6 +207,7 @@
 	{"radius_flag",				INT_PARAM, &radius_flag			},
 	{"radius_missed_flag",		INT_PARAM, &radius_missed_flag		},
 	{"service_type", 		INT_PARAM, &service_type },
+	{"swap_direction",             INT_PARAM, &swap_dir},
 #endif
 /* DIAMETER	*/
 #ifdef DIAM_ACC
@@ -414,7 +416,7 @@
 	 * don't be worried about parsing outcome -- if it failed, 
 	 * we will report N/A
 	 */
-	parse_headers(rq, HDR_CALLID| HDR_FROM| HDR_TO, 0 );
+	parse_headers(rq, HDR_CALLID| HDR_FROM| HDR_TO| HDR_ROUTE, 0 );
 	parse_from_header(rq);
 
 	if (strchr(log_fmt, 'p') || strchr(log_fmt, 'D')) {
Index: modules/acc/acc_mod.h
===================================================================
RCS file: /cvsroot/ser/sip_router/modules/acc/Attic/acc_mod.h,v
retrieving revision 1.14
diff -u -r1.14 acc_mod.h
--- modules/acc/acc_mod.h	24 Aug 2004 08:58:23 -0000	1.14
+++ modules/acc/acc_mod.h	25 Dec 2005 17:35:21 -0000
@@ -87,6 +87,7 @@
 extern char* acc_totag_col;
 extern char* acc_fromtag_col;
 
+extern int swap_dir;
 
 #endif /* SQL_ACC */
 
Index: parser/parse_param.c
===================================================================
RCS file: /cvsroot/ser/sip_router/parser/parse_param.c,v
retrieving revision 1.21
diff -u -r1.21 parse_param.c
--- parser/parse_param.c	1 Sep 2004 12:50:40 -0000	1.21
+++ parser/parse_param.c	25 Dec 2005 17:35:26 -0000
@@ -144,6 +144,15 @@
 			_h->uri.maddr = _p;
 		}
 		break;
+
+	case 'f':
+	case 'F':
+		if ((_p->name.len == 4) &&
+		    (!strncasecmp(_p->name.s + 1, "tag", 3))) {
+			_p->type = P_FTAG;
+			_h->uri.ftag = _p;
+		}
+		break;
 	}
 }
 
@@ -475,6 +484,7 @@
 	case P_MADDR:     type = "P_MADDR";     break;
 	case P_TTL:       type = "P_TTL";       break;
 	case P_RECEIVED:  type = "P_RECEIVED";  break;
+	case P_FTAG:      type = "P_FTAG";      break;
 	default:          type = "UNKNOWN";     break;
 	}
 	
Index: parser/parse_param.h
===================================================================
RCS file: /cvsroot/ser/sip_router/parser/parse_param.h,v
retrieving revision 1.11
diff -u -r1.11 parse_param.h
--- parser/parse_param.h	1 Sep 2004 11:56:59 -0000	1.11
+++ parser/parse_param.h	25 Dec 2005 17:35:26 -0000
@@ -53,6 +53,7 @@
 	P_R2,        /* URI: r2 parameter (ser specific) */
 	P_MADDR,     /* URI: maddr parameter */
 	P_TTL,       /* URI: ttl parameter */
+	P_FTAG       /* URI: ftag parameter */
 } ptype_t;
 
 
@@ -98,6 +99,7 @@
 	struct param* r2;        /* r2 parameter */
 	struct param* maddr;     /* maddr parameter */
 	struct param* ttl;       /* ttl parameter */
+	struct param* ftag;      /* ftag parameter */
 };
 
 


More information about the sr-users mailing list