diff --git a/src/shared/firewall-util-nft.c b/src/shared/firewall-util-nft.c index 22c0dc0980c..0259a80914a 100644 --- a/src/shared/firewall-util-nft.c +++ b/src/shared/firewall-util-nft.c @@ -30,6 +30,9 @@ #define UDP_DPORT_OFFSET 2 +void nft_in6addr_to_range(const union in_addr_union *source, unsigned int prefixlen, + struct in6_addr *start, struct in6_addr *end); + static int nfnl_netlink_sendv(sd_netlink *nfnl, sd_netlink_message *messages[], size_t msgcount) { @@ -845,8 +848,8 @@ static int fw_nftables_recreate_table(sd_netlink *nfnl, int af, sd_netlink_messa return 0; } -static void nft_in6addr_to_range(const union in_addr_union *source, unsigned int prefixlen, - struct in6_addr *ret_start, struct in6_addr *ret_end) { +void nft_in6addr_to_range(const union in_addr_union *source, unsigned int prefixlen, + struct in6_addr *ret_start, struct in6_addr *ret_end) { uint8_t carry = 0; int i, j; diff --git a/src/test/test-firewall-util.c b/src/test/test-firewall-util.c index 4cb43cc585f..d5501b807d1 100644 --- a/src/test/test-firewall-util.c +++ b/src/test/test-firewall-util.c @@ -9,10 +9,25 @@ #define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))} +void nft_in6addr_to_range(const union in_addr_union *source, unsigned int prefixlen, + struct in6_addr *start, struct in6_addr *end); + static void make_in6_addr_union(const char *addr, union in_addr_union *u) { assert_se(inet_pton(AF_INET6, addr, &u->in6) >= 0); } +static bool test_in6_eq(const char *addr, const union in_addr_union *u) { + union in_addr_union tmp; + + make_in6_addr_union(addr, &tmp); + + return memcmp(&tmp.in6, &u->in6, sizeof(tmp.in6)) == 0; +} + +static void assert_in6_eq(const union in_addr_union *a, const union in_addr_union *b) { + assert_se(memcmp(&a->in6, &b->in6, sizeof(a->in6)) == 0); +} + static void test_v6(FirewallContext **ctx) { union in_addr_union u = {}, u2 = {}; uint8_t prefixlen; @@ -62,6 +77,52 @@ static void test_v6(FirewallContext **ctx) { log_error_errno(r, "Failed to modify ipv6 firewall: %m"); } +static void test_v6_range(void) { + unsigned int prefixlen = 64; + union in_addr_union a, b, s; + + make_in6_addr_union("dead:0:0:beef::", &s); + + nft_in6addr_to_range(&s, prefixlen, &a.in6, &b.in6); + + assert_in6_eq(&s, &a); + assert_se(test_in6_eq("dead:0:0:bef0::", &b)); + + make_in6_addr_union("2001::", &s); + prefixlen = 56; + nft_in6addr_to_range(&s, prefixlen, &a.in6, &b.in6); + assert_in6_eq(&s, &a); + assert_se(test_in6_eq("2001:0:0:0100::", &b)); + + prefixlen = 48; + nft_in6addr_to_range(&s, prefixlen, &a.in6, &b.in6); + assert_in6_eq(&s, &a); + + assert_se(test_in6_eq("2001:0:0001::", &b)); + + prefixlen = 65; + nft_in6addr_to_range(&s, prefixlen, &a.in6, &b.in6); + assert_se(test_in6_eq("2001::", &a)); + + assert_se(test_in6_eq("2001::8000:0:0:0", &b)); + + prefixlen = 66; + nft_in6addr_to_range(&s, prefixlen, &a.in6, &b.in6); + assert_in6_eq(&s, &a); + + assert_se(test_in6_eq("2001::4000:0:0:0", &b)); + + prefixlen = 127; + nft_in6addr_to_range(&s, prefixlen, &a.in6, &b.in6); + assert_in6_eq(&s, &a); + assert_se(test_in6_eq("2001::0002", &b)); + + make_in6_addr_union("dead:beef::1", &s); + prefixlen = 64; + nft_in6addr_to_range(&s, prefixlen, &a.in6, &b.in6); + assert_se(test_in6_eq("dead:beef::", &a)); +} + int main(int argc, char *argv[]) { _cleanup_(fw_ctx_freep) FirewallContext *ctx; int r; @@ -114,6 +175,7 @@ int main(int argc, char *argv[]) { log_error_errno(r, "Failed to modify firewall: %m"); test_v6(&ctx); + test_v6_range(); return 0; }