Skip to content

Commit

Permalink
[uac_registrant] New parameter to match reply Contact with binding_URI
Browse files Browse the repository at this point in the history
Added new string module parameter 'match_contact' to choose, what
parts of URI from Contact header should match binding_URI when
OpenSIPS chooses expiration time for registration.
  • Loading branch information
vasilevalex committed Jun 23, 2023
1 parent f69b150 commit 819283c
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 2 deletions.
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

0 comments on commit 819283c

Please sign in to comment.