IPAddress
IPAddress copied to clipboard
Exception thrown if trying to join all IPv4 and all IPv6 addresses
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);
}
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;
}
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.
Hey @seancfoley, any news on this?
@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.
Took a bit longer than a month. This was fixed in version 5.4.0. Closing.