From 55e8ff1606d4c4d8f2819fa4eb32b8b459a167f8 Mon Sep 17 00:00:00 2001 From: Sebastian Nagel Date: Tue, 16 Jun 2026 19:11:02 +0200 Subject: [PATCH] NUTCH-3187 - protocol-okhttp: IP address filter fails to compare first byte for /32 resp. /128 CIDRs --- .../apache/nutch/protocol/okhttp/CIDR.java | 38 ++++++++++++++----- .../nutch/protocol/okhttp/IPFilterRules.java | 8 ++-- .../okhttp/TestIPAddressFiltering.java | 29 ++++++++++++-- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/plugin/protocol-okhttp/src/java/org/apache/nutch/protocol/okhttp/CIDR.java b/src/plugin/protocol-okhttp/src/java/org/apache/nutch/protocol/okhttp/CIDR.java index 3add082a81..1d97e67280 100644 --- a/src/plugin/protocol-okhttp/src/java/org/apache/nutch/protocol/okhttp/CIDR.java +++ b/src/plugin/protocol-okhttp/src/java/org/apache/nutch/protocol/okhttp/CIDR.java @@ -27,10 +27,16 @@ * defined by the CIDR. */ public class CIDR { - InetAddress addr; - int mask; - public CIDR(InetAddress address, int mask) { + private final InetAddress addr; + private final int mask; + + public CIDR(InetAddress address, int mask) throws IllegalArgumentException { + int maxMask = address.getAddress().length * 8; + if (mask < 0 || mask > maxMask) { + throw new IllegalArgumentException( + "Invalid CIDR mask /" + mask + " for " + address); + } this.addr = address; this.mask = mask; } @@ -42,16 +48,23 @@ public CIDR(String cidr) throws IllegalArgumentException { ipStr = cidr.substring(0, sep); } addr = InetAddresses.forString(ipStr); + int parsedMask; if (sep > -1) { - mask = Integer.parseInt(cidr.substring(sep + 1)); + parsedMask = Integer.parseInt(cidr.substring(sep + 1)); } else { - mask = addr.getAddress().length * 8; + parsedMask = addr.getAddress().length * 8; } if (cidr.indexOf(':') > -1 && addr.getAddress().length == 4) { // IPv4-mapped IPv6 addresses are automatically converted to IPv4, // need to shift the mask - mask = Math.max(0, mask - 96); + parsedMask = Math.max(0, parsedMask - 96); + } + int maxMask = addr.getAddress().length * 8; + if (parsedMask < 0 || parsedMask > maxMask) { + throw new IllegalArgumentException( + "Invalid CIDR mask /" + parsedMask + " for " + ipStr); } + this.mask = parsedMask; } public boolean contains(InetAddress address) { @@ -63,11 +76,18 @@ public boolean contains(InetAddress address) { } for (int i = 0; i < addr0.length; i++) { int remainingMaskBits = mask - (i * 8); - if (remainingMaskBits <= 0) + if (remainingMaskBits <= 0) { return true; - int m = ~(0xff >> remainingMaskBits); // mask for byte under cursor - if ((addr0[i] & m) != (addr1[i] & m)) + } + /* + * keep the mask within one byte so the shift does not wrap (Java shifts + * mod 32) + */ + int m = remainingMaskBits >= 8 ? 0xff + : (0xff << (8 - remainingMaskBits)) & 0xff; + if ((addr0[i] & m) != (addr1[i] & m)) { return false; + } } return true; } diff --git a/src/plugin/protocol-okhttp/src/java/org/apache/nutch/protocol/okhttp/IPFilterRules.java b/src/plugin/protocol-okhttp/src/java/org/apache/nutch/protocol/okhttp/IPFilterRules.java index 868732fe5e..9352ad74c3 100644 --- a/src/plugin/protocol-okhttp/src/java/org/apache/nutch/protocol/okhttp/IPFilterRules.java +++ b/src/plugin/protocol-okhttp/src/java/org/apache/nutch/protocol/okhttp/IPFilterRules.java @@ -30,7 +30,7 @@ * Optionally limit or block connections to IP address ranges * (localhost/loopback or site-local addresses, subnet ranges given in CIDR * notation, or single IP addresses). - * + * * IP filter rules are built from two Nutch properties: *