diff --git a/libcfnet/addr_lib.c b/libcfnet/addr_lib.c index c3c5c33871..2d4dec60f3 100644 --- a/libcfnet/addr_lib.c +++ b/libcfnet/addr_lib.c @@ -224,7 +224,6 @@ int FuzzySetMatch(const char *s1, const char *s2) if (isCIDR) { - int blocks; struct sockaddr_in6 addr1 = {0}; struct sockaddr_in6 addr2 = {0}; unsigned long mask; @@ -236,26 +235,38 @@ int FuzzySetMatch(const char *s1, const char *s2) Log(LOG_LEVEL_ERR, "Invalid IPv6 CIDR: %s", s1); return -1; } - blocks = mask / 8; + int blocks = mask / 8; + int remaining_bits = mask % 8; - if (mask % 8 != 0) + addr1.sin6_family = AF_INET6; + if (inet_pton(AF_INET6, address, &addr1.sin6_addr) != 1) { - Log(LOG_LEVEL_ERR, "Cannot handle ipv6 masks which are not 8 bit multiples (fix me)"); return -1; } - - addr1.sin6_family = AF_INET6; - inet_pton(AF_INET6, address, &addr1.sin6_addr); addr2.sin6_family = AF_INET6; - inet_pton(AF_INET6, s2, &addr2.sin6_addr); + if (inet_pton(AF_INET6, s2, &addr2.sin6_addr) != 1) + { + return -1; + } - for (i = 0; i < blocks; i++) /* blocks < 16 */ + for (i = 0; i < blocks; i++) { if (addr1.sin6_addr.s6_addr[i] != addr2.sin6_addr.s6_addr[i]) { return -1; } } + + if (remaining_bits > 0) + { + uint8_t bitmask = (uint8_t)(0xFF << (8 - remaining_bits)); + + if ((addr1.sin6_addr.s6_addr[blocks] & bitmask) != + (addr2.sin6_addr.s6_addr[blocks] & bitmask)) + { + return -1; + } + } return 0; } else @@ -530,12 +541,6 @@ bool FuzzyMatchParse(const char *s) mask = 0; sscanf(s, "%40[^/]/%d", address, &mask); - if (mask % 8 != 0) - { - Log(LOG_LEVEL_ERR, "Cannot handle ipv6 masks which are not 8 bit multiples (fix me)"); - return false; - } - if (mask > 15) { Log(LOG_LEVEL_ERR, "IPv6 CIDR mask is too large"); diff --git a/tests/acceptance/02_classes/02_functions/isipinsubnet_mask.cf b/tests/acceptance/02_classes/02_functions/isipinsubnet_mask.cf new file mode 100644 index 0000000000..bccd6ab0f0 --- /dev/null +++ b/tests/acceptance/02_classes/02_functions/isipinsubnet_mask.cf @@ -0,0 +1,27 @@ +####################################################### +# +# Test isipinsubnet() +# +####################################################### +body common control +{ + bundlesequence => { "check" }; + version => "1.0"; +} + +####################################################### +bundle agent check +{ + classes: + "ok" + expression => isipinsubnet( + "2001:700:100::/41", "2001:0700:0100:0000:0000:0000:0000:0000" + ); + + reports: + ok:: + "$(this.promise_filename) Pass"; + + !ok:: + "$(this.promise_filename) FAIL"; +}