Преглед на файлове

permissions: match trusted rules considering priority and regexp over r-uri

- two new columns to set priority of the rule as well as regular
  expression matching over r-uri
Emmanuel Schmidbauer преди 10 години
родител
ревизия
4f635fadff
променени са 5 файла, в които са добавени 157 реда и са изтрити 43 реда
  1. 81 17
      modules/permissions/hash.c
  2. 5 3
      modules/permissions/hash.h
  3. 4 0
      modules/permissions/permissions.c
  4. 2 0
      modules/permissions/permissions.h
  5. 65 23
      modules/permissions/trusted.c

+ 81 - 17
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,13 +117,15 @@ 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, priority> 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, int priority)
 {
 	struct trusted_list *np;
+	struct trusted_list *np0 = NULL;
+	struct trusted_list *np1 = NULL;
 	unsigned int hash_val;
 
 	np = (struct trusted_list *) shm_malloc(sizeof(*np));
@@ -179,13 +182,27 @@ int hash_table_insert(struct trusted_list** table, char* src_ip,
 		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;
 		}
@@ -195,9 +212,29 @@ int hash_table_insert(struct trusted_list** table, char* src_ip,
 		np->tag.s = 0;
 	}
 
+	np->priority = priority;
+
 	hash_val = perm_hash(np->src_ip);
-	np->next = table[hash_val];
-	table[hash_val] = np;
+	if(table[hash_val]==NULL) {
+		np->next = NULL;
+		table[hash_val] = np;
+	} else {
+		np1 = NULL;
+		np0 = table[hash_val];
+		while(np0) {
+			if(np0->priority < np->priority)
+				break;
+			np1 = np0;
+			np0 = np0->next;
+		}
+		if(np1==NULL) {
+			np->next = table[hash_val];
+			table[hash_val] = np;
+		} else {
+			np->next = np1->next;
+			np1->next = np;
+		}
+	}
 
 	return 1;
 }
@@ -212,8 +249,9 @@ int hash_table_insert(struct trusted_list** table, char* src_ip,
 int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 		char *src_ip_c_str, int proto)
 {
-	str uri;
+	str uri, ruri;
 	char uri_string[MAX_URI_SIZE + 1];
+	char ruri_string[MAX_URI_SIZE + 1];
 	regex_t preg;
 	struct trusted_list *np;
 	str src_ip;
@@ -233,6 +271,13 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 		}
 		memcpy(uri_string, uri.s, uri.len);
 		uri_string[uri.len] = (char)0;
+		ruri = msg->first_line.u.request.uri;
+		if (ruri.len > MAX_URI_SIZE) {
+			LM_ERR("message has Request URI too large\n");
+			return -1;
+		}
+		memcpy(ruri_string, ruri.s, ruri.len);
+		ruri_string[ruri.len] = (char)0;
 	}
 
 	for (np = table[perm_hash(src_ip)]; np != NULL; np = np->next) {
@@ -240,16 +285,31 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 		(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 (IS_SIP(msg)) {
+		    if (np->pattern) {
+		        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 (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
+		    if (np->ruri_pattern) {
+			if (regcomp(&preg, np->ruri_pattern, REG_NOSUB)) {
+			    LM_ERR("invalid regular expression\n");
+			    continue;
+			}
+			if (regexec(&preg, ruri_string, 0, (regmatch_t *)0, 0)) {
+			    regfree(&preg);
+			    continue;
+			}
 			regfree(&preg);
-			continue;
 		    }
-		    regfree(&preg);
 		}
 		/* Found a match */
 		if (tag_avp.n && np->tag.s) {
@@ -283,12 +343,14 @@ int hash_table_mi_print(struct trusted_list** table, struct mi_node* rpl)
 		np = table[i];
 		while (np) {
 			if (addf_mi_node_child(rpl, 0, 0, 0,
-						"%4d <%.*s, %d, %s, %s>",
+						"%4d <%.*s, %d, %s, %s, %s, %d>",
 						i,
 						np->src_ip.len, ZSW(np->src_ip.s),
 						np->proto,
 						np->pattern?np->pattern:"NULL",
-						np->tag.len?np->tag.s:"NULL") == 0) {
+						np->ruri_pattern?np->ruri_pattern:"NULL",
+						np->tag.len?np->tag.s:"NULL",
+						np->priority) == 0) {
 				return -1;
 			}
 			np = np->next;
@@ -329,9 +391,11 @@ 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, "dsssd", "proto",  np->proto,
 						"pattern",  np->pattern ? np->pattern : "NULL",
-						"tag",  np->tag.len ? np->tag.s : "NULL") < 0)
+						"ruri_pattern",  np->ruri_pattern ? np->ruri_pattern : "NULL",
+						"tag",  np->tag.len ? np->tag.s : "NULL",
+						"priority", np->priority) < 0)
 			{
 				rpc->fault(c, 500, "Internal error creating rpc data");
 				return -1;

+ 5 - 3
modules/permissions/hash.h

@@ -41,7 +41,9 @@ 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 */
+	int priority;               /* priority */
 	struct trusted_list *next;  /* Next element in the list */
 };
 
@@ -77,16 +79,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, priority> 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, int priority);
 
 
 /* 
  * 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);

+ 4 - 0
modules/permissions/permissions.c

@@ -68,7 +68,9 @@ 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 priority_col = str_init("priority");   /* Name of priority 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,7 +168,9 @@ 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         },
+	{"priority_col",       PARAM_STR, &priority_col    },
 	{"peer_tag_avp",       PARAM_STR, &tag_avp_param   },
 	{"peer_tag_mode",      INT_PARAM, &peer_tag_mode     },
 	{"address_table",      PARAM_STR, &address_table   },

+ 2 - 0
modules/permissions/permissions.h

@@ -55,7 +55,9 @@ 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 priority_col;  /* Name of priority column */
 extern str address_table; /* Name of address table */
 extern str grp_col;       /* Name of address group column */
 extern str ip_addr_col;   /* Name of ip address column */

