diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-04-23 05:29:38 +0200 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-04-24 05:22:05 +0200 |
commit | 21ae0b4b3cc82d4f63d4426ce9ff78167b69122c (patch) | |
tree | 0fb6be451dc2b89217e6c4f5ea9a75ac3102196a /src/basic/in-addr-util.c | |
parent | sd-radv: allow to send multiple routes or prefix64 that have intersection wit... (diff) | |
download | systemd-21ae0b4b3cc82d4f63d4426ce9ff78167b69122c.tar.xz systemd-21ae0b4b3cc82d4f63d4426ce9ff78167b69122c.zip |
in-addr-util: introduce in{4,6}_addr_prefix_intersect()
Diffstat (limited to 'src/basic/in-addr-util.c')
-rw-r--r-- | src/basic/in-addr-util.c | 79 |
1 files changed, 45 insertions, 34 deletions
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 82c8ff9a2d..c077f0aa7d 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -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; } |