Generalized the IP range and mask parsing code.

This commit is contained in:
Jan Vidar Krey 2009-07-26 03:12:35 +02:00
parent 78bb1d3527
commit 041ce7a1fb
5 changed files with 129 additions and 127 deletions

View File

@ -9,8 +9,8 @@ static struct ip_addr_encap ip6_a;
static struct ip_addr_encap ip6_b; static struct ip_addr_encap ip6_b;
static struct ip_addr_encap ip6_c; static struct ip_addr_encap ip6_c;
static struct ip_addr_encap mask; static struct ip_addr_encap mask;
static struct ip_ban_record ban6; static struct ip_range ban6;
static struct ip_ban_record ban4; static struct ip_range ban4;
EXO_TEST(prepare_network, { EXO_TEST(prepare_network, {
return net_initialize() == 0; return net_initialize() == 0;

View File

@ -115,7 +115,7 @@ static int check_cmd_user(const char* cmd, int status, struct linked_list* list,
} }
static void add_ip_range(struct linked_list* list, struct ip_ban_record* info) static void add_ip_range(struct linked_list* list, struct ip_range* info)
{ {
char buf1[INET6_ADDRSTRLEN+1]; char buf1[INET6_ADDRSTRLEN+1];
char buf2[INET6_ADDRSTRLEN+1]; char buf2[INET6_ADDRSTRLEN+1];
@ -136,119 +136,38 @@ static void add_ip_range(struct linked_list* list, struct ip_ban_record* info)
} }
static int check_ip_range(const char* lo, const char* hi, struct ip_ban_record* info)
{
int ret1, ret2;
if ((ip_is_valid_ipv4(lo) && ip_is_valid_ipv4(hi)) ||
(ip_is_valid_ipv6(lo) && ip_is_valid_ipv6(hi)))
{
ret1 = ip_convert_to_binary(lo, &info->lo);
ret2 = ip_convert_to_binary(hi, &info->hi);
if (ret1 == -1 || ret2 == -1 || ret1 != ret2)
{
return -1;
}
return 0;
}
return -1;
}
static int check_ip_mask(const char* text_addr, int bits, struct ip_ban_record* info)
{
LOG_DEBUG("ACL: Deny access for: %s/%d", text_addr, bits);
if (ip_is_valid_ipv4(text_addr) ||
ip_is_valid_ipv6(text_addr))
{
struct ip_addr_encap addr;
struct ip_addr_encap mask1;
struct ip_addr_encap mask2;
int af = ip_convert_to_binary(text_addr, &addr); /* 192.168.1.2 */
int maxbits = af == AF_INET6 ? 128 : 32;
ip_mask_create_left(af, bits, &mask1); /* 255.255.255.0 */
ip_mask_create_right(af, maxbits - bits, &mask2); /* 0.0.0.255 */
ip_mask_apply_AND(&addr, &mask1, &info->lo); /* 192.168.1.0 */
ip_mask_apply_OR(&info->lo, &mask2, &info->hi); /* 192.168.1.255 */
return 0;
}
return -1;
}
static int check_cmd_addr(const char* cmd, struct linked_list* list, char* line, int line_count) static int check_cmd_addr(const char* cmd, struct linked_list* list, char* line, int line_count)
{ {
char* data1; char* data;
char* data2; struct ip_range* range = 0;
struct ip_ban_record* info = 0;
int cidr_bits = 0;
if (!strncmp(line, cmd, strlen(cmd))) if (!strncmp(line, cmd, strlen(cmd)))
{ {
data1 = &line[strlen(cmd)]; data = &line[strlen(cmd)];
data2 = 0; data[0] = '\0';
data1[0] = '\0'; data++;
data1++;
data1 = strip_white_space(data1); data = strip_white_space(data);
if (!*data1) if (!*data)
{ {
LOG_FATAL("ACL parse error on line %d", line_count); LOG_FATAL("ACL parse error on line %d", line_count);
return -1; return -1;
} }
info = hub_malloc_zero(sizeof(struct ip_ban_record)); range = hub_malloc_zero(sizeof(struct ip_range));
if (!info) if (!range)
{ {
LOG_ERROR("ACL parse error. Out of memory!"); LOG_ERROR("ACL parse error. Out of memory!");
return -1; return -1;
} }
/* Extract IP-range */ if (ip_convert_address_to_range(data, range))
data2 = strrchr(data1, '-');
if (data2)
{ {
cidr_bits = -1; add_ip_range(list, range);
data2[0] = 0;
data2++;
if (check_ip_range(data1, data2, info) == -1)
{
hub_free(info);
return 0;
}
add_ip_range(list, info);
return 1;
}
else
{
/* Extract IP-bitmask */
data2 = strrchr(data1, '/');
if (data2)
{
data2[0] = 0;
data2++;
cidr_bits = uhub_atoi(data2);
}
else
{
cidr_bits = 128;
}
if (check_ip_mask(data1, cidr_bits, info) == -1)
{
hub_free(info);
return 0;
}
add_ip_range(list, info);
return 1; return 1;
} }
hub_free(range);
} }
return 0; return 0;
} }
@ -480,16 +399,16 @@ int acl_user_unban_cid(struct acl_handle* handle, const char* cid)
int acl_is_ip_banned(struct acl_handle* handle, const char* ip_address) int acl_is_ip_banned(struct acl_handle* handle, const char* ip_address)
{ {
struct ip_addr_encap raw; struct ip_addr_encap raw;
struct ip_ban_record* info = (struct ip_ban_record*) list_get_first(handle->networks); struct ip_range* info = (struct ip_range*) list_get_first(handle->networks);
ip_convert_to_binary(ip_address, &raw); ip_convert_to_binary(ip_address, &raw);
while (info) while (info)
{ {
if (acl_check_ip_range(&raw, info)) if (ip_in_range(&raw, info))
{ {
return 1; return 1;
} }
info = (struct ip_ban_record*) list_get_next(handle->networks); info = (struct ip_range*) list_get_next(handle->networks);
} }
return 0; return 0;
} }
@ -497,26 +416,21 @@ int acl_is_ip_banned(struct acl_handle* handle, const char* ip_address)
int acl_is_ip_nat_override(struct acl_handle* handle, const char* ip_address) int acl_is_ip_nat_override(struct acl_handle* handle, const char* ip_address)
{ {
struct ip_addr_encap raw; struct ip_addr_encap raw;
struct ip_ban_record* info = (struct ip_ban_record*) list_get_first(handle->nat_override); struct ip_range* info = (struct ip_range*) list_get_first(handle->nat_override);
ip_convert_to_binary(ip_address, &raw); ip_convert_to_binary(ip_address, &raw);
while (info) while (info)
{ {
if (acl_check_ip_range(&raw, info)) if (ip_in_range(&raw, info))
{ {
return 1; return 1;
} }
info = (struct ip_ban_record*) list_get_next(handle->nat_override); info = (struct ip_range*) list_get_next(handle->nat_override);
} }
return 0; return 0;
} }
int acl_check_ip_range(struct ip_addr_encap* addr, struct ip_ban_record* info)
{
return (addr->af == info->lo.af && ip_compare(&info->lo, addr) <= 0 && ip_compare(addr, &info->hi) <= 0);
}
/* /*
* This will generate the same challenge to the same user, always. * This will generate the same challenge to the same user, always.
* The challenge is made up of the time of the user connected * The challenge is made up of the time of the user connected

View File

@ -45,12 +45,6 @@ struct hub_user_access_info
enum user_credentials status; enum user_credentials status;
}; };
struct ip_ban_record
{
struct ip_addr_encap lo;
struct ip_addr_encap hi;
};
struct acl_handle struct acl_handle
{ {
struct linked_list* users; /* Known users. See enum user_status */ struct linked_list* users; /* Known users. See enum user_status */
@ -78,8 +72,6 @@ extern int acl_user_ban_cid(struct acl_handle* handle, const char* cid);
extern int acl_user_unban_nick(struct acl_handle* handle, const char* nick); extern int acl_user_unban_nick(struct acl_handle* handle, const char* nick);
extern int acl_user_unban_cid(struct acl_handle* handle, const char* cid); extern int acl_user_unban_cid(struct acl_handle* handle, const char* cid);
extern int acl_check_ip_range(struct ip_addr_encap* addr, struct ip_ban_record* info);
extern const char* acl_password_generate_challenge(struct acl_handle* acl, struct hub_user* user); extern const char* acl_password_generate_challenge(struct acl_handle* acl, struct hub_user* user);
/** /**

View File

@ -19,7 +19,6 @@
#include "uhub.h" #include "uhub.h"
int ip_is_valid_ipv4(const char* address) int ip_is_valid_ipv4(const char* address)
{ {
int i = 0; /* address index */ int i = 0; /* address index */
@ -413,13 +412,80 @@ int ip_compare(struct ip_addr_encap* a, struct ip_addr_encap* b)
return ret; return ret;
} }
static int check_ip_mask(const char* text_addr, int bits, struct ip_range* range)
{
if (ip_is_valid_ipv4(text_addr) || ip_is_valid_ipv6(text_addr))
{
struct ip_addr_encap addr;
struct ip_addr_encap mask1;
struct ip_addr_encap mask2;
int af = ip_convert_to_binary(text_addr, &addr); /* 192.168.1.2 */
int maxbits = (af == AF_INET6 ? 128 : 32);
bits = MIN(MAX(bits, 0), maxbits);
ip_mask_create_left(af, bits, &mask1); /* 255.255.255.0 */
ip_mask_create_right(af, maxbits - bits, &mask2); /* 0.0.0.255 */
ip_mask_apply_AND(&addr, &mask1, &range->lo); /* 192.168.1.0 */
ip_mask_apply_OR(&range->lo, &mask2, &range->hi); /* 192.168.1.255 */
return 1;
}
return 0;
}
static int check_ip_range(const char* lo, const char* hi, struct ip_range* range)
{
int ret1, ret2;
if ((ip_is_valid_ipv4(lo) && ip_is_valid_ipv4(hi)) || (ip_is_valid_ipv6(lo) && ip_is_valid_ipv6(hi)))
{
ret1 = ip_convert_to_binary(lo, &range->lo);
ret2 = ip_convert_to_binary(hi, &range->hi);
if (ret1 == -1 || ret2 == -1 || ret1 != ret2)
{
return 0;
}
return 1;
}
return 0;
}
int ip_convert_address_to_range(const char* address, struct ip_range* range)
{
int ret = 0;
char* addr = 0;
if (!address || !range)
return 0;
const char* split = strrchr(address, '/');
if (split)
{
int mask = uhub_atoi(split+1);
if (mask == 0 && split[1] != '0') return 0;
addr = hub_strndup(address, split - address);
ret = check_ip_mask(addr, mask, range);
hub_free(addr);
return ret;
}
split = strrchr(address, '-');
if (split)
{
addr = hub_strndup(address, split - address);
ret = check_ip_range(addr, split+1, range);
hub_free(addr);
return ret;
}
if (ip_is_valid_ipv4(address) || ip_is_valid_ipv6(address))
{
if (ip_convert_to_binary(address, &range->lo) == -1)
return 0;
memcpy(&range->hi, &range->lo, sizeof(struct ip_addr_encap));
return 1;
}
return 0;
}
int ip_in_range(struct ip_addr_encap* addr, struct ip_range* range)
{
return (addr->af == range->lo.af && ip_compare(&range->lo, addr) <= 0 && ip_compare(addr, &range->hi) <= 0);
}

View File

@ -33,26 +33,57 @@ struct ip_addr_encap {
} internal_ip_data; } internal_ip_data;
}; };
struct ip_range
{
struct ip_addr_encap lo;
struct ip_addr_encap hi;
};
extern int ip_convert_to_binary(const char* text_addr, struct ip_addr_encap* raw); extern int ip_convert_to_binary(const char* text_addr, struct ip_addr_encap* raw);
extern const char* ip_convert_to_string(struct ip_addr_encap* raw); extern const char* ip_convert_to_string(struct ip_addr_encap* raw);
/**
* Convert a string on the form:
* ip-ip or ip/mask to an iprange.
*
* Note: both IPv4 and IPv6 addresses are valid, but if a range is given
* both addresses must be of the same address family.
*
* Valid examples of address
* IPv4:
* 192.168.2.1
* 192.168.0.0/16
* 192.168.0.0-192.168.255.255
*
* IPv6:
* 2001:4860:A005::68
* 2001:4860:A005::0/80
* 2001:4860:A005::0-2001:4860:A005:ffff:ffff:ffff:ffff:ffff
*
* @return 0 if invalid, 1 if OK
*/
extern int ip_convert_address_to_range(const char* address, struct ip_range* range);
/* /**
* @return 1 if addr is inside range, 0 otherwise
*/
extern int ip_in_range(struct ip_addr_encap* addr, struct ip_range* range);
/**
* @return 1 if address is a valid IPv4 address in text notation * @return 1 if address is a valid IPv4 address in text notation
* 0 if invalid * 0 if invalid
*/ */
extern int ip_is_valid_ipv4(const char* address); extern int ip_is_valid_ipv4(const char* address);
/* /**
* @return 1 if address is a valid IPv6 address in text notation * @return 1 if address is a valid IPv6 address in text notation
* 0 if invalid * 0 if invalid
*/ */
extern int ip_is_valid_ipv6(const char* address); extern int ip_is_valid_ipv6(const char* address);
/* /**
* This function converts an IP address in text_address to a binary * This function converts an IP address in text_address to a binary
* struct sockaddr. * struct sockaddr.
* This will auto-detect if the IP-address is IPv6 (and that is supported), * This will auto-detect if the IP-address is IPv6 (and that is supported),
@ -66,7 +97,6 @@ extern int ip_is_valid_ipv6(const char* address);
*/ */
extern int ip_convert_address(const char* text_address, int port, struct sockaddr* addr, socklen_t* addr_len); extern int ip_convert_address(const char* text_address, int port, struct sockaddr* addr, socklen_t* addr_len);
extern int ip_mask_create_left(int af, int bits, struct ip_addr_encap* result); extern int ip_mask_create_left(int af, int bits, struct ip_addr_encap* result);
extern int ip_mask_create_right(int af, int bits, struct ip_addr_encap* result); extern int ip_mask_create_right(int af, int bits, struct ip_addr_encap* result);