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.
kamailio/modules_s/permissions/ip_set_rpc.c

290 lines
7.2 KiB

/*
* $Id$
*
* allow_trusted related functions
*
* Copyright (C) 2003 Juha Heinanen
*
* 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:
* --------
* 2008-08-01: released
*/
#include "../../dprint.h"
#include "../../lib/srdb2/db.h"
#include "../../mem/shm_mem.h"
#include "permissions.h"
#include "ip_set.h"
#include "ip_set_rpc.h"
static struct ip_set_list_item *ip_set_list = NULL;
static int ip_set_list_count = 0;
int ip_set_list_malloc(int num, str* names) {
int i, j;
if (num) {
ip_set_list = shm_malloc(num*sizeof(*ip_set_list));
if (!ip_set_list) return -1;
ip_set_list_count = num;
for (i=0; i<ip_set_list_count; i++) {
ip_set_list[i].idx = i;
ip_set_list[i].name = names[i];
lock_init(&ip_set_list[i].read_lock);
lock_init(&ip_set_list[i].write_lock);
ip_set_list[i].ip_set = NULL;
ip_set_init(&ip_set_list[i].ip_set_pending, 1);
for (j=0; j<ip_set_list[i].name.len; j++) {
if (ip_set_list[i].name.s[j]=='=') {
str s;
s.s = ip_set_list[i].name.s + j + 1;
s.len = ip_set_list[i].name.len - j - 1;
ip_set_list[i].name.len = j;
ip_set_list[i].ip_set = shm_malloc(sizeof(*ip_set_list[i].ip_set));
if (!ip_set_list[i].ip_set) return -1;
atomic_set(&ip_set_list[i].ip_set->refcnt, 1);
ip_set_add_list(&ip_set_list[i].ip_set->ip_set, s); /* allow pass even in case of error */
}
}
}
}
return 0;
}
void ip_set_list_free() {
int i;
if (!ip_set_list) return;
for (i=0; i<ip_set_list_count; i++) {
lock_destroy(&ip_set_list[i].read_lock);
lock_destroy(&ip_set_list[i].write_lock);
if (ip_set_list[i].ip_set) {
if (atomic_dec_and_test(&ip_set_list[i].ip_set->refcnt)) { /* do not destroy cloned sets because if they can live only in local copy after commit,
they must be deleted separately in local copy before this procedure is called*/
ip_set_destroy(&ip_set_list[i].ip_set->ip_set);
shm_free(ip_set_list[i].ip_set);
}
}
ip_set_destroy(&ip_set_list[i].ip_set_pending);
}
shm_free(ip_set_list);
ip_set_list = NULL;
}
struct ip_set_list_item* ip_set_list_find_by_name(str name) {
int i;
for (i=0; i<ip_set_list_count; i++) {
if (ip_set_list[i].name.len == name.len && memcmp(ip_set_list[i].name.s, name.s, name.len) == 0)
return &ip_set_list[i];
}
return NULL;
}
const char* rpc_ip_set_clean_doc[] = {
"Clean ip set.",
0
};
void rpc_ip_set_clean(rpc_t* rpc, void* ctx) {
str name;
struct ip_set_list_item *p;
if (rpc->scan(ctx, "S", &name) < 1) {
return;
}
p = ip_set_list_find_by_name(name);
if (!p) {
rpc->fault(ctx, 400, "Ip set not found");
return;
}
lock_get(&p->write_lock);
ip_set_destroy(&p->ip_set_pending);
ip_set_init(&p->ip_set_pending, 1);
lock_release(&p->write_lock);
}
const char* rpc_ip_set_add_doc[] = {
"Add IP/mask in ip set.",
0
};
void rpc_ip_set_add(rpc_t* rpc, void* ctx) {
str name, ip, mask;
struct ip_set_list_item* p;
if (rpc->scan(ctx, "SSS", &name, &ip, &mask) < 1) {
return;
}
while (mask.len && mask.s[0]=='/') { /* rpc cannot read plain number as string, adding '/' helps */
mask.s++;
mask.len--;
}
p = ip_set_list_find_by_name(name);
if (!p) {
rpc->fault(ctx, 400, "Ip set not found");
return;
}
lock_get(&p->write_lock);
if (ip_set_add_ip_s(&p->ip_set_pending, ip, mask) < 0) {
lock_release(&p->write_lock);
rpc->fault(ctx, 400, "Cannot add ip/mask into ip set");
return;
}
lock_release(&p->write_lock);
}
const char* rpc_ip_set_commit_doc[] = {
"Commit changes in ip set.",
0
};
void rpc_ip_set_commit(rpc_t* rpc, void* ctx) {
str name;
struct ip_set_list_item *p;
struct ip_set_ref *new_ip_set;
if (rpc->scan(ctx, "S", &name) < 1) {
return;
}
p = ip_set_list_find_by_name(name);
if (!p) {
rpc->fault(ctx, 400, "Ip set not found");
return;
}
lock_get(&p->write_lock);
lock_get(&p->read_lock);
new_ip_set = shm_malloc(sizeof(*new_ip_set));
if (!new_ip_set) {
rpc->fault(ctx, 500, "Not enough memory");
goto err;
}
if (p->ip_set) {
if (atomic_dec_and_test(&p->ip_set->refcnt)) {
ip_set_destroy(&p->ip_set->ip_set); /* not used in local copy */
shm_free(p->ip_set);
}
}
new_ip_set->ip_set = p->ip_set_pending;
atomic_set(&new_ip_set->refcnt, 1);
p->ip_set = new_ip_set;
ip_set_init(&p->ip_set_pending, 1);
err:
lock_release(&p->read_lock);
lock_release(&p->write_lock);
}
const char* rpc_ip_set_list_doc[] = {
"List ip set names.",
0
};
void rpc_ip_set_list(rpc_t* rpc, void* ctx) {
int i;
void *c;
rpc->add(ctx, "{", &c);
for (i=0; i<ip_set_list_count; i++) {
if (rpc->struct_add(c, "S", "Name", &ip_set_list[i].name) < 0) {
rpc->fault(ctx, 500, "Error when listing ip sets");
}
}
}
const char* rpc_ip_set_print_doc[] = {
"Print ip set.",
0
};
static int rpc_ip_tree_print(rpc_t* rpc, void *ctx, char *prefix, struct ip_tree_leaf *tree, unsigned int indent) {
int j;
if (!tree) {
if (rpc->struct_printf(ctx, "", "%*snil", indent, prefix) < 0) return -1;
}
else {
str s;
s = ip_tree_mask_to_str(tree->prefix_match, tree->prefix_match_len);
if (rpc->struct_printf(ctx, "", "%*smatch %d bits {%.*s}", indent, prefix, tree->prefix_match_len, s.len, s.s) < 0)
return -1;
for (j=0; j<=1; j++) {
if (rpc_ip_tree_print(rpc, ctx, j==0?"0:":"1:", tree->next[j], indent+2) < 0)
return -1;
}
}
return 0;
}
void rpc_ip_set_print(rpc_t* rpc, void* ctx) {
struct ip_set_list_item *p;
struct ip_set *ip_set, ip_set2;
void *c;
str name;
int pending;
if (rpc->scan(ctx, "Sd", &name, &pending) < 1) {
return;
}
p = ip_set_list_find_by_name(name);
if (!p) {
rpc->fault(ctx, 400, "Ip set not found");
return;
}
if (pending) {
lock_get(&p->write_lock);
ip_set = &p->ip_set_pending;
} else {
lock_get(&p->read_lock);
if (!p->ip_set) {
ip_set_init(&ip_set2, 1); /* dummy to return empty ip set */
ip_set = &ip_set2;
}
else
ip_set = &p->ip_set->ip_set;
}
/* nested array/struct not supported */
rpc->add(ctx, "{", &c);
if (rpc->struct_add(c, "s", "IPv", "4") < 0)
goto err;
if (rpc_ip_tree_print(rpc, c, "", ip_set->ipv4_tree, 0) < 0)
goto err;
rpc->add(ctx, "{", &c);
if (rpc->struct_add(c, "s", "IPv", "6") < 0)
goto err;
#ifdef USE_IPV6
if (rpc_ip_tree_print(rpc, c, "", ip_set->ipv6_tree, 0) < 0)
goto err;
#endif
err:
if (pending)
lock_release(&p->write_lock);
else
lock_release(&p->read_lock);
}