mirror of https://github.com/apache/druid.git
Add IPAddress java library as dependency and migrate IPv4 functions to use the new library. (#11634)
* Add ipaddress library as dependency. * IPv4 functions to use the inet.ipaddr package. * Remove unused imports. * Add new function. * Minor rename. * Add more unit tests. * IPv4 address expr utils unit tests and address options. * Adjust the IPv4Util functions. * Move the UTs a bit around. * Javadoc comments. * Add license info for IPAddress. * Fix groupId, artifact and version in license.yaml. * Remove redundant subnet in messages - fixes UT. * Remove unused commons-net dependency for /processing project. * Make class and methods public so it can be accessed. * Add initial version of benchmark * Add subnetutils package for benchmarks. * Auto generate ip addresses. * Add more v4 address representations in setup to avoid bias. * Use ThreadLocalRandom to avoid forbidden API usage. * Adjust IPv4AddressBenchmark to adhere to codestyle rules. * Update ipaddress library to latest 5.3.4 * Add ipaddress package dependency to benchmarks project.
This commit is contained in:
parent
9e5a940cf1
commit
9177515be2
|
@ -37,6 +37,10 @@
|
|||
<version>${jmh.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
<artifactId>commons-net</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
|
@ -174,7 +178,11 @@
|
|||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.seancfoley</groupId>
|
||||
<artifactId>ipaddress</artifactId>
|
||||
<version>5.3.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.druid.benchmark;
|
||||
|
||||
import com.google.common.net.InetAddresses;
|
||||
import inet.ipaddr.IPAddress;
|
||||
import inet.ipaddr.IPAddressString;
|
||||
import inet.ipaddr.ipv4.IPv4Address;
|
||||
import org.apache.commons.net.util.SubnetUtils;
|
||||
import org.apache.druid.java.util.common.IAE;
|
||||
import org.apache.druid.query.expression.ExprUtils;
|
||||
import org.apache.druid.query.expression.IPv4AddressExprUtils;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Param;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.runner.Runner;
|
||||
import org.openjdk.jmh.runner.RunnerException;
|
||||
import org.openjdk.jmh.runner.options.Options;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@Fork(value = 1)
|
||||
@Warmup(iterations = 5)
|
||||
@Measurement(iterations = 5)
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public class IPv4AddressBenchmark
|
||||
{
|
||||
private static final Pattern IPV4_PATTERN = Pattern.compile(
|
||||
"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
|
||||
);
|
||||
// Different representations of IPv4 addresses.
|
||||
private static List<String> IPV4_ADDRESS_STRS;
|
||||
private static List<IPv4Address> IPV4_ADDRESSES;
|
||||
private static List<Inet4Address> INET4_ADDRESSES;
|
||||
private static List<Long> IPV4_ADDRESS_LONGS;
|
||||
private static List<String> IPV4_SUBNETS;
|
||||
@Param({"10", "100", "1000"})
|
||||
public int numOfAddresses;
|
||||
|
||||
static boolean isValidAddress(String string)
|
||||
{
|
||||
return string != null && IPV4_PATTERN.matcher(string).matches();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws RunnerException
|
||||
{
|
||||
Options opt = new OptionsBuilder()
|
||||
.include(IPv4AddressBenchmark.class.getSimpleName())
|
||||
.forks(1)
|
||||
.build();
|
||||
new Runner(opt).run();
|
||||
}
|
||||
|
||||
@Setup
|
||||
public void setUp()
|
||||
{
|
||||
IPV4_ADDRESS_STRS = new ArrayList<>(numOfAddresses);
|
||||
IPV4_ADDRESSES = new ArrayList<>(numOfAddresses);
|
||||
INET4_ADDRESSES = new ArrayList<>(numOfAddresses);
|
||||
IPV4_SUBNETS = new ArrayList<>(numOfAddresses);
|
||||
IPV4_ADDRESS_LONGS = new ArrayList<>(numOfAddresses);
|
||||
|
||||
for (int i = 0; i < numOfAddresses; i++) {
|
||||
Random r = ThreadLocalRandom.current();
|
||||
String genIpAddress = r.nextInt(256) + "." + r.nextInt(256) + "." + r.nextInt(256) + "." + r.nextInt(256);
|
||||
IPAddressString ipAddressString = new IPAddressString(genIpAddress);
|
||||
IPAddress prefixBlock = ipAddressString.getAddress().applyPrefixLength(r.nextInt(32)).toPrefixBlock();
|
||||
IPV4_ADDRESS_STRS.add(ipAddressString.toString());
|
||||
IPV4_SUBNETS.add(prefixBlock.toString());
|
||||
|
||||
IPv4Address iPv4Address = ipAddressString.getAddress().toIPv4();
|
||||
|
||||
IPV4_ADDRESSES.add(iPv4Address);
|
||||
INET4_ADDRESSES.add(iPv4Address.toInetAddress());
|
||||
IPV4_ADDRESS_LONGS.add(iPv4Address.longValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void stringContainsUsingIpAddr()
|
||||
{
|
||||
for (int i = 0; i < IPV4_ADDRESS_STRS.size(); i++) {
|
||||
String v4Subnet = IPV4_SUBNETS.get(i);
|
||||
String v4Address = IPV4_ADDRESS_STRS.get(i);
|
||||
|
||||
IPAddressString subnetString = new IPAddressString(v4Subnet);
|
||||
IPv4Address iPv4Address = IPv4AddressExprUtils.parse(v4Address);
|
||||
if (iPv4Address != null) {
|
||||
subnetString.contains(iPv4Address.toAddressString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void stringContainsUsingSubnetUtils() throws IAE
|
||||
{
|
||||
for (int i = 0; i < IPV4_ADDRESS_STRS.size(); i++) {
|
||||
String v4Subnet = IPV4_SUBNETS.get(i);
|
||||
String v4Address = IPV4_ADDRESS_STRS.get(i);
|
||||
|
||||
SubnetUtils.SubnetInfo subnetInfo = getSubnetInfo(v4Subnet);
|
||||
if (isValidAddress(v4Address)) {
|
||||
subnetInfo.isInRange(v4Address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void parseLongUsingIpAddr()
|
||||
{
|
||||
for (Long v4Address : IPV4_ADDRESS_LONGS) {
|
||||
IPv4AddressExprUtils.parse(v4Address);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Inet4Address parseUsingSubnetUtils(long longValue)
|
||||
{
|
||||
if (IPv4AddressExprUtils.overflowsUnsignedInt(longValue)) {
|
||||
return InetAddresses.fromInteger((int) longValue);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void parseLongUsingSubnetUtils()
|
||||
{
|
||||
for (Long v4Address : IPV4_ADDRESS_LONGS) {
|
||||
parseUsingSubnetUtils(v4Address);
|
||||
}
|
||||
}
|
||||
|
||||
private long toLongUsingSubnetUtils(Inet4Address address)
|
||||
{
|
||||
int value = InetAddresses.coerceToInteger(address);
|
||||
return Integer.toUnsignedLong(value);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void toLongUsingSubnetUtils()
|
||||
{
|
||||
for (Inet4Address v4InetAddress : INET4_ADDRESSES) {
|
||||
toLongUsingSubnetUtils(v4InetAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void toLongUsingIpAddr()
|
||||
{
|
||||
for (IPv4Address v4Address : IPV4_ADDRESSES) {
|
||||
IPv4AddressExprUtils.toLong(v4Address);
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void longContainsUsingSubnetUtils()
|
||||
{
|
||||
for (int i = 0; i < IPV4_ADDRESS_LONGS.size(); i++) {
|
||||
long v4Long = IPV4_ADDRESS_LONGS.get(i);
|
||||
String v4Subnet = IPV4_SUBNETS.get(i);
|
||||
SubnetUtils.SubnetInfo subnetInfo = getSubnetInfo(v4Subnet);
|
||||
|
||||
if (!IPv4AddressExprUtils.overflowsUnsignedInt(v4Long)) {
|
||||
subnetInfo.isInRange((int) v4Long);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void longContainsUsingIpAddr()
|
||||
{
|
||||
for (int i = 0; i < IPV4_ADDRESS_LONGS.size(); i++) {
|
||||
long v4Long = IPV4_ADDRESS_LONGS.get(i);
|
||||
String v4Subnet = IPV4_SUBNETS.get(i);
|
||||
|
||||
IPv4Address iPv4Address = IPv4AddressExprUtils.parse(v4Long);
|
||||
IPAddressString subnetString = new IPAddressString(v4Subnet);
|
||||
if (iPv4Address != null) {
|
||||
subnetString.contains(iPv4Address.toAddressString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void parseStringUsingIpAddr()
|
||||
{
|
||||
for (String ipv4Addr : IPV4_ADDRESS_STRS) {
|
||||
IPv4AddressExprUtils.parse(ipv4Addr);
|
||||
}
|
||||
}
|
||||
|
||||
private Inet4Address parseUsingSubnetUtils(String string)
|
||||
{
|
||||
if (isValidAddress(string)) {
|
||||
InetAddress address = InetAddresses.forString(string);
|
||||
if (address instanceof Inet4Address) {
|
||||
return (Inet4Address) address;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
public void parseStringUsingSubnetUtils()
|
||||
{
|
||||
for (String ipv4Addr : IPV4_ADDRESS_STRS) {
|
||||
parseUsingSubnetUtils(ipv4Addr);
|
||||
}
|
||||
}
|
||||
|
||||
private SubnetUtils.SubnetInfo getSubnetInfo(String subnet)
|
||||
{
|
||||
SubnetUtils subnetUtils;
|
||||
try {
|
||||
subnetUtils = new SubnetUtils(subnet);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new IAE(e, ExprUtils.createErrMsg("getSubnetInfo()", " arg has an invalid format: " + subnet));
|
||||
}
|
||||
subnetUtils.setInclusiveHostCount(true); // make network and broadcast addresses match
|
||||
return subnetUtils.getInfo();
|
||||
}
|
||||
}
|
|
@ -596,6 +596,16 @@ libraries:
|
|||
|
||||
---
|
||||
|
||||
name: IPAddress
|
||||
license_category: binary
|
||||
module: java-core
|
||||
license_name: Apache License version 2.0
|
||||
version: 5.3.4
|
||||
libraries:
|
||||
- com.github.seancfoley: ipaddress
|
||||
|
||||
---
|
||||
|
||||
name: Apache Commons Collections
|
||||
license_category: binary
|
||||
module: java-core
|
||||
|
|
5
pom.xml
5
pom.xml
|
@ -246,6 +246,11 @@
|
|||
<artifactId>commons-net</artifactId>
|
||||
<version>3.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.seancfoley</groupId>
|
||||
<artifactId>ipaddress</artifactId>
|
||||
<version>5.3.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
|
|
|
@ -96,8 +96,9 @@
|
|||
<artifactId>commons-math3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
<artifactId>commons-net</artifactId>
|
||||
<groupId>com.github.seancfoley</groupId>
|
||||
<artifactId>ipaddress</artifactId>
|
||||
<version>5.3.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
|
|
|
@ -19,66 +19,81 @@
|
|||
|
||||
package org.apache.druid.query.expression;
|
||||
|
||||
import com.google.common.net.InetAddresses;
|
||||
import inet.ipaddr.IPAddressString;
|
||||
import inet.ipaddr.IPAddressStringParameters;
|
||||
import inet.ipaddr.ipv4.IPv4Address;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
class IPv4AddressExprUtils
|
||||
public class IPv4AddressExprUtils
|
||||
{
|
||||
private static final Pattern IPV4_PATTERN = Pattern.compile(
|
||||
"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
|
||||
);
|
||||
|
||||
private static final IPAddressStringParameters IPV4_ADDRESS_PARAMS = new IPAddressStringParameters.Builder().allowSingleSegment(false).allow_inet_aton(false).allowIPv6(false).allowPrefix(false).allowEmpty(false).toParams();
|
||||
private static final IPAddressStringParameters IPV4_SUBNET_PARAMS = new IPAddressStringParameters.Builder().allowSingleSegment(false).allow_inet_aton(false).allowEmpty(false).allowIPv6(false).toParams();
|
||||
|
||||
/**
|
||||
* @return True if argument cannot be represented by an unsigned integer (4 bytes), else false
|
||||
*/
|
||||
static boolean overflowsUnsignedInt(long value)
|
||||
public static boolean overflowsUnsignedInt(long value)
|
||||
{
|
||||
return value < 0L || 0xff_ff_ff_ffL < value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if argument is a valid IPv4 address dotted-decimal string
|
||||
* @return True if argument is a valid IPv4 address dotted-decimal string. Single segments, Inet addresses and subnets are not allowed.
|
||||
*/
|
||||
static boolean isValidAddress(@Nullable String string)
|
||||
static boolean isValidIPv4Address(@Nullable String addressString)
|
||||
{
|
||||
return string != null && IPV4_PATTERN.matcher(string).matches();
|
||||
return addressString != null && new IPAddressString(addressString, IPV4_ADDRESS_PARAMS).isIPv4();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Inet4Address parse(@Nullable String string)
|
||||
/**
|
||||
* @return True if argument is a valid IPv4 subnet address.
|
||||
*/
|
||||
static boolean isValidIPv4Subnet(@Nullable String subnetString)
|
||||
{
|
||||
// Explicitly check for valid address to avoid overhead of InetAddresses#forString() potentially
|
||||
// throwing IllegalArgumentException
|
||||
if (isValidAddress(string)) {
|
||||
// Do not use java.lang.InetAddress#getByName() as it may do DNS lookups
|
||||
InetAddress address = InetAddresses.forString(string);
|
||||
if (address instanceof Inet4Address) {
|
||||
return (Inet4Address) address;
|
||||
}
|
||||
return subnetString != null && new IPAddressString(subnetString, IPV4_SUBNET_PARAMS).isPrefixed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IPv4 address if the supplied string is a valid dotted-decimal IPv4 Address string.
|
||||
*/
|
||||
@Nullable
|
||||
public static IPv4Address parse(@Nullable String string)
|
||||
{
|
||||
IPAddressString ipAddressString = new IPAddressString(string, IPV4_ADDRESS_PARAMS);
|
||||
if (ipAddressString.isIPv4()) {
|
||||
return ipAddressString.getAddress().toIPv4();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Inet4Address parse(int value)
|
||||
/**
|
||||
* @return IPv4 address if the supplied integer is a valid IPv4 integer number.
|
||||
*/
|
||||
@Nullable
|
||||
public static IPv4Address parse(long value)
|
||||
{
|
||||
return InetAddresses.fromInteger(value);
|
||||
if (!overflowsUnsignedInt(value)) {
|
||||
return new IPv4Address((int) value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IPv4 address dotted-decimal notated string
|
||||
* @return IPv4 address dotted-decimal canonical string.
|
||||
*/
|
||||
static String toString(Inet4Address address)
|
||||
public static String toString(IPv4Address address)
|
||||
{
|
||||
return address.getHostAddress();
|
||||
return address.toString();
|
||||
}
|
||||
|
||||
static long toLong(Inet4Address address)
|
||||
/**
|
||||
*
|
||||
* @return IPv4 address as an integer.
|
||||
*/
|
||||
public static long toLong(IPv4Address address)
|
||||
{
|
||||
int value = InetAddresses.coerceToInteger(address);
|
||||
return Integer.toUnsignedLong(value);
|
||||
return address.longValue();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
|
||||
package org.apache.druid.query.expression;
|
||||
|
||||
import org.apache.commons.net.util.SubnetUtils;
|
||||
import inet.ipaddr.IPAddressString;
|
||||
import inet.ipaddr.ipv4.IPv4Address;
|
||||
import org.apache.druid.java.util.common.IAE;
|
||||
import org.apache.druid.java.util.common.StringUtils;
|
||||
import org.apache.druid.math.expr.Expr;
|
||||
|
@ -70,17 +71,17 @@ public class IPv4AddressMatchExprMacro implements ExprMacroTable.ExprMacro
|
|||
throw new IAE(ExprUtils.createErrMsg(name(), "must have 2 arguments"));
|
||||
}
|
||||
|
||||
SubnetUtils.SubnetInfo subnetInfo = getSubnetInfo(args);
|
||||
IPAddressString subnetInfo = getSubnetInfo(args);
|
||||
Expr arg = args.get(0);
|
||||
|
||||
class IPv4AddressMatchExpr extends ExprMacroTable.BaseScalarUnivariateMacroFunctionExpr
|
||||
{
|
||||
private final SubnetUtils.SubnetInfo subnetInfo;
|
||||
private final IPAddressString subnetString;
|
||||
|
||||
private IPv4AddressMatchExpr(Expr arg, SubnetUtils.SubnetInfo subnetInfo)
|
||||
private IPv4AddressMatchExpr(Expr arg, IPAddressString subnetString)
|
||||
{
|
||||
super(FN_NAME, arg);
|
||||
this.subnetInfo = subnetInfo;
|
||||
this.subnetString = subnetString;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
@ -104,12 +105,14 @@ public class IPv4AddressMatchExprMacro implements ExprMacroTable.ExprMacro
|
|||
|
||||
private boolean isStringMatch(String stringValue)
|
||||
{
|
||||
return IPv4AddressExprUtils.isValidAddress(stringValue) && subnetInfo.isInRange(stringValue);
|
||||
IPv4Address iPv4Address = IPv4AddressExprUtils.parse(stringValue);
|
||||
return iPv4Address != null && subnetString.contains(iPv4Address.toAddressString());
|
||||
}
|
||||
|
||||
private boolean isLongMatch(long longValue)
|
||||
{
|
||||
return !IPv4AddressExprUtils.overflowsUnsignedInt(longValue) && subnetInfo.isInRange((int) longValue);
|
||||
IPv4Address iPv4Address = IPv4AddressExprUtils.parse(longValue);
|
||||
return iPv4Address != null && subnetString.contains(iPv4Address.toAddressString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,22 +138,15 @@ public class IPv4AddressMatchExprMacro implements ExprMacroTable.ExprMacro
|
|||
return new IPv4AddressMatchExpr(arg, subnetInfo);
|
||||
}
|
||||
|
||||
private SubnetUtils.SubnetInfo getSubnetInfo(List<Expr> args)
|
||||
private IPAddressString getSubnetInfo(List<Expr> args)
|
||||
{
|
||||
String subnetArgName = "subnet";
|
||||
Expr arg = args.get(ARG_SUBNET);
|
||||
ExprUtils.checkLiteralArgument(name(), arg, subnetArgName);
|
||||
String subnet = (String) arg.getLiteralValue();
|
||||
|
||||
SubnetUtils subnetUtils;
|
||||
try {
|
||||
subnetUtils = new SubnetUtils(subnet);
|
||||
if (!IPv4AddressExprUtils.isValidIPv4Subnet(subnet)) {
|
||||
throw new IAE(ExprUtils.createErrMsg(name(), subnetArgName + " arg has an invalid format: " + subnet));
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new IAE(e, ExprUtils.createErrMsg(name(), subnetArgName + " arg has an invalid format: " + subnet));
|
||||
}
|
||||
subnetUtils.setInclusiveHostCount(true); // make network and broadcast addresses match
|
||||
|
||||
return subnetUtils.getInfo();
|
||||
return new IPAddressString(subnet);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.apache.druid.query.expression;
|
||||
|
||||
import inet.ipaddr.ipv4.IPv4Address;
|
||||
import org.apache.druid.java.util.common.IAE;
|
||||
import org.apache.druid.math.expr.Expr;
|
||||
import org.apache.druid.math.expr.ExprEval;
|
||||
|
@ -27,7 +28,6 @@ import org.apache.druid.math.expr.ExpressionType;
|
|||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.net.Inet4Address;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -107,7 +107,7 @@ public class IPv4AddressParseExprMacro implements ExprMacroTable.ExprMacro
|
|||
|
||||
private static ExprEval evalAsString(ExprEval eval)
|
||||
{
|
||||
Inet4Address address = IPv4AddressExprUtils.parse(eval.asString());
|
||||
IPv4Address address = IPv4AddressExprUtils.parse(eval.asString());
|
||||
Long value = address == null ? null : IPv4AddressExprUtils.toLong(address);
|
||||
return ExprEval.ofLong(value);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.apache.druid.query.expression;
|
||||
|
||||
import inet.ipaddr.ipv4.IPv4Address;
|
||||
import org.apache.druid.java.util.common.IAE;
|
||||
import org.apache.druid.math.expr.Expr;
|
||||
import org.apache.druid.math.expr.ExprEval;
|
||||
|
@ -27,7 +28,6 @@ import org.apache.druid.math.expr.ExpressionType;
|
|||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.net.Inet4Address;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -106,7 +106,7 @@ public class IPv4AddressStringifyExprMacro implements ExprMacroTable.ExprMacro
|
|||
|
||||
private static ExprEval evalAsString(ExprEval eval)
|
||||
{
|
||||
if (IPv4AddressExprUtils.isValidAddress(eval.asString())) {
|
||||
if (IPv4AddressExprUtils.isValidIPv4Address(eval.asString())) {
|
||||
return eval;
|
||||
}
|
||||
return ExprEval.of(null);
|
||||
|
@ -118,12 +118,10 @@ public class IPv4AddressStringifyExprMacro implements ExprMacroTable.ExprMacro
|
|||
return ExprEval.of(null);
|
||||
}
|
||||
|
||||
long longValue = eval.asLong();
|
||||
if (IPv4AddressExprUtils.overflowsUnsignedInt(longValue)) {
|
||||
IPv4Address address = IPv4AddressExprUtils.parse(eval.asLong());
|
||||
if (address == null) {
|
||||
return ExprEval.of(null);
|
||||
}
|
||||
|
||||
Inet4Address address = IPv4AddressExprUtils.parse((int) longValue);
|
||||
return ExprEval.of(IPv4AddressExprUtils.toString(address));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,11 @@
|
|||
|
||||
package org.apache.druid.query.expression;
|
||||
|
||||
import inet.ipaddr.IPAddressNetwork;
|
||||
import inet.ipaddr.ipv4.IPv4Address;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -57,10 +56,26 @@ public class IPv4AddressExprUtilsTest
|
|||
"a.2.3.4", // first octet not number
|
||||
"1.a.3.4", // second octet not number
|
||||
"1.2.c.4", // third octet not number
|
||||
"1.2.3.d" // fourth octet not number
|
||||
"1.2.3.d", // fourth octet not number
|
||||
"1.2.3.0/24" // prefixed cidr
|
||||
);
|
||||
private static final String IPV6_MAPPED = "::ffff:192.168.0.1";
|
||||
private static final String IPV6_COMPATIBLE = "::192.168.0.1";
|
||||
private static final List<String> VALID_IPV4_SUBNETS = Arrays.asList(
|
||||
"1.1.1.0/24",
|
||||
"255.255.255.0/18",
|
||||
"1.2.3.0/21",
|
||||
"1.0.0.0/8"
|
||||
);
|
||||
|
||||
private static final List<String> INVALID_IPV4_SUBNETS = Arrays.asList(
|
||||
"1.2.3.0/45", // subnet mask too large
|
||||
"1.1.1/24", // missing octet
|
||||
"1/24", // missing octets
|
||||
"1", // missing octets
|
||||
"::/23", // IPv6 subnet
|
||||
"1.1.1.1" // no subnet mask
|
||||
);
|
||||
|
||||
@Test
|
||||
public void testOverflowsUnsignedIntTooLow()
|
||||
|
@ -93,39 +108,62 @@ public class IPv4AddressExprUtilsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidAddressNull()
|
||||
public void testIsValidIPv4AddressNull()
|
||||
{
|
||||
Assert.assertFalse(IPv4AddressExprUtils.isValidAddress(null));
|
||||
Assert.assertFalse(IPv4AddressExprUtils.isValidIPv4Address(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidAddressIPv4()
|
||||
public void testIsValidIPv4Address()
|
||||
{
|
||||
for (String address : VALID_IPV4_ADDRESSES) {
|
||||
Assert.assertTrue(getErrMsg(address), IPv4AddressExprUtils.isValidAddress(address));
|
||||
Assert.assertTrue(getErrMsg(address), IPv4AddressExprUtils.isValidIPv4Address(address));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidAddressIPv6Mapped()
|
||||
public void testIsValidIPv4AddressIPv6Mapped()
|
||||
{
|
||||
Assert.assertFalse(IPv4AddressExprUtils.isValidAddress(IPV6_MAPPED));
|
||||
Assert.assertFalse(IPv4AddressExprUtils.isValidIPv4Address(IPV6_MAPPED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidAddressIPv6Compatible()
|
||||
public void testIsValidIPv4AddressIPv6Compatible()
|
||||
{
|
||||
Assert.assertFalse(IPv4AddressExprUtils.isValidAddress(IPV6_COMPATIBLE));
|
||||
Assert.assertFalse(IPv4AddressExprUtils.isValidIPv4Address(IPV6_COMPATIBLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidAddressNotIpAddress()
|
||||
public void testIsValidIPv4AddressNotIpAddress()
|
||||
{
|
||||
for (String address : INVALID_IPV4_ADDRESSES) {
|
||||
Assert.assertFalse(getErrMsg(address), IPv4AddressExprUtils.isValidAddress(address));
|
||||
Assert.assertFalse(getErrMsg(address), IPv4AddressExprUtils.isValidIPv4Address(address));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidSubnetNull()
|
||||
{
|
||||
Assert.assertFalse(IPv4AddressExprUtils.isValidIPv4Subnet(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidIPv4SubnetValid()
|
||||
{
|
||||
for (String address : VALID_IPV4_SUBNETS) {
|
||||
Assert.assertTrue(getErrMsg(address), IPv4AddressExprUtils.isValidIPv4Subnet(address));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidIPv4SubnetInvalid()
|
||||
{
|
||||
for (String address : INVALID_IPV4_SUBNETS) {
|
||||
Assert.assertFalse(getErrMsg(address), IPv4AddressExprUtils.isValidIPv4Subnet(address));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseNull()
|
||||
{
|
||||
|
@ -137,9 +175,9 @@ public class IPv4AddressExprUtilsTest
|
|||
{
|
||||
for (String string : VALID_IPV4_ADDRESSES) {
|
||||
String errMsg = getErrMsg(string);
|
||||
Inet4Address address = IPv4AddressExprUtils.parse(string);
|
||||
IPv4Address address = IPv4AddressExprUtils.parse(string);
|
||||
Assert.assertNotNull(errMsg, address);
|
||||
Assert.assertEquals(errMsg, string, address.getHostAddress());
|
||||
Assert.assertEquals(errMsg, string, address.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,26 +202,31 @@ public class IPv4AddressExprUtilsTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testParseInt()
|
||||
public void testParseLong()
|
||||
{
|
||||
Inet4Address address = IPv4AddressExprUtils.parse((int) 0xC0A80001L);
|
||||
Assert.assertArrayEquals(new byte[]{(byte) 0xC0, (byte) 0xA8, 0x00, 0x01}, address.getAddress());
|
||||
IPv4Address address = IPv4AddressExprUtils.parse(0xC0A80001L);
|
||||
Assert.assertNotNull(address);
|
||||
Assert.assertArrayEquals(new byte[]{(byte) 0xC0, (byte) 0xA8, 0x00, 0x01}, address.getBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() throws UnknownHostException
|
||||
public void testToString()
|
||||
{
|
||||
byte[] bytes = new byte[]{(byte) 192, (byte) 168, 0, 1};
|
||||
InetAddress address = InetAddress.getByAddress(bytes);
|
||||
Assert.assertEquals("192.168.0.1", IPv4AddressExprUtils.toString((Inet4Address) address));
|
||||
|
||||
IPAddressNetwork.IPAddressGenerator generator = new IPAddressNetwork.IPAddressGenerator();
|
||||
IPv4Address iPv4Address = generator.from(bytes).toIPv4();
|
||||
Assert.assertEquals("192.168.0.1", IPv4AddressExprUtils.toString(iPv4Address));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToLong() throws UnknownHostException
|
||||
public void testToLong()
|
||||
{
|
||||
byte[] bytes = new byte[]{(byte) 0xC0, (byte) 0xA8, 0x00, 0x01};
|
||||
InetAddress address = InetAddress.getByAddress(bytes);
|
||||
Assert.assertEquals(0xC0A80001L, IPv4AddressExprUtils.toLong((Inet4Address) address));
|
||||
|
||||
IPAddressNetwork.IPAddressGenerator generator = new IPAddressNetwork.IPAddressGenerator();
|
||||
IPv4Address iPv4Address = generator.from(bytes).toIPv4();
|
||||
Assert.assertEquals(0xC0A80001L, IPv4AddressExprUtils.toLong(iPv4Address));
|
||||
}
|
||||
|
||||
private String getErrMsg(String msg)
|
||||
|
|
Loading…
Reference in New Issue