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.
192 lines
5.3 KiB
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;
|
|
}
|
|
|
|
|
|
|