From 1534c5791ae8b581df4cc8fc321cc6a757998be0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 17 Feb 2021 22:55:01 +0900 Subject: [PATCH] in-addr-util: introduce in_addr_prefix_range() This will replace nft_in6addr_to_range() in later commit. --- src/basic/in-addr-util.c | 37 +++++++++++++++++++++++++++++++ src/basic/in-addr-util.h | 6 ++++++ src/test/test-in-addr-util.c | 42 ++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index aa681b7bb79..641c5de7a37 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -350,6 +350,43 @@ int in_addr_random_prefix( return -EAFNOSUPPORT; } +int in_addr_prefix_range( + int family, + const union in_addr_union *in, + unsigned prefixlen, + union in_addr_union *ret_start, + union in_addr_union *ret_end) { + + union in_addr_union start, end; + int r; + + assert(in); + + if (!IN_SET(family, AF_INET, AF_INET6)) + return -EAFNOSUPPORT; + + if (ret_start) { + start = *in; + r = in_addr_prefix_nth(family, &start, prefixlen, 0); + if (r < 0) + return r; + } + + if (ret_end) { + end = *in; + r = in_addr_prefix_nth(family, &end, prefixlen, 1); + if (r < 0) + return r; + } + + if (ret_start) + *ret_start = start; + if (ret_end) + *ret_end = end; + + return 0; +} + int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { _cleanup_free_ char *x = NULL; size_t l; diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 24308b702e2..a5ce8258fd9 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -41,6 +41,12 @@ int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth); int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen); +int in_addr_prefix_range( + int family, + const union in_addr_union *in, + unsigned prefixlen, + union in_addr_union *ret_start, + union in_addr_union *ret_end); int in_addr_to_string(int family, const union in_addr_union *u, char **ret); int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret); int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret); diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c index c2cf26d7206..509ea7e31e5 100644 --- a/src/test/test-in-addr-util.c +++ b/src/test/test-in-addr-util.c @@ -314,6 +314,47 @@ static void test_in_addr_prefix_nth(void) { test_in_addr_prefix_nth_one(AF_INET6, "1234:5678:90ab:cdef:1234:5678:90ab:cdef", 12, 1, "1240::"); } +static void test_in_addr_prefix_range_one( + int family, + const char *in, + unsigned prefixlen, + const char *expected_start, + const char *expected_end) { + + union in_addr_union a, s, e; + + log_info("/* %s(%s, prefixlen=%u) */", __func__, in, prefixlen); + + assert_se(in_addr_from_string(family, in, &a) >= 0); + assert_se((in_addr_prefix_range(family, &a, prefixlen, &s, &e) >= 0) == !!expected_start); + + if (expected_start) { + union in_addr_union es; + + assert_se(in_addr_from_string(family, expected_start, &es) >= 0); + assert_se(in_addr_equal(family, &s, &es) > 0); + } + if (expected_end) { + union in_addr_union ee; + + assert_se(in_addr_from_string(family, expected_end, &ee) >= 0); + assert_se(in_addr_equal(family, &e, &ee) > 0); + } +} + +static void test_in_addr_prefix_range(void) { + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 24, "192.168.123.0", "192.168.124.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 16, "192.168.0.0", "192.169.0.0"); + + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 64, "dead:beef::", "dead:beef:0:1::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:0:0:beef::", 64, "dead:0:0:beef::", "dead:0:0:bef0::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 48, "2001::", "2001:0:1::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 56, "2001::", "2001:0:0:0100::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 65, "2001::", "2001::8000:0:0:0"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 66, "2001::", "2001::4000:0:0:0"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 127, "2001::", "2001::2"); +} + static void test_in_addr_to_string_one(int f, const char *addr) { union in_addr_union ua; _cleanup_free_ char *r = NULL; @@ -342,6 +383,7 @@ int main(int argc, char *argv[]) { test_in_addr_prefix_intersect(); test_in_addr_prefix_next(); test_in_addr_prefix_nth(); + test_in_addr_prefix_range(); test_in_addr_to_string(); return 0;