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/obsolete/permissions/ip_set.c

192 lines
5.3 KiB

/* $Id$
*
* Copyright (C) 2008 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "ip_set.h"
#include "../../resolve.h"
#include <stdio.h>
#include <string.h>
void ip_set_init(struct ip_set *ip_set, int use_shm) {
memset(ip_set, 0, sizeof(*ip_set));
ip_set->use_shm = use_shm;
ip_tree_init(&ip_set->ipv4_tree);
ip_tree_init(&ip_set->ipv6_tree);
}
void ip_set_destroy(struct ip_set *ip_set) {
ip_tree_destroy(&ip_set->ipv4_tree, 0, ip_set->use_shm);
ip_tree_destroy(&ip_set->ipv6_tree, 0, ip_set->use_shm);
}
int ip_set_add_ip(struct ip_set *ip_set, struct ip_addr *ip, unsigned int network_prefix) {
switch (ip->af) {
case AF_INET:
return ip_tree_add_ip(&ip_set->ipv4_tree, ip->u.addr, (ip->len*8<network_prefix)?ip->len*8:network_prefix, ip_set->use_shm);
case AF_INET6:
return ip_tree_add_ip(&ip_set->ipv6_tree, ip->u.addr, (ip->len*8<network_prefix)?ip->len*8:network_prefix, ip_set->use_shm);
default:
return -1;
}
}
int ip_set_ip_exists(struct ip_set *ip_set, struct ip_addr *ip) {
struct ip_tree_find h;
switch (ip->af) {
case AF_INET:
return ip_tree_find_ip(ip_set->ipv4_tree, ip->u.addr, ip->len*8, &h) > 0;
case AF_INET6:
return ip_tree_find_ip(ip_set->ipv6_tree, ip->u.addr, ip->len*8, &h) > 0;
default:
return -1;
}
}
void ip_set_print(FILE *stream, struct ip_set *ip_set) {
fprintf(stream, "IPv4:\n");
ip_tree_print(stream, ip_set->ipv4_tree, 2);
fprintf(stream, "IPv6:\n");
ip_tree_print(stream, ip_set->ipv6_tree, 2);
}
int ip_set_add_list(struct ip_set *ip_set, str ip_set_s){
str ip_s, mask_s;
/* parse comma delimited string of IPs and masks, e.g. 1.2.3.4,2.3.5.3/24,[abcd:12456:2775:ab::7533],9.8.7.6/255.255.255.0 */
while (ip_set_s.len) {
while (ip_set_s.len && (*ip_set_s.s == ',' || *ip_set_s.s == ';' || *ip_set_s.s == ' ')) {
ip_set_s.s++;
ip_set_s.len--;
}
if (!ip_set_s.len) break;
ip_s.s = ip_set_s.s;
ip_s.len = 0;
while (ip_s.len < ip_set_s.len && (ip_s.s[ip_s.len] != ',' && ip_s.s[ip_s.len] != ';' && ip_s.s[ip_s.len] != ' ' && ip_s.s[ip_s.len] != '/')) {
ip_s.len++;
}
ip_set_s.s += ip_s.len;
ip_set_s.len -= ip_s.len;
mask_s.len = 0;
mask_s.s=0;
if (ip_set_s.len && ip_set_s.s[0] == '/') {
ip_set_s.s++;
ip_set_s.len--;
mask_s.s = ip_set_s.s;
while (mask_s.len < ip_set_s.len && (mask_s.s[mask_s.len] != ',' && mask_s.s[mask_s.len] != ';' && mask_s.s[mask_s.len] != ' ')) {
mask_s.len++;
}
ip_set_s.s += mask_s.len;
ip_set_s.len -= mask_s.len;
}
if (ip_set_add_ip_s(ip_set, ip_s, mask_s) < 0) {
return -1;
}
}
return 0;
}
int ip_set_add_ip_s(struct ip_set *ip_set, str ip_s, str mask_s){
int fl;
struct ip_addr *ip, ip_buff;
unsigned int prefix, i;
if ( ((ip = str2ip(&ip_s))==0)
&& ((ip = str2ip6(&ip_s))==0)
){
ERR("ip_set_add_ip_s: string to ip conversion error '%.*s'\n", ip_s.len, ip_s.s);
return -1;
}
ip_buff = *ip;
if (mask_s.len > 0) {
i = 0;
fl = 0;
while (i < mask_s.len &&
((mask_s.s[i] >= '0' && mask_s.s[i] <= '9') ||
(mask_s.s[i] >= 'a' && mask_s.s[i] <= 'f') ||
(mask_s.s[i] >= 'A' && mask_s.s[i] <= 'F') ||
mask_s.s[i] == '.' ||
mask_s.s[i] == ':' ||
mask_s.s[i] == '[' ||
mask_s.s[i] == ']'
) ) {
fl |= mask_s.s[i] < '0' || mask_s.s[i] > '9';
i++;
}
if (fl) { /* 255.255.255.0 format */
if ( ((ip = str2ip(&mask_s))==0)
&& ((ip = str2ip6(&mask_s))==0)
){
ERR("ip_set_add_ip_s: string to ip mask conversion error '%.*s'\n", mask_s.len, mask_s.s);
return -1;
}
if (ip_buff.af != ip->af) {
ERR("ip_set_add_ip_s: IPv4 vs. IPv6 near '%.*s' vs. '%.*s'\n", ip_s.len, ip_s.s, mask_s.len, mask_s.s);
return -1;
}
fl = 0;
prefix = 0;
for (i=0; i<ip->len; i++) {
unsigned char msk;
msk = 0x80;
while (msk) {
if ((ip->u.addr[i] & msk) != 0) {
if (fl) {
ERR("ip_set_add_ip_s: bad IP mask '%.*s'\n", mask_s.len, mask_s.s);
return -1;
}
prefix++;
}
else {
fl = 1;
}
msk /= 2;
}
}
}
else { /* 24 format */
if (str2int(&mask_s, &prefix) < 0) {
ERR("ip_set_add_ip_s: cannot convert mask '%.*s'\n", mask_s.len, mask_s.s);
return -1;
}
}
}
else {
prefix = ip_buff.len*8;
}
if (ip_set_add_ip(ip_set, &ip_buff, prefix) < 0) {
ERR("ip_set_add_ip_s: cannot add IP into ip set\n");
return -1;
}
return 0;
}