diff --git a/modules/uac_registrant/doc/uac_registrant_admin.xml b/modules/uac_registrant/doc/uac_registrant_admin.xml index 86fe926f2f2..eb39f2f84fc 100644 --- a/modules/uac_registrant/doc/uac_registrant_admin.xml +++ b/modules/uac_registrant/doc/uac_registrant_admin.xml @@ -181,6 +181,47 @@ modparam("uac_registrant", "enable_clustering", 1) +
+ <varname>match_contact</varname> (string) + + A list of URI parts delimited by ';'. + This parameter lets you select which parts of the URI from the Contact + header of the 200 OK reply should match the binding_URI. + The module compares the Contact header with the binding_URI when it + receives a 200 OK reply to the REGISTER request. If they match, + it uses the expiration time given in the reply. + The default behavior is to compare the entire URI. + + Possible URI parts for matching: + + + type + user + host + port + transport + ttl + userparam + maddr + method + all + + + + + Default value is "all". + + + + Set <varname>match_contact</varname> parameter + +... +modparam("uac_registrant", "match_contact", "type;user") +... + + +
+
<varname>db_url</varname> (string) diff --git a/modules/uac_registrant/registrant.c b/modules/uac_registrant/registrant.c index 7c4fbe9b8a2..14f0d3dfe57 100644 --- a/modules/uac_registrant/registrant.c +++ b/modules/uac_registrant/registrant.c @@ -110,6 +110,8 @@ uac_auth_api_t uac_auth_api; unsigned int default_expires = 3600; unsigned int timer_interval = 100; +enum uri_match_flags match_contact = URI_MATCH_NONE; +str match_contact_str = str_init("all"); reg_table_t reg_htable = NULL; unsigned int reg_hsize = 1; @@ -140,6 +142,7 @@ static const param_export_t params[]= { {"default_expires", INT_PARAM, &default_expires}, {"timer_interval", INT_PARAM, &timer_interval}, {"enable_clustering", INT_PARAM, &enable_clustering}, + {"match_contact", STR_PARAM, &match_contact_str.s}, {"db_url", STR_PARAM, &db_url.s}, {"table_name", STR_PARAM, ®_table_name.s}, {"registrar_column", STR_PARAM, ®istrar_column.s}, @@ -258,6 +261,11 @@ static int mod_init(void) return -1; } + if(match_contact_str.s) { + match_contact = parse_uri_options(&match_contact_str); + } + LM_DBG("Match contact value: [%d]\n", (unsigned)match_contact); + reg_table_name.len = strlen(reg_table_name.s); registrar_column.len = strlen(registrar_column.s); proxy_column.len = strlen(proxy_column.s); @@ -481,8 +489,7 @@ int run_reg_tm_cback(void *e_data, void *data, void *r_data) contact = ((contact_body_t*)msg->contact->parsed)->contacts; while (contact) { /* Check for binding */ - if (contact->uri.len==rec->contact_uri.len && - strncmp(contact->uri.s,rec->contact_uri.s,contact->uri.len)==0){ + if (compare_uris_parts(&contact->uri, &rec->contact_uri, match_contact) == 0) { if (contact->expires && contact->expires->body.len) { if (str2int(&contact->expires->body, &exp)<0) { LM_ERR("Unable to extract expires from [%.*s]" diff --git a/parser/parse_uri.c b/parser/parse_uri.c index 937ea70cec1..26da08d199b 100644 --- a/parser/parse_uri.c +++ b/parser/parse_uri.c @@ -53,6 +53,52 @@ static const str uri_type_names[7] = { str_init("urn:nena:service") }; +struct uri_match_part uri_match_parts[] = { + { str_const_init("type"), URI_MATCH_TYPE }, + { str_const_init("user"), URI_MATCH_USER }, + { str_const_init("password"), URI_MATCH_PASSWD }, + { str_const_init("host"), URI_MATCH_HOST }, + { str_const_init("port"), URI_MATCH_PORT }, + { str_const_init("transport"), URI_MATCH_TRANSPORT }, + { str_const_init("ttl"), URI_MATCH_TTL }, + { str_const_init("userparam"), URI_MATCH_USERPARAM }, + { str_const_init("maddr"), URI_MATCH_MADDR }, + { str_const_init("method"), URI_MATCH_METHOD }, + { str_const_init("lr"), URI_MATCH_LR }, + { str_const_init("r2"), URI_MATCH_R2 }, + { str_const_init("all"), URI_MATCH_ALL }, +}; + +enum uri_match_flags parse_uri_options(str *options_str) +{ + enum uri_match_flags flags = URI_MATCH_NONE; + char *p, *e; + str *s = options_str; + int i; + + if (options_str == NULL || options_str->s == NULL || options_str->len == 0) { + return flags; + } + e = s->s + strlen(s->s); + while (s->s < e) { + p = strchr(s->s, ';'); + s->len = (p ? (p - s->s) : strlen(s->s)); + str_trim_spaces_lr(*s); + /* check if this is among the possible options */ + for(i = 0; i< (sizeof(uri_match_parts)/sizeof(uri_match_parts[0])); i++) { + if (s->len == uri_match_parts[i].name.len && + strncasecmp(s->s, uri_match_parts[i].name.s, + uri_match_parts[i].name.len) == 0) + flags |= uri_match_parts[i].flag; + } + if (p) + s->s = p + 1; + else + break; + } + return flags; +} + char* uri_type2str(const uri_type type, char *result) { if (type == ERROR_URI_T) @@ -1855,3 +1901,89 @@ int compare_uris(str *raw_uri_a,struct sip_uri* parsed_uri_a, compare_uri_val(headers,strncasecmp); return 0; } + +/* Compare 2 SIP URIs by parts according to opts + * + * Return value : 0 if URIs match + * 1 if URIs don't match + * -1 if errors have occurred + */ +int compare_uris_parts(str *raw_uri_a, str *raw_uri_b, enum uri_match_flags opts) +{ + #define UNESCAPED_BUF_LEN 1024 + char unescaped_a[UNESCAPED_BUF_LEN], unescaped_b[UNESCAPED_BUF_LEN]; + + str unescaped_userA={unescaped_a, UNESCAPED_BUF_LEN}; + str unescaped_userB={unescaped_b, UNESCAPED_BUF_LEN}; + + struct sip_uri first; + struct sip_uri second; + + if ( (!raw_uri_a) || (!raw_uri_b) ) + { + LM_ERR("Provide either a raw form of a SIP URI\n"); + return -1; + } + + /* maybe we're lucky and straight-forward comparison succeeds */ + if ((opts & URI_MATCH_ALL) && (raw_uri_a->len == raw_uri_b->len)) + if (strncasecmp(raw_uri_a->s,raw_uri_b->s,raw_uri_a->len) == 0) + { + LM_DBG("straight-forward URI match\n"); + return 0; + } + + if (parse_uri(raw_uri_a->s,raw_uri_a->len,&first) < 0) + { + LM_ERR("Failed to parse first URI\n"); + return -1; + } + + if (parse_uri(raw_uri_b->s,raw_uri_b->len,&second) < 0) + { + LM_ERR("Failed to parse second URI\n"); + return -1; + } + + if (opts & URI_MATCH_TYPE) + if (first.type != second.type) + { + LM_DBG("Different uri types\n"); + return 1; + } + + if (unescape_user(&first.user, &unescaped_userA) < 0 || + unescape_user(&second.user, &unescaped_userB) < 0) { + LM_ERR("Failed to unescape user!\n"); + return -1; + } + + first.user = unescaped_userA; + second.user = unescaped_userB; + + if (opts & URI_MATCH_USER) + compare_uri_val(user,strncmp); + if (opts & URI_MATCH_PASSWD) + compare_uri_val(passwd,strncmp); + if (opts & URI_MATCH_HOST) + compare_uri_val(host,strncasecmp); + if (opts & URI_MATCH_PORT) + compare_uri_val(port,strncmp); + + if (opts & URI_MATCH_TRANSPORT) + compare_uri_val(transport_val,strncasecmp); + if (opts & URI_MATCH_TTL) + compare_uri_val(ttl_val,strncasecmp); + if (opts & URI_MATCH_USERPARAM) + compare_uri_val(user_param_val,strncasecmp); + if (opts & URI_MATCH_MADDR) + compare_uri_val(maddr_val,strncasecmp); + if (opts & URI_MATCH_METHOD) + compare_uri_val(method_val,strncasecmp); + if (opts & URI_MATCH_LR) + compare_uri_val(lr_val,strncasecmp); + if (opts & URI_MATCH_R2) + compare_uri_val(r2_val,strncasecmp); + + return 0; +} diff --git a/parser/parse_uri.h b/parser/parse_uri.h index f9c700e57d2..0fa88bdceaa 100644 --- a/parser/parse_uri.h +++ b/parser/parse_uri.h @@ -42,6 +42,35 @@ #define URN_NENA_SERVICE_STR ":nena:service:" #define URN_NENA_SERVICE_STR_LEN (sizeof(URN_NENA_SERVICE_STR) - 1) +/* The possible values of the URI parts used for compare URIs + */ +enum uri_match_flags { + URI_MATCH_NONE = 0, + URI_MATCH_TYPE = (1<<0), + URI_MATCH_USER = (1<<1), + URI_MATCH_PASSWD = (1<<2), + URI_MATCH_HOST = (1<<3), + URI_MATCH_PORT = (1<<4), + URI_MATCH_TRANSPORT = (1<<5), + URI_MATCH_TTL = (1<<6), + URI_MATCH_USERPARAM = (1<<7), + URI_MATCH_MADDR = (1<<8), + URI_MATCH_METHOD = (1<<9), + URI_MATCH_LR = (1<<10), + URI_MATCH_R2 = (1<<11), + URI_MATCH_ALL = (URI_MATCH_TYPE | URI_MATCH_USER | URI_MATCH_PASSWD | URI_MATCH_HOST | URI_MATCH_PORT | URI_MATCH_TRANSPORT | + URI_MATCH_TTL | URI_MATCH_USERPARAM | URI_MATCH_MADDR | URI_MATCH_METHOD | URI_MATCH_LR | URI_MATCH_R2), +}; +struct uri_match_part { + str_const name; + enum uri_match_flags flag; +}; + +/* options_str= options to match Contact URI for uac_registrant + * returns: binary flags to match URI + */ +enum uri_match_flags parse_uri_options(str *options_str); + /* buf= pointer to beginning of uri (sip:x@foo.bar:5060;a=b?h=i) * len= len of uri * returns: fills uri & returns <0 on error or 0 if ok @@ -69,6 +98,7 @@ int parse_sip_msg_uri(struct sip_msg* msg); int parse_orig_ruri(struct sip_msg* msg); int compare_uris(str *raw_uri_a,struct sip_uri* parsed_uri_a, str *raw_uri_b,struct sip_uri *parsed_uri_b); +int compare_uris_parts(str *raw_uri_a, str *raw_uri_b, enum uri_match_flags opts); static inline int get_uri_param_val(const struct sip_uri *uri, const str *param, str *val); static inline int get_uri_param_idx(const str *param,