[SR-Users] permissions module, regular expression matching Request URI

E. Schmidbauer eschmidbauer at gmail.com
Wed May 6 22:11:49 CEST 2015


Hello,
I have written a patch to add checking for the Request-URI.
Please see attached diff.
I hope you consider pushing this code upstream.
Thanks,
Emmanuel

On Wed, May 6, 2015 at 12:14 PM, Vik Killa <vipkilla at gmail.com> wrote:

> Hello,
> We would like to match specific calls based on two factors:
> 1. the source IP address
> 2. the Request URI
>
> I see in the permissions module, it is possible to match based on the
> Source IP + the From URI.
> We need two match both in order to return the appropriate 'tag' attribute
> from table.
>
> Would anyone know of a way to accomplish this?
>
>
> Also, I noticed that matching source IP + from uri, you cannot control
> which result is returned by permissions module based on regular expression.
> In other words if more than one match is made, permissions module seems to
> return the first result.
>
> Thank you and I look forward to your response.
> V
>
> _______________________________________________
> SIP Express Router (SER) and Kamailio (OpenSER) - sr-users mailing list
> sr-users at lists.sip-router.org
> http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.sip-router.org/pipermail/sr-users/attachments/20150506/f8be483c/attachment.html>
-------------- next part --------------
diff --git a/modules/permissions/hash.c b/modules/permissions/hash.c
index 7b11ebd..97e0578 100644
--- a/modules/permissions/hash.c
+++ b/modules/permissions/hash.c
@@ -22,6 +22,7 @@
 
 #include <sys/types.h>
 #include <regex.h>
+#include "parse_config.h"
 #include "../../mem/shm_mem.h"
 #include "../../parser/parse_from.h"
 #include "../../ut.h"
