diff options
Diffstat (limited to 'src/ipaddrcheck_functions.c')
-rw-r--r-- | src/ipaddrcheck_functions.c | 141 |
1 files changed, 119 insertions, 22 deletions
diff --git a/src/ipaddrcheck_functions.c b/src/ipaddrcheck_functions.c index fdbca77..e3e2c86 100644 --- a/src/ipaddrcheck_functions.c +++ b/src/ipaddrcheck_functions.c @@ -2,7 +2,7 @@ * ipaddrcheck_functions.c: IPv4/IPv6 validation functions for ipaddrcheck * * Copyright (C) 2013 Daniil Baturin - * Copyright (C) 2018 VyOS maintainers and contributors + * Copyright (C) 2018-2024 VyOS maintainers and contributors * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -456,6 +456,50 @@ int is_any_net(CIDR *address) return(result); } +/* Split a hyphen-separated range into its left and right components. + * This function is patently unsafe, + * whether it's safe to do what it does should be determined by its callers. + */ +void split_range(char* range_str, char* left, char*right) +{ + char* ptr = left; + int length = strlen(range_str); + int pos = 0; + int index = 0; + while(pos < length) + { + if( range_str[pos] == '-' ) + { + ptr[index] = '\0'; + ptr = right; + index = 0; + } + else + { + ptr[index] = range_str[pos]; + index++; + } + + pos++; + } + ptr[index] = '\0'; + + return; +} + +int compare_ipv6(struct in6_addr *left, struct in6_addr *right) +{ + int i = 0; + for( i = 0; i < 16; i++ ) + { + if (left->s6_addr[i] < right->s6_addr[i]) + return -1; + else if (left->s6_addr[i] > right->s6_addr[i]) + return 1; + } + return 0; +} + /* Is it a valid IPv4 address range? */ int is_ipv4_range(char* range_str, int verbose) { @@ -482,41 +526,93 @@ int is_ipv4_range(char* range_str, int verbose) /* Split the string at the hyphen. If the regex check succeeded, we know the hyphen is there. */ - char* ptr = left; - int length = strlen(range_str); - int pos = 0; - int index = 0; - while(pos < length) + split_range(range_str, left, right); + + if( !is_ipv4_single(left) ) { - if( range_str[pos] == '-' ) + if( verbose ) { - ptr[index] = '\0'; - ptr = right; - index = 0; + fprintf(stderr, "Malformed range %s: %s is not a valid IPv4 address\n", range_str, left); + } + result = RESULT_FAILURE; + } + else if( !is_ipv4_single(right) ) + { + if( verbose ) + { + fprintf(stderr, "Malformed range %s: %s is not a valid IPv4 address\n", range_str, right); + } + result = RESULT_FAILURE; + } + else + { + CIDR* left_addr = cidr_from_str(left); + CIDR* right_addr = cidr_from_str(right); + struct in_addr* left_in_addr = cidr_to_inaddr(left_addr, NULL); + struct in_addr* right_in_addr = cidr_to_inaddr(right_addr, NULL); + + if( left_in_addr->s_addr <= right_in_addr->s_addr ) + { + result = RESULT_SUCCESS; } else { - ptr[index] = range_str[pos]; - index++; + if( verbose ) + { + fprintf(stderr, "Malformed IPv4 range %s: its first address is greater than the last\n", range_str); + } + result = RESULT_FAILURE; } - pos++; + cidr_free(left_addr); + cidr_free(right_addr); } - ptr[index] = '\0'; + } - if( !is_ipv4_single(left) ) + return(result); +} + +/* Is it a valid IPv6 address range? */ +int is_ipv6_range(char* range_str, int verbose) +{ + int result = RESULT_SUCCESS; + + int regex_check_res = regex_matches("^([0-9a-fA-F:]+\\-[0-9a-fA-F:]+)$", range_str); + + if( !regex_check_res ) + { + if( verbose ) + { + fprintf(stderr, "Malformed range %s: must be a pair of hyphen-separated IPv6 addresses\n", range_str); + } + result = RESULT_FAILURE; + } + else + { + /* Extract sub-components from the range string. */ + + /* Allocate memory for the components of the range. + We need at most 39 characters for an IPv6 address, plus space for the terminating null byte. */ + char left[40]; + char right[40]; + + /* Split the string at the hyphen. + If the regex check succeeded, we know the hyphen is there. */ + split_range(range_str, left, right); + + if( !is_ipv6_single(left) ) { if( verbose ) { - fprintf(stderr, "Malformed range %s: %s is not a valid IPv4 address\n", range_str, left); + fprintf(stderr, "Malformed range %s: %s is not a valid IPv6 address\n", range_str, left); } result = RESULT_FAILURE; } - else if( !is_ipv4_single(right) ) + else if( !is_ipv6_single(right) ) { if( verbose ) { - fprintf(stderr, "Malformed range %s: %s is not a valid IPv4 address\n", range_str, right); + fprintf(stderr, "Malformed range %s: %s is not a valid IPv6 address\n", range_str, right); } result = RESULT_FAILURE; } @@ -524,10 +620,10 @@ int is_ipv4_range(char* range_str, int verbose) { CIDR* left_addr = cidr_from_str(left); CIDR* right_addr = cidr_from_str(right); - struct in_addr* left_in_addr = cidr_to_inaddr(left_addr, NULL); - struct in_addr* right_in_addr = cidr_to_inaddr(right_addr, NULL); + struct in6_addr* left_in6_addr = cidr_to_in6addr(left_addr, NULL); + struct in6_addr* right_in6_addr = cidr_to_in6addr(right_addr, NULL); - if( left_in_addr->s_addr < right_in_addr->s_addr ) + if( compare_ipv6(left_in6_addr, right_in6_addr) <= 0 ) { result = RESULT_SUCCESS; } @@ -535,7 +631,7 @@ int is_ipv4_range(char* range_str, int verbose) { if( verbose ) { - fprintf(stderr, "Malformed IPv4 range %s: its first address is greater than the last\n", range_str); + fprintf(stderr, "Malformed IPv6 range %s: its first address is greater than the last\n", range_str); } result = RESULT_FAILURE; } @@ -547,3 +643,4 @@ int is_ipv4_range(char* range_str, int verbose) return(result); } + |