+ 65 - 23
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[6];
 	db1_res_t* res = NULL;
 	db_row_t* row;
 	db_val_t* val;
@@ -66,13 +66,16 @@ int reload_trusted_table(void)
 	struct trusted_list **new_hash_table;
 	struct trusted_list **old_hash_table;
 	int i;
+	int priority;
 
-	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;
+	cols[5] = &priority_col;
 
 	if (db_handle == 0) {
 	    LM_ERR("no connection to database\n");
@@ -84,7 +87,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, 6, 0, &res) < 0) {
 		LM_ERR("failed to query database\n");
 		return -1;
 	}
@@ -103,7 +106,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) == 6) &&
 		((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))
@@ -111,30 +114,42 @@ int reload_trusted_table(void)
 		(VAL_NULL(val + 2) ||
 		 (((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_TYPE(val + 3) == DB1_STRING) || (VAL_TYPE(val + 3) == DB1_STR) )&&
+		!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 (VAL_NULL(val + 5)) {
+		    priority = 0;
+		} else {
+		    priority = (int)VAL_INT(val + 5);
 		}
 		if (hash_table_insert(new_hash_table,
 				      (char *)VAL_STRING(val),
 				      (char *)VAL_STRING(val + 1),
-				      pattern, tag) == -1) {
+				      pattern, ruri_pattern, tag, priority) == -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);
@@ -362,8 +377,9 @@ static inline int match_proto(const char *proto_string, int proto_int)
 static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 {
 	int i, tag_avp_type;
-	str uri;
+	str uri, ruri;
 	char uri_string[MAX_URI_SIZE+1];
+	char ruri_string[MAX_URI_SIZE+1];
 	db_row_t* row;
 	db_val_t* val;
 	regex_t preg;
@@ -379,6 +395,13 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 		}
 		memcpy(uri_string, uri.s, uri.len);
 		uri_string[uri.len] = (char)0;
+		ruri = msg->first_line.u.request.uri;
+		if (ruri.len > MAX_URI_SIZE) {
+			LM_ERR("message has Request URI too large\n");
+			return -1;
+		}
+		memcpy(ruri_string, ruri.s, ruri.len);
+		ruri_string[ruri.len] = (char)0;
 	}
 	get_tag_avp(&tag_avp, &tag_avp_type);
 
@@ -386,28 +409,45 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 
 	for(i = 0; i < RES_ROW_N(_r); i++) {
 		val = ROW_VALUES(row + i);
-		if ((ROW_N(row + i) == 3) &&
+		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_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))) &&
+		    (VAL_NULL(val + 3) ||
+		      ((VAL_TYPE(val + 3) == DB1_STRING) && !VAL_NULL(val + 3))))
 		{
-			if (!VAL_NULL(val + 1) && IS_SIP(msg)) {
+			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");
-					continue;
+					if (VAL_NULL(val + 2)) {
+						continue;
+					}
 				}
 				if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
 					regfree(&preg);
 					continue;
 				}
-			    regfree(&preg);
+				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_string, 0, (regmatch_t *)0, 0)) {
+					regfree(&preg);
+					continue;
+				}
+				regfree(&preg);
+			    }
 			}
 			/* Found a match */
-			if (tag_avp.n && !VAL_NULL(val + 2)) {
-				avp_val.s.s = (char *)VAL_STRING(val + 2);
+			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");
@@ -437,9 +477,10 @@ 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) {
+		db_key_t order = &priority_col;
 	
 	        if (db_handle == 0) {
 		    LM_ERR("no connection to database\n");
@@ -449,7 +490,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 +502,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, order,
 				   &res) < 0){
 			LM_ERR("failed to query database\n");
 			return -1;