@@ -116,11 +117,11 @@ void free_hash_table(struct trusted_list** table)
 
 
 /* 
- * Add <src_ip, proto, pattern, tag> into hash table, where proto is integer
+ * Add <src_ip, proto, pattern, ruri_pattern, tag> into hash table, where proto is integer
  * representation of string argument proto.
  */
 int hash_table_insert(struct trusted_list** table, char* src_ip, 
-		char* proto, char* pattern, char* tag)
+		char* proto, char* pattern, char* ruri_pattern, char* tag)
 {
 	struct trusted_list *np;
 	unsigned int hash_val;
@@ -178,14 +179,28 @@ int hash_table_insert(struct trusted_list** table, char* src_ip,
 	} else {
 		np->pattern = 0;
 	}
+	
+	if (ruri_pattern) {
+		np->ruri_pattern = (char *) shm_malloc(strlen(ruri_pattern)+1);
+		if (np->ruri_pattern == NULL) {
+			LM_CRIT("cannot allocate shm memory for ruri_pattern string\n");
+			shm_free(np->src_ip.s);
+			shm_free(np);
+			return -1;
+		}
+		(void) strcpy(np->ruri_pattern, ruri_pattern);
+	} else {
+		np->ruri_pattern = 0;
+	}
 
 	if (tag) {
 		np->tag.len = strlen(tag);
 		np->tag.s = (char *) shm_malloc((np->tag.len) + 1);
 		if (np->tag.s == NULL) {
-			LM_CRIT("cannot allocate shm memory for pattern string\n");
+			LM_CRIT("cannot allocate shm memory for pattern or ruri_pattern string\n");
 			shm_free(np->src_ip.s);
 			shm_free(np->pattern);
+			shm_free(np->ruri_pattern);
 			shm_free(np);
 			return -1;
 		}
@@ -220,9 +235,23 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 	int_str val;
 	int count = 0;
 
+	int len;
+	static char ruri_str[EXPRESSION_LENGTH+1];
+	
+	len = msg->parsed_uri.user.len + msg->parsed_uri.host.len + 5;
+	if (len > EXPRESSION_LENGTH) {
+		LM_ERR("Request URI is too long: %d chars\n", len);
+		return -1;
+	}
+	strcpy(ruri_str, "sip:");
+	memcpy(ruri_str + 4, msg->parsed_uri.user.s, msg->parsed_uri.user.len);
+	ruri_str[msg->parsed_uri.user.len + 4] = '@';
+	memcpy(ruri_str + msg->parsed_uri.user.len + 5, msg->parsed_uri.host.s, msg->parsed_uri.host.len);
+	ruri_str[len] = '\0';
+
 	src_ip.s = src_ip_c_str;
 	src_ip.len = strlen(src_ip.s);
-
+	
 	if (IS_SIP(msg))
 	{
 		if (parse_from_header(msg) < 0) return -1;
@@ -236,33 +265,46 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 	}
 
 	for (np = table[perm_hash(src_ip)]; np != NULL; np = np->next) {
-	    if ((np->src_ip.len == src_ip.len) && 
-		(strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) &&
-		((np->proto == PROTO_NONE) || (proto == PROTO_NONE) ||
-		 (np->proto == proto))) {
-		if (np->pattern && IS_SIP(msg)) {
-		    if (regcomp(&preg, np->pattern, REG_NOSUB)) {
-			LM_ERR("invalid regular expression\n");
-			continue;
-		    }
-		    if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
-			regfree(&preg);
-			continue;
-		    }
-		    regfree(&preg);
-		}
-		/* Found a match */
-		if (tag_avp.n && np->tag.s) {
-		    val.s = np->tag;
-		    if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
-			LM_ERR("setting of tag_avp failed\n");
-			return -1;
-		    }
+		if ((np->src_ip.len == src_ip.len) &&
+			(strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) &&
+			((np->proto == PROTO_NONE) || (proto == PROTO_NONE) ||
+			 (np->proto == proto))) {
+			if (np->pattern && IS_SIP(msg)) {
+				if (regcomp(&preg, np->pattern, REG_NOSUB)) {
+					LM_ERR("invalid regular expression\n");
+					if (!np->ruri_pattern) {
+						continue;
+					}
+				}
+				if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
+					regfree(&preg);
+					continue;
+				}
+				regfree(&preg);
+				if (np->ruri_pattern) {
+					if (regcomp(&preg, np->ruri_pattern, REG_NOSUB)) {
+						LM_ERR("invalid regular expression\n");
+						continue;
+					}
+					if (regexec(&preg, ruri_str, 0, (regmatch_t *)0, 0)) {
+						regfree(&preg);
+						continue;
+					}
+					regfree(&preg);
+				}
+			}
+			/* Found a match */
+			if (tag_avp.n && np->tag.s) {
+				val.s = np->tag;
+				if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
+					LM_ERR("setting of tag_avp failed\n");
+					return -1;
+				}
+			}
+			if (!peer_tag_mode)
+				return 1;
+			count++;
 		}
-		if (!peer_tag_mode)
-		    return 1;
-		count++;
-	    }
 	}
 	if (!count)
 	    return -1;
@@ -288,6 +330,7 @@ int hash_table_mi_print(struct trusted_list** table, struct mi_node* rpl)
 						np->src_ip.len, ZSW(np->src_ip.s),
 						np->proto,
 						np->pattern?np->pattern:"NULL",
+						np->ruri_pattern?np->ruri_pattern:"NULL",
 						np->tag.len?np->tag.s:"NULL") == 0) {
 				return -1;
 			}
@@ -329,8 +372,9 @@ int hash_table_rpc_print(struct trusted_list** hash_table, rpc_t* rpc, void* c)
 				rpc->fault(c, 500, "Internal error creating rpc data (ip)");
 				return -1;
 			}
