Generalized the IP range and mask parsing code.
This commit is contained in:
parent
78bb1d3527
commit
041ce7a1fb
|
@ -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;
|
||||||
|
|
132
src/core/auth.c
132
src/core/auth.c
|
@ -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++;
|
|
||||||
|
data = strip_white_space(data);
|
||||||
data1 = strip_white_space(data1);
|
if (!*data)
|
||||||
if (!*data1)
|
|
||||||
{
|
{
|
||||||
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 */
|
|
||||||
data2 = strrchr(data1, '-');
|
|
||||||
if (data2)
|
|
||||||
{
|
|
||||||
cidr_bits = -1;
|
|
||||||
data2[0] = 0;
|
|
||||||
data2++;
|
|
||||||
|
|
||||||
if (check_ip_range(data1, data2, info) == -1)
|
|
||||||
{
|
|
||||||
hub_free(info);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_ip_range(list, info);
|
|
||||||
|
|
||||||
return 1;
|
if (ip_convert_address_to_range(data, range))
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
/* Extract IP-bitmask */
|
add_ip_range(list, range);
|
||||||
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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue