]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
in-addr-util: introduce in{4,6}_addr_prefix_intersect()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 23 Apr 2024 03:29:38 +0000 (12:29 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 24 Apr 2024 03:22:05 +0000 (12:22 +0900)
src/basic/in-addr-util.c
src/basic/in-addr-util.h

index 82c8ff9a2d4cae0942defcd77ff469bddf8e789f..c077f0aa7db71f9cf6f143c12a0054958be0f8d6 100644 (file)
@@ -194,58 +194,69 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_
         return -EAFNOSUPPORT;
 }
 
-int in_addr_prefix_intersect(
-                int family,
-                const union in_addr_union *a,
+bool in4_addr_prefix_intersect(
+                const struct in_addr *a,
                 unsigned aprefixlen,
-                const union in_addr_union *b,
+                const struct in_addr *b,
                 unsigned bprefixlen) {
 
-        unsigned m;
-
         assert(a);
         assert(b);
 
-        /* Checks whether there are any addresses that are in both networks */
+        unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in_addr) * 8));
+        if (m == 0)
+                return true; /* Let's return earlier, to avoid shift by 32. */
 
-        m = MIN(aprefixlen, bprefixlen);
+        uint32_t x = be32toh(a->s_addr ^ b->s_addr);
+        uint32_t n = 0xFFFFFFFFUL << (32 - m);
+        return (x & n) == 0;
+}
 
-        if (family == AF_INET) {
-                uint32_t x, nm;
+bool in6_addr_prefix_intersect(
+                const struct in6_addr *a,
+                unsigned aprefixlen,
+                const struct in6_addr *b,
+                unsigned bprefixlen) {
 
-                x = be32toh(a->in.s_addr ^ b->in.s_addr);
-                nm = m == 0 ? 0 : 0xFFFFFFFFUL << (32 - m);
+        assert(a);
+        assert(b);
 
-                return (x & nm) == 0;
-        }
+        unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in6_addr) * 8));
+        if (m == 0)
+                return true;
 
-        if (family == AF_INET6) {
-                unsigned i;
+        for (size_t i = 0; i < sizeof(struct in6_addr); i++) {
+                uint8_t x = a->s6_addr[i] ^ b->s6_addr[i];
+                uint8_t n = m < 8 ? (0xFF << (8 - m)) : 0xFF;
+                if ((x & n) != 0)
+                        return false;
 
-                if (m > 128)
-                        m = 128;
+                if (m <= 8)
+                        break;
 
-                for (i = 0; i < 16; i++) {
-                        uint8_t x, nm;
+                m -= 8;
+        }
 
-                        x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
+        return true;
+}
 
-                        if (m < 8)
-                                nm = 0xFF << (8 - m);
-                        else
-                                nm = 0xFF;
+int in_addr_prefix_intersect(
+                int family,
+                const union in_addr_union *a,
+                unsigned aprefixlen,
+                const union in_addr_union *b,
+                unsigned bprefixlen) {
+
+        assert(a);
+        assert(b);
 
-                        if ((x & nm) != 0)
-                                return 0;
+        /* Checks whether there are any addresses that are in both networks. */
 
-                        if (m > 8)
-                                m -= 8;
-                        else
-                                m = 0;
-                }
+        if (family == AF_INET)
+                return in4_addr_prefix_intersect(&a->in, aprefixlen, &b->in, bprefixlen);
 
-                return 1;
-        }
+        if (family == AF_INET6)
+                return in6_addr_prefix_intersect(&a->in6, aprefixlen, &b->in6, bprefixlen);
 
         return -EAFNOSUPPORT;
 }
index 5c820c6ec6ac23aa0aba0ce2a80ee2b86b615af9..9cd0aca9a4e73670ad232faa5cfee91d106400c1 100644 (file)
@@ -61,7 +61,22 @@ bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a);
 bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b);
 bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b);
 int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
-int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
+bool in4_addr_prefix_intersect(
+                const struct in_addr *a,
+                unsigned aprefixlen,
+                const struct in_addr *b,
+                unsigned bprefixlen);
+bool in6_addr_prefix_intersect(
+                const struct in6_addr *a,
+                unsigned aprefixlen,
+                const struct in6_addr *b,
+                unsigned bprefixlen);
+int in_addr_prefix_intersect(
+                int family,
+                const union in_addr_union *a,
+                unsigned aprefixlen,
+                const union in_addr_union *b,
+                unsigned bprefixlen);
 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);