diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index bdedfc967a..623ec93d99 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -264,93 +264,6 @@ int in_addr_prefix_intersect( return -EAFNOSUPPORT; } -int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) { - assert(u); - - /* Increases the network part of an address by one. Returns 0 if that succeeds, or -ERANGE if - * this overflows. */ - - return in_addr_prefix_nth(family, u, prefixlen, 1); -} - -/* - * Calculates the nth prefix of size prefixlen starting from the address denoted by u. - * - * On success 0 will be returned and the calculated prefix will be available in - * u. In case the calculation cannot be performed (invalid prefix length, - * overflows would occur) -ERANGE is returned. If the address family given isn't - * supported -EAFNOSUPPORT will be returned. - * - * Examples: - * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 0, writes 192.168.2.0 to u - * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 0, no data written - * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 24, 1), returns -ERANGE, no data written - * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 0, 1), returns -ERANGE, no data written - * - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 0, writes 2001:0db8:0000:ff00:: to u - */ -int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth) { - assert(u); - - if (prefixlen <= 0) - return -ERANGE; - - if (family == AF_INET) { - uint32_t c, n, t; - - if (prefixlen > 32) - return -ERANGE; - - c = be32toh(u->in.s_addr); - - t = nth << (32 - prefixlen); - - /* Check for wrap */ - if (c > UINT32_MAX - t) - return -ERANGE; - - n = c + t; - - n &= UINT32_C(0xFFFFFFFF) << (32 - prefixlen); - u->in.s_addr = htobe32(n); - return 0; - } - - if (family == AF_INET6) { - bool overflow = false; - - if (prefixlen > 128) - return -ERANGE; - - for (unsigned i = 16; i > 0; i--) { - unsigned t, j = i - 1, p = j * 8; - - if (p >= prefixlen) { - u->in6.s6_addr[j] = 0; - continue; - } - - if (prefixlen - p < 8) { - u->in6.s6_addr[j] &= 0xff << (8 - (prefixlen - p)); - t = u->in6.s6_addr[j] + ((nth & 0xff) << (8 - (prefixlen - p))); - nth >>= prefixlen - p; - } else { - t = u->in6.s6_addr[j] + (nth & 0xff) + overflow; - nth >>= 8; - } - - overflow = t > UINT8_MAX; - u->in6.s6_addr[j] = (uint8_t) (t & 0xff); - } - - if (overflow || nth != 0) - return -ERANGE; - - return 0; - } - - return -EAFNOSUPPORT; -} - int in_addr_random_prefix( int family, union in_addr_union *u, @@ -435,28 +348,50 @@ int in_addr_prefix_range( 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)) + /* Note, on overflow, e.g. input is 255.255.255.255, then ret_end will be a null address. */ + + switch (family) { + case AF_INET: + if (prefixlen > 32) + return -EINVAL; + break; + case AF_INET6: + if (prefixlen > 128) + return -EINVAL; + break; + default: 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 (prefixlen == 0) { + /* shortcut for trivial case */ + if (ret_start) + *ret_start = IN_ADDR_NULL; + if (ret_end) + *ret_end = IN_ADDR_NULL; + return 0; } + union in_addr_union start = *in; + r = in_addr_mask(family, &start, prefixlen); + if (r < 0) + return r; + + union in_addr_union end = start; + uint8_t add = UINT8_C(1) << ((FAMILY_ADDRESS_SIZE(family) * 8 - prefixlen) % 8); + for (unsigned i = DIV_ROUND_UP(prefixlen, 8); i-- > 0;) + if (add > UINT8_MAX - end.bytes[i]) { + end.bytes[i] = 0; + add = 1; + } else { + end.bytes[i] += add; + break; + } + if (ret_start) *ret_start = start; if (ret_end) diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index cb76ef221c..64563e49cd 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -73,8 +73,6 @@ int in_addr_prefix_intersect( unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen) _pure_; -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, diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index 239ccd4e8f..eb9fc8b961 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -822,45 +822,7 @@ int fw_nftables_del_table(sd_netlink *nfnl, int family) { static int nft_message_append_setelem_iprange( sd_netlink_message *m, - const union in_addr_union *source, - unsigned prefixlen) { - - uint32_t mask, start, end; - unsigned nplen; - int r; - - assert(m); - assert(source); - assert(prefixlen <= 32); - - nplen = 32 - prefixlen; - - mask = (1U << nplen) - 1U; - mask = htobe32(~mask); - start = source->in.s_addr & mask; - - r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS); - if (r < 0) - return r; - - r = sd_nfnl_nft_message_append_setelem(m, 0, &start, sizeof(start), NULL, 0, 0); - if (r < 0) - return r; - - end = be32toh(start) + (1U << nplen); - if (end < be32toh(start)) - end = 0U; - end = htobe32(end); - - r = sd_nfnl_nft_message_append_setelem(m, 1, &end, sizeof(end), NULL, 0, NFT_SET_ELEM_INTERVAL_END); - if (r < 0) - return r; - - return sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */ -} - -static int nft_message_append_setelem_ip6range( - sd_netlink_message *m, + int af, const union in_addr_union *source, unsigned prefixlen) { @@ -868,9 +830,10 @@ static int nft_message_append_setelem_ip6range( int r; assert(m); + assert(IN_SET(af, AF_INET, AF_INET6)); assert(source); - r = in_addr_prefix_range(AF_INET6, source, prefixlen, &start, &end); + r = in_addr_prefix_range(af, source, prefixlen, &start, &end); if (r < 0) return r; @@ -878,11 +841,15 @@ static int nft_message_append_setelem_ip6range( if (r < 0) return r; - r = sd_nfnl_nft_message_append_setelem(m, 0, &start.in6, sizeof(start.in6), NULL, 0, 0); + r = sd_nfnl_nft_message_append_setelem( + m, /* index= */ 0, &start, FAMILY_ADDRESS_SIZE(af), + /* data= */ NULL, /* data_len= */ 0, /* flags= */ 0); if (r < 0) return r; - r = sd_nfnl_nft_message_append_setelem(m, 1, &end.in6, sizeof(end.in6), NULL, 0, NFT_SET_ELEM_INTERVAL_END); + r = sd_nfnl_nft_message_append_setelem( + m, /* index= */ 1, &end, FAMILY_ADDRESS_SIZE(af), + /* data= */ NULL, /* data_len= */ 0, NFT_SET_ELEM_INTERVAL_END); if (r < 0) return r; @@ -907,21 +874,13 @@ int nft_set_element_modify_iprange( assert(nfproto_is_valid(nfproto)); assert(table); assert(set); - - if (!source || source_prefixlen == 0) - return -EINVAL; - - if (af == AF_INET6 && source_prefixlen < 8) - return -EINVAL; + assert(source); r = sd_nfnl_nft_message_new_setelems(nfnl, &m, add, nfproto, table, set); if (r < 0) return r; - if (af == AF_INET) - r = nft_message_append_setelem_iprange(m, source, source_prefixlen); - else - r = nft_message_append_setelem_ip6range(m, source, source_prefixlen); + r = nft_message_append_setelem_iprange(m, af, source, source_prefixlen); if (r < 0) return r; @@ -945,9 +904,7 @@ int nft_set_element_modify_ip( assert(nfproto_is_valid(nfproto)); assert(table); assert(set); - - if (!source) - return -EINVAL; + assert(source); r = sd_nfnl_nft_message_new_setelems(nfnl, &m, add, nfproto, table, set); if (r < 0) @@ -1020,6 +977,7 @@ int fw_nftables_add_masquerade( assert(nfnl); assert(IN_SET(af, AF_INET, AF_INET6)); + assert(source); if (!socket_ipv6_is_supported() && af == AF_INET6) return -EOPNOTSUPP; diff --git a/src/test/test-firewall-util.c b/src/test/test-firewall-util.c index cdf1864b21..70735654ed 100644 --- a/src/test/test-firewall-util.c +++ b/src/test/test-firewall-util.c @@ -56,14 +56,14 @@ TEST(v4) { ASSERT_NOT_NULL(nfnl); - ASSERT_ERROR(fw_nftables_add_masquerade(nfnl, true, AF_INET, NULL, 0), EINVAL); - ASSERT_ERROR(fw_nftables_add_masquerade(nfnl, true, AF_INET, parse_addr("10.1.2.0", &u), 0), EINVAL); - ASSERT_OK_OR(r = fw_nftables_add_masquerade(nfnl, true, AF_INET, parse_addr("10.1.2.3", &u), 32), -EPERM, -EOPNOTSUPP, -ENOPROTOOPT); if (r < 0) return (void) log_tests_skipped_errno(r, "Failed to add IPv4 masquerade"); + ASSERT_OK(fw_nftables_add_masquerade(nfnl, true, AF_INET, parse_addr("10.1.2.0", &u), 0)); + ASSERT_ERROR(fw_nftables_add_masquerade(nfnl, true, AF_INET, parse_addr("10.0.2.0", &u), 28), EEXIST); + ASSERT_OK(fw_nftables_add_masquerade(nfnl, false, AF_INET, parse_addr("10.1.2.0", &u), 0)); ASSERT_OK(fw_nftables_add_masquerade(nfnl, true, AF_INET, parse_addr("10.0.2.0", &u), 28)); ASSERT_OK(fw_nftables_add_masquerade(nfnl, false, AF_INET, parse_addr("10.0.2.0", &u), 28)); ASSERT_OK(fw_nftables_add_masquerade(nfnl, false, AF_INET, parse_addr("10.1.2.3", &u), 32)); diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c index 769cb8f083..f7bc62f8e6 100644 --- a/src/test/test-in-addr-util.c +++ b/src/test/test-in-addr-util.c @@ -213,85 +213,6 @@ TEST(in_addr_prefix_intersect) { test_in_addr_prefix_intersect_one(AF_INET6, "1::1", 121, "1::00ff", 121, 0); } -static void test_in_addr_prefix_next_one(unsigned f, const char *before, unsigned pl, const char *after) { - union in_addr_union ubefore, uafter, t; - - log_debug("/* %s(%s, prefixlen=%u) */", __func__, before, pl); - - assert_se(in_addr_from_string(f, before, &ubefore) >= 0); - - t = ubefore; - assert_se((in_addr_prefix_next(f, &t, pl) >= 0) == !!after); - - if (after) { - assert_se(in_addr_from_string(f, after, &uafter) >= 0); - assert_se(in_addr_equal(f, &t, &uafter) > 0); - } -} - -TEST(in_addr_prefix_next) { - test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 24, "192.168.1.0"); - test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 16, "192.169.0.0"); - test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 20, "192.168.16.0"); - - test_in_addr_prefix_next_one(AF_INET, "0.0.0.0", 32, "0.0.0.1"); - test_in_addr_prefix_next_one(AF_INET, "255.255.255.254", 32, "255.255.255.255"); - test_in_addr_prefix_next_one(AF_INET, "255.255.255.255", 32, NULL); - test_in_addr_prefix_next_one(AF_INET, "255.255.255.0", 24, NULL); - - test_in_addr_prefix_next_one(AF_INET6, "4400::", 128, "4400::0001"); - test_in_addr_prefix_next_one(AF_INET6, "4400::", 120, "4400::0100"); - test_in_addr_prefix_next_one(AF_INET6, "4400::", 127, "4400::0002"); - test_in_addr_prefix_next_one(AF_INET6, "4400::", 8, "4500::"); - test_in_addr_prefix_next_one(AF_INET6, "4400::", 7, "4600::"); - - test_in_addr_prefix_next_one(AF_INET6, "::", 128, "::1"); - - test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, NULL); - test_in_addr_prefix_next_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00", 120, NULL); -} - -static void test_in_addr_prefix_nth_one(unsigned f, const char *before, unsigned pl, uint64_t nth, const char *after) { - union in_addr_union ubefore, uafter, t; - - log_debug("/* %s(%s, prefixlen=%u, nth=%"PRIu64") */", __func__, before, pl, nth); - - assert_se(in_addr_from_string(f, before, &ubefore) >= 0); - - t = ubefore; - assert_se((in_addr_prefix_nth(f, &t, pl, nth) >= 0) == !!after); - - if (after) { - assert_se(in_addr_from_string(f, after, &uafter) >= 0); - assert_se(in_addr_equal(f, &t, &uafter) > 0); - } -} - -TEST(in_addr_prefix_nth) { - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 0, "192.168.0.0"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.123", 24, 0, "192.168.0.0"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.123", 24, 1, "192.168.1.0"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 4, "192.168.4.0"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 25, 1, "192.168.0.128"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.255.0", 25, 1, "192.168.255.128"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.255.0", 24, 0, "192.168.255.0"); - test_in_addr_prefix_nth_one(AF_INET, "255.255.255.255", 32, 1, NULL); - test_in_addr_prefix_nth_one(AF_INET, "255.255.255.255", 0, 1, NULL); - - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 8, 1, "4500::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 7, 1, "4600::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 64, 1, "4400:0:0:1::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 64, 2, "4400:0:0:2::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 64, 0xbad, "4400:0:0:0bad::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400:0:0:ffff::", 64, 1, "4400:0:1::"); - test_in_addr_prefix_nth_one(AF_INET6, "4400::", 56, ((uint64_t)1<<48) -1, "44ff:ffff:ffff:ff00::"); - test_in_addr_prefix_nth_one(AF_INET6, "0000::", 8, 255, "ff00::"); - test_in_addr_prefix_nth_one(AF_INET6, "0000::", 8, 256, NULL); - test_in_addr_prefix_nth_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, 1, NULL); - test_in_addr_prefix_nth_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0, 1, NULL); - 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, @@ -299,38 +220,94 @@ static void test_in_addr_prefix_range_one( const char *expected_start, const char *expected_end) { - union in_addr_union a, s, e; + assert(!expected_start == !expected_end); log_debug("/* %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); + union in_addr_union a, s, e; + ASSERT_OK(in_addr_from_string(family, in, &a)); - 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_start) { + ASSERT_ERROR(in_addr_prefix_range(family, &a, prefixlen, NULL, NULL), EINVAL); + ASSERT_ERROR(in_addr_prefix_range(family, &a, prefixlen, &s, NULL), EINVAL); + ASSERT_ERROR(in_addr_prefix_range(family, &a, prefixlen, NULL, &e), EINVAL); + ASSERT_ERROR(in_addr_prefix_range(family, &a, prefixlen, &s, &e), EINVAL); + return; } - 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); - } + ASSERT_OK(in_addr_prefix_range(family, &a, prefixlen, NULL, NULL)); + ASSERT_OK(in_addr_prefix_range(family, &a, prefixlen, &s, NULL)); + ASSERT_OK(in_addr_prefix_range(family, &a, prefixlen, NULL, &e)); + ASSERT_OK(in_addr_prefix_range(family, &a, prefixlen, &s, &e)); + + union in_addr_union es; + ASSERT_OK(in_addr_from_string(family, expected_start, &es)); + ASSERT_OK_POSITIVE(in_addr_equal(family, &s, &es)); + + union in_addr_union ee; + ASSERT_OK(in_addr_from_string(family, expected_end, &ee)); + ASSERT_OK_POSITIVE(in_addr_equal(family, &e, &ee)); } TEST(in_addr_prefix_range) { - 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", 0, "0.0.0.0", "0.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 1, "128.0.0.0", "0.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 2, "192.0.0.0", "0.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 3, "192.0.0.0", "224.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 4, "192.0.0.0", "208.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 5, "192.0.0.0", "200.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 6, "192.0.0.0", "196.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 7, "192.0.0.0", "194.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 8, "192.0.0.0", "193.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 9, "192.128.0.0", "193.0.0.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 10, "192.128.0.0", "192.192.0.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_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", 32, "192.168.123.123", "192.168.123.124"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 33, NULL, NULL); + + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 0, "::", "::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 1, "8000::", "::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 2, "c000::", "::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 3, "c000::", "e000::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 4, "d000::", "e000::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 7, "de00::", "e000::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 8, "de00::", "df00::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 9, "de80::", "df00::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 16, "dead:0000::", "deae:0000::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 17, "dead:8000::", "deae:0000::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 18, "dead:8000::", "dead:c000::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 19, "dead:a000::", "dead:c000::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 20, "dead:b000::", "dead:c000::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 21, "dead:b800::", "dead:c000::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 28, "dead:bee0::", "dead:bef0::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 29, "dead:bee8::", "dead:bef0::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 30, "dead:beec::", "dead:bef0::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 31, "dead:beee::", "dead:bef0::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 32, "dead:beef::", "dead:bef0::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 33, "dead:beef::", "dead:beef:8000::"); + 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:beef::", 128, "dead:beef::", "dead:beef::1"); + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 129, NULL, NULL); - 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, "dead:beef:0:ffff::", 64, "dead:beef:0:ffff::", "dead:beef:1::"); + test_in_addr_prefix_range_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "::"); + + test_in_addr_prefix_range_one(AF_INET6, "2001::", 0, "::", "::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 1, "::", "8000::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 2, "::", "4000::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 3, "2000::", "4000::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 4, "2000::", "3000::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 8, "2000::", "2100::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 16, "2001::", "2002::"); 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"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 128, "2001::", "2001::1"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 129, NULL, NULL); } static void test_in_addr_to_string_one(int f, const char *addr) {