[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