-			if(rpc->struct_add(ih, "dss", "proto",  np->proto,
+			if(rpc->struct_add(ih, "dsss", "proto",  np->proto,
 						"pattern",  np->pattern ? np->pattern : "NULL",
+						"ruri_pattern",  np->ruri_pattern ? np->ruri_pattern : "NULL",
 						"tag",  np->tag.len ? np->tag.s : "NULL") < 0)
 			{
 				rpc->fault(c, 500, "Internal error creating rpc data");
@@ -356,6 +400,7 @@ void empty_hash_table(struct trusted_list **table)
 		while (np) {
 			if (np->src_ip.s) shm_free(np->src_ip.s);
 			if (np->pattern) shm_free(np->pattern);
+			if (np->ruri_pattern) shm_free(np->ruri_pattern);
 			if (np->tag.s) shm_free(np->tag.s);
 			next = np->next;
 			shm_free(np);
diff --git a/modules/permissions/hash.h b/modules/permissions/hash.h
index 1ae0072..81eebb0 100644
--- a/modules/permissions/hash.h
+++ b/modules/permissions/hash.h
@@ -41,6 +41,7 @@ struct trusted_list {
 	str src_ip;                 /* Source IP of SIP message */
 	int proto;                  /* Protocol -- UDP, TCP, TLS, or SCTP */
 	char *pattern;              /* Pattern matching From header field */
+	char *ruri_pattern;      	/* Pattern matching Request URI */
 	str tag;                    /* Tag to be assigned to AVP */
 	struct trusted_list *next;  /* Next element in the list */
 };
@@ -77,16 +78,16 @@ void destroy_hash_table(struct trusted_list** table);
 
 
 /* 
- * Add <src_ip, proto, pattern> into hash table, where proto is integer
+ * Add <src_ip, proto, pattern, ruri_pattern> into hash table, where proto is integer
  * representation of string argument proto.
  */
 int hash_table_insert(struct trusted_list** hash_table, char* src_ip,
-		      char* proto, char* pattern, char* tag);
+		      char* proto, char* pattern, char* ruri_pattern, char* tag);
 
 
 /* 
  * Check if an entry exists in hash table that has given src_ip and protocol
- * value and pattern that matches to From URI.
+ * value and pattern or ruri_pattern that matches to From URI.
  */
 int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 		     char *scr_ip, int proto);
diff --git a/modules/permissions/permissions.c b/modules/permissions/permissions.c
index 4170fef..9200406 100644
--- a/modules/permissions/permissions.c
+++ b/modules/permissions/permissions.c
@@ -68,6 +68,7 @@ str trusted_table = str_init("trusted");   /* Name of trusted table */
 str source_col = str_init("src_ip");       /* Name of source address column */
 str proto_col = str_init("proto");         /* Name of protocol column */
 str from_col = str_init("from_pattern");   /* Name of from pattern column */
+str ruri_col = str_init("ruri_pattern");   /* Name of RURI pattern column */
 str tag_col = str_init("tag");             /* Name of tag column */
 str tag_avp_param = {NULL, 0};             /* Peer tag AVP spec */
 int peer_tag_mode = 0;                     /* Add tags form all mathcing peers to avp */
@@ -166,6 +167,7 @@ static param_export_t params[] = {
 	{"source_col",         PARAM_STR, &source_col      },
 	{"proto_col",          PARAM_STR, &proto_col       },
 	{"from_col",           PARAM_STR, &from_col        },
+	{"ruri_col",           PARAM_STR, &ruri_col        },
 	{"tag_col",            PARAM_STR, &tag_col         },
 	{"peer_tag_avp",       PARAM_STR, &tag_avp_param   },
 	{"peer_tag_mode",      INT_PARAM, &peer_tag_mode     },
diff --git a/modules/permissions/permissions.h b/modules/permissions/permissions.h
index 0d2fa39..0c0c9ac 100644
--- a/modules/permissions/permissions.h
+++ b/modules/permissions/permissions.h
@@ -25,6 +25,7 @@
  * History:
  * --------
  *  2003-09-03  replaced /usr/local/et/ser/ with CFG_DIR (andrei)
+ *  2015-05-06  added regular expression matching R-URI (eschmidbauer at voipxswitch.com)
  */
  
 #ifndef PERMISSIONS_H
@@ -55,6 +56,7 @@ extern str trusted_table; /* Name of trusted table */
 extern str source_col;    /* Name of source address column */
 extern str proto_col;     /* Name of protocol column */
 extern str from_col;      /* Name of from pattern column */
+extern str ruri_col;      /* Name of RURI pattern column */
 extern str tag_col;       /* Name of tag column */
 extern str address_table; /* Name of address table */
 extern str grp_col;       /* Name of address group column */
diff --git a/modules/permissions/trusted.c b/modules/permissions/trusted.c
index db20e8f..08a989d 100644
--- a/modules/permissions/trusted.c
+++ b/modules/permissions/trusted.c
@@ -41,7 +41,7 @@
 #include "../../parser/parse_from.h"
 #include "../../usr_avp.h"
 
-#define TABLE_VERSION 5
+#define TABLE_VERSION 6
 
 struct trusted_list ***hash_table;     /* Pointer to current hash table pointer */
 struct trusted_list **hash_table_1;   /* Pointer to hash table 1 */
@@ -58,7 +58,7 @@ static db_func_t perm_dbf;
  */
 int reload_trusted_table(void)
 {
-	db_key_t cols[4];
+	db_key_t cols[5];
 	db1_res_t* res = NULL;
 	db_row_t* row;
 	db_val_t* val;
@@ -67,12 +67,13 @@ int reload_trusted_table(void)
 	struct trusted_list **old_hash_table;
 	int i;
 
-	char *pattern, *tag;
+	char *pattern, *ruri_pattern, *tag;
 
 	cols[0] = &source_col;
 	cols[1] = &proto_col;
 	cols[2] = &from_col;
-	cols[3] = &tag_col;
+	cols[3] = &ruri_col;
+	cols[4] = &tag_col;
 
 	if (db_handle == 0) {
 	    LM_ERR("no connection to database\n");
@@ -84,7 +85,7 @@ int reload_trusted_table(void)
 		return -1;
 	}
 
-	if (perm_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 4, 0, &res) < 0) {
+	if (perm_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 5, 0, &res) < 0) {
 		LM_ERR("failed to query database\n");
 		return -1;
 	}
@@ -103,7 +104,7 @@ int reload_trusted_table(void)
 		
 	for (i = 0; i < RES_ROW_N(res); i++) {
 	    val = ROW_VALUES(row + i);
-	    if ((ROW_N(row + i) == 4) &&
+	    if ((ROW_N(row + i) == 5) &&
 		((VAL_TYPE(val) == DB1_STRING) || (VAL_TYPE(val) == DB1_STR) ) && 
 		!VAL_NULL(val) &&
 		((VAL_TYPE(val + 1) == DB1_STRING) || (VAL_TYPE(val + 1) == DB1_STR))
@@ -112,29 +113,36 @@ int reload_trusted_table(void)
 		 (((VAL_TYPE(val + 2) == DB1_STRING) || (VAL_TYPE(val + 2) == DB1_STR)) &&
 		!VAL_NULL(val + 2))) && (VAL_NULL(val + 3) ||
 		 (((VAL_TYPE(val + 3) == DB1_STRING) || (VAL_TYPE(val + 3) == DB1_STR) )&& 
-		!VAL_NULL(val + 3)))) {
+		!VAL_NULL(val + 3))) && (VAL_NULL(val + 4) ||
+		 (((VAL_TYPE(val + 4) == DB1_STRING) || (VAL_TYPE(val + 4) == DB1_STR) )&& 
+		!VAL_NULL(val + 4)))) {
 		if (VAL_NULL(val + 2)) {
 		    pattern = 0;
 		} else {
 		    pattern = (char *)VAL_STRING(val + 2);
 		}
 		if (VAL_NULL(val + 3)) {
+		    ruri_pattern = 0;
+		} else {
+		    ruri_pattern = (char *)VAL_STRING(val + 3);
+		}
+		if (VAL_NULL(val + 4)) {
 		    tag = 0;
 		} else {
-		    tag = (char *)VAL_STRING(val + 3);
+		    tag = (char *)VAL_STRING(val + 4);
 		}
 		if (hash_table_insert(new_hash_table,
 				      (char *)VAL_STRING(val),
 				      (char *)VAL_STRING(val + 1),
-				      pattern, tag) == -1) {
+				      pattern, ruri_pattern, tag) == -1) {
 		    LM_ERR("hash table problem\n");
 		    perm_dbf.free_result(db_handle, res);
 		    empty_hash_table(new_hash_table);
 		    return -1;
 		}
-		LM_DBG("tuple <%s, %s, %s, %s> inserted into trusted hash "
+		LM_DBG("tuple <%s, %s, %s, %s, %s> inserted into trusted hash "
 		    "table\n", VAL_STRING(val), VAL_STRING(val + 1),
-		    pattern, tag);
+		    pattern, ruri_pattern, tag);
 	    } else {
 		LM_ERR("database problem\n");
 		perm_dbf.free_result(db_handle, res);
@@ -369,6 +377,20 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 	regex_t preg;
 	int_str tag_avp, avp_val;
 	int count = 0;
+	
+	int len;
+	static char ruri_str[EXPRESSION_LENGTH+1];
+	
+	len = msg->parsed_uri.user.len + msg->parsed_uri.host.len + 5;
+	if (len > EXPRESSION_LENGTH) {
+		LM_ERR("Request URI is too long: %d chars\n", len);
+		return -1;
+	}
+	strcpy(ruri_str, "sip:");
+	memcpy(ruri_str + 4, msg->parsed_uri.user.s, msg->parsed_uri.user.len);
+	ruri_str[msg->parsed_uri.user.len + 4] = '@';
+	memcpy(ruri_str + msg->parsed_uri.user.len + 5, msg->parsed_uri.host.s, msg->parsed_uri.host.len);
+	ruri_str[len] = '\0';
 
 	if (IS_SIP(msg)) {
 		if (parse_from_header(msg) < 0) return -1;
@@ -385,39 +407,56 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 	row = RES_ROWS(_r);
 
 	for(i = 0; i < RES_ROW_N(_r); i++) {
-		val = ROW_VALUES(row + i);
-		if ((ROW_N(row + i) == 3) &&
-		    (VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) &&
-		    match_proto(VAL_STRING(val), proto) &&
-		    (VAL_NULL(val + 1) ||
-		      ((VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1))) &&
-		    (VAL_NULL(val + 2) ||
-		      ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))))
-		{
-			if (!VAL_NULL(val + 1) && IS_SIP(msg)) {
-				if (regcomp(&preg, (char *)VAL_STRING(val + 1), REG_NOSUB)) {
-					LM_ERR("invalid regular expression\n");
-					continue;
-				}
-				if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
-					regfree(&preg);
-					continue;
+			val = ROW_VALUES(row + i);
+			if ((ROW_N(row + i) == 4) &&
+				(VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) &&
+				match_proto(VAL_STRING(val), proto) &&
+				(VAL_NULL(val + 1) ||
+				  ((VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1))) &&
+				(VAL_NULL(val + 2) ||
+				  ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))) &&
+				(VAL_NULL(val + 3) ||
+				  ((VAL_TYPE(val + 3) == DB1_STRING) && !VAL_NULL(val + 3))))
+			{
+				if (IS_SIP(msg)) {
+					if (!VAL_NULL(val + 1)) {
+						if (regcomp(&preg, (char *)VAL_STRING(val + 1), REG_NOSUB)) {
+								LM_ERR("invalid regular expression\n");
+								if (VAL_NULL(val + 2)) {
+									continue;
+								}
+						}
+						if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
+								regfree(&preg);
+								continue;
+						}
+						regfree(&preg);
+						if (!VAL_NULL(val + 2)) {
+							if (regcomp(&preg, (char *)VAL_STRING(val + 2), REG_NOSUB)) {
+									LM_ERR("invalid regular expression\n");
+									continue;
+							}
+							if (regexec(&preg, ruri_str, 0, (regmatch_t *)0, 0)) {
+									regfree(&preg);
+									continue;
+							}
+							regfree(&preg);
+						}
+					}
 				}
-			    regfree(&preg);
-			}
-			/* Found a match */
-			if (tag_avp.n && !VAL_NULL(val + 2)) {
-				avp_val.s.s = (char *)VAL_STRING(val + 2);
-				avp_val.s.len = strlen(avp_val.s.s);
-				if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, avp_val) != 0) {
-					LM_ERR("failed to set of tag_avp failed\n");
-					return -1;
+				/* Found a match */
+				if (tag_avp.n && !VAL_NULL(val + 3)) {
+						avp_val.s.s = (char *)VAL_STRING(val + 3);
+						avp_val.s.len = strlen(avp_val.s.s);
+						if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, avp_val) != 0) {
+								LM_ERR("failed to set of tag_avp failed\n");
+								return -1;
+						}
 				}
