EQL: Fix cidrMatch function fails to match when used in scripts (#56246) Addresses https://github.com/elastic/elasticsearch/issues/55709
This commit is contained in:
parent
83e9ff42da
commit
87a10806ab
|
@ -14,6 +14,43 @@ query = '''
|
||||||
file where between(file_path, "dev", ".json", true) == "\\TestLogs\\something"
|
file where between(file_path, "dev", ".json", true) == "\\TestLogs\\something"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
[[queries]]
|
||||||
|
expected_event_ids = [75304, 75305]
|
||||||
|
query = '''
|
||||||
|
network where cidrMatch(source_address, "10.6.48.157/8") == true
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[queries]]
|
||||||
|
expected_event_ids = [75304, 75305]
|
||||||
|
query = '''
|
||||||
|
network where string(cidrMatch(source_address, "10.6.48.157/8")) == "true"
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[queries]]
|
||||||
|
expected_event_ids = [75304, 75305]
|
||||||
|
query = '''
|
||||||
|
network where true == cidrMatch(source_address, "10.6.48.157/8")
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[queries]]
|
||||||
|
expected_event_ids = []
|
||||||
|
query = '''
|
||||||
|
network where cidrMatch(source_address, "192.168.0.0/16") == true
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[queries]]
|
||||||
|
expected_event_ids = [75304, 75305]
|
||||||
|
query = '''
|
||||||
|
network where cidrMatch(source_address, "192.168.0.0/16", "10.6.48.157/8") == true
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[queries]]
|
||||||
|
expected_event_ids = [75304, 75305]
|
||||||
|
query = '''
|
||||||
|
network where cidrMatch(source_address, "0.0.0.0/0") == true
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
[[queries]]
|
[[queries]]
|
||||||
description = "test string concatenation. update test to avoid case-sensitivity issues"
|
description = "test string concatenation. update test to avoid case-sensitivity issues"
|
||||||
query = '''
|
query = '''
|
||||||
|
@ -41,7 +78,6 @@ query = 'process where serial_event_id < 5 and concat(process_name, null, null)
|
||||||
expected_event_ids = [1, 2, 3, 4]
|
expected_event_ids = [1, 2, 3, 4]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[queries]]
|
[[queries]]
|
||||||
query = 'process where serial_event_id < 5 and concat(parent_process_name, null) == null'
|
query = 'process where serial_event_id < 5 and concat(parent_process_name, null) == null'
|
||||||
expected_event_ids = [1, 2, 3, 4]
|
expected_event_ids = [1, 2, 3, 4]
|
||||||
|
|
|
@ -6,58 +6,55 @@
|
||||||
|
|
||||||
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
|
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.logging.LoggerMessageFormat;
|
||||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||||
import org.elasticsearch.xpack.ql.expression.Expressions;
|
import org.elasticsearch.xpack.ql.expression.Expressions;
|
||||||
import org.elasticsearch.xpack.ql.expression.Expressions.ParamOrdinal;
|
import org.elasticsearch.xpack.ql.expression.Expressions.ParamOrdinal;
|
||||||
import org.elasticsearch.xpack.ql.expression.function.scalar.BaseSurrogateFunction;
|
import org.elasticsearch.xpack.ql.expression.FieldAttribute;
|
||||||
import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction;
|
import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction;
|
||||||
import org.elasticsearch.xpack.ql.expression.predicate.logical.Or;
|
import org.elasticsearch.xpack.ql.expression.gen.pipeline.Pipe;
|
||||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.Equals;
|
import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.gen.script.Scripts;
|
||||||
import org.elasticsearch.xpack.ql.tree.NodeInfo;
|
import org.elasticsearch.xpack.ql.tree.NodeInfo;
|
||||||
import org.elasticsearch.xpack.ql.tree.Source;
|
import org.elasticsearch.xpack.ql.tree.Source;
|
||||||
import org.elasticsearch.xpack.ql.type.DataType;
|
import org.elasticsearch.xpack.ql.type.DataType;
|
||||||
import org.elasticsearch.xpack.ql.type.DataTypes;
|
import org.elasticsearch.xpack.ql.type.DataTypes;
|
||||||
import org.elasticsearch.xpack.ql.util.CollectionUtils;
|
import org.elasticsearch.xpack.ql.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static org.elasticsearch.xpack.eql.expression.function.scalar.string.CIDRMatchFunctionProcessor.doProcess;
|
||||||
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isFoldable;
|
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isFoldable;
|
||||||
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isIPAndExact;
|
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isIPAndExact;
|
||||||
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isStringAndExact;
|
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isStringAndExact;
|
||||||
|
import static org.elasticsearch.xpack.ql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EQL specific cidrMatch function
|
* EQL specific cidrMatch function
|
||||||
* Returns true if the source address matches any of the provided CIDR blocks.
|
* Returns true if the source address matches any of the provided CIDR blocks.
|
||||||
* Refer to: https://eql.readthedocs.io/en/latest/query-guide/functions.html#cidrMatch
|
* Refer to: https://eql.readthedocs.io/en/latest/query-guide/functions.html#cidrMatch
|
||||||
*/
|
*/
|
||||||
public class CIDRMatch extends BaseSurrogateFunction {
|
public class CIDRMatch extends ScalarFunction {
|
||||||
|
|
||||||
private final Expression field;
|
private final Expression field;
|
||||||
private final List<Expression> addresses;
|
private final List<Expression> addresses;
|
||||||
|
|
||||||
public CIDRMatch(Source source, Expression field, List<Expression> addresses) {
|
public CIDRMatch(Source source, Expression field, List<Expression> addresses) {
|
||||||
super(source, CollectionUtils.combine(singletonList(field), addresses));
|
super(source, CollectionUtils.combine(singletonList(field), addresses == null ? emptyList() : addresses));
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.addresses = addresses;
|
this.addresses = addresses == null ? emptyList() : addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Expression field() {
|
||||||
protected NodeInfo<? extends Expression> info() {
|
return field;
|
||||||
return NodeInfo.create(this, CIDRMatch::new, field, addresses);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public List<Expression> addresses() {
|
||||||
public Expression replaceChildren(List<Expression> newChildren) {
|
return addresses;
|
||||||
if (newChildren.size() < 2) {
|
|
||||||
throw new IllegalArgumentException("expected at least [2] children but received [" + newChildren.size() + "]");
|
|
||||||
}
|
|
||||||
return new CIDRMatch(source(), newChildren.get(0), newChildren.subList(1, newChildren.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataType dataType() {
|
|
||||||
return DataTypes.BOOLEAN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -71,15 +68,6 @@ public class CIDRMatch extends BaseSurrogateFunction {
|
||||||
return resolution;
|
return resolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Expression addr : addresses) {
|
|
||||||
// Currently we have limited enum for ordinal numbers
|
|
||||||
// So just using default here for error messaging
|
|
||||||
resolution = isStringAndExact(addr, sourceText(), ParamOrdinal.DEFAULT);
|
|
||||||
if (resolution.unresolved()) {
|
|
||||||
return resolution;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int index = 1;
|
int index = 1;
|
||||||
|
|
||||||
for (Expression addr : addresses) {
|
for (Expression addr : addresses) {
|
||||||
|
@ -101,14 +89,60 @@ public class CIDRMatch extends BaseSurrogateFunction {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ScalarFunction makeSubstitute() {
|
protected Pipe makePipe() {
|
||||||
ScalarFunction func = null;
|
ArrayList<Pipe> arr = new ArrayList<>(addresses.size());
|
||||||
|
|
||||||
for (Expression address : addresses) {
|
for (Expression address : addresses) {
|
||||||
final Equals eq = new Equals(source(), field, address);
|
arr.add(Expressions.pipe(address));
|
||||||
func = (func == null) ? eq : new Or(source(), func, eq);
|
}
|
||||||
|
return new CIDRMatchFunctionPipe(source(), this, Expressions.pipe(field), arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return func;
|
@Override
|
||||||
|
public boolean foldable() {
|
||||||
|
return field.foldable() && Expressions.foldable(addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object fold() {
|
||||||
|
return doProcess(field.fold(), Expressions.fold(addresses));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NodeInfo<? extends Expression> info() {
|
||||||
|
return NodeInfo.create(this, CIDRMatch::new, field, addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScriptTemplate asScript() {
|
||||||
|
ScriptTemplate leftScript = asScript(field);
|
||||||
|
|
||||||
|
List<Object> values = new ArrayList<>(new LinkedHashSet<>(Expressions.fold(addresses)));
|
||||||
|
return new ScriptTemplate(
|
||||||
|
formatTemplate(LoggerMessageFormat.format("{eql}.","cidrMatch({}, {})", leftScript.template())),
|
||||||
|
paramsBuilder()
|
||||||
|
.script(leftScript.params())
|
||||||
|
.variable(values)
|
||||||
|
.build(),
|
||||||
|
dataType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScriptTemplate scriptWithField(FieldAttribute field) {
|
||||||
|
return new ScriptTemplate(processScript(Scripts.DOC_VALUE),
|
||||||
|
paramsBuilder().variable(field.exactAttribute().name()).build(),
|
||||||
|
dataType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType dataType() {
|
||||||
|
return DataTypes.BOOLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Expression replaceChildren(List<Expression> newChildren) {
|
||||||
|
if (newChildren.size() < 2) {
|
||||||
|
throw new IllegalArgumentException("expected at least [2] children but received [" + newChildren.size() + "]");
|
||||||
|
}
|
||||||
|
return new CIDRMatch(source(), newChildren.get(0), newChildren.subList(1, newChildren.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.ql.execution.search.QlSourceBuilder;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.gen.pipeline.Pipe;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.gen.processor.Processor;
|
||||||
|
import org.elasticsearch.xpack.ql.tree.NodeInfo;
|
||||||
|
import org.elasticsearch.xpack.ql.tree.Source;
|
||||||
|
import org.elasticsearch.xpack.ql.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class CIDRMatchFunctionPipe extends Pipe {
|
||||||
|
|
||||||
|
private final Pipe source;
|
||||||
|
private final List<Pipe> addresses;
|
||||||
|
|
||||||
|
public CIDRMatchFunctionPipe(Source source, Expression expression, Pipe src, List<Pipe> addresses) {
|
||||||
|
super(source, expression, CollectionUtils.combine(Collections.singletonList(src), addresses));
|
||||||
|
this.source = src;
|
||||||
|
this.addresses = addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Pipe replaceChildren(List<Pipe> newChildren) {
|
||||||
|
if (newChildren.size() < 2) {
|
||||||
|
throw new IllegalArgumentException("expected at least [2] children but received [" + newChildren.size() + "]");
|
||||||
|
}
|
||||||
|
return replaceChildren(newChildren.get(0), newChildren.subList(1, newChildren.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Pipe resolveAttributes(AttributeResolver resolver) {
|
||||||
|
Pipe newSource = source.resolveAttributes(resolver);
|
||||||
|
boolean same = (newSource == source);
|
||||||
|
|
||||||
|
ArrayList<Pipe> newAddresses = new ArrayList<Pipe>(addresses.size());
|
||||||
|
for (Pipe address : addresses) {
|
||||||
|
Pipe newAddress = address.resolveAttributes(resolver);
|
||||||
|
newAddresses.add(newAddress);
|
||||||
|
same = same && (address == newAddress);
|
||||||
|
}
|
||||||
|
if (same) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return replaceChildren(newSource, newAddresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportedByAggsOnlyQuery() {
|
||||||
|
if (source.supportedByAggsOnlyQuery() == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Pipe address : addresses) {
|
||||||
|
if (address.supportedByAggsOnlyQuery() == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean resolved() {
|
||||||
|
if (source.resolved() == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Pipe address : addresses) {
|
||||||
|
if (address.resolved() == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Pipe replaceChildren(Pipe newSource, List<Pipe> newAddresses) {
|
||||||
|
return new CIDRMatchFunctionPipe(source(), expression(), newSource, newAddresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void collectFields(QlSourceBuilder sourceBuilder) {
|
||||||
|
source.collectFields(sourceBuilder);
|
||||||
|
for (Pipe address : addresses) {
|
||||||
|
address.collectFields(sourceBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NodeInfo<CIDRMatchFunctionPipe> info() {
|
||||||
|
return NodeInfo.create(this, CIDRMatchFunctionPipe::new, expression(), source, addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CIDRMatchFunctionProcessor asProcessor() {
|
||||||
|
ArrayList<Processor> processors = new ArrayList<>(addresses.size());
|
||||||
|
for (Pipe address: addresses) {
|
||||||
|
processors.add(address.asProcessor());
|
||||||
|
}
|
||||||
|
return new CIDRMatchFunctionProcessor(source.asProcessor(), processors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pipe src() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Pipe> addresses() {
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(source(), addresses());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CIDRMatchFunctionPipe other = (CIDRMatchFunctionPipe) obj;
|
||||||
|
return Objects.equals(source(), other.source())
|
||||||
|
&& Objects.equals(addresses(), other.addresses());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.gen.processor.Processor;
|
||||||
|
import org.elasticsearch.xpack.ql.util.Check;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class CIDRMatchFunctionProcessor implements Processor {
|
||||||
|
|
||||||
|
public static final String NAME = "cdrm";
|
||||||
|
|
||||||
|
private final Processor source;
|
||||||
|
private final List<Processor> addresses;
|
||||||
|
|
||||||
|
public CIDRMatchFunctionProcessor(Processor source, List<Processor> addresses) {
|
||||||
|
this.source = source;
|
||||||
|
this.addresses = addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CIDRMatchFunctionProcessor(StreamInput in) throws IOException {
|
||||||
|
source = in.readNamedWriteable(Processor.class);
|
||||||
|
addresses = in.readNamedWriteableList(Processor.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void writeTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeNamedWriteable(source);
|
||||||
|
out.writeNamedWriteableList(addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWriteableName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object process(Object input) {
|
||||||
|
Object src = source.process(input);
|
||||||
|
ArrayList<Object> arr = new ArrayList<>(addresses.size());
|
||||||
|
for (Processor address : addresses) {
|
||||||
|
arr.add(address.process(input));
|
||||||
|
}
|
||||||
|
return doProcess(src, arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object doProcess(Object source, List<Object> addresses) {
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Check.isString(source);
|
||||||
|
|
||||||
|
String[] arr = new String[addresses.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (Object address: addresses) {
|
||||||
|
Check.isString(address);
|
||||||
|
arr[i++] = (String)address;
|
||||||
|
}
|
||||||
|
return CIDRUtils.isInRange((String)source, arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Processor source() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Processor> addresses() {
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(source(), addresses());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CIDRMatchFunctionProcessor other = (CIDRMatchFunctionProcessor) obj;
|
||||||
|
return Objects.equals(source(), other.source())
|
||||||
|
&& Objects.equals(addresses(), other.addresses());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.FutureArrays;
|
||||||
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
|
import org.elasticsearch.common.network.InetAddresses;
|
||||||
|
import org.elasticsearch.xpack.eql.EqlIllegalArgumentException;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
public class CIDRUtils {
|
||||||
|
// Borrowed from Lucene, rfc4291 prefix
|
||||||
|
static final byte[] IPV4_PREFIX = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1};
|
||||||
|
|
||||||
|
private CIDRUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isInRange(String address, String... cidrAddresses) {
|
||||||
|
try {
|
||||||
|
// Check if address is parsable first
|
||||||
|
byte[] addr = InetAddresses.forString(address).getAddress();
|
||||||
|
|
||||||
|
if (cidrAddresses == null || cidrAddresses.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String cidrAddress : cidrAddresses) {
|
||||||
|
if (cidrAddress == null) continue;
|
||||||
|
byte[] lower, upper;
|
||||||
|
if (cidrAddress.contains("/")) {
|
||||||
|
final Tuple<byte[], byte[]> range = getLowerUpper(InetAddresses.parseCidr(cidrAddress));
|
||||||
|
lower = range.v1();
|
||||||
|
upper = range.v2();
|
||||||
|
} else {
|
||||||
|
lower = InetAddresses.forString(cidrAddress).getAddress();
|
||||||
|
upper = lower;
|
||||||
|
}
|
||||||
|
if (isBetween(addr, lower, upper)) return true;
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new EqlIllegalArgumentException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Tuple<byte[], byte[]> getLowerUpper(Tuple<InetAddress, Integer> cidr) {
|
||||||
|
final InetAddress value = cidr.v1();
|
||||||
|
final Integer prefixLength = cidr.v2();
|
||||||
|
|
||||||
|
if (prefixLength < 0 || prefixLength > 8 * value.getAddress().length) {
|
||||||
|
throw new IllegalArgumentException("illegal prefixLength '" + prefixLength +
|
||||||
|
"'. Must be 0-32 for IPv4 ranges, 0-128 for IPv6 ranges");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] lower = value.getAddress();
|
||||||
|
byte[] upper = value.getAddress();
|
||||||
|
// Borrowed from Lucene
|
||||||
|
for (int i = prefixLength; i < 8 * lower.length; i++) {
|
||||||
|
int m = 1 << (7 - (i & 7));
|
||||||
|
lower[i >> 3] &= ~m;
|
||||||
|
upper[i >> 3] |= m;
|
||||||
|
}
|
||||||
|
return new Tuple<>(lower, upper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isBetween(byte[] addr, byte[] lower, byte[] upper) {
|
||||||
|
// Encode the addresses bytes if lengths do not match
|
||||||
|
if (addr.length != lower.length) {
|
||||||
|
addr = encode(addr);
|
||||||
|
lower = encode(lower);
|
||||||
|
upper = encode(upper);
|
||||||
|
}
|
||||||
|
return FutureArrays.compareUnsigned(lower, 0, lower.length, addr, 0, addr.length) <= 0 &&
|
||||||
|
FutureArrays.compareUnsigned(upper, 0, upper.length, addr, 0, addr.length) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Borrowed from Lucene to make this consistent IP fields matching for the mix of IPv4 and IPv6 values
|
||||||
|
// Modified signature to avoid extra conversions
|
||||||
|
private static byte[] encode(byte[] address) {
|
||||||
|
if (address.length == 4) {
|
||||||
|
byte[] mapped = new byte[16];
|
||||||
|
System.arraycopy(IPV4_PREFIX, 0, mapped, 0, IPV4_PREFIX.length);
|
||||||
|
System.arraycopy(address, 0, mapped, IPV4_PREFIX.length, address.length);
|
||||||
|
address = mapped;
|
||||||
|
} else if (address.length != 16) {
|
||||||
|
throw new UnsupportedOperationException("Only IPv4 and IPv6 addresses are supported");
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
package org.elasticsearch.xpack.eql.expression.function.scalar.whitelist;
|
package org.elasticsearch.xpack.eql.expression.function.scalar.whitelist;
|
||||||
|
|
||||||
import org.elasticsearch.xpack.eql.expression.function.scalar.string.BetweenFunctionProcessor;
|
import org.elasticsearch.xpack.eql.expression.function.scalar.string.BetweenFunctionProcessor;
|
||||||
|
import org.elasticsearch.xpack.eql.expression.function.scalar.string.CIDRMatchFunctionProcessor;
|
||||||
import org.elasticsearch.xpack.eql.expression.function.scalar.string.ConcatFunctionProcessor;
|
import org.elasticsearch.xpack.eql.expression.function.scalar.string.ConcatFunctionProcessor;
|
||||||
import org.elasticsearch.xpack.eql.expression.function.scalar.string.EndsWithFunctionProcessor;
|
import org.elasticsearch.xpack.eql.expression.function.scalar.string.EndsWithFunctionProcessor;
|
||||||
import org.elasticsearch.xpack.eql.expression.function.scalar.string.IndexOfFunctionProcessor;
|
import org.elasticsearch.xpack.eql.expression.function.scalar.string.IndexOfFunctionProcessor;
|
||||||
|
@ -32,6 +33,10 @@ public class InternalEqlScriptUtils extends InternalQlScriptUtils {
|
||||||
return (String) BetweenFunctionProcessor.doProcess(s, left, right, greedy, caseSensitive);
|
return (String) BetweenFunctionProcessor.doProcess(s, left, right, greedy, caseSensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean cidrMatch(String s, List<Object> addresses) {
|
||||||
|
return (Boolean) CIDRMatchFunctionProcessor.doProcess(s, addresses);
|
||||||
|
}
|
||||||
|
|
||||||
public static String concat(List<Object> values) {
|
public static String concat(List<Object> values) {
|
||||||
return (String) ConcatFunctionProcessor.doProcess(values);
|
return (String) ConcatFunctionProcessor.doProcess(values);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.xpack.eql.planner;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.ql.planner.QlTranslatorHandler;
|
||||||
|
import org.elasticsearch.xpack.ql.querydsl.query.Query;
|
||||||
|
|
||||||
|
public class EqlTranslatorHandler extends QlTranslatorHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Query asQuery(Expression e) {
|
||||||
|
return QueryTranslator.toQuery(e, this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,7 +69,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
|
||||||
EsQueryExec exec = (EsQueryExec) plan.child();
|
EsQueryExec exec = (EsQueryExec) plan.child();
|
||||||
QueryContainer qContainer = exec.queryContainer();
|
QueryContainer qContainer = exec.queryContainer();
|
||||||
|
|
||||||
Query query = ExpressionTranslators.toQuery(plan.condition());
|
Query query = QueryTranslator.toQuery(plan.condition());
|
||||||
|
|
||||||
if (qContainer.query() != null || query != null) {
|
if (qContainer.query() != null || query != null) {
|
||||||
query = ExpressionTranslators.and(plan.source(), qContainer.query(), query);
|
query = ExpressionTranslators.and(plan.source(), qContainer.query(), query);
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.xpack.eql.planner;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.eql.expression.function.scalar.string.CIDRMatch;
|
||||||
|
import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.Expressions;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.FieldAttribute;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.predicate.logical.And;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.predicate.logical.Or;
|
||||||
|
import org.elasticsearch.xpack.ql.planner.ExpressionTranslator;
|
||||||
|
import org.elasticsearch.xpack.ql.planner.ExpressionTranslators;
|
||||||
|
import org.elasticsearch.xpack.ql.planner.TranslatorHandler;
|
||||||
|
import org.elasticsearch.xpack.ql.querydsl.query.Query;
|
||||||
|
import org.elasticsearch.xpack.ql.querydsl.query.ScriptQuery;
|
||||||
|
import org.elasticsearch.xpack.ql.querydsl.query.TermsQuery;
|
||||||
|
import org.elasticsearch.xpack.ql.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.ql.planner.ExpressionTranslators.and;
|
||||||
|
import static org.elasticsearch.xpack.ql.planner.ExpressionTranslators.or;
|
||||||
|
|
||||||
|
final class QueryTranslator {
|
||||||
|
|
||||||
|
public static final List<ExpressionTranslator<?>> QUERY_TRANSLATORS = Arrays.asList(
|
||||||
|
new ExpressionTranslators.BinaryComparisons(),
|
||||||
|
new ExpressionTranslators.Ranges(),
|
||||||
|
new BinaryLogic(),
|
||||||
|
new ExpressionTranslators.Nots(),
|
||||||
|
new ExpressionTranslators.Likes(),
|
||||||
|
new ExpressionTranslators.InComparisons(),
|
||||||
|
new ExpressionTranslators.StringQueries(),
|
||||||
|
new ExpressionTranslators.Matches(),
|
||||||
|
new ExpressionTranslators.MultiMatches(),
|
||||||
|
new Scalars()
|
||||||
|
);
|
||||||
|
|
||||||
|
public static Query toQuery(Expression e) {
|
||||||
|
return toQuery(e, new EqlTranslatorHandler());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Query toQuery(Expression e, TranslatorHandler handler) {
|
||||||
|
Query translation = null;
|
||||||
|
for (ExpressionTranslator<?> translator : QUERY_TRANSLATORS) {
|
||||||
|
translation = translator.translate(e, handler);
|
||||||
|
if (translation != null) {
|
||||||
|
return translation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new QlIllegalArgumentException("Don't know how to translate {} {}", e.nodeName(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BinaryLogic extends ExpressionTranslator<org.elasticsearch.xpack.ql.expression.predicate.logical.BinaryLogic> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Query asQuery(org.elasticsearch.xpack.ql.expression.predicate.logical.BinaryLogic e, TranslatorHandler handler) {
|
||||||
|
if (e instanceof And) {
|
||||||
|
return and(e.source(), toQuery(e.left(), handler), toQuery(e.right(), handler));
|
||||||
|
}
|
||||||
|
if (e instanceof Or) {
|
||||||
|
return or(e.source(), toQuery(e.left(), handler), toQuery(e.right(), handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object valueOf(Expression e) {
|
||||||
|
if (e.foldable()) {
|
||||||
|
return e.fold();
|
||||||
|
}
|
||||||
|
throw new QlIllegalArgumentException("Cannot determine value for {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Scalars extends ExpressionTranslator<ScalarFunction> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Query asQuery(ScalarFunction f, TranslatorHandler handler) {
|
||||||
|
return doTranslate(f, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Query doTranslate(ScalarFunction f, TranslatorHandler handler) {
|
||||||
|
Query q = ExpressionTranslators.Scalars.doKnownTranslate(f, handler);
|
||||||
|
if (q != null) {
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
if (f instanceof CIDRMatch) {
|
||||||
|
CIDRMatch cm = (CIDRMatch) f;
|
||||||
|
if (cm.field() instanceof FieldAttribute && Expressions.foldable(cm.addresses())) {
|
||||||
|
String targetFieldName = handler.nameOf(((FieldAttribute) cm.field()).exactAttribute());
|
||||||
|
|
||||||
|
Set<Object> set = new LinkedHashSet<>(CollectionUtils.mapSize(cm.addresses().size()));
|
||||||
|
|
||||||
|
for (Expression e : cm.addresses()) {
|
||||||
|
set.add(valueOf(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TermsQuery(f.source(), targetFieldName, set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler.wrapFunctionQuery(f, f, new ScriptQuery(f.source(), f.asScript()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,6 +66,7 @@ class org.elasticsearch.xpack.eql.expression.function.scalar.whitelist.InternalE
|
||||||
# ASCII Functions
|
# ASCII Functions
|
||||||
#
|
#
|
||||||
String between(String, String, String, Boolean, Boolean)
|
String between(String, String, String, Boolean, Boolean)
|
||||||
|
Boolean cidrMatch(String, java.util.List)
|
||||||
String concat(java.util.List)
|
String concat(java.util.List)
|
||||||
Boolean endsWith(String, String)
|
Boolean endsWith(String, String)
|
||||||
Integer indexOf(String, String, Number)
|
Integer indexOf(String, String, Number)
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
|
||||||
|
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.xpack.eql.EqlIllegalArgumentException;
|
||||||
|
import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
|
||||||
|
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.ql.expression.function.scalar.FunctionTestUtils.l;
|
||||||
|
import static org.elasticsearch.xpack.ql.tree.Source.EMPTY;
|
||||||
|
|
||||||
|
public class CIDRMatchProcessorTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testCIDRMatchFunctionValidInput() {
|
||||||
|
// Expects null if source was null
|
||||||
|
assertNull(new CIDRMatch(EMPTY, l(null), null).makePipe().asProcessor().process(null));
|
||||||
|
|
||||||
|
ArrayList<Expression> addresses = new ArrayList<>();
|
||||||
|
assertNull(new CIDRMatch(EMPTY, l(null), addresses).makePipe().asProcessor().process(null));
|
||||||
|
|
||||||
|
assertFalse((Boolean) new CIDRMatch(EMPTY, l("10.6.48.157"), addresses).makePipe().asProcessor().process(null));
|
||||||
|
|
||||||
|
addresses.add(l("10.6.48.157/8"));
|
||||||
|
assertTrue((Boolean) new CIDRMatch(EMPTY, l("10.6.48.157"), addresses).makePipe().asProcessor().process(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCIDRMatchFunctionInvalidInput() {
|
||||||
|
ArrayList<Expression> addresses = new ArrayList<>();
|
||||||
|
|
||||||
|
// Invalid source address
|
||||||
|
EqlIllegalArgumentException e = expectThrows(EqlIllegalArgumentException.class,
|
||||||
|
() -> new CIDRMatch(EMPTY, l("10.6.48"), addresses).makePipe().asProcessor().process(null));
|
||||||
|
|
||||||
|
assertEquals("'10.6.48' is not an IP string literal.", e.getMessage());
|
||||||
|
|
||||||
|
// Invalid match ip address
|
||||||
|
addresses.add(l("10.6.48"));
|
||||||
|
e = expectThrows(EqlIllegalArgumentException.class,
|
||||||
|
() -> new CIDRMatch(EMPTY, l("10.6.48.157"), addresses).makePipe().asProcessor().process(null));
|
||||||
|
|
||||||
|
assertEquals("'10.6.48' is not an IP string literal.", e.getMessage());
|
||||||
|
addresses.clear();
|
||||||
|
|
||||||
|
// Invalid CIDR
|
||||||
|
addresses.add(l("10.6.12/12"));
|
||||||
|
e = expectThrows(EqlIllegalArgumentException.class,
|
||||||
|
() -> new CIDRMatch(EMPTY, l("10.6.48.157"), addresses).makePipe().asProcessor().process(null));
|
||||||
|
|
||||||
|
assertEquals("'10.6.12' is not an IP string literal.", e.getMessage());
|
||||||
|
addresses.clear();
|
||||||
|
|
||||||
|
// Invalid source type
|
||||||
|
QlIllegalArgumentException eqe = expectThrows(QlIllegalArgumentException.class,
|
||||||
|
() -> new CIDRMatch(EMPTY, l(12345), addresses).makePipe().asProcessor().process(null));
|
||||||
|
|
||||||
|
assertEquals("A string/char is required; received [12345]", eqe.getMessage());
|
||||||
|
|
||||||
|
|
||||||
|
// Invalid cidr type
|
||||||
|
addresses.add(l(5678));
|
||||||
|
eqe = expectThrows(QlIllegalArgumentException.class,
|
||||||
|
() -> new CIDRMatch(EMPTY, l("10.6.48.157"), addresses).makePipe().asProcessor().process(null));
|
||||||
|
|
||||||
|
assertEquals("A string/char is required; received [5678]", eqe.getMessage());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
|
||||||
|
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
public class CIDRUtilsTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testCIDRUtils() {
|
||||||
|
// Missing or empty param
|
||||||
|
assertFalse(CIDRUtils.isInRange("10.6.48.157"));
|
||||||
|
assertFalse(CIDRUtils.isInRange("10.6.48.157", (String)null));
|
||||||
|
|
||||||
|
// EQL tests matches
|
||||||
|
assertTrue(CIDRUtils.isInRange("10.6.48.157", "10.6.48.157/8"));
|
||||||
|
assertFalse(CIDRUtils.isInRange("10.6.48.157", "192.168.0.0/16"));
|
||||||
|
assertTrue(CIDRUtils.isInRange("10.6.48.157", "192.168.0.0/16", "10.6.48.157/8"));
|
||||||
|
assertTrue(CIDRUtils.isInRange("10.6.48.157", "0.0.0.0/0"));
|
||||||
|
assertFalse(CIDRUtils.isInRange("10.6.48.157", "0.0.0.0"));
|
||||||
|
|
||||||
|
// Random things
|
||||||
|
assertTrue(CIDRUtils.isInRange("192.168.2.1", "192.168.2.1"));
|
||||||
|
assertFalse(CIDRUtils.isInRange("192.168.2.1", "192.168.2.0/32"));
|
||||||
|
assertTrue(CIDRUtils.isInRange("192.168.2.5", "192.168.2.0/24"));
|
||||||
|
assertFalse(CIDRUtils.isInRange("92.168.2.1", "fe80:0:0:0:0:0:c0a8:1/120"));
|
||||||
|
assertTrue(CIDRUtils.isInRange("192.168.2.5", "192.168.2.0/24"));
|
||||||
|
|
||||||
|
assertTrue(CIDRUtils.isInRange("fe80:0:0:0:0:0:c0a8:11", "fe80:0:0:0:0:0:c0a8:1/120"));
|
||||||
|
assertFalse(CIDRUtils.isInRange("fe80:0:0:0:0:0:c0a8:11", "fe80:0:0:0:0:0:c0a8:1/128"));
|
||||||
|
assertFalse(CIDRUtils.isInRange("fe80:0:0:0:0:0:c0a8:11", "192.168.2.0/32"));
|
||||||
|
|
||||||
|
|
||||||
|
assertTrue(CIDRUtils.isInRange("2001:db8:3c0d:5b6d:0:0:42:8329", "2001:db8:3c0d:5b6d:0:0:42:8329/58"));
|
||||||
|
assertTrue(CIDRUtils.isInRange("2001:db8:3c0d:5b40::", "2001:db8:3c0d:5b6d:0:0:42:8329/58"));
|
||||||
|
assertTrue(CIDRUtils.isInRange("2001:db8:3c0d:5b7f:ffff:ffff:ffff:ffff", "2001:db8:3c0d:5b6d:0:0:42:8329/58"));
|
||||||
|
assertTrue(CIDRUtils.isInRange("2001:db8:3c0d:5b53:0:0:0:1", "2001:db8:3c0d:5b6d:0:0:42:8329/58"));
|
||||||
|
assertFalse(CIDRUtils.isInRange("2001:db8:3c0d:5b3f:ffff:ffff:ffff:ffff", "2001:db8:3c0d:5b6d:0:0:42:8329/58"));
|
||||||
|
assertFalse(CIDRUtils.isInRange("2001:db8:3c0d:5b80::", "2001:db8:3c0d:5b6d:0:0:42:8329/58"));
|
||||||
|
|
||||||
|
assertTrue(CIDRUtils.isInRange("2001:db8:3c0d:5b6d:0:0:42:8329", "2001:db8:3c0d:5b6d:0:0:42:8329/128"));
|
||||||
|
|
||||||
|
assertFalse(CIDRUtils.isInRange("2001:db8:3c0d:5b6d:0:0:42:8329", "192.168.2.0/32"));
|
||||||
|
|
||||||
|
assertTrue(CIDRUtils.isInRange("127.0.0.1", "127.0.0.1/8"));
|
||||||
|
|
||||||
|
assertTrue(CIDRUtils.isInRange("127.0.0.1", "::1/64"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,7 +90,7 @@ public class QueryFolderFailTests extends AbstractQueryFolderTestCase {
|
||||||
() -> plan("process where cidrMatch(source_address, 12345)"));
|
() -> plan("process where cidrMatch(source_address, 12345)"));
|
||||||
String msg = e.getMessage();
|
String msg = e.getMessage();
|
||||||
assertEquals("Found 1 problem\n" +
|
assertEquals("Found 1 problem\n" +
|
||||||
"line 1:15: argument of [cidrMatch(source_address, 12345)] must be [string], found value [12345] type [integer]", msg);
|
"line 1:15: second argument of [cidrMatch(source_address, 12345)] must be [string], found value [12345] type [integer]", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testConcatWithInexact() {
|
public void testConcatWithInexact() {
|
||||||
|
|
|
@ -78,28 +78,28 @@ functionEqualsTrue
|
||||||
process where cidrMatch(source_address, "10.0.0.0/8") == true
|
process where cidrMatch(source_address, "10.0.0.0/8") == true
|
||||||
;
|
;
|
||||||
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
||||||
{"term":{"source_address":{"value":"10.0.0.0/8"
|
{"terms":{"source_address":["10.0.0.0/8"]
|
||||||
;
|
;
|
||||||
|
|
||||||
functionEqualsFalse
|
functionEqualsFalse
|
||||||
process where cidrMatch(source_address, "10.0.0.0/8") == false
|
process where cidrMatch(source_address, "10.0.0.0/8") == false
|
||||||
;
|
;
|
||||||
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
||||||
{"bool":{"must_not":[{"term":{"source_address":{"value":"10.0.0.0/8"
|
{"bool":{"must_not":[{"terms":{"source_address":["10.0.0.0/8"]
|
||||||
;
|
;
|
||||||
|
|
||||||
functionNotEqualsTrue
|
functionNotEqualsTrue
|
||||||
process where cidrMatch(source_address, "10.0.0.0/8") != true
|
process where cidrMatch(source_address, "10.0.0.0/8") != true
|
||||||
;
|
;
|
||||||
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
||||||
{"bool":{"must_not":[{"term":{"source_address":{"value":"10.0.0.0/8"
|
{"bool":{"must_not":[{"terms":{"source_address":["10.0.0.0/8"]
|
||||||
;
|
;
|
||||||
|
|
||||||
functionNotEqualsFalse
|
functionNotEqualsFalse
|
||||||
process where cidrMatch(source_address, "10.0.0.0/8") != false
|
process where cidrMatch(source_address, "10.0.0.0/8") != false
|
||||||
;
|
;
|
||||||
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
||||||
{"term":{"source_address":{"value":"10.0.0.0/8"
|
{"terms":{"source_address":["10.0.0.0/8"]
|
||||||
;
|
;
|
||||||
|
|
||||||
twoFunctionsEqualsBooleanLiterals
|
twoFunctionsEqualsBooleanLiterals
|
||||||
|
@ -221,22 +221,44 @@ InternalEqlScriptUtils.concat([InternalQlScriptUtils.docValue(doc,params.v0),par
|
||||||
cidrMatchFunctionOne
|
cidrMatchFunctionOne
|
||||||
process where cidrMatch(source_address, "10.0.0.0/8")
|
process where cidrMatch(source_address, "10.0.0.0/8")
|
||||||
;
|
;
|
||||||
"term":{"source_address":{"value":"10.0.0.0/8"
|
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
||||||
|
{"terms":{"source_address":["10.0.0.0/8"]
|
||||||
|
;
|
||||||
|
|
||||||
|
cidrMatchFunctionOneBool
|
||||||
|
process where cidrMatch(source_address, "10.0.0.0/8") == true
|
||||||
|
;
|
||||||
|
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
||||||
|
{"terms":{"source_address":["10.0.0.0/8"]
|
||||||
;
|
;
|
||||||
|
|
||||||
cidrMatchFunctionTwo
|
cidrMatchFunctionTwo
|
||||||
process where cidrMatch(source_address, "10.0.0.0/8", "192.168.0.0/16")
|
process where cidrMatch(source_address, "10.0.0.0/8", "192.168.0.0/16")
|
||||||
;
|
;
|
||||||
"term":{"source_address":{"value":"10.0.0.0/8"
|
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
||||||
"term":{"source_address":{"value":"192.168.0.0/16"
|
{"terms":{"source_address":["10.0.0.0/8","192.168.0.0/16"]
|
||||||
|
;
|
||||||
|
|
||||||
|
cidrMatchFunctionTwoWithOr
|
||||||
|
process where cidrMatch(source_address, "10.0.0.0/8") or cidrMatch(source_address, "192.168.0.0/16")
|
||||||
|
;
|
||||||
|
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
||||||
|
{"bool":{"should":[{"terms":{"source_address":["10.0.0.0/8"],"boost":1.0}},{"terms":{"source_address":["192.168.0.0/16"],"boost":1.0}}
|
||||||
;
|
;
|
||||||
|
|
||||||
cidrMatchFunctionThree
|
cidrMatchFunctionThree
|
||||||
process where cidrMatch(source_address, "10.0.0.0/8", "192.168.0.0/16", "2001:db8::/32")
|
process where cidrMatch(source_address, "10.0.0.0/8", "192.168.0.0/16", "2001:db8::/32")
|
||||||
;
|
;
|
||||||
"term":{"source_address":{"value":"10.0.0.0/8"
|
{"bool":{"must":[{"term":{"event.category":{"value":"process"
|
||||||
"term":{"source_address":{"value":"192.168.0.0/16"
|
{"terms":{"source_address":["10.0.0.0/8","192.168.0.0/16","2001:db8::/32"]
|
||||||
"term":{"source_address":{"value":"2001:db8::/32"
|
;
|
||||||
|
|
||||||
|
cidrMatchFunctionWrapped
|
||||||
|
process where string(cidrMatch(source_address, "10.6.48.157/8")) == "true"
|
||||||
|
;
|
||||||
|
{"script":{"source":"InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.eq(InternalEqlScriptUtils.string(
|
||||||
|
InternalEqlScriptUtils.cidrMatch(InternalQlScriptUtils.docValue(doc,params.v0),params.v1)),params.v2))"
|
||||||
|
"params":{"v0":"source_address","v1":["10.6.48.157/8"],"v2":"true"}
|
||||||
;
|
;
|
||||||
|
|
||||||
matchFunctionOne
|
matchFunctionOne
|
||||||
|
|
|
@ -375,6 +375,14 @@ public final class ExpressionTranslators {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Query doTranslate(ScalarFunction f, TranslatorHandler handler) {
|
public static Query doTranslate(ScalarFunction f, TranslatorHandler handler) {
|
||||||
|
Query q = doKnownTranslate(f, handler);
|
||||||
|
if (q != null) {
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
return handler.wrapFunctionQuery(f, f, new ScriptQuery(f.source(), f.asScript()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Query doKnownTranslate(ScalarFunction f, TranslatorHandler handler) {
|
||||||
if (f instanceof StartsWith) {
|
if (f instanceof StartsWith) {
|
||||||
StartsWith sw = (StartsWith) f;
|
StartsWith sw = (StartsWith) f;
|
||||||
if (sw.isCaseSensitive() && sw.field() instanceof FieldAttribute && sw.pattern().foldable()) {
|
if (sw.isCaseSensitive() && sw.field() instanceof FieldAttribute && sw.pattern().foldable()) {
|
||||||
|
@ -384,8 +392,7 @@ public final class ExpressionTranslators {
|
||||||
return new PrefixQuery(f.source(), targetFieldName, pattern);
|
return new PrefixQuery(f.source(), targetFieldName, pattern);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
return handler.wrapFunctionQuery(f, f, new ScriptQuery(f.source(), f.asScript()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue