Reject IPv6-mapped IPv4 addresses when using the CIDR notation. (#26254)
It introduces ambiguity as to whether the prefix length should be interpreted as a v4 prefix length or a v6 prefix length. See https://issues.apache.org/jira/browse/LUCENE-7920. Closes #26078
This commit is contained in:
parent
262ea9534f
commit
d692ccf261
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.elasticsearch.common.network;
|
||||
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
|
@ -354,4 +356,32 @@ public class InetAddresses {
|
|||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an IP address and its prefix length using the CIDR notation.
|
||||
* @throws IllegalArgumentException if the string is not formatted as {@code ip_address/prefix_length}
|
||||
* @throws IllegalArgumentException if the IP address is an IPv6-mapped ipv4 address
|
||||
* @throws IllegalArgumentException if the prefix length is not in 0-32 for IPv4 addresses and 0-128 for IPv6 addresses
|
||||
* @throws NumberFormatException if the prefix length is not an integer
|
||||
*/
|
||||
public static Tuple<InetAddress, Integer> parseCidr(String maskedAddress) {
|
||||
String[] fields = maskedAddress.split("/");
|
||||
if (fields.length == 2) {
|
||||
final String addressString = fields[0];
|
||||
final InetAddress address = forString(addressString);
|
||||
if (addressString.contains(":") && address.getAddress().length == 4) {
|
||||
throw new IllegalArgumentException("CIDR notation is not allowed with IPv6-mapped IPv4 address [" + addressString +
|
||||
" as it introduces ambiguity as to whether the prefix length should be interpreted as a v4 prefix length or a" +
|
||||
" v6 prefix length");
|
||||
}
|
||||
final int prefixLength = Integer.parseInt(fields[1]);
|
||||
if (prefixLength < 0 || prefixLength > 8 * address.getAddress().length) {
|
||||
throw new IllegalArgumentException("Illegal prefix length [" + prefixLength + "] in [" + maskedAddress +
|
||||
"]. Must be 0-32 for IPv4 ranges, 0-128 for IPv6 ranges");
|
||||
}
|
||||
return new Tuple<>(address, prefixLength);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expected [ip/prefix] but was [" + maskedAddress + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.apache.lucene.util.ArrayUtil;
|
|||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.Explicit;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.network.InetAddresses;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -163,14 +164,8 @@ public class IpFieldMapper extends FieldMapper {
|
|||
}
|
||||
String term = value.toString();
|
||||
if (term.contains("/")) {
|
||||
String[] fields = term.split("/");
|
||||
if (fields.length == 2) {
|
||||
InetAddress address = InetAddresses.forString(fields[0]);
|
||||
int prefixLength = Integer.parseInt(fields[1]);
|
||||
return InetAddressPoint.newPrefixQuery(name(), address, prefixLength);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expected [ip/prefix] but was [" + term + "]");
|
||||
}
|
||||
final Tuple<InetAddress, Integer> cidr = InetAddresses.parseCidr(term);
|
||||
return InetAddressPoint.newPrefixQuery(name(), cidr.v1(), cidr.v2());
|
||||
}
|
||||
InetAddress address = InetAddresses.forString(term);
|
||||
return InetAddressPoint.newExactQuery(name(), address);
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.apache.lucene.document.InetAddressPoint;
|
|||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.network.InetAddresses;
|
||||
|
@ -127,21 +128,12 @@ public final class IpRangeAggregationBuilder
|
|||
}
|
||||
|
||||
Range(String key, String mask) {
|
||||
String[] splits = mask.split("/");
|
||||
if (splits.length != 2) {
|
||||
throw new IllegalArgumentException("Expected [ip/prefix_length] but got [" + mask
|
||||
+ "], which contains zero or more than one [/]");
|
||||
}
|
||||
InetAddress value = InetAddresses.forString(splits[0]);
|
||||
int prefixLength = Integer.parseInt(splits[1]);
|
||||
// copied from InetAddressPoint.newPrefixQuery
|
||||
if (prefixLength < 0 || prefixLength > 8 * value.getAddress().length) {
|
||||
throw new IllegalArgumentException("illegal prefixLength [" + prefixLength
|
||||
+ "] in [" + mask + "]. Must be 0-32 for IPv4 ranges, 0-128 for IPv6 ranges");
|
||||
}
|
||||
final Tuple<InetAddress, Integer> cidr = InetAddresses.parseCidr(mask);
|
||||
final InetAddress address = cidr.v1();
|
||||
final int prefixLength = cidr.v2();
|
||||
// create the lower value by zeroing out the host portion, upper value by filling it with all ones.
|
||||
byte lower[] = value.getAddress();
|
||||
byte upper[] = value.getAddress();
|
||||
byte lower[] = address.getAddress();
|
||||
byte upper[] = address.getAddress();
|
||||
for (int i = prefixLength; i < 8 * lower.length; i++) {
|
||||
int m = 1 << (7 - (i & 7));
|
||||
lower[i >> 3] &= ~m;
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package org.elasticsearch.common.network;
|
||||
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.hamcrest.Matchers;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
@ -214,4 +216,34 @@ public class InetAddressesTests extends ESTestCase {
|
|||
InetAddress ip = InetAddresses.forString(ipStr);
|
||||
assertEquals("[3ffe::1]", InetAddresses.toUriString(ip));
|
||||
}
|
||||
|
||||
public void testParseCidr() {
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> InetAddresses.parseCidr(""));
|
||||
assertThat(e.getMessage(), Matchers.containsString("Expected [ip/prefix] but was []"));
|
||||
|
||||
e = expectThrows(IllegalArgumentException.class, () -> InetAddresses.parseCidr("192.168.1.42/33"));
|
||||
assertThat(e.getMessage(), Matchers.containsString("Illegal prefix length"));
|
||||
|
||||
e = expectThrows(IllegalArgumentException.class, () -> InetAddresses.parseCidr("::1/129"));
|
||||
assertThat(e.getMessage(), Matchers.containsString("Illegal prefix length"));
|
||||
|
||||
e = expectThrows(IllegalArgumentException.class, () -> InetAddresses.parseCidr("::ffff:0:0/96"));
|
||||
assertThat(e.getMessage(), Matchers.containsString("CIDR notation is not allowed with IPv6-mapped IPv4 address"));
|
||||
|
||||
Tuple<InetAddress, Integer> cidr = InetAddresses.parseCidr("192.168.0.0/24");
|
||||
assertEquals(InetAddresses.forString("192.168.0.0"), cidr.v1());
|
||||
assertEquals(Integer.valueOf(24), cidr.v2());
|
||||
|
||||
cidr = InetAddresses.parseCidr("::fffe:0:0/95");
|
||||
assertEquals(InetAddresses.forString("::fffe:0:0"), cidr.v1());
|
||||
assertEquals(Integer.valueOf(95), cidr.v2());
|
||||
|
||||
cidr = InetAddresses.parseCidr("192.168.0.0/32");
|
||||
assertEquals(InetAddresses.forString("192.168.0.0"), cidr.v1());
|
||||
assertEquals(Integer.valueOf(32), cidr.v2());
|
||||
|
||||
cidr = InetAddresses.parseCidr("::fffe:0:0/128");
|
||||
assertEquals(InetAddresses.forString("::fffe:0:0"), cidr.v1());
|
||||
assertEquals(Integer.valueOf(128), cidr.v2());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue