LUCENE-7738: Fix min/max verification bug in InetAddressRange to correctly compare IPv4 and IPv6. Update tests.

This commit is contained in:
Nicholas Knize 2017-04-05 11:10:15 -05:00
parent cb9f151db4
commit ef8126e5ea
2 changed files with 50 additions and 64 deletions

View File

@ -68,9 +68,6 @@ public class InetAddressRange extends Field {
* @param max range max value; defined as an {@code InetAddress}
*/
public void setRangeValues(InetAddress min, InetAddress max) {
if (StringHelper.compare(BYTES, min.getAddress(), 0, max.getAddress(), 0) > 0) {
throw new IllegalArgumentException("min value cannot be greater than max value for range field (name=" + name + ")");
}
final byte[] bytes;
if (fieldsData == null) {
bytes = new byte[BYTES*2];
@ -83,8 +80,15 @@ public class InetAddressRange extends Field {
/** encode the min/max range into the provided byte array */
private static void encode(final InetAddress min, final InetAddress max, final byte[] bytes) {
System.arraycopy(InetAddressPoint.encode(min), 0, bytes, 0, BYTES);
System.arraycopy(InetAddressPoint.encode(max), 0, bytes, BYTES, BYTES);
// encode min and max value (consistent w/ InetAddressPoint encoding)
final byte[] minEncoded = InetAddressPoint.encode(min);
final byte[] maxEncoded = InetAddressPoint.encode(max);
// ensure min is lt max
if (StringHelper.compare(BYTES, minEncoded, 0, maxEncoded, 0) > 0) {
throw new IllegalArgumentException("min value cannot be greater than max value for InetAddressRange field");
}
System.arraycopy(minEncoded, 0, bytes, 0, BYTES);
System.arraycopy(maxEncoded, 0, bytes, BYTES, BYTES);
}
/** encode the min/max range and return the byte array */

View File

@ -19,6 +19,7 @@ package org.apache.lucene.search;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.lucene.document.InetAddressPoint;
import org.apache.lucene.document.InetAddressRange;
import org.apache.lucene.util.StringHelper;
@ -28,16 +29,12 @@ import org.apache.lucene.util.StringHelper;
public class TestInetAddressRangeQueries extends BaseRangeFieldQueryTestCase {
private static final String FIELD_NAME = "ipRangeField";
private IPVersion ipVersion;
private enum IPVersion {IPv4, IPv6}
@Override
protected Range nextRange(int dimensions) throws Exception {
InetAddress min = nextInetaddress();
byte[] bMin = min.getAddress();
byte[] bMin = InetAddressPoint.encode(min);
InetAddress max = nextInetaddress();
byte[] bMax = max.getAddress();
byte[] bMax = InetAddressPoint.encode(max);
if (StringHelper.compare(bMin.length, bMin, 0, bMax, 0) > 0) {
return new IpRange(max, min);
}
@ -46,89 +43,74 @@ public class TestInetAddressRangeQueries extends BaseRangeFieldQueryTestCase {
/** return random IPv4 or IPv6 address */
private InetAddress nextInetaddress() throws UnknownHostException {
byte[] b;
switch (ipVersion) {
case IPv4:
b = new byte[4];
break;
case IPv6:
b = new byte[16];
break;
default:
throw new IllegalArgumentException("incorrect IP version: " + ipVersion);
}
byte[] b = random().nextBoolean() ? new byte[4] : new byte[16];
random().nextBytes(b);
return InetAddress.getByAddress(b);
}
/** randomly select version across tests */
private IPVersion ipVersion() {
return random().nextBoolean() ? IPVersion.IPv4 : IPVersion.IPv6;
}
@Override
public void testRandomTiny() throws Exception {
ipVersion = ipVersion();
super.testRandomTiny();
}
@Override
public void testMultiValued() throws Exception {
ipVersion = ipVersion();
super.testRandomMedium();
}
@Override
public void testRandomMedium() throws Exception {
ipVersion = ipVersion();
super.testMultiValued();
}
@Nightly
@Override
public void testRandomBig() throws Exception {
ipVersion = ipVersion();
super.testRandomBig();
}
/** return random range */
@Override
protected InetAddressRange newRangeField(Range r) {
return new InetAddressRange(FIELD_NAME, ((IpRange)r).min, ((IpRange)r).max);
return new InetAddressRange(FIELD_NAME, ((IpRange)r).minAddress, ((IpRange)r).maxAddress);
}
/** return random intersects query */
@Override
protected Query newIntersectsQuery(Range r) {
return InetAddressRange.newIntersectsQuery(FIELD_NAME, ((IpRange)r).min, ((IpRange)r).max);
return InetAddressRange.newIntersectsQuery(FIELD_NAME, ((IpRange)r).minAddress, ((IpRange)r).maxAddress);
}
/** return random contains query */
@Override
protected Query newContainsQuery(Range r) {
return InetAddressRange.newContainsQuery(FIELD_NAME, ((IpRange)r).min, ((IpRange)r).max);
return InetAddressRange.newContainsQuery(FIELD_NAME, ((IpRange)r).minAddress, ((IpRange)r).maxAddress);
}
/** return random within query */
@Override
protected Query newWithinQuery(Range r) {
return InetAddressRange.newWithinQuery(FIELD_NAME, ((IpRange)r).min, ((IpRange)r).max);
return InetAddressRange.newWithinQuery(FIELD_NAME, ((IpRange)r).minAddress, ((IpRange)r).maxAddress);
}
/** return random crosses query */
@Override
protected Query newCrossesQuery(Range r) {
return InetAddressRange.newCrossesQuery(FIELD_NAME, ((IpRange)r).min, ((IpRange)r).max);
return InetAddressRange.newCrossesQuery(FIELD_NAME, ((IpRange)r).minAddress, ((IpRange)r).maxAddress);
}
/** encapsulated IpRange for test validation */
private class IpRange extends Range {
InetAddress min;
InetAddress max;
InetAddress minAddress;
InetAddress maxAddress;
byte[] min;
byte[] max;
IpRange(InetAddress min, InetAddress max) {
this.min = min;
this.max = max;
this.minAddress = min;
this.maxAddress = max;
this.min = InetAddressPoint.encode(min);
this.max = InetAddressPoint.encode(max);
}
@Override
@ -138,33 +120,39 @@ public class TestInetAddressRangeQueries extends BaseRangeFieldQueryTestCase {
@Override
protected InetAddress getMin(int dim) {
return min;
return minAddress;
}
@Override
protected void setMin(int dim, Object val) {
byte[] v = ((InetAddress)val).getAddress();
InetAddress v = (InetAddress)val;
byte[] e = InetAddressPoint.encode(v);
if (StringHelper.compare(v.length, min.getAddress(), 0, v, 0) < 0) {
max = (InetAddress)val;
if (StringHelper.compare(e.length, min, 0, e, 0) < 0) {
max = e;
maxAddress = v;
} else {
min = (InetAddress) val;
min = e;
minAddress = v;
}
}
@Override
protected InetAddress getMax(int dim) {
return max;
return maxAddress;
}
@Override
protected void setMax(int dim, Object val) {
byte[] v = ((InetAddress)val).getAddress();
InetAddress v = (InetAddress)val;
byte[] e = InetAddressPoint.encode(v);
if (StringHelper.compare(v.length, max.getAddress(), 0, v, 0) > 0) {
min = (InetAddress)val;
if (StringHelper.compare(e.length, max, 0, e, 0) > 0) {
min = e;
minAddress = v;
} else {
max = (InetAddress) val;
max = e;
maxAddress = v;
}
}
@ -177,37 +165,31 @@ public class TestInetAddressRangeQueries extends BaseRangeFieldQueryTestCase {
@Override
protected boolean isDisjoint(Range o) {
IpRange other = (IpRange)o;
byte[] bMin = min.getAddress();
byte[] bMax = max.getAddress();
return StringHelper.compare(bMin.length, bMin, 0, other.max.getAddress(), 0) > 0 ||
StringHelper.compare(bMax.length, bMax, 0, other.min.getAddress(), 0) < 0;
return StringHelper.compare(min.length, min, 0, other.max, 0) > 0 ||
StringHelper.compare(max.length, max, 0, other.min, 0) < 0;
}
@Override
protected boolean isWithin(Range o) {
IpRange other = (IpRange)o;
byte[] bMin = min.getAddress();
byte[] bMax = max.getAddress();
return StringHelper.compare(bMin.length, bMin, 0, other.min.getAddress(), 0) >= 0 &&
StringHelper.compare(bMax.length, bMax, 0, other.max.getAddress(), 0) <= 0;
return StringHelper.compare(min.length, min, 0, other.min, 0) >= 0 &&
StringHelper.compare(max.length, max, 0, other.max, 0) <= 0;
}
@Override
protected boolean contains(Range o) {
IpRange other = (IpRange)o;
byte[] bMin = min.getAddress();
byte[] bMax = max.getAddress();
return StringHelper.compare(bMin.length, bMin, 0, other.min.getAddress(), 0) <= 0 &&
StringHelper.compare(bMax.length, bMax, 0, other.max.getAddress(), 0) >= 0;
return StringHelper.compare(min.length, min, 0, other.min, 0) <= 0 &&
StringHelper.compare(max.length, max, 0, other.max, 0) >= 0;
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("Box(");
b.append(min.getHostAddress());
b.append(minAddress.getHostAddress());
b.append(" TO ");
b.append(max.getHostAddress());
b.append(maxAddress.getHostAddress());
b.append(")");
return b.toString();
}