IPAddress icon indicating copy to clipboard operation
IPAddress copied to clipboard

Exception thrown if trying to join all IPv4 and all IPv6 addresses

Open dbardbar opened this issue 2 years ago • 2 comments

I'm ipaddress version 5.3.4 on Java 8.

My use-case is that I have multiple ranges of IPs, both IPv4 and IPv6 (possibly with various overlaps), and I want to compact them all, and later do a binary search on the sorted array given by IPAddressSeqRange.join() to quickly check if a given IP (v4 or v6) is in any of those ranges. join() seems to work fine with a mix of IPv4 and IPv6, but I encountered one annoying edge case where the ranges span all possible v4 and v6 addresses.

I have not encountered problems when trying to join full IPv4 range with additional ranges. As far as I can see this is the only problematic edge case.

I get an exception of

1, IP Address error: exceeds address size inet.ipaddr.AddressValueException: 1, IP Address error: exceeds address size at inet.ipaddr.format.standard.AddressDivisionGrouping.checkOverflow(AddressDivisionGrouping.java:1204) at inet.ipaddr.ipv4.IPv4AddressSection.increment(IPv4AddressSection.java:1209) at inet.ipaddr.ipv4.IPv4Address.increment(IPv4Address.java:717) at inet.ipaddr.ipv4.IPv4Address.increment(IPv4Address.java:70) at inet.ipaddr.IPAddressSeqRange.join(IPAddressSeqRange.java:668)

Provided is a test case that causes the exception

@Test
void bugExample() {
	IPAddress minIpv4 = new IPAddressString("0.0.0.0").getAddress();
	IPAddress maxIpv4 = new IPAddressString("255.255.255.255").getAddress();
	IPAddress minIpv6 = new IPAddressString("0::0").getAddress();
	IPAddress maxIpv6 = new IPAddressString("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").getAddress();
	IPAddressSeqRange allIpv4 = minIpv4.spanWithRange(maxIpv4);
	IPAddressSeqRange allIpv6 = minIpv6.spanWithRange(maxIpv6);
	IPAddressSeqRange.join(allIpv4, allIpv6);
}

dbardbar avatar May 29 '22 06:05 dbardbar

Yes, this is a bug. Thanks for providing the test case. The issue will happen when joining both IPv4 and IPv6 ranges, and one of the IPv4 ranges includes the address 255.255.255.255.

I will have this fixed in a maintenance release soon. In the meantime, you could use the following work-around which is almost as efficient as the original:

static IPAddressSeqRange[] workAroundJoin(IPAddressSeqRange... ranges) {
	boolean useWorkAround = false;
	boolean hasMaxIPv4 = false;
	boolean hasIPv6 = false;
	for(IPAddressSeqRange rng : ranges) {
		if(rng == null) {
			continue;
		}
		IPAddress upper = rng.getUpper();
		hasMaxIPv4 = hasMaxIPv4 || (upper.isIPv4() && upper.includesMax());
		hasIPv6 = hasIPv6 || upper.isIPv6();
		useWorkAround = hasMaxIPv4 && hasIPv6;
		if(useWorkAround) {
			break;
		}
	}
	if(!useWorkAround) {
		// joining the ranges will not throw
		return IPAddressSeqRange.join(ranges);
	}
	// joining the ranges will throw, use work-around
	IPAddressSeqRange ranges1[] = new IPAddressSeqRange[ranges.length];
	IPAddressSeqRange ranges2[] = new IPAddressSeqRange[ranges.length];
	int i1 = 0, i2 = 0;
	for(IPAddressSeqRange rng : ranges) {
		if(rng == null) {
			continue;
		} else if(rng.getLower().isIPv4()) {
			ranges1[i1++] = rng;
		} else {
			ranges2[i2++] = rng;
		}
	}
	ranges1 = IPAddressSeqRange.join(ranges1);
	ranges2 = IPAddressSeqRange.join(ranges2);
	IPAddressSeqRange ranges3[] = new IPAddressSeqRange[ranges1.length + ranges2.length];
	System.arraycopy(ranges1, 0, ranges3, 0, ranges1.length);
	System.arraycopy(ranges2, 0, ranges3, ranges1.length, ranges2.length);
	return ranges3;
}

seancfoley avatar May 29 '22 17:05 seancfoley

Thanks for prompt response. I did the same workaround. Separated the ranges by family, join()-ed each one, and then combined the two resulting arrays.

dbardbar avatar May 29 '22 17:05 dbardbar

Hey @seancfoley, any news on this?

dbardbar avatar Nov 01 '22 05:11 dbardbar

@dbardbar I have not yet released the next maintenance release, but it is certainly time to do so, so I should get to it within a month.

seancfoley avatar Nov 01 '22 18:11 seancfoley

Took a bit longer than a month. This was fixed in version 5.4.0. Closing.

seancfoley avatar Dec 15 '22 14:12 seancfoley