mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
769 lines
22 KiB
769 lines
22 KiB
/*
|
|
* $Id$
|
|
*
|
|
* PERMISSIONS module
|
|
*
|
|
* Copyright (C) 2003 Miklós Tirpák (mtirpak@sztaki.hu)
|
|
* Copyright (C) 2003 iptel.org
|
|
* Copyright (C) 2003 Juha Heinanen (jh@tutpro.com)
|
|
* Copyright (C) 2006 iptelorg GmbH
|
|
*
|
|
* This file is part of ser, a free SIP server.
|
|
*
|
|
* ser is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* For a license to use the ser software under conditions
|
|
* other than those described here, or to purchase support for this
|
|
* software, please contact iptel.org by e-mail at the following addresses:
|
|
* info@iptel.org
|
|
*
|
|
* ser is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* History:
|
|
* --------
|
|
* 2006-08-10: file operation functions are moved to allow_files.c
|
|
* memory is not allocated for file containers if not needed
|
|
* safe_file_load module parameter introduced (Miklos)
|
|
* 2006-08-14: child processes do not keep the DB connection open
|
|
* if cache is enabled (Miklos)
|
|
* 2008-07-xx: added ip_is_trusted function (tma)
|
|
* 2008-08-01: added ipset manipulable via RPC (tma)
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "../../mem/mem.h"
|
|
#include "../../mem/shm_mem.h"
|
|
#include "permissions.h"
|
|
#include "trusted.h"
|
|
#include "allow_files.h"
|
|
#include "ipmatch.h"
|
|
#include "im_db.h"
|
|
#include "permissions_rpc.h"
|
|
#include "ip_set.h"
|
|
#include "../../resolve.h"
|
|
|
|
MODULE_VERSION
|
|
|
|
rule_file_t *allow = NULL; /* Parsed allow files */
|
|
rule_file_t *deny = NULL; /* Parsed deny files */
|
|
static int allow_rules_num = 0; /* Number of parsed allow files (excluding default file) */
|
|
static int deny_rules_num = 0; /* Number of parsed deny files (excluding default file) */
|
|
|
|
/* Module parameter variables */
|
|
/* general parameters */
|
|
char* db_url = 0; /* Don't connect to the database by default */
|
|
int db_mode = DISABLE_CACHE; /* Database usage mode: 0=no cache, 1=cache */
|
|
int max_rule_files = MAX_RULE_FILES; /* maximum nuber of allowed allow/deny file pairs */
|
|
|
|
/* parameters for allow_* functions */
|
|
static char* default_allow_file = DEFAULT_ALLOW_FILE;
|
|
static char* default_deny_file = DEFAULT_DENY_FILE;
|
|
static char* allow_suffix = ".allow";
|
|
static char* deny_suffix = ".deny";
|
|
int check_all_branches = 1; /* By default we check all branches */
|
|
int safe_file_load = 0;
|
|
|
|
/* for allow_trusted function */
|
|
char* trusted_table = "trusted"; /* Name of trusted table */
|
|
char* source_col = "src_ip"; /* Name of source address column */
|
|
char* proto_col = "proto"; /* Name of protocol column */
|
|
char* from_col = "from_pattern"; /* Name of from pattern column */
|
|
|
|
/* parameters for ipmatch functions */
|
|
char *ipmatch_table = "ipmatch";
|
|
|
|
/* Database API */
|
|
db_ctx_t *db_conn = NULL;
|
|
|
|
static str *ip_set_list_names = NULL; /* declared names */
|
|
static struct ip_set_ref **ip_set_list_local = NULL; /* local copy of ip set in shared memory */
|
|
static int ip_set_list_count = 0; /* number of declared names */
|
|
|
|
/* fixup function prototypes */
|
|
static int fixup_files_1(void** param, int param_no);
|
|
static int fixup_files_2(void** param, int param_no);
|
|
static int fixup_ip_is_trusted(void** param, int param_no);
|
|
static int fixup_w_im(void **, int);
|
|
static int fixup_w_im_onsend(void **, int);
|
|
static int fixup_param_declare_ip_set( modparam_t type, void* val);
|
|
|
|
/* module function prototypes */
|
|
static int allow_routing_0(struct sip_msg* msg, char* str1, char* str2);
|
|
static int allow_routing_1(struct sip_msg* msg, char* basename, char* str2);
|
|
static int allow_routing_2(struct sip_msg* msg, char* allow_file, char* deny_file);
|
|
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_refer_to_1(struct sip_msg* msg, char* basename, char* s);
|
|
static int allow_refer_to_2(struct sip_msg* msg, char* allow_file, char* deny_file);
|
|
int w_im_2(struct sip_msg *msg, char *str1, char *str2);
|
|
int w_im_1(struct sip_msg *msg, char *str1, char *str2);
|
|
int w_im_onsend(struct sip_msg *msg, char *str1, char *str2);
|
|
int w_im_filter(struct sip_msg *msg, char *str1, char *str2);
|
|
static int w_ip_is_trusted(struct sip_msg *msg, char *str1, char *str2);
|
|
|
|
|
|
/* module interface function prototypes */
|
|
static int mod_init(void);
|
|
static void mod_exit(void);
|
|
static int child_init(int rank);
|
|
|
|
|
|
/* Exported functions */
|
|
static cmd_export_t cmds[] = {
|
|
{"allow_routing", allow_routing_0, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"allow_routing", allow_routing_1, 1, fixup_files_1, REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"allow_routing", allow_routing_2, 2, fixup_files_2, REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"allow_register", allow_register_1, 1, fixup_files_1, REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"allow_register", allow_register_2, 2, fixup_files_2, REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"allow_refer_to", allow_refer_to_1, 1, fixup_files_1, REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"allow_refer_to", allow_refer_to_2, 2, fixup_files_2, REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"allow_trusted", allow_trusted, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"ipmatch", w_im_1, 1, fixup_w_im, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
|
|
{"ipmatch", w_im_2, 2, fixup_w_im, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
|
|
{"ipmatch_onsend", w_im_onsend, 1, fixup_w_im_onsend, ONSEND_ROUTE },
|
|
{"ipmatch_filter", w_im_filter, 1, fixup_int_1, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | ONSEND_ROUTE},
|
|
{"ip_is_trusted", w_ip_is_trusted, 2, fixup_ip_is_trusted, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | ONSEND_ROUTE | BRANCH_ROUTE},
|
|
{"ip_is_in_ipset", w_ip_is_trusted, 2, fixup_ip_is_trusted, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | ONSEND_ROUTE | BRANCH_ROUTE},
|
|
|
|
{0, 0, 0, 0, 0}
|
|
};
|
|
|
|
/* Exported parameters */
|
|
static param_export_t params[] = {
|
|
{"db_url", PARAM_STRING, &db_url },
|
|
{"db_mode", PARAM_INT, &db_mode },
|
|
{"default_allow_file", PARAM_STRING, &default_allow_file},
|
|
{"default_deny_file", PARAM_STRING, &default_deny_file },
|
|
{"check_all_branches", PARAM_INT, &check_all_branches},
|
|
{"allow_suffix", PARAM_STRING, &allow_suffix },
|
|
{"deny_suffix", PARAM_STRING, &deny_suffix },
|
|
{"max_rule_files", PARAM_INT, &max_rule_files },
|
|
{"safe_file_load", PARAM_INT, &safe_file_load },
|
|
{"trusted_table", PARAM_STRING, &trusted_table },
|
|
{"source_col", PARAM_STRING, &source_col },
|
|
{"proto_col", PARAM_STRING, &proto_col },
|
|
{"from_col", PARAM_STRING, &from_col },
|
|
{"ipmatch_table", PARAM_STRING, &ipmatch_table },
|
|
{"declare_ipset", PARAM_STRING|PARAM_USE_FUNC, fixup_param_declare_ip_set},
|
|
|
|
{0, 0, 0}
|
|
};
|
|
|
|
/* Module interface */
|
|
struct module_exports exports = {
|
|
"permissions",
|
|
cmds, /* Exported functions */
|
|
permissions_rpc, /* RPC methods */
|
|
params, /* Exported parameters */
|
|
mod_init, /* module initialization function */
|
|
0, /* response function */
|
|
mod_exit, /* destroy function */
|
|
0, /* oncancel function */
|
|
child_init /* child initialization function */
|
|
};
|
|
|
|
/*
|
|
* Convert the name of the files into table index
|
|
*/
|
|
static int fixup_files_2(void** param, int param_no)
|
|
{
|
|
int idx;
|
|
|
|
if (param_no == 1) {
|
|
idx = load_file(*param, &allow, &allow_rules_num, 0);
|
|
} else if( param_no == 2) {
|
|
idx = load_file(*param, &deny, &deny_rules_num, 0);
|
|
} else {
|
|
return 0;
|
|
}
|
|
if (idx < 0) return -1;
|
|
|
|
pkg_free(*param);
|
|
*param = (void*)(long)idx;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Convert the name of the file into table index
|
|
*/
|
|
static int fixup_files_1(void** param, int param_no)
|
|
{
|
|
char* buffer;
|
|
int param_len, suffix_len;
|
|
int idx1, idx2;
|
|
|
|
if (param_no != 1) return 0;
|
|
|
|
param_len = strlen((char*)*param);
|
|
if (strlen(allow_suffix) > strlen(deny_suffix)) {
|
|
suffix_len = strlen(allow_suffix);
|
|
} else {
|
|
suffix_len = strlen(deny_suffix);
|
|
}
|
|
|
|
buffer = pkg_malloc(param_len + suffix_len + 1);
|
|
if (!buffer) {
|
|
LOG(L_ERR, "fixup_files_1(): No memory left\n");
|
|
return -1;
|
|
}
|
|
|
|
strcpy(buffer, (char*)*param);
|
|
strcat(buffer, allow_suffix);
|
|
|
|
/* load allow file */
|
|
idx1 = load_file(buffer, &allow, &allow_rules_num, 0);
|
|
if (idx1 < 0) {
|
|
pkg_free(buffer);
|
|
return -1;
|
|
}
|
|
|
|
strcpy(buffer + param_len, deny_suffix);
|
|
idx2 = load_file(buffer, &deny, &deny_rules_num, 0);
|
|
if (idx2 < 0) {
|
|
pkg_free(buffer);
|
|
return -1;
|
|
}
|
|
|
|
if (idx1 != idx2) {
|
|
LOG(L_ERR, "fixup_files_1(): allow and deny indexes are not equal!\n");
|
|
pkg_free(buffer);
|
|
return -1;
|
|
}
|
|
|
|
pkg_free(*param);
|
|
*param = (void*)(long)idx1;
|
|
pkg_free(buffer);
|
|
return 0;
|
|
}
|
|
|
|
/* connect to the database */
|
|
static int perm_init_db(void)
|
|
{
|
|
db_conn = db_ctx("permissions");
|
|
if (db_conn == NULL) {
|
|
LOG(L_ERR, "perm_init_db(): Unable to create database context\n");
|
|
return -1;
|
|
}
|
|
if (db_add_db(db_conn, db_url) < 0) {
|
|
LOG(L_ERR, "perm_init_db(): cannot add the url to database context\n");
|
|
return -1;
|
|
}
|
|
if (db_connect(db_conn) < 0) {
|
|
LOG(L_ERR, "perm_init_db(): Unable to connect to database\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* destroy the DB connection */
|
|
static void perm_destroy_db(void)
|
|
{
|
|
if (db_conn) {
|
|
db_disconnect(db_conn);
|
|
db_ctx_free(db_conn);
|
|
db_conn = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* module initialization function
|
|
*/
|
|
static int mod_init(void)
|
|
{
|
|
LOG(L_INFO, "permissions - initializing\n");
|
|
|
|
|
|
/* do not load the files if not necessary */
|
|
if (strlen(default_allow_file) || strlen(default_deny_file)) {
|
|
if (load_file(default_allow_file, &allow, &allow_rules_num, 1) != 0) goto error;
|
|
if (load_file(default_deny_file, &deny, &deny_rules_num, 1) != 0) goto error;
|
|
}
|
|
|
|
if (db_url && (db_mode == ENABLE_CACHE)) {
|
|
/* database backend is enabled, and cache is requested -- load the DB */
|
|
if (perm_init_db()) goto error;
|
|
|
|
/* prepare DB commands for trusted table */
|
|
if (init_trusted_db()) {
|
|
LOG(L_ERR, "Error while preparing DB commands for trusted table\n");
|
|
goto error;
|
|
}
|
|
|
|
/* init trusted tables */
|
|
if (init_trusted() != 0) {
|
|
LOG(L_ERR, "Error while initializing allow_trusted function\n");
|
|
goto error;
|
|
}
|
|
|
|
/* prepare DB commands for ipmatch table */
|
|
if (init_im_db()) {
|
|
LOG(L_ERR, "Error while preparing DB commands for ipmatch table\n");
|
|
goto error;
|
|
}
|
|
|
|
/* init ipmatch table */
|
|
if (init_ipmatch() != 0) {
|
|
LOG(L_ERR, "Error while initializing ipmatch table\n");
|
|
goto error;
|
|
}
|
|
|
|
/* Destory DB connection, we do not need it anymore,
|
|
each child process will create its own connection */
|
|
destroy_trusted_db();
|
|
destroy_im_db();
|
|
perm_destroy_db();
|
|
}
|
|
|
|
if (ip_set_list_malloc(ip_set_list_count, ip_set_list_names) < 0) goto error;
|
|
if (ip_set_list_count > 0) {
|
|
ip_set_list_local = pkg_malloc(ip_set_list_count*sizeof(*ip_set_list_local));
|
|
if (!ip_set_list_local) goto error;
|
|
memset(ip_set_list_local, 0, sizeof(*ip_set_list_local)*ip_set_list_count);
|
|
}
|
|
if (ip_set_list_names)
|
|
pkg_free(ip_set_list_names); /* we need not longer names in pkg memory */
|
|
|
|
return 0;
|
|
|
|
error:
|
|
/* free file containers */
|
|
delete_files(&allow, allow_rules_num);
|
|
delete_files(&deny, deny_rules_num);
|
|
|
|
/* destroy DB cmds */
|
|
destroy_trusted_db();
|
|
destroy_im_db();
|
|
|
|
/* destory DB connection */
|
|
perm_destroy_db();
|
|
|
|
/* free the cache */
|
|
clean_trusted();
|
|
clean_ipmatch();
|
|
|
|
ip_set_list_free();
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int child_init(int rank)
|
|
{
|
|
if ((rank <= 0) && (rank != PROC_RPC) && (rank != PROC_UNIXSOCK))
|
|
return 0;
|
|
|
|
if (db_url) {
|
|
/* Connect to the DB regarless of cache or non-cache mode,
|
|
because we either have to query the DB runtime, or reload
|
|
the cache via RPC call */
|
|
if (perm_init_db()) goto error;
|
|
|
|
/* prepare DB commands for trusted tables */
|
|
if (init_trusted_db()) {
|
|
LOG(L_ERR, "Error while preparing DB commands for trusted table\n");
|
|
goto error;
|
|
}
|
|
|
|
/* prepare DB commands for ipmatch tables */
|
|
if (init_im_db()) {
|
|
LOG(L_ERR, "Error while preparing DB commands for ipmatch table\n");
|
|
goto error;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
error:
|
|
/* destroy DB cmds */
|
|
destroy_trusted_db();
|
|
destroy_im_db();
|
|
|
|
/* destroy DB connection */
|
|
perm_destroy_db();
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* destroy function
|
|
*/
|
|
static void mod_exit(void)
|
|
{
|
|
int i;
|
|
/* free file containers */
|
|
delete_files(&allow, allow_rules_num);
|
|
delete_files(&deny, deny_rules_num);
|
|
|
|
clean_trusted();
|
|
clean_ipmatch();
|
|
|
|
if (ip_set_list_local) {
|
|
for (i=0; i<ip_set_list_count; i++) {
|
|
/* we need delete all cloned sets because might not exist in global list after commit, they have refcnt>1 */
|
|
if (ip_set_list_local[i])
|
|
shm_free(ip_set_list_local[i]);
|
|
}
|
|
}
|
|
ip_set_list_free();
|
|
}
|
|
|
|
|
|
/*
|
|
* Uses default rule files from the module parameters
|
|
*/
|
|
int allow_routing_0(struct sip_msg* msg, char* str1, char* str2)
|
|
{
|
|
return check_routing(msg, 0);
|
|
}
|
|
|
|
|
|
int allow_routing_1(struct sip_msg* msg, char* basename, char* s)
|
|
{
|
|
return check_routing(msg, (int)(long)basename);
|
|
}
|
|
|
|
|
|
/*
|
|
* Accepts allow and deny files as parameters
|
|
*/
|
|
int allow_routing_2(struct sip_msg* msg, char* allow_file, char* deny_file)
|
|
{
|
|
/* Index converted by fixup_files_2 */
|
|
return check_routing(msg, (int)(long)allow_file);
|
|
}
|
|
|
|
int allow_register_1(struct sip_msg* msg, char* basename, char* s)
|
|
{
|
|
return check_register(msg, (int)(long)basename);
|
|
}
|
|
|
|
|
|
int allow_register_2(struct sip_msg* msg, char* allow_file, char* deny_file)
|
|
{
|
|
return check_register(msg, (int)(long)allow_file);
|
|
}
|
|
|
|
int allow_refer_to_1(struct sip_msg* msg, char* basename, char* s)
|
|
{
|
|
return check_refer_to(msg, (int)(long)basename);
|
|
}
|
|
|
|
|
|
int allow_refer_to_2(struct sip_msg* msg, char* allow_file, char* deny_file)
|
|
{
|
|
return check_refer_to(msg, (int)(long)allow_file);
|
|
}
|
|
|
|
/* fixup function for w_ipmatch_* */
|
|
static int fixup_w_im(void **param, int param_no)
|
|
{
|
|
int ret;
|
|
str *s;
|
|
|
|
if (param_no == 1) {
|
|
ret = fix_param(FPARAM_AVP, param);
|
|
if (ret <= 0) return ret;
|
|
ret = fix_param(FPARAM_SELECT, param);
|
|
if (ret <= 0) return ret;
|
|
ret = fix_param(FPARAM_STR, param);
|
|
if (ret == 0) {
|
|
s = &((fparam_t *)*param)->v.str;
|
|
if ((s->len == 3) && (memcmp(s->s, "src", 3) == 0)) return 0;
|
|
if ((s->len == 4) && (memcmp(s->s, "via2", 4) == 0)) return 0;
|
|
|
|
LOG(L_ERR, "ERROR: fixup_w_im(): unknown string parameter\n");
|
|
return -1;
|
|
|
|
} else if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
LOG(L_ERR, "ERROR: fixup_w_im(): unknown parameter type\n");
|
|
return -1;
|
|
|
|
} else if (param_no == 2) {
|
|
if (fix_param(FPARAM_AVP, param) != 0) {
|
|
LOG(L_ERR, "ERROR: fixup_w_im(): unknown AVP identifier: %s\n", (char*)*param);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* fixup function for w_ipmatch_onsend */
|
|
static int fixup_w_im_onsend(void **param, int param_no)
|
|
{
|
|
char *ch;
|
|
|
|
if (param_no == 1) {
|
|
ch = (char *)*param;
|
|
if ((ch[0] != 'd') && (ch[0] != 'r')) {
|
|
LOG(L_ERR, "ERROR: fixup_w_im_onsend(): unknown string parameter\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* wrapper function for ipmatch */
|
|
int w_im_2(struct sip_msg *msg, char *str1, char *str2)
|
|
{
|
|
if (db_mode != ENABLE_CACHE) {
|
|
LOG(L_ERR, "ERROR: w_im_2(): ipmatch function supports only cache mode, set db_mode module parameter!\n");
|
|
return -1;
|
|
}
|
|
|
|
return ipmatch_2(msg, str1, str2);
|
|
}
|
|
|
|
/* wrapper function for ipmatch */
|
|
int w_im_1(struct sip_msg *msg, char *str1, char *str2)
|
|
{
|
|
if (db_mode != ENABLE_CACHE) {
|
|
LOG(L_ERR, "ERROR: w_im_1(): ipmatch function supports only cache mode, set db_mode module parameter!\n");
|
|
return -1;
|
|
}
|
|
|
|
return ipmatch_1(msg, str1, str2);
|
|
}
|
|
|
|
/* wrapper function for ipmatch */
|
|
int w_im_onsend(struct sip_msg *msg, char *str1, char *str2)
|
|
{
|
|
if (db_mode != ENABLE_CACHE) {
|
|
LOG(L_ERR, "ERROR: w_im_onsend(): ipmatch function supports only cache mode, set db_mode module parameter!\n");
|
|
return -1;
|
|
}
|
|
|
|
return ipmatch_onsend(msg, str1, str2);
|
|
}
|
|
|
|
/* wrapper function for ipmatch_filter */
|
|
int w_im_filter(struct sip_msg *msg, char *str1, char *str2)
|
|
{
|
|
if (db_mode != ENABLE_CACHE) {
|
|
LOG(L_ERR, "ERROR: w_im_filter(): ipmatch function supports only cache mode, set db_mode module parameter!\n");
|
|
return -1;
|
|
}
|
|
|
|
return ipmatch_filter(msg, str1, str2);
|
|
}
|
|
|
|
struct ip_set_param {
|
|
enum {IP_SET_PARAM_KIND_GLOBAL, IP_SET_PARAM_KIND_LOCAL} kind;
|
|
union {
|
|
struct {
|
|
str s;
|
|
unsigned int sz;
|
|
struct ip_set ip_set;
|
|
fparam_t *fparam;
|
|
} local;
|
|
struct {
|
|
struct ip_set_list_item *ip_set;
|
|
} global;
|
|
}u;
|
|
};
|
|
|
|
#define MODULE_NAME "permissions"
|
|
|
|
static inline int is_ip_set_name(str *s) {
|
|
return (s->len && ((s->s[0] >= 'A' && s->s[0] <= 'Z') || (s->s[0] >= 'a' && s->s[0] <= 'z') || s->s[0] == '_'));
|
|
}
|
|
|
|
|
|
static int fixup_param_declare_ip_set( modparam_t type, void* val) {
|
|
str *p;
|
|
int i;
|
|
str s;
|
|
s.s = val;
|
|
s.len = strlen(s.s);
|
|
for (i=0; i<s.len && s.s[i]!='='; i++);
|
|
s.len = i;
|
|
|
|
for (i=0; i<ip_set_list_count; i++) {
|
|
if (ip_set_list_names[i].len>=s.len && memcmp(val, ip_set_list_names[i].s, s.len) == 0) {
|
|
ERR(MODULE_NAME": declare_ip_set: ip set '%.*s' already exists\n", s.len, s.s);
|
|
return E_CFG;
|
|
}
|
|
}
|
|
if (!is_ip_set_name(&s)) {
|
|
ERR(MODULE_NAME": declare_ip_set: ip set '%.*s' is not correct identifier\n", s.len, s.s);
|
|
return E_CFG;
|
|
}
|
|
s.len = strlen(s.s);
|
|
p = pkg_realloc(ip_set_list_names, sizeof(*p)*(ip_set_list_count+1));
|
|
if (!p) return E_OUT_OF_MEM;
|
|
p[ip_set_list_count] = s;
|
|
ip_set_list_count++;
|
|
ip_set_list_names = p;
|
|
return E_OK;
|
|
};
|
|
|
|
|
|
static int w_ip_is_trusted(struct sip_msg* msg, char* _ip_set, char* _ip) {
|
|
str ip_set_s, ip_s;
|
|
struct ip_addr *ip, ip_buf;
|
|
struct ip_set new_ip_set, *ip_set;
|
|
struct ip_set_list_item *isli = NULL;
|
|
int kind;
|
|
kind = ((struct ip_set_param*)_ip_set)->kind;
|
|
if (kind == IP_SET_PARAM_KIND_LOCAL) {
|
|
if (get_str_fparam(&ip_set_s, msg, ((struct ip_set_param*)_ip_set)->u.local.fparam) < 0) {
|
|
ERR(MODULE_NAME": ip_is_trusted: Error while obtaining ip_set parameter value\n");
|
|
return -1;
|
|
}
|
|
if (is_ip_set_name(&ip_set_s)) {
|
|
isli = ip_set_list_find_by_name(ip_set_s);
|
|
if (!isli) {
|
|
ERR(MODULE_NAME": ip_is_trusted: ip set '%.*s' is not declared\n", ip_set_s.len, ip_set_s.s);
|
|
return -1;
|
|
}
|
|
kind = IP_SET_PARAM_KIND_GLOBAL;
|
|
goto force_global;
|
|
}
|
|
ip_set = &((struct ip_set_param*)_ip_set)->u.local.ip_set;
|
|
}
|
|
else {
|
|
isli = ((struct ip_set_param*)_ip_set)->u.global.ip_set;
|
|
force_global:
|
|
if (!isli->ip_set) return -1; /* empty ip set */
|
|
|
|
if (unlikely(isli->ip_set != ip_set_list_local[isli->idx])) { /* global ip set has changed ? */
|
|
if (ip_set_list_local[isli->idx]) {
|
|
if (atomic_dec_and_test(&ip_set_list_local[isli->idx]->refcnt)) {
|
|
ip_set_destroy(&ip_set_list_local[isli->idx]->ip_set);
|
|
shm_free(ip_set_list_local[isli->idx]);
|
|
ip_set_list_local[isli->idx] = NULL;
|
|
}
|
|
}
|
|
lock_get(&isli->read_lock);
|
|
atomic_inc(&isli->ip_set->refcnt);
|
|
ip_set_list_local[isli->idx] = isli->ip_set;
|
|
lock_release(&isli->read_lock);
|
|
}
|
|
ip_set = &ip_set_list_local[isli->idx]->ip_set;
|
|
}
|
|
|
|
if (get_str_fparam(&ip_s, msg, (fparam_t*)_ip) < 0) {
|
|
ERR(MODULE_NAME": ip_is_trusted: Error while obtaining ip parameter value\n");
|
|
return -1;
|
|
}
|
|
if (!ip_s.len || !ip_set_s.len) return -1;
|
|
switch (ip_s.s[0]) {
|
|
case 's': /* src */
|
|
case 'S':
|
|
ip = &msg->rcv.src_ip;
|
|
break;
|
|
case 'd': /* dst */
|
|
case 'D':
|
|
ip = &msg->rcv.dst_ip;
|
|
break;
|
|
case 'r': /* rcv */
|
|
case 'R':
|
|
ip = &msg->rcv.bind_address->address;
|
|
break;
|
|
default:
|
|
/* string -> ip */
|
|
|
|
if ( ((ip = str2ip(&ip_s))==0)
|
|
#ifdef USE_IPV6
|
|
&& ((ip = str2ip6(&ip_s))==0)
|
|
#endif
|
|
){
|
|
ERR(MODULE_NAME": ip_is_trusted: string to ip conversion error '%.*s'\n", ip_s.len, ip_s.s);
|
|
return -1;
|
|
}
|
|
ip_buf = *ip;
|
|
ip = &ip_buf; /* value has been in static buffer */
|
|
break;
|
|
}
|
|
|
|
/* test if ip_set string has changed since last call */
|
|
if (kind == IP_SET_PARAM_KIND_LOCAL) {
|
|
if (((struct ip_set_param*)_ip_set)->u.local.s.len != ip_set_s.len ||
|
|
memcmp(((struct ip_set_param*)_ip_set)->u.local.s.s, ip_set_s.s, ip_set_s.len) != 0) {
|
|
|
|
ip_set_init(&new_ip_set, 0);
|
|
if (ip_set_add_list(&new_ip_set, ip_set_s) < 0) {
|
|
ip_set_destroy(&new_ip_set);
|
|
return -1;
|
|
};
|
|
if (((struct ip_set_param*)_ip_set)->u.local.sz < ip_set_s.len) {
|
|
void *p;
|
|
p = pkg_realloc(((struct ip_set_param*)_ip_set)->u.local.s.s, ip_set_s.len);
|
|
if (!p) {
|
|
ip_set_destroy(&new_ip_set);
|
|
return E_OUT_OF_MEM;
|
|
}
|
|
((struct ip_set_param*)_ip_set)->u.local.s.s = p;
|
|
((struct ip_set_param*)_ip_set)->u.local.sz = ip_set_s.len;
|
|
}
|
|
memcpy(((struct ip_set_param*)_ip_set)->u.local.s.s, ip_set_s.s, ip_set_s.len);
|
|
((struct ip_set_param*)_ip_set)->u.local.s.len = ip_set_s.len;
|
|
ip_set_destroy(&((struct ip_set_param*)_ip_set)->u.local.ip_set);
|
|
((struct ip_set_param*)_ip_set)->u.local.ip_set = new_ip_set;
|
|
}
|
|
}
|
|
/* ip_set_print(stderr, &ip_set); */
|
|
switch (ip_set_ip_exists(ip_set, ip)) {
|
|
case IP_TREE_FIND_FOUND:
|
|
case IP_TREE_FIND_FOUND_UPPER_SET:
|
|
return 1;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static int fixup_ip_is_trusted(void** param, int param_no) {
|
|
int ret = E_CFG;
|
|
struct ip_set_param *p;
|
|
str s;
|
|
if (param_no == 1) {
|
|
|
|
p = pkg_malloc(sizeof(*p));
|
|
if (!p) return E_OUT_OF_MEM;
|
|
memset(p, 0, sizeof(*p));
|
|
s.s = *param;
|
|
s.len = strlen(s.s);
|
|
|
|
if (is_ip_set_name(&s)) {
|
|
p->u.global.ip_set = ip_set_list_find_by_name(s);
|
|
if (!p->u.global.ip_set) {
|
|
ERR(MODULE_NAME": fixup_ip_is_trusted: ip set '%.*s' is not declared\n", s.len, s.s);
|
|
goto err;
|
|
}
|
|
p->kind = IP_SET_PARAM_KIND_GLOBAL;
|
|
} else {
|
|
ret = fixup_var_str_12(param, param_no);
|
|
if (ret < 0) goto err;
|
|
ip_set_init(&p->u.local.ip_set, 0);
|
|
p->u.local.fparam = *param;
|
|
*param = p;
|
|
p->kind = IP_SET_PARAM_KIND_LOCAL;
|
|
}
|
|
}
|
|
else {
|
|
return fixup_var_str_12(param, param_no);
|
|
|
|
}
|
|
return E_OK;
|
|
err:
|
|
pkg_free(p);
|
|
return ret;
|
|
}
|
|
|
|
|