metron-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject [24/26] incubator-metron git commit: METRON-870: Add filtering by packet payload to the pcap query closes apache/incubator-metron#541
Date Thu, 27 Apr 2017 22:13:59 GMT
http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bf2528fd/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java
b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java
index a7751b4..001b500 100644
--- a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java
+++ b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilter.java
@@ -21,6 +21,7 @@ package org.apache.metron.pcap.filter.fixed;
 import com.google.common.base.Joiner;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.metron.common.Constants;
+import org.apache.metron.common.dsl.MapVariableResolver;
 import org.apache.metron.common.dsl.VariableResolver;
 import org.apache.metron.pcap.PacketInfo;
 import org.apache.metron.pcap.PcapHelper;
@@ -28,69 +29,123 @@ import org.apache.metron.pcap.filter.PcapFilter;
 import org.apache.metron.pcap.filter.PcapFilterConfigurator;
 import org.apache.metron.pcap.filter.PcapFilters;
 import org.apache.metron.pcap.filter.PcapFieldResolver;
+import org.apache.metron.pcap.pattern.ByteArrayMatchingUtil;
 
+import javax.xml.bind.DatatypeConverter;
 import java.util.EnumMap;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
 
 
 public class FixedPcapFilter implements PcapFilter {
 
-  public static class Configurator implements PcapFilterConfigurator<EnumMap<Constants.Fields,
String>> {
+  public static class Configurator implements PcapFilterConfigurator<Map<String, String>>
{
     @Override
-    public void addToConfig(EnumMap<Constants.Fields, String> fields, Configuration
conf) {
-      for (Map.Entry<Constants.Fields, String> kv : fields.entrySet()) {
-        conf.set(kv.getKey().getName(), kv.getValue());
+    public void addToConfig(Map<String, String> fields, Configuration conf) {
+      for (Map.Entry<String, String> kv : fields.entrySet()) {
+        conf.set(kv.getKey(), kv.getValue());
       }
       conf.set(PCAP_FILTER_NAME_CONF, PcapFilters.FIXED.name());
     }
 
     @Override
-    public String queryToString(EnumMap<Constants.Fields, String> fields) {
+    public String queryToString(Map<String, String> fields) {
       return (fields == null ? "" : Joiner.on("_").join(fields.values()));
     }
   }
 
+  private String packetFilter;
   private String srcAddr;
   private Integer srcPort;
   private String dstAddr;
   private Integer dstPort;
   private String protocol;
   private boolean includesReverseTraffic = false;
+  private boolean doHeaderFiltering = false;
 
   @Override
   public void configure(Iterable<Map.Entry<String, String>> config) {
     for (Map.Entry<String, String> kv : config) {
       if (kv.getKey().equals(Constants.Fields.DST_ADDR.getName())) {
+        System.out.println("Processing: " + kv.getKey() + " => " + kv.getValue());
         this.dstAddr = kv.getValue();
+        doHeaderFiltering = true;
       }
       if (kv.getKey().equals(Constants.Fields.SRC_ADDR.getName())) {
+        System.out.println("Processing: " + kv.getKey() + " => " + kv.getValue());
         this.srcAddr = kv.getValue();
+        doHeaderFiltering = true;
       }
       if (kv.getKey().equals(Constants.Fields.DST_PORT.getName())) {
+        System.out.println("Processing: " + kv.getKey() + " => " + kv.getValue());
         this.dstPort = Integer.parseInt(kv.getValue());
+        doHeaderFiltering = true;
       }
       if (kv.getKey().equals(Constants.Fields.SRC_PORT.getName())) {
+        System.out.println("Processing: " + kv.getKey() + " => " + kv.getValue());
         this.srcPort = Integer.parseInt(kv.getValue());
+        doHeaderFiltering = true;
       }
       if (kv.getKey().equals(Constants.Fields.PROTOCOL.getName())) {
+        System.out.println("Processing: " + kv.getKey() + " => " + kv.getValue());
         this.protocol = kv.getValue();
+        doHeaderFiltering = true;
       }
       if (kv.getKey().equals(Constants.Fields.INCLUDES_REVERSE_TRAFFIC.getName())) {
+        System.out.println("Processing: " + kv.getKey() + " => " + kv.getValue());
         this.includesReverseTraffic = Boolean.parseBoolean(kv.getValue());
       }
+      if(kv.getKey().equals(PcapHelper.PacketFields.PACKET_FILTER.getName())) {
+        System.out.println("Processing: " + kv.getKey() + " => " + kv.getValue());
+        this.packetFilter = kv.getValue();
+      }
     }
   }
 
 
   @Override
   public boolean test(PacketInfo pi) {
-    VariableResolver resolver = new PcapFieldResolver(packetToFields(pi));
+    Map<String, Object> fields = packetToFields(pi);
+    VariableResolver resolver = new MapVariableResolver(fields);
     String srcAddrIn = (String) resolver.resolve(Constants.Fields.SRC_ADDR.getName());
     Integer srcPortIn = (Integer) resolver.resolve(Constants.Fields.SRC_PORT.getName());
     String dstAddrIn = (String) resolver.resolve(Constants.Fields.DST_ADDR.getName());
     Integer dstPortIn = (Integer) resolver.resolve(Constants.Fields.DST_PORT.getName());
+
     String protocolIn = "" + resolver.resolve(Constants.Fields.PROTOCOL.getName());
+    if(!doHeaderFiltering || testHeader(srcAddrIn, srcPortIn, dstAddrIn, dstPortIn, protocolIn))
{
+      //if we don't do header filtering *or* if we have tested the header and decided it's
a match
+      if(packetFilter != null) {
+        //and we have a packet filter, then we need to filter the packet
+        byte[] data = (byte[])resolver.resolve(PcapHelper.PacketFields.PACKET_DATA.getName());
+        try {
+          return ByteArrayMatchingUtil.INSTANCE.match(packetFilter, data);
+        } catch (ExecutionException e) {
+          throw new IllegalStateException("Unable to perform binary filter: " + packetFilter
+ " on " +  DatatypeConverter.printHexBinary(data), e);
+        }
+      }
+      else if(!doHeaderFiltering){
+        //otherwise we aren't doing packet filtering either, so we aren't doing any filtering,
then we should
+        //pass the test
+        return true;
+      }
+      else {
+        //and if we *are* doing header filtering and not packet filtering, then we want to
pass the test
+        return true;
+      }
+    }
+    else {
+      //in this case we're doing header filtering and we failed the header filter test.
+      return false;
+    }
+  }
 
+  private boolean testHeader( String srcAddrIn
+                            , Integer srcPortIn
+                            , String dstAddrIn
+                            , Integer dstPortIn
+                            , String protocolIn
+  ) {
     if (areMatch(protocol, protocolIn)) {
       if (matchesSourceAndDestination(srcAddrIn, srcPortIn, dstAddrIn, dstPortIn)) {
         return true;
@@ -102,7 +157,7 @@ public class FixedPcapFilter implements PcapFilter {
   }
 
   private boolean areMatch(Integer filter, Integer input) {
-    return filter == null || areMatch(Integer.toUnsignedString(filter), Integer.toUnsignedString(input));
+    return filter == null || areMatch(Integer.toUnsignedString(filter), input == null?null:Integer.toUnsignedString(input));
   }
 
   private boolean areMatch(String filter, String input) {
@@ -113,7 +168,7 @@ public class FixedPcapFilter implements PcapFilter {
     }
   }
 
-  protected EnumMap<Constants.Fields, Object> packetToFields(PacketInfo pi) {
+  protected Map<String, Object> packetToFields(PacketInfo pi) {
     return PcapHelper.packetToFields(pi);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bf2528fd/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java
b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java
index 28a8b93..d6fa203 100644
--- a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java
+++ b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/filter/query/QueryPcapFilter.java
@@ -21,6 +21,7 @@ package org.apache.metron.pcap.filter.query;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.metron.common.Constants;
 import org.apache.metron.common.dsl.Context;
+import org.apache.metron.common.dsl.MapVariableResolver;
 import org.apache.metron.common.dsl.StellarFunctions;
 import org.apache.metron.common.stellar.StellarPredicateProcessor;
 import org.apache.metron.common.dsl.VariableResolver;
@@ -69,12 +70,12 @@ public class QueryPcapFilter implements PcapFilter {
 
   @Override
   public boolean test(PacketInfo input) {
-    EnumMap<Constants.Fields, Object> fields = packetToFields(input);
-    VariableResolver resolver = new PcapFieldResolver(fields);
+    Map<String, Object> fields = packetToFields(input);
+    VariableResolver resolver = new MapVariableResolver(fields);
     return predicateProcessor.parse(queryString, resolver, StellarFunctions.FUNCTION_RESOLVER(),
Context.EMPTY_CONTEXT());
   }
 
-  protected EnumMap<Constants.Fields, Object> packetToFields(PacketInfo pi) {
+  protected Map<String, Object> packetToFields(PacketInfo pi) {
     return PcapHelper.packetToFields(pi);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bf2528fd/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/pattern/ByteArrayMatcherFunction.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/pattern/ByteArrayMatcherFunction.java
b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/pattern/ByteArrayMatcherFunction.java
new file mode 100644
index 0000000..a4a74f3
--- /dev/null
+++ b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/pattern/ByteArrayMatcherFunction.java
@@ -0,0 +1,63 @@
+/**
+ * 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.metron.pcap.pattern;
+
+import org.apache.metron.common.dsl.Context;
+import org.apache.metron.common.dsl.ParseException;
+import org.apache.metron.common.dsl.Stellar;
+import org.apache.metron.common.dsl.StellarFunction;
+
+import javax.xml.bind.DatatypeConverter;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+@Stellar(namespace="BYTEARRAY"
+        ,name="MATCHER"
+        ,description = "Determine if a regex defined sequence of bytes (or strings) exists
in a byte array."
+        ,params = {
+            "binary_regex - Regex defining what to look for in the byte array. Note syntax
guide for binary regex is at https://github.com/nishihatapalmer/byteseek/blob/master/sequencesyntax.md"
+           ,"data - The byte array to evaluate."
+                  }
+        ,returns="result: Boolean indicating whether or not the byte array is a match."
+        )
+public class ByteArrayMatcherFunction implements StellarFunction {
+  @Override
+  public Object apply(List<Object> args, Context context) throws ParseException {
+    if(args.size() != 2) {
+      return new IllegalStateException("Expected 2 arguments: regex and data");
+    }
+    String regex = (String)args.get(0);
+    byte[] data = (byte[])args.get(1);
+    try {
+      return ByteArrayMatchingUtil.INSTANCE.match(regex, data);
+    }
+    catch (ExecutionException e) {
+      throw new IllegalStateException("Unable to process " + regex + " against " + DatatypeConverter.printHexBinary(data));
+    }
+  }
+
+  @Override
+  public void initialize(Context context) {
+
+  }
+
+  @Override
+  public boolean isInitialized() {
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bf2528fd/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/pattern/ByteArrayMatchingUtil.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/pattern/ByteArrayMatchingUtil.java
b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/pattern/ByteArrayMatchingUtil.java
new file mode 100644
index 0000000..bd57b7c
--- /dev/null
+++ b/metron-platform/metron-pcap/src/main/java/org/apache/metron/pcap/pattern/ByteArrayMatchingUtil.java
@@ -0,0 +1,64 @@
+/**
+ * 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.metron.pcap.pattern;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import net.byteseek.compiler.CompileException;
+import net.byteseek.compiler.matcher.MatcherCompilerUtils;
+import net.byteseek.compiler.matcher.SequenceMatcherCompiler;
+import net.byteseek.matcher.sequence.SequenceMatcher;
+import net.byteseek.searcher.Searcher;
+import net.byteseek.searcher.sequence.horspool.BoyerMooreHorspoolSearcher;
+import net.byteseek.searcher.sequence.horspool.HorspoolFinalFlagSearcher;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+public enum ByteArrayMatchingUtil {
+  INSTANCE;
+  private LoadingCache<String, Searcher<SequenceMatcher>> sequenceMatchers =
CacheBuilder.newBuilder()
+          .maximumSize(1000)
+          .expireAfterWrite(10, TimeUnit.MINUTES)
+          .build(
+                  new CacheLoader<String, Searcher<SequenceMatcher>>() {
+                    public Searcher<SequenceMatcher> load(String pattern) throws Exception
{
+                      return new HorspoolFinalFlagSearcher(compile(pattern));
+                    }
+                  });
+  private SequenceMatcherCompiler compiler = new SequenceMatcherCompiler();
+
+  private SequenceMatcher compile(String pattern) throws CompileException {
+
+    return compiler.compile(pattern);
+  }
+
+  public boolean match(String pattern, byte[] data) throws ExecutionException {
+    if(pattern == null) {
+      return false;
+    }
+    Searcher<SequenceMatcher> searcher = sequenceMatchers.get(pattern);
+    if(data == null) {
+      return false;
+    }
+    else {
+      return !searcher.searchForwards(data).isEmpty();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bf2528fd/metron-platform/metron-pcap/src/test/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilterTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-pcap/src/test/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilterTest.java
b/metron-platform/metron-pcap/src/test/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilterTest.java
index b75b9c8..af2afd3 100644
--- a/metron-platform/metron-pcap/src/test/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilterTest.java
+++ b/metron-platform/metron-pcap/src/test/java/org/apache/metron/pcap/filter/fixed/FixedPcapFilterTest.java
@@ -22,7 +22,7 @@ import org.apache.metron.common.Constants;
 import org.junit.Assert;
 import org.junit.Test;
 
-import java.util.EnumMap;
+import java.util.LinkedHashMap;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 
@@ -30,12 +30,12 @@ public class FixedPcapFilterTest {
 
   @Test
   public void string_representation_of_query_gets_formatted() throws Exception {
-    final EnumMap<Constants.Fields, String> fields = new EnumMap<Constants.Fields,
String>(Constants.Fields.class) {{
-      put(Constants.Fields.SRC_ADDR, "src_ip");
-      put(Constants.Fields.SRC_PORT, "0");
-      put(Constants.Fields.DST_ADDR, "dst_ip");
-      put(Constants.Fields.DST_PORT, "1");
-      put(Constants.Fields.INCLUDES_REVERSE_TRAFFIC, "false");
+    final LinkedHashMap<String, String> fields = new LinkedHashMap<String, String>()
{{
+      put(Constants.Fields.SRC_ADDR.getName(), "src_ip");
+      put(Constants.Fields.SRC_PORT.getName(), "0");
+      put(Constants.Fields.DST_ADDR.getName(), "dst_ip");
+      put(Constants.Fields.DST_PORT.getName(), "1");
+      put(Constants.Fields.INCLUDES_REVERSE_TRAFFIC.getName(), "false");
     }};
     String actual = new FixedPcapFilter.Configurator().queryToString(fields);
     String expected = "src_ip_0_dst_ip_1_false";
@@ -45,7 +45,7 @@ public class FixedPcapFilterTest {
   @Test
   public void string_representation_of_empty_fields_empty() throws Exception {
     {
-      final EnumMap<Constants.Fields, String> fields = new EnumMap<Constants.Fields,
String>(Constants.Fields.class);
+      final LinkedHashMap<String, String> fields = new LinkedHashMap<String, String>();
       String actual = new FixedPcapFilter.Configurator().queryToString(fields);
       String expected = "";
       Assert.assertThat("string representation did not match", actual, equalTo(expected));
@@ -56,9 +56,9 @@ public class FixedPcapFilterTest {
       Assert.assertThat("string representation did not match", actual, equalTo(expected));
     }
     {
-      final EnumMap<Constants.Fields, String> fields = new EnumMap<Constants.Fields,
String>(Constants.Fields.class) {{
-        put(Constants.Fields.SRC_ADDR, "");
-        put(Constants.Fields.SRC_PORT, "");
+      final LinkedHashMap<String, String> fields = new LinkedHashMap<String, String>()
{{
+        put(Constants.Fields.SRC_ADDR.getName(), "");
+        put(Constants.Fields.SRC_PORT.getName(), "");
       }};
       String actual = new FixedPcapFilter.Configurator().queryToString(fields);
       String expected = "_";

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/bf2528fd/metron-platform/metron-pcap/src/test/java/org/apache/metron/pcap/pattern/ByteArrayMatchingUtilTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-pcap/src/test/java/org/apache/metron/pcap/pattern/ByteArrayMatchingUtilTest.java
b/metron-platform/metron-pcap/src/test/java/org/apache/metron/pcap/pattern/ByteArrayMatchingUtilTest.java
new file mode 100644
index 0000000..37b3f3f
--- /dev/null
+++ b/metron-platform/metron-pcap/src/test/java/org/apache/metron/pcap/pattern/ByteArrayMatchingUtilTest.java
@@ -0,0 +1,133 @@
+/**
+ * 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.metron.pcap.pattern;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.metron.common.utils.StellarProcessorUtils;
+import org.apache.metron.pcap.pattern.ByteArrayMatchingUtil;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import javax.xml.bind.DatatypeConverter;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Predicate;
+
+@RunWith(Parameterized.class)
+public class ByteArrayMatchingUtilTest {
+  public static byte[] DEADBEEF = new byte[] {(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte)
0xef};
+  public static byte[] DEADBEEF_DONUTHOLE = new byte[] {(byte) 0xde, (byte) 0xad, (byte)0x00,
(byte)0x00, (byte) 0xbe, (byte) 0xef};
+  public static byte[] ALLFS = new byte[] {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte)
0xff};
+  public static byte[] REALPACKET = DatatypeConverter.parseHexBinary("d4c3b2a1020004000000000000000000ffff0000010000000dfbea560923090062000000620000000a002700000008002796a47a0800451000547cdf40004006b7e9c0a84279c0a842010016d9ef129035948b92f427801801f5061200000101080a0014f5d511bdf9915bf6b70140db6d4fb551229ef07d2f56abd814bc56420489ca38e7faf8cec3d4");
+
+  interface Evaluator {
+    boolean evaluate(String pattern, byte[] data);
+  }
+
+  public enum EvaluationStrategy implements Evaluator{
+     STELLAR_WITH_VARIABLES((pattern, data) -> {
+       Map<String, Object> args = new HashMap<>();
+       args.put("pattern", pattern);
+       args.put("data", data);
+       return (boolean) StellarProcessorUtils.run("BYTEARRAY_MATCHER(pattern, data)" , args);
+     }
+            ),
+    STELLAR_WITH_PATTERN_STRING((pattern, data) -> {
+       Map<String, Object> args = new HashMap<>();
+       args.put("data", data);
+       return (boolean) StellarProcessorUtils.run(String.format("BYTEARRAY_MATCHER('%s',
data)", pattern) , args);
+     }
+            )
+    , UTIL((pattern, data) -> {
+      try {
+        return ByteArrayMatchingUtil.INSTANCE.match(pattern, data);
+      } catch (ExecutionException e) {
+        throw new IllegalArgumentException(e);
+      }
+    })
+    ;
+    Evaluator evaluator;
+    EvaluationStrategy(Evaluator evaluator) {
+      this.evaluator = evaluator;
+    }
+    @Override
+    public boolean evaluate(String pattern, byte[] data) {
+      return evaluator.evaluate(pattern, data);
+    }
+  }
+  private EvaluationStrategy strategy = null;
+  public ByteArrayMatchingUtilTest(EvaluationStrategy strategy) {
+    this.strategy = strategy;
+  }
+
+  @Parameterized.Parameters
+  public static Collection<Object[]> strategies() {
+    List<Object[]> strategies = new ArrayList<>();
+    for(EvaluationStrategy s : EvaluationStrategy.values()) {
+      strategies.add(new Object[] { s });
+    }
+    return strategies;
+  }
+
+  @Test
+  public void testStringMatch() throws ExecutionException {
+    Assert.assertTrue(strategy.evaluate("`metron`", "metron".getBytes()));
+    Assert.assertTrue(strategy.evaluate("`metron`", "metron example".getBytes()));
+    Assert.assertTrue(strategy.evaluate("`metron`", "edward metron example".getBytes()));
+    Assert.assertFalse(strategy.evaluate("`metron`", "apache".getBytes()));
+  }
+
+  @Test
+  public void testBytesMatch() throws ExecutionException {
+    Assert.assertTrue(strategy.evaluate("2f56abd814bc56420489ca38e7faf8cec3d4", REALPACKET));
+    Assert.assertTrue(strategy.evaluate("2f56..14bc56420489ca38e7faf8cec3d4", REALPACKET));
+    Assert.assertTrue(strategy.evaluate("(2f56)(.){2}(14bc56420489ca38e7faf8cec3d4)", REALPACKET));
+    Assert.assertFalse(strategy.evaluate("(3f56)(.){2}(14bc56420489ca38e7faf8cec3d4)", REALPACKET));
+    Assert.assertFalse(strategy.evaluate("3f56abd814bc56420489ca38e7faf8cec3d4", REALPACKET));
+    Assert.assertTrue(strategy.evaluate("deadbeef", join(DEADBEEF, "metron".getBytes())));
+    Assert.assertTrue(strategy.evaluate("deadbeef", join(DEADBEEF, "metron".getBytes())));
+    Assert.assertTrue(strategy.evaluate("deadbeef `metron`", join(DEADBEEF, "metron".getBytes())));
+    Assert.assertTrue(strategy.evaluate("deadbeef `metron`", join(DEADBEEF, "metronjones".getBytes())));
+    Assert.assertTrue(strategy.evaluate("deadbeef `metron`", join(DEADBEEF, "metronjones".getBytes(),
DEADBEEF)));
+    Assert.assertTrue(strategy.evaluate("([ff]){4}", ALLFS));
+    Assert.assertFalse(strategy.evaluate("([ff]){6}", ALLFS));
+    Assert.assertTrue(strategy.evaluate("[^ff]", new byte[] { (byte)0x00 }));
+    Assert.assertTrue(strategy.evaluate("&01", new byte[] { (byte)0x07 }));
+    Assert.assertFalse(strategy.evaluate("&01", new byte[] { (byte)0x00 }));
+    Assert.assertTrue(strategy.evaluate("&01", new byte[] { (byte)0x00, (byte)0x01 }));
+    Assert.assertTrue(strategy.evaluate("(dead).{2}(beef)", DEADBEEF_DONUTHOLE));
+  }
+
+  public byte[] join(byte[]... array) {
+    byte[] ret;
+    int size = 0;
+    for(int i = 0;i < array.length;++i) {
+      size += array[i].length;
+    }
+    ret = new byte[size];
+    int j = 0;
+    for(int i = 0;i < array.length;++i) {
+      for(int k = 0;k < array[i].length;++k,++j) {
+        ret[j] = array[i][k];
+      }
+    }
+    return ret;
+  }
+}


Mime
View raw message