+				if (!peer_tag_mode)
+						return 1;
+				count++;
 			}
-			if (!peer_tag_mode) 
-				return 1;
-			count++;
-		}
 	}
 	if (!count)
 		return -1;
@@ -437,7 +476,7 @@ int allow_trusted(struct sip_msg* msg, char *src_ip, int proto)
 	
 	db_key_t keys[1];
 	db_val_t vals[1];
-	db_key_t cols[3];
+	db_key_t cols[4];
 
 	if (db_mode == DISABLE_CACHE) {
 	
@@ -449,7 +488,8 @@ int allow_trusted(struct sip_msg* msg, char *src_ip, int proto)
 		keys[0] = &source_col;
 		cols[0] = &proto_col;
 		cols[1] = &from_col;
-		cols[2] = &tag_col;
+		cols[2] = &ruri_col;
+		cols[3] = &tag_col;
 
 		if (perm_dbf.use_table(db_handle, &trusted_table) < 0) {
 			LM_ERR("failed to use trusted table\n");
@@ -460,7 +500,7 @@ int allow_trusted(struct sip_msg* msg, char *src_ip, int proto)
 		VAL_NULL(vals) = 0;
 		VAL_STRING(vals) = src_ip;
 
-		if (perm_dbf.query(db_handle, keys, 0, vals, cols, 1, 3, 0,
+		if (perm_dbf.query(db_handle, keys, 0, vals, cols, 1, 4, 0,
 				   &res) < 0){
 			LM_ERR("failed to query database\n");
 			return -1;
diff --git a/utils/kamctl/postgres/permissions-create.sql b/utils/kamctl/postgres/permissions-create.sql
index 95f13de..e005243 100644
--- a/utils/kamctl/postgres/permissions-create.sql
+++ b/utils/kamctl/postgres/permissions-create.sql
@@ -1,9 +1,10 @@
-INSERT INTO version (table_name, table_version) values ('trusted','5');
+INSERT INTO version (table_name, table_version) values ('trusted','6');
 CREATE TABLE trusted (
     id SERIAL PRIMARY KEY NOT NULL,
     src_ip VARCHAR(50) NOT NULL,
     proto VARCHAR(4) NOT NULL,
     from_pattern VARCHAR(64) DEFAULT NULL,
+    ruri_pattern VARCHAR(64) DEFAULT NULL,
     tag VARCHAR(64)
 );
 


More information about the sr-users mailing list