diff options
| author | Daniil Baturin <daniil@vyos.io> | 2024-01-04 13:38:37 -0500 |
|---|---|---|
| committer | Daniil Baturin <daniil@vyos.io> | 2024-01-04 13:38:37 -0500 |
| commit | 23e0eda853a9bfa42a2fa0d50b31eea874a01a9c (patch) | |
| tree | ba5e579ed670d0275fea996b0284b3a74da78f28 /src/ipaddrcheck_functions.c | |
| parent | 346aedbcd2257512208195bb165cc857e2907922 (diff) | |
| download | ipaddrcheck-23e0eda853a9bfa42a2fa0d50b31eea874a01a9c.tar.gz ipaddrcheck-23e0eda853a9bfa42a2fa0d50b31eea874a01a9c.zip | |
Add --range-prefix-length option
to require the range boundaries to lie within the same subnet
of a given size
Diffstat (limited to 'src/ipaddrcheck_functions.c')
| -rw-r--r-- | src/ipaddrcheck_functions.c | 65 |
1 files changed, 60 insertions, 5 deletions
diff --git a/src/ipaddrcheck_functions.c b/src/ipaddrcheck_functions.c index e3e2c86..2b3cc22 100644 --- a/src/ipaddrcheck_functions.c +++ b/src/ipaddrcheck_functions.c @@ -460,7 +460,7 @@ int is_any_net(CIDR *address) * 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) +void split_range(char* range_str, char* left, char* right) { char* ptr = left; int length = strlen(range_str); @@ -487,6 +487,9 @@ void split_range(char* range_str, char* left, char*right) return; } +/* in6_addr fields are byte arrays, so we cannot compare them as numbers + * and needs custom comparison logic + */ int compare_ipv6(struct in6_addr *left, struct in6_addr *right) { int i = 0; @@ -501,7 +504,7 @@ int compare_ipv6(struct in6_addr *left, struct in6_addr *right) } /* Is it a valid IPv4 address range? */ -int is_ipv4_range(char* range_str, int verbose) +int is_ipv4_range(char* range_str, int prefix_length, int verbose) { int result = RESULT_SUCCESS; @@ -553,7 +556,33 @@ int is_ipv4_range(char* range_str, int verbose) if( left_in_addr->s_addr <= right_in_addr->s_addr ) { - result = RESULT_SUCCESS; + /* If non-zero prefix_length is given, + check if the right address is within the network of the first one. */ + if( prefix_length > 0 ) + { + char left_pref_str[19]; + + /* XXX: Prefix length size is checked elsewhere, so it can't be more than 2 characters (32) + and overflow cannot occur. + */ + sprintf(left_pref_str, "%s/%u", left, prefix_length); + CIDR* left_addr_with_pref = cidr_from_str(left_pref_str); + CIDR* left_net = cidr_addr_network(left_addr_with_pref); + if( cidr_contains(left_net, right_addr) == 0 ) + { + result = RESULT_SUCCESS; + } + else + { + result = RESULT_FAILURE; + } + cidr_free(left_addr_with_pref); + cidr_free(left_net); + } + else + { + result = RESULT_SUCCESS; + } } else { @@ -573,7 +602,7 @@ int is_ipv4_range(char* range_str, int verbose) } /* Is it a valid IPv6 address range? */ -int is_ipv6_range(char* range_str, int verbose) +int is_ipv6_range(char* range_str, int prefix_length, int verbose) { int result = RESULT_SUCCESS; @@ -625,7 +654,33 @@ int is_ipv6_range(char* range_str, int verbose) if( compare_ipv6(left_in6_addr, right_in6_addr) <= 0 ) { - result = RESULT_SUCCESS; + /* If non-zero prefix_length is given, + check if the right address is within the network of the first one. */ + if( prefix_length > 0 ) + { + char left_pref_str[44]; + + /* XXX: Prefix length size is checked elsewhere, so it can't be more than 3 characters (128) + and overflow cannot occur. + */ + sprintf(left_pref_str, "%s/%u", left, prefix_length); + CIDR* left_addr_with_pref = cidr_from_str(left_pref_str); + CIDR* left_net = cidr_addr_network(left_addr_with_pref); + if( cidr_contains(left_net, right_addr) == 0 ) + { + result = RESULT_SUCCESS; + } + else + { + result = RESULT_FAILURE; + } + cidr_free(left_addr_with_pref); + cidr_free(left_net); + } + else + { + result = RESULT_SUCCESS; + } } else { |
