diff options
author | Vladimír Čunát <vladimir.cunat@nic.cz> | 2024-06-26 15:05:54 +0200 |
---|---|---|
committer | Vladimír Čunát <vladimir.cunat@nic.cz> | 2024-07-22 13:03:40 +0200 |
commit | 062eafbd4f02275e4191b71ee5dd748c37764ef2 (patch) | |
tree | 0efe3cbf4b02edd0b58aa4da5f2d6f42c1c1105c /lib | |
parent | Merge branch 'kresctl-convert-policy-loader' into 'master' (diff) | |
download | knot-resolver-062eafbd4f02275e4191b71ee5dd748c37764ef2.tar.xz knot-resolver-062eafbd4f02275e4191b71ee5dd748c37764ef2.zip |
lib/rules: fix a bug in subnet computations
The problem mainly affected subnets not aligned on whole bytes,
but maybe also others. Reported:
https://lists.nic.cz/hyperkitty/list/knot-resolver-users@lists.nic.cz/message/6P2JPK72WMVLP45TDV42DTACEA2N5NW2/
I'm really sorry about this; no idea why I thought that the simple
multiplication would suffice.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rules/api.c | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/lib/rules/api.c b/lib/rules/api.c index 9dc01a4f..2725e9a4 100644 --- a/lib/rules/api.c +++ b/lib/rules/api.c @@ -842,13 +842,22 @@ static int subnet_encode(const struct sockaddr *addr, int sub_len, uint8_t buf[3 // - 00 -> beyond the subnet's prefix // - 10 -> zero bit within the subnet's prefix // - 11 -> one bit within the subnet's prefix - // Multiplying one uint8_t by 01010101 (in binary) will do interleaving. int i; // Let's hope that compiler optimizes this into something reasonable. for (i = 0; sub_len > 0; ++i, sub_len -= 8) { - uint16_t x = a[i] * 85; // interleave by zero bits - uint8_t sub_mask = 255 >> (8 - MIN(sub_len, 8)); - uint16_t r = x | (sub_mask * 85 * 2); + // r = a[i] interleaved by 1 bits (with 1s on the higher-value positions) + // https://graphics.stanford.edu/~seander/bithacks.html#Interleave64bitOps + // but we modify it slightly: no need for the 0x5555 mask (==0b0101010101010101) + // or the y-part - we instead just set all odd bits to 1s. + uint16_t r = ( + (a[i] * 0x0101010101010101ULL & 0x8040201008040201ULL) + * 0x0102040810204081ULL >> 49 + ) | 0xAAAAU/* = 0b1010'1010'1010'1010 */; + // now r might just need clipping + if (sub_len < 8) { + uint16_t mask = 0xFFFFffffU << (2 * (8 - sub_len)); + r &= mask; + } buf[(ssize_t)2*i] = r / 256; buf[(ssize_t)2*i + 1] = r % 256; } |