Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[uac_registrant] Match reply Contact with binding_URI by parameter. #2558

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions modules/uac_registrant/doc/uac_registrant_admin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,47 @@ modparam("uac_registrant", "enable_clustering", 1)
</example>
</section>

<section id="param_match_contact" xreflabel="match_contact">
<title><varname>match_contact</varname> (string)</title>
<para>
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.
</para>
<para>Possible URI parts for matching:</para>
<para>
<itemizedlist>
<listitem><para>type</para></listitem>
<listitem><para>user</para></listitem>
<listitem><para>host</para></listitem>
<listitem><para>port</para></listitem>
<listitem><para>transport</para></listitem>
<listitem><para>ttl</para></listitem>
<listitem><para>userparam</para></listitem>
<listitem><para>maddr</para></listitem>
<listitem><para>method</para></listitem>
<listitem><para>all</para></listitem>
</itemizedlist>
</para>
<para>
<emphasis>
Default value is "all".
</emphasis>
</para>
<example>
<title>Set <varname>match_contact</varname> parameter</title>
<programlisting format="linespecific">
...
modparam("uac_registrant", "match_contact", "type;user")
...
</programlisting>
</example>
</section>

<section id="param_db_url" xreflabel="db_url">
<title><varname>db_url</varname> (string)</title>
<para>
Expand Down
11 changes: 9 additions & 2 deletions modules/uac_registrant/registrant.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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, &reg_table_name.s},
{"registrar_column", STR_PARAM, &registrar_column.s},
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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]"
Expand Down
132 changes: 132 additions & 0 deletions parser/parse_uri.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
30 changes: 30 additions & 0 deletions parser/parse_uri.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:[email protected]:5060;a=b?h=i)
* len= len of uri
* returns: fills uri & returns <0 on error or 0 if ok
Expand Down Expand Up @@ -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,
Expand Down