From: Yu Watanabe Date: Thu, 21 Feb 2019 04:23:25 +0000 (+0900) Subject: util: introduce in_addr_random_prefix() X-Git-Tag: v242-rc1~209^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c5236acdd7c99a7c9a6254075386bf669264c533;p=thirdparty%2Fsystemd.git util: introduce in_addr_random_prefix() --- diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index c715075c14f..bc6b9ce44d5 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -11,6 +11,7 @@ #include "in-addr-util.h" #include "macro.h" #include "parse-util.h" +#include "random-util.h" #include "util.h" bool in4_addr_is_null(const struct in_addr *a) { @@ -215,6 +216,83 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) return -EAFNOSUPPORT; } +int in_addr_random_prefix( + int family, + union in_addr_union *u, + unsigned prefixlen_fixed_part, + unsigned prefixlen) { + + assert(u); + + /* Random network part of an address by one. */ + + if (prefixlen <= 0) + return 0; + + if (family == AF_INET) { + uint32_t c, n; + + if (prefixlen_fixed_part > 32) + prefixlen_fixed_part = 32; + if (prefixlen > 32) + prefixlen = 32; + if (prefixlen_fixed_part >= prefixlen) + return -EINVAL; + + c = be32toh(u->in.s_addr); + c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part); + + random_bytes(&n, sizeof(n)); + n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen); + + u->in.s_addr = htobe32(n | c); + return 1; + } + + if (family == AF_INET6) { + struct in6_addr n; + unsigned i, j; + + if (prefixlen_fixed_part > 128) + prefixlen_fixed_part = 128; + if (prefixlen > 128) + prefixlen = 128; + if (prefixlen_fixed_part >= prefixlen) + return -EINVAL; + + random_bytes(&n, sizeof(n)); + + for (i = 0; i < 16; i++) { + uint8_t mask_fixed_part = 0, mask = 0; + + if (i < (prefixlen_fixed_part + 7) / 8) { + if (i < prefixlen_fixed_part / 8) + mask_fixed_part = 0xffu; + else { + j = prefixlen_fixed_part % 8; + mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j); + } + } + + if (i < (prefixlen + 7) / 8) { + if (i < prefixlen / 8) + mask = 0xffu ^ mask_fixed_part; + else { + j = prefixlen % 8; + mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part; + } + } + + u->in6.s6_addr[i] &= mask_fixed_part; + u->in6.s6_addr[i] |= n.s6_addr[i] & mask; + } + + return 1; + } + + return -EAFNOSUPPORT; +} + int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { char *x; size_t l; diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index c21567122ca..3517fe1ea35 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -35,6 +35,7 @@ bool in4_addr_is_non_local(const struct in_addr *a); 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); int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); +int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen); int in_addr_to_string(int family, const union in_addr_union *u, char **ret); int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret); int in_addr_from_string(int family, const char *s, union in_addr_union *ret);