diff --git a/src/modules/permissions/doc/permissions.xml b/src/modules/permissions/doc/permissions.xml index 10b16ae1e91..a8adfdf9444 100644 --- a/src/modules/permissions/doc/permissions.xml +++ b/src/modules/permissions/doc/permissions.xml @@ -48,6 +48,13 @@ eschmidbauer@voipxswitch.com + + Donat + Zenichev +
+ dzenichev@sipwise.com +
+
2003 diff --git a/src/modules/permissions/doc/permissions_admin.xml b/src/modules/permissions/doc/permissions_admin.xml index 4ddde99d621..494a7ecc0fb 100644 --- a/src/modules/permissions/doc/permissions_admin.xml +++ b/src/modules/permissions/doc/permissions_admin.xml @@ -121,6 +121,8 @@ similar to the algorithm described in . The only difference is in the way how pairs are created. + Additionally one can use allow_register_include_port + function in order to include the port value of the Contact into the check. Instead of the From header field the function uses the To header field because @@ -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 allow_routing or + allow_register_include_port or allow_register is used. @@ -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 allow_routing or + allow_register_include_port or allow_register is used. @@ -1094,6 +1098,98 @@ if (method=="REGISTER") { }; }; ... + + + +
+ + <function moreinfo="none">allow_register_include_port(basename)</function> + + + The function does exacty the same thing as allow_register(basename) + apart that it tells the module to include the port value of Contact into the check. + No additional function parameters required. + + Meaning of the parameters is as follows: + + + basename - Basename from which allow + and deny filenames will be created by appending contents of + allow_suffix and deny_suffix + parameters. + + + 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. + + + + + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. + + + <function>allow_register_include_port(basename)</function> usage + +... +if (method=="REGISTER") { + if (allow_register_include_port("register")) { + save("location"); + exit; + } else { + sl_send_reply("403", "Forbidden"); + }; +}; +... + + +
+
+ + <function moreinfo="none">allow_register_include_port(allow_file, deny_file)</function> + + + The function does exacty the same thing as allow_register(allow_file, deny_file) + apart that it tells the module to include the port value of Contact into the check. + No additional function parameters required. + + Meaning of the parameters is as follows: + + + allow_file - File containing allow rules. + + + 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. + + + + deny_file - File containing deny rules. + + + 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. + + + + + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. + + + <function>allow_register_include_port(allow_file, deny_file)</function> usage + +... +if (method=="REGISTER") { + if (allow_register_include_port("register.allow", "register.deny")) { + save("location"); + exit; + } else { + sl_send_reply("403", "Forbidden"); + }; +}; +...
@@ -1492,4 +1588,50 @@ if (allow_trusted("$si", "any", "$ai")) { +
+ Register File Format + + 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. + + + Each record line has the format: + + +... +(from_list,str) (req_uri_list,str) +... + + + The 'str' indicates that the value has to be a string compatible with + POSIX Extended Regular Expressions. + + + Register File Sample + +... +# 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" +... + + + +
+ diff --git a/src/modules/permissions/permissions.c b/src/modules/permissions/permissions.c index 2b860b81b2f..f91f1a0f112 100644 --- a/src/modules/permissions/permissions.c +++ b/src/modules/permissions/permissions.c @@ -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); @@ -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}, @@ -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; @@ -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) { @@ -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'; @@ -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; @@ -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]; @@ -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; @@ -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); }