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.
486 lines
12 KiB
486 lines
12 KiB
/*
|
|
* Domain table related functions
|
|
*
|
|
* Copyright (C) 2002-2012 Juha Heinanen
|
|
*
|
|
* This file is part of Kamailio, a free SIP server.
|
|
*
|
|
* Kamailio 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
|
|
*
|
|
* Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#include "domain_mod.h"
|
|
#include "hash.h"
|
|
#include "../../lib/srdb1/db.h"
|
|
#include "../../parser/parse_uri.h"
|
|
#include "../../parser/parse_from.h"
|
|
#include "../../ut.h"
|
|
#include "../../dset.h"
|
|
#include "../../route.h"
|
|
#include "../../pvar.h"
|
|
#include "../../str.h"
|
|
|
|
static db1_con_t* db_handle=0;
|
|
static db_func_t domain_dbf;
|
|
|
|
/* helper db functions*/
|
|
|
|
int domain_db_bind(const str* db_url)
|
|
{
|
|
if (db_bind_mod(db_url, &domain_dbf )) {
|
|
LM_ERR("Cannot bind to database module!\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int domain_db_init(const str* db_url)
|
|
{
|
|
if (domain_dbf.init==0){
|
|
LM_ERR("Unbound database module\n");
|
|
goto error;
|
|
}
|
|
if (db_handle!=0)
|
|
return 0;
|
|
|
|
db_handle=domain_dbf.init(db_url);
|
|
if (db_handle==0){
|
|
LM_ERR("Cannot initialize database connection\n");
|
|
goto error;
|
|
}
|
|
return 0;
|
|
error:
|
|
return -1;
|
|
}
|
|
|
|
|
|
void domain_db_close(void)
|
|
{
|
|
if (db_handle && domain_dbf.close){
|
|
domain_dbf.close(db_handle);
|
|
db_handle=0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int domain_db_ver(str* name, int version)
|
|
{
|
|
if (db_handle==0){
|
|
LM_ERR("null database handler\n");
|
|
return -1;
|
|
}
|
|
return db_check_table_version(&domain_dbf, db_handle, name, version);
|
|
}
|
|
|
|
|
|
/*
|
|
* Check if domain is local
|
|
*/
|
|
int is_domain_local(str* _host)
|
|
{
|
|
str did;
|
|
struct attr_list *attrs;
|
|
|
|
return hash_table_lookup(_host, &did, &attrs);
|
|
}
|
|
|
|
/*
|
|
* Check if host in From uri is local
|
|
*/
|
|
int is_from_local(struct sip_msg* _msg, char* _s1, char* _s2)
|
|
{
|
|
struct sip_uri *puri;
|
|
str did;
|
|
struct attr_list *attrs;
|
|
|
|
if ((puri=parse_from_uri(_msg))==NULL) {
|
|
LM_ERR("Error while parsing From header\n");
|
|
return -2;
|
|
}
|
|
|
|
return hash_table_lookup(&(puri->host), &did, &attrs);
|
|
}
|
|
|
|
/*
|
|
* Check if host in Request URI is local
|
|
*/
|
|
int is_uri_host_local(struct sip_msg* _msg, char* _s1, char* _s2)
|
|
{
|
|
str branch;
|
|
qvalue_t q;
|
|
struct sip_uri puri;
|
|
struct attr_list *attrs;
|
|
str did;
|
|
|
|
if ( is_route_type(REQUEST_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE) ) {
|
|
if (parse_sip_msg_uri(_msg) < 0) {
|
|
LM_ERR("error while parsing R-URI\n");
|
|
return -1;
|
|
}
|
|
return hash_table_lookup(&(_msg->parsed_uri.host), &did, &attrs);
|
|
} else if (is_route_type(FAILURE_ROUTE)) {
|
|
branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0, 0, 0, 0);
|
|
if (branch.s) {
|
|
if (parse_uri(branch.s, branch.len, &puri) < 0) {
|
|
LM_ERR("error while parsing branch URI\n");
|
|
return -1;
|
|
}
|
|
return hash_table_lookup(&(puri.host), &did, &attrs);
|
|
} else {
|
|
LM_ERR("branch is missing, error in script\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
LM_ERR("unsupported route type\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Check if domain given as value of pseudo variable parameter is local.
|
|
*/
|
|
int w_is_domain_local(struct sip_msg* _msg, char* _sp, char* _s2)
|
|
{
|
|
pv_spec_t *sp;
|
|
pv_value_t pv_val;
|
|
struct attr_list *attrs;
|
|
str did;
|
|
|
|
sp = (pv_spec_t *)_sp;
|
|
|
|
if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
|
|
if (pv_val.flags & PV_VAL_STR) {
|
|
if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
|
|
LM_DBG("missing domain name\n");
|
|
return -1;
|
|
}
|
|
return hash_table_lookup(&(pv_val.rs), &did, &attrs);
|
|
} else {
|
|
LM_DBG("domain pseudo variable value is not string\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
LM_DBG("cannot get domain pseudo variable value\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check if domain is local and, if it is, add attributes as AVPs
|
|
*/
|
|
int w_lookup_domain(struct sip_msg* _msg, char* _sp, char* _prefix)
|
|
{
|
|
pv_spec_t *sp;
|
|
pv_value_t pv_val;
|
|
int_str name, val;
|
|
struct attr_list *attrs;
|
|
str *prefix, did;
|
|
unsigned short flags;
|
|
|
|
sp = (pv_spec_t *)_sp;
|
|
prefix = (str *)_prefix;
|
|
|
|
if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
|
|
if (pv_val.flags & PV_VAL_STR) {
|
|
if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
|
|
LM_DBG("domain name pseudo variable is missing\n");
|
|
return -1;
|
|
}
|
|
if (hash_table_lookup(&(pv_val.rs), &did, &attrs) == 1) {
|
|
while (attrs) {
|
|
if (attrs->type == 2)
|
|
flags = AVP_NAME_STR | AVP_VAL_STR;
|
|
else
|
|
flags = AVP_NAME_STR;
|
|
if (_prefix) {
|
|
name.s.len = prefix->len + attrs->name.len;
|
|
name.s.s = pkg_malloc(name.s.len);
|
|
if (name.s.s == NULL) {
|
|
ERR("no pkg memory for avp name\n");
|
|
return -1;
|
|
}
|
|
memcpy(name.s.s, prefix->s, prefix->len);
|
|
memcpy(name.s.s + prefix->len, attrs->name.s,
|
|
attrs->name.len);
|
|
} else {
|
|
name.s = attrs->name;
|
|
}
|
|
if (add_avp(flags, name, attrs->val) < 0) {
|
|
LM_ERR("unable to add a new AVP '%.*s'\n",
|
|
name.s.len, name.s.s);
|
|
if (_prefix) pkg_free(name.s.s);
|
|
return -1;
|
|
}
|
|
LM_DBG("added AVP '%.*s'\n", name.s.len, name.s.s);
|
|
if (prefix) pkg_free(name.s.s);
|
|
attrs = attrs->next;
|
|
}
|
|
flags = AVP_NAME_STR | AVP_VAL_STR;
|
|
if (_prefix) {
|
|
name.s.len = prefix->len + 3;
|
|
name.s.s = pkg_malloc(name.s.len);
|
|
if (name.s.s == NULL) {
|
|
ERR("no pkg memory for avp name\n");
|
|
return -1;
|
|
}
|
|
memcpy(name.s.s, prefix->s, prefix->len);
|
|
memcpy(name.s.s + prefix->len, "did", 3);
|
|
} else {
|
|
name.s.s = "did";
|
|
name.s.len = 3;
|
|
}
|
|
val.s = did;
|
|
if (add_avp(flags, name, val) < 0) {
|
|
LM_ERR("unable to add a new AVP '%.*s'\n",
|
|
name.s.len, name.s.s);
|
|
if (_prefix) pkg_free(name.s.s);
|
|
return -1;
|
|
}
|
|
LM_DBG("added AVP '%.*s'\n", name.s.len, name.s.s);
|
|
if (_prefix) pkg_free(name.s.s);
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
} else {
|
|
LM_DBG("domain name pseudo variable value is not string\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
LM_DBG("cannot get domain name pseudo variable value\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check if domain is local and, if it is, add attributes as AVPs
|
|
*/
|
|
int w_lookup_domain_no_prefix(struct sip_msg* _msg, char* _domain, char* _str)
|
|
{
|
|
return w_lookup_domain(_msg, _domain, NULL);
|
|
}
|
|
|
|
int domain_check_self(str* host, unsigned short port, unsigned short proto)
|
|
{
|
|
struct attr_list *attrs;
|
|
str did;
|
|
if (hash_table_lookup(host, &did, &attrs) > 0)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Reload domain table to new hash table and when done, make new hash table
|
|
* current one.
|
|
*/
|
|
int reload_tables ( void )
|
|
{
|
|
db_key_t cols[4];
|
|
db1_res_t* res = NULL;
|
|
db_row_t* row;
|
|
struct domain_list **new_hash_table;
|
|
int i;
|
|
short type;
|
|
str did, domain, name, value;
|
|
int_str val;
|
|
|
|
/* Choose new hash table and free its old contents */
|
|
if (*hash_table == hash_table_1) {
|
|
hash_table_free(hash_table_2);
|
|
new_hash_table = hash_table_2;
|
|
} else {
|
|
hash_table_free(hash_table_1);
|
|
new_hash_table = hash_table_1;
|
|
}
|
|
|
|
cols[0] = &did_col;
|
|
cols[1] = &name_col;
|
|
cols[2] = &type_col;
|
|
cols[3] = &value_col;
|
|
|
|
if (domain_db_init(&db_url) < 0) {
|
|
LM_ERR("unable to open database connection\n");
|
|
return -1;
|
|
}
|
|
|
|
if (domain_dbf.use_table(db_handle, &domain_attrs_table) < 0) {
|
|
LM_ERR("error while trying to use domain_attrs table\n");
|
|
goto err;
|
|
}
|
|
|
|
if (domain_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 4, 0, &res) < 0) {
|
|
LM_ERR("error while querying database\n");
|
|
goto err;
|
|
}
|
|
|
|
row = RES_ROWS(res);
|
|
|
|
LM_DBG("number of rows in domain_attrs table: %d\n", RES_ROW_N(res));
|
|
|
|
for (i = 0; i < RES_ROW_N(res); i++) {
|
|
|
|
row = RES_ROWS(res) + i;
|
|
|
|
if ((VAL_NULL(ROW_VALUES(row)) == 1) ||
|
|
(VAL_TYPE(ROW_VALUES(row)) != DB1_STRING)) {
|
|
LM_ERR("did at row <%u> is null or not string\n", i);
|
|
goto err;
|
|
}
|
|
did.s = (char *)VAL_STRING(ROW_VALUES(row));
|
|
did.len = strlen(did.s);
|
|
if (did.len == 0) {
|
|
LM_ERR("did at row <%u> is empty string\n", i);
|
|
goto err;
|
|
}
|
|
|
|
if ((VAL_NULL(ROW_VALUES(row) + 1) == 1) ||
|
|
(VAL_TYPE(ROW_VALUES(row) + 1) != DB1_STRING)) {
|
|
LM_ERR("name at row <%u> is null or not string\n", i);
|
|
goto err;
|
|
}
|
|
name.s = (char *)VAL_STRING(ROW_VALUES(row) + 1);
|
|
name.len = strlen(name.s);
|
|
if (name.len == 0) {
|
|
LM_ERR("name at row <%u> is empty string\n", i);
|
|
goto err;
|
|
}
|
|
|
|
if ((VAL_NULL(ROW_VALUES(row) + 2) == 1) ||
|
|
((VAL_TYPE(ROW_VALUES(row) + 2) != DB1_INT) &&
|
|
(VAL_TYPE(ROW_VALUES(row) + 2) != DB1_BIGINT))) {
|
|
LM_ERR("type at row <%u> is null or not int\n", i);
|
|
goto err;
|
|
}
|
|
if(VAL_TYPE(ROW_VALUES(row) + 2) == DB1_BIGINT) {
|
|
type = (int)VAL_BIGINT(ROW_VALUES(row) + 2);
|
|
} else {
|
|
type = (int)VAL_INT(ROW_VALUES(row) + 2);
|
|
}
|
|
if ((type != 0) && (type != 2)) {
|
|
LM_ERR("unknown type <%d> at row <%u>\n", type, i);
|
|
goto err;
|
|
}
|
|
|
|
if ((VAL_NULL(ROW_VALUES(row) + 3) == 1) ||
|
|
(VAL_TYPE(ROW_VALUES(row) + 3) != DB1_STRING)) {
|
|
LM_ERR("value at row <%u> is null or not string\n", i);
|
|
goto err;
|
|
}
|
|
value.s = (char *)VAL_STRING(ROW_VALUES(row) + 3);
|
|
value.len = strlen(value.s);
|
|
|
|
if (type == 0) {
|
|
if (str2sint(&value, &(val.n)) == -1) {
|
|
LM_ERR("value at row <%u> is invalid int\n", i);
|
|
goto err;
|
|
}
|
|
} else {
|
|
val.s = value;
|
|
}
|
|
|
|
if (type == 0)
|
|
LM_DBG("inserting <did/name/type/value> = <%s/%s/%d/%d> into attribute list\n", did.s, name.s, type, val.n);
|
|
else
|
|
LM_DBG("inserting <did/name/type/value> = <%s/%s/%d/%s> into attribute list\n", did.s, name.s, type, val.s.s);
|
|
|
|
if (hash_table_attr_install(new_hash_table, &did, &name, type,
|
|
&val) == -1) {
|
|
LM_ERR("could not install attribute into hash table\n");
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
domain_dbf.free_result(db_handle, res);
|
|
res = NULL;
|
|
|
|
cols[0] = &domain_col;
|
|
cols[1] = &did_col;
|
|
|
|
if (domain_dbf.use_table(db_handle, &domain_table) < 0) {
|
|
LM_ERR("error while trying to use domain table\n");
|
|
goto err;
|
|
}
|
|
|
|
if (domain_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 2, 0, &res) < 0) {
|
|
LM_ERR("error while querying database\n");
|
|
goto err;
|
|
}
|
|
|
|
row = RES_ROWS(res);
|
|
|
|
LM_DBG("number of rows in domain table: %d\n", RES_ROW_N(res));
|
|
|
|
for (i = 0; i < RES_ROW_N(res); i++) {
|
|
|
|
row = RES_ROWS(res) + i;
|
|
|
|
if ((VAL_NULL(ROW_VALUES(row)) == 1) ||
|
|
(VAL_TYPE(ROW_VALUES(row)) != DB1_STRING)) {
|
|
LM_ERR("domain at row <%u> is null or not string\n", i);
|
|
goto err;
|
|
}
|
|
domain.s = (char *)VAL_STRING(ROW_VALUES(row));
|
|
domain.len = strlen(domain.s);
|
|
if (domain.len == 0) {
|
|
LM_ERR("domain at row <%u> is empty string\n", i);
|
|
goto err;
|
|
}
|
|
|
|
if ((VAL_NULL(ROW_VALUES(row) + 1) != 1) &&
|
|
(VAL_TYPE(ROW_VALUES(row) + 1) != DB1_STRING)) {
|
|
LM_ERR("did at row <%u> is not null or string\n", i);
|
|
goto err;
|
|
}
|
|
if (VAL_NULL(ROW_VALUES(row) + 1) == 1) {
|
|
did.s = domain.s;
|
|
did.len = domain.len;
|
|
} else {
|
|
did.s = (char *)VAL_STRING(ROW_VALUES(row) + 1);
|
|
did.len = strlen(did.s);
|
|
if (did.len == 0) {
|
|
LM_ERR("did at row <%u> is empty string\n", i);
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
LM_DBG("inserting <did/domain> = <%s/%s> into hash table\n",
|
|
did.s, domain.s);
|
|
|
|
if (hash_table_install(new_hash_table, &did, &domain) == -1) {
|
|
LM_ERR("could not install domain into hash table\n");
|
|
domain_dbf.free_result(db_handle, res);
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
domain_dbf.free_result(db_handle, res);
|
|
res = NULL;
|
|
|
|
*hash_table = new_hash_table;
|
|
|
|
domain_db_close();
|
|
return 1;
|
|
|
|
err:
|
|
domain_dbf.free_result(db_handle, res);
|
|
res = NULL;
|
|
domain_db_close();
|
|
return -1;
|
|
}
|