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_c; | ||||
| static struct ip_addr_encap mask; | ||||
| static struct ip_ban_record ban6; | ||||
| static struct ip_ban_record ban4; | ||||
| static struct ip_range ban6; | ||||
| static struct ip_range ban4; | ||||
| 
 | ||||
| EXO_TEST(prepare_network, { | ||||
|     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 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) | ||||
| { | ||||
| 	char* data1; | ||||
| 	char* data2; | ||||
| 	struct ip_ban_record* info = 0; | ||||
| 	int cidr_bits = 0; | ||||
| 		 | ||||
| 	char* data; | ||||
| 	struct ip_range* range = 0; | ||||
| 
 | ||||
| 	if (!strncmp(line, cmd, strlen(cmd))) | ||||
| 	{ | ||||
| 		data1 = &line[strlen(cmd)]; | ||||
| 		data2 = 0; | ||||
| 		data1[0] = '\0'; | ||||
| 		data1++; | ||||
| 		 | ||||
| 		data1 = strip_white_space(data1); | ||||
| 		if (!*data1) | ||||
| 		data = &line[strlen(cmd)]; | ||||
| 		data[0] = '\0'; | ||||
| 		data++; | ||||
| 
 | ||||
| 		data = strip_white_space(data); | ||||
| 		if (!*data) | ||||
| 		{ | ||||
| 			LOG_FATAL("ACL parse error on line %d", line_count); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		 | ||||
| 		info = hub_malloc_zero(sizeof(struct ip_ban_record)); | ||||
| 		 | ||||
| 		if (!info) | ||||
| 
 | ||||
| 		range = hub_malloc_zero(sizeof(struct ip_range)); | ||||
| 
 | ||||
| 		if (!range) | ||||
| 		{ | ||||
| 			LOG_ERROR("ACL parse error. Out of memory!"); | ||||
| 			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; | ||||
| 		} | ||||
| 		else | ||||
| 		if (ip_convert_address_to_range(data, range)) | ||||
| 		{ | ||||
| 			/* 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); | ||||
| 			 | ||||
| 			add_ip_range(list, range); | ||||
| 			return 1; | ||||
| 		} | ||||
| 		hub_free(range); | ||||
| 	} | ||||
| 	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) | ||||
| { | ||||
| 	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); | ||||
| 	 | ||||
| 	while (info) | ||||
| 	{ | ||||
| 		if (acl_check_ip_range(&raw, info)) | ||||
| 		if (ip_in_range(&raw, info)) | ||||
| 		{ | ||||
| 			return 1; | ||||
| 		} | ||||
| 		info = (struct ip_ban_record*) list_get_next(handle->networks); | ||||
| 		info = (struct ip_range*) list_get_next(handle->networks); | ||||
| 	} | ||||
| 	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) | ||||
| { | ||||
| 	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); | ||||
| 	 | ||||
| 	while (info) | ||||
| 	{ | ||||
| 		if (acl_check_ip_range(&raw, info)) | ||||
| 		if (ip_in_range(&raw, info)) | ||||
| 		{ | ||||
| 			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; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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. | ||||
|  * 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; | ||||
| }; | ||||
| 
 | ||||
| struct ip_ban_record | ||||
| { | ||||
| 	struct ip_addr_encap lo; | ||||
| 	struct ip_addr_encap hi; | ||||
| }; | ||||
| 
 | ||||
| struct acl_handle | ||||
| { | ||||
| 	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_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); | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
| @ -19,7 +19,6 @@ | ||||
| 
 | ||||
| #include "uhub.h" | ||||
| 
 | ||||
| 
 | ||||
| int ip_is_valid_ipv4(const char* address) | ||||
| { | ||||
| 	int i = 0; /* address index */ | ||||
| @ -413,13 +412,80 @@ int ip_compare(struct ip_addr_encap* a, struct ip_addr_encap* b) | ||||
| 	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; | ||||
| }; | ||||
| 
 | ||||
| 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 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 | ||||
|  *         0 if invalid | ||||
|  */ | ||||
| extern int ip_is_valid_ipv4(const char* address); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * @return 1 if address is a valid IPv6 address in text notation | ||||
|  *         0 if invalid | ||||
|  */ | ||||
| extern int ip_is_valid_ipv6(const char* address); | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * This function converts an IP address in text_address to a binary | ||||
|  * struct sockaddr. | ||||
|  * 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_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); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user