Skip to content

Commit

Permalink
permissions: introduce func allow_register_include_port()
Browse files Browse the repository at this point in the history
Introduce new function: `allow_register_include_port()`
to be able to check the whole Contact header including port.

Example, register.deny content is:
	ALL : "^sip:.*192.168.0.101:5062"

If the Contact is: "Contact: <sip:[email protected]:5062>"
then this will check the Contact hf including port of it.

Otherwise if usual `allow_register()` function is used,
then only the "[email protected]" will be taken into
account, which will lead the regex to be failing and letting
the check to pass through.

The func `allow_register_include_port()` works similarly
as `allow_register()` except it checks Contact's port.

Full backwards compatibility is kept in place,
no need for users of the module to change anything in
their configuration or kamailio script itself.
  • Loading branch information
zenichev authored and linuxmaniac committed May 27, 2024
1 parent 82cfea3 commit 534a359
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 12 deletions.
7 changes: 7 additions & 0 deletions src/modules/permissions/doc/permissions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@
<email>[email protected]</email>
</address>
</editor>
<editor>
<firstname>Donat</firstname>
<surname>Zenichev</surname>
<address>
<email>[email protected]</email>
</address>
</editor>
</authorgroup>
<copyright>
<year>2003</year>
Expand Down
142 changes: 142 additions & 0 deletions src/modules/permissions/doc/permissions_admin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@
similar to the algorithm described in
<xref linkend="sec-call-routing"/>. The only difference is in the way
how pairs are created.
Additionally one can use <function moreinfo="none">allow_register_include_port</function>
function in order to include the port value of the Contact into the check.
</para>
<para>
Instead of the From header field the function uses the To header field because
Expand Down Expand Up @@ -384,6 +386,7 @@ modparam("permissions", "check_all_branches", 0)
Suffix to be appended to basename to create filename of the allow
file when version with one parameter of either
<function moreinfo="none">allow_routing</function> or
<function moreinfo="none">allow_register_include_port</function> or
<function moreinfo="none">allow_register</function> is used.
</para>
<note>
Expand Down Expand Up @@ -411,6 +414,7 @@ modparam("permissions", "allow_suffix", ".allow")
Suffix to be appended to basename to create filename of the deny file
when version with one parameter of either
<function moreinfo="none">allow_routing</function> or
<function moreinfo="none">allow_register_include_port</function> or
<function moreinfo="none">allow_register</function> is used.
</para>
<note>
Expand Down Expand Up @@ -1094,6 +1098,98 @@ if (method=="REGISTER") {
};
};
...
</programlisting>
</example>
</section>
<section id ="permissions.f.allow_register_include_port">
<title>
<function moreinfo="none">allow_register_include_port(basename)</function>
</title>
<para>
The function does exacty the same thing as <function>allow_register(basename)</function>
apart that it tells the module to include the port value of Contact into the check.
No additional function parameters required.
</para>
<para>Meaning of the parameters is as follows:</para>
<itemizedlist>
<listitem>
<para><emphasis>basename</emphasis> - Basename from which allow
and deny filenames will be created by appending contents of
<varname>allow_suffix</varname> and <varname>deny_suffix</varname>
parameters.
</para>
<para>
If the parameter doesn't contain full pathname then the function
expects the file to be located in the same directory as the main
configuration file of the server.
</para>
</listitem>
</itemizedlist>
<para>
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
</para>
<example>
<title><function>allow_register_include_port(basename)</function> usage</title>
<programlisting format="linespecific">
...
if (method=="REGISTER") {
if (allow_register_include_port("register")) {
save("location");
exit;
} else {
sl_send_reply("403", "Forbidden");
};
};
...
</programlisting>
</example>
</section>
<section id ="permissions.f.allow_register_include_port_fileargs">
<title>
<function moreinfo="none">allow_register_include_port(allow_file, deny_file)</function>
</title>
<para>
The function does exacty the same thing as <function>allow_register(allow_file, deny_file)</function>
apart that it tells the module to include the port value of Contact into the check.
No additional function parameters required.
</para>
<para>Meaning of the parameters is as follows:</para>
<itemizedlist>
<listitem>
<para><emphasis>allow_file</emphasis> - File containing allow rules.
</para>
<para>
If the parameter doesn't contain full pathname then the function
expects the file to be located in the same directory as the main
configuration file of the server.
</para>
</listitem>
<listitem>
<para><emphasis>deny_file</emphasis> - File containing deny rules.
</para>
<para>
If the parameter doesn't contain full pathname then the function
expects the file to be located in the same directory as the main
configuration file of the server.
</para>
</listitem>
</itemizedlist>
<para>
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
</para>
<example>
<title><function>allow_register_include_port(allow_file, deny_file)</function> usage</title>
<programlisting format="linespecific">
...
if (method=="REGISTER") {
if (allow_register_include_port("register.allow", "register.deny")) {
save("location");
exit;
} else {
sl_send_reply("403", "Forbidden");
};
};
...
</programlisting>
</example>
</section>
Expand Down Expand Up @@ -1492,4 +1588,50 @@ if (allow_trusted("$si", "any", "$ai")) {

</section> <!-- Address File Format -->

<section>
<title>Register File Format</title>
<para>
It is a text file with one record per line. Lines starting with '#' are
considered comments and ignored. Comments can be also at the end of
records, by using '#' to start the comment part of the line.
</para>
<para>
Each record line has the format:
</para>
<programlisting format="linespecific">
...
(from_list,str) (req_uri_list,str)
...
</programlisting>
<para>
The 'str' indicates that the value has to be a string compatible with
POSIX Extended Regular Expressions.
</para>
<example>
<title>Register File Sample</title>
<programlisting format="linespecific">
...
# Syntax:
# from_list [EXCEPT from_list] : req_uri_list [EXCEPT req_uri_list]
#
# from_list and req_uri_list are comma separated expressions
# Expressions are treated as case insensitive POSIX Extended Regular Expressions.
# Keyword ALL matches any expression.
#
# Examples (requires a usage of allow_register() function):
# ALL : "^sip:361[0-9]*@abc\.com$" EXCEPT "^sip:361[0-9]*3@abc\.com$", "^sip:361[0-9]*4@abc\.com$"
#
# "^sip:3677[0-9]*@abc\.com$" : "^sip:361[0-9]*@abc\.com$"
#
# All : ALL
#
# Examples including port check (requires a usage of allow_register_include_port() function):
#
# ALL : "^sip:.*@192.168.0.1:5062"
...
</programlisting>
</example>

</section> <!-- Register File Format -->

</chapter>
63 changes: 51 additions & 12 deletions src/modules/permissions/permissions.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ static int allow_routing_2(
static int allow_register_1(struct sip_msg *msg, char *basename, char *s);
static int allow_register_2(
struct sip_msg *msg, char *allow_file, char *deny_file);
static int allow_register_include_port_1(
struct sip_msg *msg, char *basename, char *s);
static int allow_register_include_port_2(
struct sip_msg *msg, char *allow_file, char *deny_file);
static int allow_uri(struct sip_msg *msg, char *basename, char *uri);

static int mod_init(void);
Expand All @@ -142,6 +146,12 @@ static cmd_export_t cmds[] = {
REQUEST_ROUTE | FAILURE_ROUTE},
{"allow_register", (cmd_function)allow_register_2, 2, load_fixup, 0,
REQUEST_ROUTE | FAILURE_ROUTE},
{"allow_register_include_port",
(cmd_function)allow_register_include_port_1, 1, single_fixup, 0,
REQUEST_ROUTE | FAILURE_ROUTE},
{"allow_register_include_port",
(cmd_function)allow_register_include_port_2, 2, load_fixup, 0,
REQUEST_ROUTE | FAILURE_ROUTE},
{"allow_trusted", (cmd_function)allow_trusted_0, 0, 0, 0, ANY_ROUTE},
{"allow_trusted", (cmd_function)allow_trusted_2, 2, fixup_spve_spve,
fixup_free_spve_spve, ANY_ROUTE},
Expand Down Expand Up @@ -285,7 +295,7 @@ static int find_index(rule_file_t *array, char *pathname)
* sip:username@domain, resulting buffer is statically allocated and
* zero terminated
*/
static char *get_plain_uri(const str *uri)
static char *get_plain_uri(const str *uri, int check_port)
{
static char buffer[EXPRESSION_LENGTH + 1];
struct sip_uri puri;
Expand All @@ -300,9 +310,14 @@ static char *get_plain_uri(const str *uri)
}

if(puri.user.len) {
len = puri.user.len + puri.host.len + 5;
len = puri.user.len + puri.host.len + 5; /* +5 is 'sip:' and '@' */
} else {
len = puri.host.len + 4;
len = puri.host.len + 4; /* +4 is 'sip:' */
}

if(check_port && puri.port.len) {
LM_DBG("Port number will also be used to check the Contact value\n");
len += (puri.port.len + 1); /* +1 is ':' */
}

if(len > EXPRESSION_LENGTH) {
Expand All @@ -312,11 +327,22 @@ static char *get_plain_uri(const str *uri)

strcpy(buffer, "sip:");
if(puri.user.len) {
memcpy(buffer + 4, puri.user.s, puri.user.len);
memcpy(buffer + 4, puri.user.s, puri.user.len); /* +4 is 'sip:' */
buffer[puri.user.len + 4] = '@';
memcpy(buffer + puri.user.len + 5, puri.host.s, puri.host.len);
memcpy(buffer + puri.user.len + 5, puri.host.s,
puri.host.len); /* +5 is 'sip:' and '@' */
if(check_port && puri.port.len) {
buffer[puri.user.len + puri.host.len + 5] = ':';
memcpy(buffer + puri.user.len + puri.host.len + 6, puri.port.s,
puri.port.len); /* +6 is 'sip:', '@' and ':' */
}
} else {
memcpy(buffer + 4, puri.host.s, puri.host.len);
if(check_port && puri.port.len) {
buffer[puri.host.len + 4] = ':';
memcpy(buffer + puri.host.len + 5, puri.port.s,
puri.port.len); /* +5 is 'sip:' and ':' */
}
}

buffer[len] = '\0';
Expand Down Expand Up @@ -416,7 +442,7 @@ static int check_routing(struct sip_msg *msg, int idx)
br_idx, &branch.len, &q, 0, 0, 0, 0, 0, 0, 0))
!= 0;
br_idx++) {
uri_str = get_plain_uri(&branch);
uri_str = get_plain_uri(&branch, 0);
if(!uri_str) {
LM_ERR("failed to extract plain URI\n");
return -1;
Expand Down Expand Up @@ -755,9 +781,11 @@ int allow_routing_2(struct sip_msg *msg, char *allow_file, char *deny_file)
* against rules in allow and deny files passed as parameters. The function
* iterates over all Contacts and creates a pair with To for each contact
* found. That allows to restrict what IPs may be used in registrations, for
* example
* example.
*
* If check_port is 0, then port isn't taken into account.
*/
static int check_register(struct sip_msg *msg, int idx)
static int check_register(struct sip_msg *msg, int idx, int check_port)
{
int len;
static char to_str[EXPRESSION_LENGTH + 1];
Expand Down Expand Up @@ -821,7 +849,8 @@ static int check_register(struct sip_msg *msg, int idx)
}

while(c) {
contact_str = get_plain_uri(&c->uri);
/* if check_port = 1, then port is included into regex check */
contact_str = get_plain_uri(&c->uri, check_port);
if(!contact_str) {
LM_ERR("can't extract plain Contact URI\n");
return -1;
Expand Down Expand Up @@ -854,13 +883,23 @@ static int check_register(struct sip_msg *msg, int idx)

int allow_register_1(struct sip_msg *msg, char *basename, char *s)
{
return check_register(msg, (int)(long)basename);
return check_register(msg, (int)(long)basename, 0);
}


int allow_register_2(struct sip_msg *msg, char *allow_file, char *deny_file)
{
return check_register(msg, (int)(long)allow_file);
return check_register(msg, (int)(long)allow_file, 0);
}

int allow_register_include_port_1(struct sip_msg *msg, char *basename, char *s)
{
return check_register(msg, (int)(long)basename, 1);
}

int allow_register_include_port_2(
struct sip_msg *msg, char *allow_file, char *deny_file)
{
return check_register(msg, (int)(long)allow_file, 1);
}


Expand Down

0 comments on commit 534a359

Please sign in to comment.